diff options
Diffstat (limited to 'editeng/source')
119 files changed, 84949 insertions, 0 deletions
diff --git a/editeng/source/accessibility/AccessibleComponentBase.cxx b/editeng/source/accessibility/AccessibleComponentBase.cxx new file mode 100644 index 000000000000..dd4094a39d91 --- /dev/null +++ b/editeng/source/accessibility/AccessibleComponentBase.cxx @@ -0,0 +1,240 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleComponentBase.cxx,v $ + * $Revision: 1.17 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + + +#include <editeng/AccessibleComponentBase.hxx> + +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/drawing/XShapeDescriptor.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> + +#include <tools/color.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +namespace accessibility { + +//===== internal ============================================================ + +AccessibleComponentBase::AccessibleComponentBase (void) +{ +} + + + + +AccessibleComponentBase::~AccessibleComponentBase (void) +{ +} + + + + +//===== XAccessibleComponent ================================================ + +sal_Bool SAL_CALL AccessibleComponentBase::containsPoint ( + const ::com::sun::star::awt::Point& aPoint) + throw (::com::sun::star::uno::RuntimeException) +{ + awt::Size aSize (getSize()); + return (aPoint.X >= 0) + && (aPoint.X < aSize.Width) + && (aPoint.Y >= 0) + && (aPoint.Y < aSize.Height); +} + + + + +uno::Reference<XAccessible > SAL_CALL + AccessibleComponentBase::getAccessibleAtPoint ( + const awt::Point& /*aPoint*/) + throw (uno::RuntimeException) +{ + return uno::Reference<XAccessible>(); +} + + + + +awt::Rectangle SAL_CALL AccessibleComponentBase::getBounds (void) + throw (uno::RuntimeException) +{ + return awt::Rectangle(); +} + + + + +awt::Point SAL_CALL AccessibleComponentBase::getLocation (void) + throw (::com::sun::star::uno::RuntimeException) +{ + awt::Rectangle aBBox (getBounds()); + return awt::Point (aBBox.X, aBBox.Y); +} + + + + +awt::Point SAL_CALL AccessibleComponentBase::getLocationOnScreen (void) + throw (::com::sun::star::uno::RuntimeException) +{ + return awt::Point(); +} + + + + +::com::sun::star::awt::Size SAL_CALL AccessibleComponentBase::getSize (void) + throw (::com::sun::star::uno::RuntimeException) +{ + awt::Rectangle aBBox (getBounds()); + return awt::Size (aBBox.Width, aBBox.Height); +} + + + + +void SAL_CALL AccessibleComponentBase::addFocusListener ( + const ::com::sun::star::uno::Reference< + ::com::sun::star::awt::XFocusListener >& /*xListener*/) + throw (::com::sun::star::uno::RuntimeException) +{ + // Ignored +} + + + + +void SAL_CALL AccessibleComponentBase::removeFocusListener (const ::com::sun::star::uno::Reference< + ::com::sun::star::awt::XFocusListener >& /*xListener*/ ) + throw (::com::sun::star::uno::RuntimeException) +{ + // Ignored +} + + + + +void SAL_CALL AccessibleComponentBase::grabFocus (void) + throw (::com::sun::star::uno::RuntimeException) +{ + uno::Reference<XAccessibleContext> xContext (this, uno::UNO_QUERY); + uno::Reference<XAccessibleSelection> xSelection ( + xContext->getAccessibleParent(), uno::UNO_QUERY); + if (xSelection.is()) + { + // Do a single selection on this object. + xSelection->clearAccessibleSelection(); + xSelection->selectAccessibleChild (xContext->getAccessibleIndexInParent()); + } +} + + + + +sal_Int32 SAL_CALL AccessibleComponentBase::getForeground (void) + throw (::com::sun::star::uno::RuntimeException) +{ + return Color(COL_BLACK).GetColor(); +} + + + + +sal_Int32 SAL_CALL AccessibleComponentBase::getBackground (void) + throw (::com::sun::star::uno::RuntimeException) +{ + return Color(COL_WHITE).GetColor(); +} + + + + +//===== XAccessibleExtendedComponent ======================================== + +::com::sun::star::uno::Reference< ::com::sun::star::awt::XFont > SAL_CALL + AccessibleComponentBase::getFont (void) + throw (::com::sun::star::uno::RuntimeException) +{ + return uno::Reference<awt::XFont>(); +} + + + + +::rtl::OUString SAL_CALL AccessibleComponentBase::getTitledBorderText (void) + throw (::com::sun::star::uno::RuntimeException) +{ + return ::rtl::OUString::createFromAscii (""); +} + + + + +::rtl::OUString SAL_CALL AccessibleComponentBase::getToolTipText (void) + throw (::com::sun::star::uno::RuntimeException) +{ + return ::rtl::OUString::createFromAscii (""); +} + + + + +//===== XTypeProvider =================================================== + +uno::Sequence<uno::Type> SAL_CALL + AccessibleComponentBase::getTypes (void) + throw (uno::RuntimeException) +{ + // Get list of types from the context base implementation... + uno::Sequence<uno::Type> aTypeList (2); + // ...and add the additional type for the component. + const uno::Type aComponentType = + ::getCppuType((const uno::Reference<XAccessibleComponent>*)0); + const uno::Type aExtendedComponentType = + ::getCppuType((const uno::Reference<XAccessibleExtendedComponent>*)0); + aTypeList[0] = aComponentType; + aTypeList[1] = aExtendedComponentType; + + return aTypeList; +} + + +} // end of namespace accessibility diff --git a/editeng/source/accessibility/AccessibleContextBase.cxx b/editeng/source/accessibility/AccessibleContextBase.cxx new file mode 100644 index 000000000000..6af01a54a579 --- /dev/null +++ b/editeng/source/accessibility/AccessibleContextBase.cxx @@ -0,0 +1,718 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleContextBase.cxx,v $ + * $Revision: 1.28.144.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + + +#include <editeng/AccessibleContextBase.hxx> + +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> + +#include <unotools/accessiblestatesethelper.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <comphelper/accessibleeventnotifier.hxx> +#include <rtl/uuid.h> +#include <vos/mutex.hxx> +//#include <vcl/svapp.hxx> + +#include <utility> + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; +using ::com::sun::star::uno::Reference; + +namespace accessibility { + +//===== internal ============================================================ + +// Define a shortcut for the somewhot longish base class name. +typedef ::cppu::WeakComponentImplHelper4< + ::com::sun::star::accessibility::XAccessible, + ::com::sun::star::accessibility::XAccessibleContext, + ::com::sun::star::accessibility::XAccessibleEventBroadcaster, + ::com::sun::star::lang::XServiceInfo> BaseClass; + +AccessibleContextBase::AccessibleContextBase ( + const uno::Reference<XAccessible>& rxParent, + const sal_Int16 aRole) + : BaseClass (MutexOwner::maMutex), + mxStateSet (NULL), + mxRelationSet (NULL), + mxParent(rxParent), + msDescription(), + meDescriptionOrigin(NotSet), + msName(), + meNameOrigin(NotSet), + mnClientId(0), + maRole(aRole) +{ + // Create the state set. + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper (); + mxStateSet = pStateSet; + + // Set some states. Don't use the SetState method because no events + // shall be broadcastet (that is not yet initialized anyway). + if (pStateSet != NULL) + { + pStateSet->AddState (AccessibleStateType::ENABLED); + pStateSet->AddState (AccessibleStateType::SENSITIVE); + pStateSet->AddState (AccessibleStateType::SHOWING); + pStateSet->AddState (AccessibleStateType::VISIBLE); + pStateSet->AddState (AccessibleStateType::FOCUSABLE); + pStateSet->AddState (AccessibleStateType::SELECTABLE); + } + + // Create the relation set. + ::utl::AccessibleRelationSetHelper* pRelationSet = new ::utl::AccessibleRelationSetHelper (); + mxRelationSet = pRelationSet; +} + + + + +AccessibleContextBase::~AccessibleContextBase(void) +{ +} + + + + +sal_Bool AccessibleContextBase::SetState (sal_Int16 aState) +{ + ::osl::ClearableMutexGuard aGuard (maMutex); + ::utl::AccessibleStateSetHelper* pStateSet = + static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if ((pStateSet != NULL) && !pStateSet->contains(aState)) + { + pStateSet->AddState (aState); + // Clear the mutex guard so that it is not locked during calls to + // listeners. + aGuard.clear(); + + // Send event for all states except the DEFUNC state. + if (aState != AccessibleStateType::DEFUNC) + { + uno::Any aNewValue; + aNewValue <<= aState; + CommitChange( + AccessibleEventId::STATE_CHANGED, + aNewValue, + uno::Any()); + } + return sal_True; + } + else + return sal_False; +} + + + + +sal_Bool AccessibleContextBase::ResetState (sal_Int16 aState) +{ + ::osl::ClearableMutexGuard aGuard (maMutex); + ::utl::AccessibleStateSetHelper* pStateSet = + static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if ((pStateSet != NULL) && pStateSet->contains(aState)) + { + pStateSet->RemoveState (aState); + // Clear the mutex guard so that it is not locked during calls to listeners. + aGuard.clear(); + + uno::Any aOldValue; + aOldValue <<= aState; + CommitChange( + AccessibleEventId::STATE_CHANGED, + uno::Any(), + aOldValue); + return sal_True; + } + else + return sal_False; +} + + + + +sal_Bool AccessibleContextBase::GetState (sal_Int16 aState) +{ + ::osl::MutexGuard aGuard (maMutex); + ::utl::AccessibleStateSetHelper* pStateSet = + static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if (pStateSet != NULL) + return pStateSet->contains(aState); + else + // If there is no state set then return false as a default value. + return sal_False; +} + + + + +void AccessibleContextBase::SetRelationSet ( + const uno::Reference<XAccessibleRelationSet>& rxNewRelationSet) + throw (::com::sun::star::uno::RuntimeException) +{ + OSL_TRACE ("setting relation set"); + + // Try to emit some meaningfull events indicating differing relations in + // both sets. + typedef std::pair<short int,short int> RD; + const RD aRelationDescriptors[] = { + RD(AccessibleRelationType::CONTROLLED_BY, AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED), + RD(AccessibleRelationType::CONTROLLER_FOR, AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED), + RD(AccessibleRelationType::LABELED_BY, AccessibleEventId::LABELED_BY_RELATION_CHANGED), + RD(AccessibleRelationType::LABEL_FOR, AccessibleEventId::LABEL_FOR_RELATION_CHANGED), + RD(AccessibleRelationType::MEMBER_OF, AccessibleEventId::MEMBER_OF_RELATION_CHANGED), + RD(AccessibleRelationType::INVALID, -1), + }; + for (int i=0; aRelationDescriptors[i].first!=AccessibleRelationType::INVALID; i++) + if (mxRelationSet->containsRelation(aRelationDescriptors[i].first) + != rxNewRelationSet->containsRelation(aRelationDescriptors[i].first)) + CommitChange (aRelationDescriptors[i].second, uno::Any(), uno::Any()); + + mxRelationSet = rxNewRelationSet; +} + + + + +//===== XAccessible ========================================================= + +uno::Reference< XAccessibleContext> SAL_CALL + AccessibleContextBase::getAccessibleContext (void) + throw (uno::RuntimeException) +{ + ThrowIfDisposed (); + return this; +} + + + + +//===== XAccessibleContext ================================================== + +/** No children. +*/ +sal_Int32 SAL_CALL + AccessibleContextBase::getAccessibleChildCount (void) + throw (uno::RuntimeException) +{ + ThrowIfDisposed (); + return 0; +} + + + + +/** Forward the request to the shape. Return the requested shape or throw + an exception for a wrong index. +*/ +uno::Reference<XAccessible> SAL_CALL + AccessibleContextBase::getAccessibleChild (sal_Int32 nIndex) + throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + throw lang::IndexOutOfBoundsException ( + ::rtl::OUString::createFromAscii ("no child with index " + nIndex), + NULL); +} + + + + +uno::Reference<XAccessible> SAL_CALL + AccessibleContextBase::getAccessibleParent (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + return mxParent; +} + + + + +sal_Int32 SAL_CALL + AccessibleContextBase::getAccessibleIndexInParent (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + // Use a simple but slow solution for now. Optimize later. + + // Iterate over all the parent's children and search for this object. + if (mxParent.is()) + { + uno::Reference<XAccessibleContext> xParentContext ( + mxParent->getAccessibleContext()); + if (xParentContext.is()) + { + sal_Int32 nChildCount = xParentContext->getAccessibleChildCount(); + for (sal_Int32 i=0; i<nChildCount; i++) + { + uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i)); + if (xChild.is()) + { + uno::Reference<XAccessibleContext> xChildContext = xChild->getAccessibleContext(); + if (xChildContext == (XAccessibleContext*)this) + return i; + } + } + } + } + + // Return -1 to indicate that this object's parent does not know about the + // object. + return -1; +} + + + + +sal_Int16 SAL_CALL + AccessibleContextBase::getAccessibleRole (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + return maRole; +} + + + + +::rtl::OUString SAL_CALL + AccessibleContextBase::getAccessibleDescription (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + + return msDescription; +} + + + + +OUString SAL_CALL + AccessibleContextBase::getAccessibleName (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + + if (meNameOrigin == NotSet) + { + // Do not send an event because this is the first time it has been + // requested. + msName = CreateAccessibleName(); + meNameOrigin = AutomaticallyCreated; + } + + return msName; +} + + + + +/** Return a copy of the relation set. +*/ +uno::Reference<XAccessibleRelationSet> SAL_CALL + AccessibleContextBase::getAccessibleRelationSet (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + + // Create a copy of the relation set and return it. + ::utl::AccessibleRelationSetHelper* pRelationSet = + static_cast< ::utl::AccessibleRelationSetHelper*>(mxRelationSet.get()); + if (pRelationSet != NULL) + { + return uno::Reference<XAccessibleRelationSet> ( + new ::utl::AccessibleRelationSetHelper (*pRelationSet)); + } + else + return uno::Reference<XAccessibleRelationSet>(NULL); +} + + + + +/** Return a copy of the state set. + Possible states are: + ENABLED + SHOWING + VISIBLE +*/ +uno::Reference<XAccessibleStateSet> SAL_CALL + AccessibleContextBase::getAccessibleStateSet (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ::utl::AccessibleStateSetHelper* pStateSet = NULL; + + if (rBHelper.bDisposed) + { + // We are already disposed! + // Create a new state set that has only set the DEFUNC state. + pStateSet = new ::utl::AccessibleStateSetHelper (); + if (pStateSet != NULL) + pStateSet->AddState (AccessibleStateType::DEFUNC); + } + else + { + // Create a copy of the state set and return it. + pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + + // Merge current focused state from edit engine. +#if 0 + if (aState == AccessibleStateType::FOCUSED + && pStateSet != NULL + && mpText != NULL) + { + if (mpText->GetFocusedState ()) + pStateSet->AddState (aState); + else + pStateSet->RemoveState (aState); + } +#endif + if (pStateSet != NULL) + pStateSet = new ::utl::AccessibleStateSetHelper (*pStateSet); + } + + return uno::Reference<XAccessibleStateSet>(pStateSet); +} + + + + +lang::Locale SAL_CALL + AccessibleContextBase::getLocale (void) + throw (IllegalAccessibleComponentStateException, + ::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + // Delegate request to parent. + if (mxParent.is()) + { + uno::Reference<XAccessibleContext> xParentContext ( + mxParent->getAccessibleContext()); + if (xParentContext.is()) + return xParentContext->getLocale (); + } + + // No locale and no parent. Therefore throw exception to indicate this + // cluelessness. + throw IllegalAccessibleComponentStateException (); +} + + + + +//===== XAccessibleEventListener ============================================ + +void SAL_CALL + AccessibleContextBase::addEventListener ( + const uno::Reference<XAccessibleEventListener >& rxListener) + throw (uno::RuntimeException) +{ + if (rxListener.is()) + { + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + uno::Reference<uno::XInterface> x ((lang::XComponent *)this, uno::UNO_QUERY); + rxListener->disposing (lang::EventObject (x)); + } + else + { + if (!mnClientId) + mnClientId = comphelper::AccessibleEventNotifier::registerClient( ); + comphelper::AccessibleEventNotifier::addEventListener( mnClientId, rxListener ); + } + } +} + + + + +void SAL_CALL + AccessibleContextBase::removeEventListener ( + const uno::Reference<XAccessibleEventListener >& rxListener ) + throw (uno::RuntimeException) +{ + ThrowIfDisposed (); + if (rxListener.is()) + { + sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener ); + if ( !nListenerCount ) + { + // no listeners anymore + // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client), + // and at least to us not firing any events anymore, in case somebody calls + // NotifyAccessibleEvent, again + comphelper::AccessibleEventNotifier::revokeClient( mnClientId ); + mnClientId = 0; + } + } +} + + + + +//===== XServiceInfo ======================================================== + +::rtl::OUString SAL_CALL + AccessibleContextBase::getImplementationName (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleContextBase")); +} + + + + +sal_Bool SAL_CALL + AccessibleContextBase::supportsService (const OUString& sServiceName) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + // Iterate over all supported service names and return true if on of them + // matches the given name. + uno::Sequence< ::rtl::OUString> aSupportedServices ( + getSupportedServiceNames ()); + for (int i=0; i<aSupportedServices.getLength(); i++) + if (sServiceName == aSupportedServices[i]) + return sal_True; + return sal_False; +} + + + + +uno::Sequence< ::rtl::OUString> SAL_CALL + AccessibleContextBase::getSupportedServiceNames (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + static const OUString sServiceNames[2] = { + OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.accessibility.Accessible")), + OUString(RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.accessibility.AccessibleContext")) + }; + return uno::Sequence<OUString> (sServiceNames, 2); +} + + + + +//===== XTypeProvider ======================================================= + +uno::Sequence< ::com::sun::star::uno::Type> + AccessibleContextBase::getTypes (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + + // This class supports no interfaces on its own. Just return those + // supported by the base class. + return BaseClass::getTypes(); +} + + + + +uno::Sequence<sal_Int8> SAL_CALL + AccessibleContextBase::getImplementationId (void) + throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + static uno::Sequence<sal_Int8> aId; + if (aId.getLength() == 0) + { + ::osl::MutexGuard aGuard (maMutex); + aId.realloc (16); + rtl_createUuid ((sal_uInt8 *)aId.getArray(), 0, sal_True); + } + return aId; +} + + + + +//===== internal ============================================================ + +void SAL_CALL AccessibleContextBase::disposing (void) +{ + SetState (AccessibleStateType::DEFUNC); + + ::osl::MutexGuard aGuard (maMutex); + + // Send a disposing to all listeners. + if ( mnClientId ) + { + comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this ); + mnClientId = 0; + } +} + + + + +void AccessibleContextBase::SetAccessibleDescription ( + const ::rtl::OUString& rDescription, + StringOrigin eDescriptionOrigin) + throw (uno::RuntimeException) +{ + if (eDescriptionOrigin < meDescriptionOrigin + || (eDescriptionOrigin == meDescriptionOrigin && msDescription != rDescription)) + { + uno::Any aOldValue, aNewValue; + aOldValue <<= msDescription; + aNewValue <<= rDescription; + + msDescription = rDescription; + meDescriptionOrigin = eDescriptionOrigin; + + CommitChange( + AccessibleEventId::DESCRIPTION_CHANGED, + aNewValue, + aOldValue); + } +} + + + + +void AccessibleContextBase::SetAccessibleName ( + const ::rtl::OUString& rName, + StringOrigin eNameOrigin) + throw (uno::RuntimeException) +{ + if (eNameOrigin < meNameOrigin + || (eNameOrigin == meNameOrigin && msName != rName)) + { + uno::Any aOldValue, aNewValue; + aOldValue <<= msName; + aNewValue <<= rName; + + msName = rName; + meNameOrigin = eNameOrigin; + + CommitChange( + AccessibleEventId::NAME_CHANGED, + aNewValue, + aOldValue); + } +} + + + + +::rtl::OUString AccessibleContextBase::CreateAccessibleDescription (void) + throw (::com::sun::star::uno::RuntimeException) +{ + return ::rtl::OUString::createFromAscii ("Empty Description"); +} + + + + +::rtl::OUString AccessibleContextBase::CreateAccessibleName (void) + throw (::com::sun::star::uno::RuntimeException) +{ + return ::rtl::OUString::createFromAscii ("Empty Name"); +} + + + + +void AccessibleContextBase::CommitChange ( + sal_Int16 nEventId, + const uno::Any& rNewValue, + const uno::Any& rOldValue) +{ + // Do not call FireEvent and do not even create the event object when no + // listener has been registered yet. Creating the event object can + // otherwise lead to a crash. See issue 93419 for details. + if (mnClientId != 0) + { + AccessibleEventObject aEvent ( + static_cast<XAccessibleContext*>(this), + nEventId, + rNewValue, + rOldValue); + + FireEvent (aEvent); + } +} + + + + +void AccessibleContextBase::FireEvent (const AccessibleEventObject& aEvent) +{ + if (mnClientId) + comphelper::AccessibleEventNotifier::addEvent( mnClientId, aEvent ); +} + + + + +void AccessibleContextBase::ThrowIfDisposed (void) + throw (::com::sun::star::lang::DisposedException) +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + OSL_TRACE ("Calling disposed object. Throwing exception:"); + throw lang::DisposedException ( + OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), + static_cast<uno::XWeak*>(this)); + } +} + + + +sal_Bool AccessibleContextBase::IsDisposed (void) +{ + return (rBHelper.bDisposed || rBHelper.bInDispose); +} + + + +void AccessibleContextBase::SetAccessibleRole( sal_Int16 _nRole ) +{ + maRole = _nRole; +} + + +} // end of namespace accessibility diff --git a/editeng/source/accessibility/AccessibleEditableTextPara.cxx b/editeng/source/accessibility/AccessibleEditableTextPara.cxx new file mode 100644 index 000000000000..141dc19af7c1 --- /dev/null +++ b/editeng/source/accessibility/AccessibleEditableTextPara.cxx @@ -0,0 +1,2204 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleEditableTextPara.cxx,v $ + * $Revision: 1.53 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +//------------------------------------------------------------------------ +// +// Global header +// +//------------------------------------------------------------------------ + +#include <limits.h> +#include <vector> +#include <algorithm> +#include <vos/mutex.hxx> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleTextType.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <comphelper/accessibleeventnotifier.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <unotools/accessiblestatesethelper.hxx> + +// --> OD 2006-01-11 #i27138# +#include <unotools/accessiblerelationsethelper.hxx> +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +// <-- +#include <vcl/unohelp.hxx> +#include <editeng/editeng.hxx> +#include <editeng/unoprnms.hxx> +#include <editeng/unoipset.hxx> +#include <editeng/outliner.hxx> + +//------------------------------------------------------------------------ +// +// Project-local header +// +//------------------------------------------------------------------------ + +#include <com/sun/star/beans/PropertyState.hpp> +#include <editeng/unolingu.hxx> +#include <editeng/unopracc.hxx> +#include "editeng/AccessibleEditableTextPara.hxx" +#include <svtools/colorcfg.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::accessibility; + + +//------------------------------------------------------------------------ +// +// AccessibleEditableTextPara implementation +// +//------------------------------------------------------------------------ + +namespace accessibility +{ + + const SvxItemPropertySet* ImplGetSvxCharAndParaPropertiesSet() + { + // PropertyMap for character and paragraph properties + static const SfxItemPropertyMapEntry aPropMap[] = + { + SVX_UNOEDIT_CHAR_PROPERTIES, + SVX_UNOEDIT_PARA_PROPERTIES, + SVX_UNOEDIT_NUMBERING_PROPERTIE, + {MAP_CHAR_LEN("TextUserDefinedAttributes"), EE_CHAR_XMLATTRIBS, &::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >*)0) , 0, 0}, + {MAP_CHAR_LEN("ParaUserDefinedAttributes"), EE_PARA_XMLATTRIBS, &::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >*)0) , 0, 0}, + {0,0,0,0,0,0} + }; + static SvxItemPropertySet aPropSet( aPropMap, EditEngine::GetGlobalItemPool() ); + return &aPropSet; + } + + + DBG_NAME( AccessibleEditableTextPara ) + + // --> OD 2006-01-11 #i27138# - add parameter <_pParaManager> + AccessibleEditableTextPara::AccessibleEditableTextPara( + const uno::Reference< XAccessible >& rParent, + const AccessibleParaManager* _pParaManager ) + : AccessibleTextParaInterfaceBase( m_aMutex ), + mnParagraphIndex( 0 ), + mnIndexInParent( 0 ), + mpEditSource( NULL ), + maEEOffset( 0, 0 ), + mxParent( rParent ), + // well, that's strictly (UNO) exception safe, though not + // really robust. We rely on the fact that this member is + // constructed last, and that the constructor body catches + // exceptions, thus no chance for exceptions once the Id is + // fetched. Nevertheless, normally should employ RAII here... + mnNotifierClientId(::comphelper::AccessibleEventNotifier::registerClient()), + // --> OD 2006-01-11 #i27138# + mpParaManager( _pParaManager ) + // <-- + { +#ifdef DBG_UTIL + DBG_CTOR( AccessibleEditableTextPara, NULL ); + OSL_TRACE( "AccessibleEditableTextPara received ID: %d\n", mnNotifierClientId ); +#endif + + try + { + // Create the state set. + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper (); + mxStateSet = pStateSet; + + // these are always on + pStateSet->AddState( AccessibleStateType::MULTI_LINE ); + pStateSet->AddState( AccessibleStateType::FOCUSABLE ); + pStateSet->AddState( AccessibleStateType::VISIBLE ); + pStateSet->AddState( AccessibleStateType::SHOWING ); + pStateSet->AddState( AccessibleStateType::ENABLED ); + pStateSet->AddState( AccessibleStateType::SENSITIVE ); + } + catch( const uno::Exception& ) {} + } + + AccessibleEditableTextPara::~AccessibleEditableTextPara() + { + DBG_DTOR( AccessibleEditableTextPara, NULL ); + + // sign off from event notifier + if( getNotifierClientId() != -1 ) + { + try + { + ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() ); +#ifdef DBG_UTIL + OSL_TRACE( "AccessibleEditableTextPara revoked ID: %d\n", mnNotifierClientId ); +#endif + } + catch( const uno::Exception& ) {} + } + } + + ::rtl::OUString AccessibleEditableTextPara::implGetText() + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return GetTextRange( 0, GetTextLen() ); + } + + ::com::sun::star::lang::Locale AccessibleEditableTextPara::implGetLocale() + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + lang::Locale aLocale; + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getLocale: paragraph index value overflow"); + + // return locale of first character in the paragraph + return SvxLanguageToLocale(aLocale, GetTextForwarder().GetLanguage( static_cast< USHORT >( GetParagraphIndex() ), 0 )); + } + + void AccessibleEditableTextPara::implGetSelection( sal_Int32& nStartIndex, sal_Int32& nEndIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + USHORT nStart, nEnd; + + if( GetSelection( nStart, nEnd ) ) + { + nStartIndex = nStart; + nEndIndex = nEnd; + } + else + { + // #102234# No exception, just set to 'invalid' + nStartIndex = -1; + nEndIndex = -1; + } + } + + void AccessibleEditableTextPara::implGetParagraphBoundary( ::com::sun::star::i18n::Boundary& rBoundary, sal_Int32 /*nIndex*/ ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + DBG_WARNING( "AccessibleEditableTextPara::implGetParagraphBoundary: only a base implementation, ignoring the index" ); + + rBoundary.startPos = 0; + rBoundary.endPos = GetTextLen(); + } + + void AccessibleEditableTextPara::implGetLineBoundary( ::com::sun::star::i18n::Boundary& rBoundary, sal_Int32 nIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + SvxTextForwarder& rCacheTF = GetTextForwarder(); + const sal_Int32 nParaIndex = GetParagraphIndex(); + + DBG_ASSERT(nParaIndex >= 0 && nParaIndex <= USHRT_MAX, + "AccessibleEditableTextPara::implGetLineBoundary: paragraph index value overflow"); + + const sal_Int32 nTextLen = rCacheTF.GetTextLen( static_cast< USHORT >( nParaIndex ) ); + + CheckPosition(nIndex); + + rBoundary.startPos = rBoundary.endPos = -1; + + const USHORT nLineCount=rCacheTF.GetLineCount( static_cast< USHORT >( nParaIndex ) ); + + if( nIndex == nTextLen ) + { + // #i17014# Special-casing one-behind-the-end character + if( nLineCount <= 1 ) + rBoundary.startPos = 0; + else + rBoundary.startPos = nTextLen - rCacheTF.GetLineLen( static_cast< USHORT >( nParaIndex ), + nLineCount-1 ); + + rBoundary.endPos = nTextLen; + } + else + { + // normal line search + USHORT nLine; + sal_Int32 nCurIndex; + for( nLine=0, nCurIndex=0; nLine<nLineCount; ++nLine ) + { + nCurIndex += rCacheTF.GetLineLen( static_cast< USHORT >( nParaIndex ), nLine); + + if( nCurIndex > nIndex ) + { + rBoundary.startPos = nCurIndex - rCacheTF.GetLineLen(static_cast< USHORT >( nParaIndex ), nLine); + rBoundary.endPos = nCurIndex; + break; + } + } + } + } + + int AccessibleEditableTextPara::getNotifierClientId() const + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return mnNotifierClientId; + } + + void AccessibleEditableTextPara::SetIndexInParent( sal_Int32 nIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + mnIndexInParent = nIndex; + } + + sal_Int32 AccessibleEditableTextPara::GetIndexInParent() const + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return mnIndexInParent; + } + + void AccessibleEditableTextPara::SetParagraphIndex( sal_Int32 nIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + sal_Int32 nOldIndex = mnParagraphIndex; + + mnParagraphIndex = nIndex; + + WeakBullet::HardRefType aChild( maImageBullet.get() ); + if( aChild.is() ) + aChild->SetParagraphIndex(mnParagraphIndex); + + try + { + if( nOldIndex != nIndex ) + { + uno::Any aOldDesc; + uno::Any aOldName; + + try + { + aOldDesc <<= getAccessibleDescription(); + aOldName <<= getAccessibleName(); + } + catch( const uno::Exception& ) {} // optional behaviour + // index and therefore description changed + FireEvent( AccessibleEventId::DESCRIPTION_CHANGED, uno::makeAny( getAccessibleDescription() ), aOldDesc ); + FireEvent( AccessibleEventId::NAME_CHANGED, uno::makeAny( getAccessibleName() ), aOldName ); + } + } + catch( const uno::Exception& ) {} // optional behaviour + } + + sal_Int32 AccessibleEditableTextPara::GetParagraphIndex() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return mnParagraphIndex; + } + + void AccessibleEditableTextPara::Dispose() + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + int nClientId( getNotifierClientId() ); + + // #108212# drop all references before notifying dispose + mxParent = NULL; + mnNotifierClientId = -1; + mpEditSource = NULL; + + // notify listeners + if( nClientId != -1 ) + { + try + { + uno::Reference < XAccessibleContext > xThis = getAccessibleContext(); + + // #106234# Delegate to EventNotifier + ::comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nClientId, xThis ); +#ifdef DBG_UTIL + OSL_TRACE( "Disposed ID: %d\n", nClientId ); +#endif + } + catch( const uno::Exception& ) {} + } + } + + void AccessibleEditableTextPara::SetEditSource( SvxEditSourceAdapter* pEditSource ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + mpEditSource = pEditSource; + + WeakBullet::HardRefType aChild( maImageBullet.get() ); + if( aChild.is() ) + aChild->SetEditSource(pEditSource); + + if( !mpEditSource ) + { + // going defunc + UnSetState( AccessibleStateType::SHOWING ); + UnSetState( AccessibleStateType::VISIBLE ); + SetState( AccessibleStateType::INVALID ); + SetState( AccessibleStateType::DEFUNC ); + + Dispose(); + } + + // #108900# Init last text content + try + { + TextChanged(); + } + catch( const uno::RuntimeException& ) {} + } + + ESelection AccessibleEditableTextPara::MakeSelection( sal_Int32 nStartEEIndex, sal_Int32 nEndEEIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + // check overflow + DBG_ASSERT(nStartEEIndex >= 0 && nStartEEIndex <= USHRT_MAX && + nEndEEIndex >= 0 && nEndEEIndex <= USHRT_MAX && + GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::MakeSelection: index value overflow"); + + USHORT nParaIndex = static_cast< USHORT >( GetParagraphIndex() ); + return ESelection( nParaIndex, static_cast< USHORT >( nStartEEIndex ), + nParaIndex, static_cast< USHORT >( nEndEEIndex ) ); + } + + ESelection AccessibleEditableTextPara::MakeSelection( sal_Int32 nEEIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return MakeSelection( nEEIndex, nEEIndex+1 ); + } + + ESelection AccessibleEditableTextPara::MakeCursor( sal_Int32 nEEIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return MakeSelection( nEEIndex, nEEIndex ); + } + + void AccessibleEditableTextPara::CheckIndex( sal_Int32 nIndex ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + if( nIndex < 0 || nIndex >= getCharacterCount() ) + throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleEditableTextPara: character index out of bounds")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > (this) ) ); // disambiguate hierarchy + } + + void AccessibleEditableTextPara::CheckPosition( sal_Int32 nIndex ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + if( nIndex < 0 || nIndex > getCharacterCount() ) + throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleEditableTextPara: character position out of bounds")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > (this) ) ); // disambiguate hierarchy + } + + void AccessibleEditableTextPara::CheckRange( sal_Int32 nStart, sal_Int32 nEnd ) SAL_THROW((lang::IndexOutOfBoundsException, uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + CheckPosition( nStart ); + CheckPosition( nEnd ); + } + + sal_Bool AccessibleEditableTextPara::GetSelection( USHORT& nStartPos, USHORT& nEndPos ) SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ESelection aSelection; + USHORT nPara = static_cast< USHORT > ( GetParagraphIndex() ); + if( !GetEditViewForwarder().GetSelection( aSelection ) ) + return sal_False; + + if( aSelection.nStartPara < aSelection.nEndPara ) + { + if( aSelection.nStartPara > nPara || + aSelection.nEndPara < nPara ) + return sal_False; + + if( nPara == aSelection.nStartPara ) + nStartPos = aSelection.nStartPos; + else + nStartPos = 0; + + if( nPara == aSelection.nEndPara ) + nEndPos = aSelection.nEndPos; + else + nEndPos = GetTextLen(); + } + else + { + if( aSelection.nStartPara < nPara || + aSelection.nEndPara > nPara ) + return sal_False; + + if( nPara == aSelection.nStartPara ) + nStartPos = aSelection.nStartPos; + else + nStartPos = GetTextLen(); + + if( nPara == aSelection.nEndPara ) + nEndPos = aSelection.nEndPos; + else + nEndPos = 0; + } + + return sal_True; + } + + String AccessibleEditableTextPara::GetText( sal_Int32 nIndex ) SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return GetTextForwarder().GetText( MakeSelection(nIndex) ); + } + + String AccessibleEditableTextPara::GetTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return GetTextForwarder().GetText( MakeSelection(nStartIndex, nEndIndex) ); + } + + USHORT AccessibleEditableTextPara::GetTextLen() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return GetTextForwarder().GetTextLen( static_cast< USHORT >( GetParagraphIndex() ) ); + } + + sal_Bool AccessibleEditableTextPara::IsVisible() const + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return mpEditSource ? sal_True : sal_False ; + } + + uno::Reference< XAccessibleText > AccessibleEditableTextPara::GetParaInterface( sal_Int32 nIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + uno::Reference< XAccessible > xParent = getAccessibleParent(); + if( xParent.is() ) + { + uno::Reference< XAccessibleContext > xParentContext = xParent->getAccessibleContext(); + if( xParentContext.is() ) + { + uno::Reference< XAccessible > xPara = xParentContext->getAccessibleChild( nIndex ); + if( xPara.is() ) + return uno::Reference< XAccessibleText > ( xPara, uno::UNO_QUERY ); + } + } + + return uno::Reference< XAccessibleText >(); + } + + SvxEditSourceAdapter& AccessibleEditableTextPara::GetEditSource() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + if( mpEditSource ) + return *mpEditSource; + else + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No edit source, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + } + + SvxAccessibleTextAdapter& AccessibleEditableTextPara::GetTextForwarder() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + SvxEditSourceAdapter& rEditSource = GetEditSource(); + SvxAccessibleTextAdapter* pTextForwarder = rEditSource.GetTextForwarderAdapter(); + + if( !pTextForwarder ) + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch text forwarder, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + + if( pTextForwarder->IsValid() ) + return *pTextForwarder; + else + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Text forwarder is invalid, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + } + + SvxViewForwarder& AccessibleEditableTextPara::GetViewForwarder() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + SvxEditSource& rEditSource = GetEditSource(); + SvxViewForwarder* pViewForwarder = rEditSource.GetViewForwarder(); + + if( !pViewForwarder ) + { + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch view forwarder, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + } + + if( pViewForwarder->IsValid() ) + return *pViewForwarder; + else + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + } + + SvxAccessibleTextEditViewAdapter& AccessibleEditableTextPara::GetEditViewForwarder( sal_Bool bCreate ) const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + SvxEditSourceAdapter& rEditSource = GetEditSource(); + SvxAccessibleTextEditViewAdapter* pTextEditViewForwarder = rEditSource.GetEditViewForwarderAdapter( bCreate ); + + if( !pTextEditViewForwarder ) + { + if( bCreate ) + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch view forwarder, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + else + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No view forwarder, object not in edit mode")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + } + + if( pTextEditViewForwarder->IsValid() ) + return *pTextEditViewForwarder; + else + { + if( bCreate ) + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + else + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, object not in edit mode")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleEditableTextPara* > (this) ) ) ); // disambiguate hierarchy + } + } + + sal_Bool AccessibleEditableTextPara::HaveEditView() const + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + SvxEditSource& rEditSource = GetEditSource(); + SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder(); + + if( !pViewForwarder ) + return sal_False; + + if( !pViewForwarder->IsValid() ) + return sal_False; + + return sal_True; + } + + sal_Bool AccessibleEditableTextPara::HaveChildren() + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::HaveChildren: paragraph index value overflow"); + + return GetTextForwarder().HaveImageBullet( static_cast< USHORT >(GetParagraphIndex()) ); + } + + sal_Bool AccessibleEditableTextPara::IsActive() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + SvxEditSource& rEditSource = GetEditSource(); + SvxEditViewForwarder* pViewForwarder = rEditSource.GetEditViewForwarder(); + + if( !pViewForwarder ) + return sal_False; + + if( pViewForwarder->IsValid() ) + return sal_False; + else + return sal_True; + } + + Rectangle AccessibleEditableTextPara::LogicToPixel( const Rectangle& rRect, const MapMode& rMapMode, SvxViewForwarder& rForwarder ) + { + // convert to screen coordinates + return Rectangle( rForwarder.LogicToPixel( rRect.TopLeft(), rMapMode ), + rForwarder.LogicToPixel( rRect.BottomRight(), rMapMode ) ); + } + + const Point& AccessibleEditableTextPara::GetEEOffset() const + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return maEEOffset; + } + + void AccessibleEditableTextPara::SetEEOffset( const Point& rOffset ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + WeakBullet::HardRefType aChild( maImageBullet.get() ); + if( aChild.is() ) + aChild->SetEEOffset(rOffset); + + maEEOffset = rOffset; + } + + void AccessibleEditableTextPara::FireEvent(const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue) const + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + uno::Reference < XAccessibleContext > xThis( const_cast< AccessibleEditableTextPara* > (this)->getAccessibleContext() ); + + AccessibleEventObject aEvent(xThis, nEventId, rNewValue, rOldValue); + + // #102261# Call global queue for focus events + if( nEventId == AccessibleEventId::STATE_CHANGED ) + vcl::unohelper::NotifyAccessibleStateEventGlobally( aEvent ); + + // #106234# Delegate to EventNotifier + if( getNotifierClientId() != -1 ) + ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(), + aEvent ); + } + + void AccessibleEditableTextPara::GotPropertyEvent( const uno::Any& rNewValue, const sal_Int16 nEventId ) const + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + FireEvent( nEventId, rNewValue ); + } + + void AccessibleEditableTextPara::LostPropertyEvent( const uno::Any& rOldValue, const sal_Int16 nEventId ) const + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + FireEvent( nEventId, uno::Any(), rOldValue ); + } + + bool AccessibleEditableTextPara::HasState( const sal_Int16 nStateId ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if( pStateSet != NULL ) + return pStateSet->contains(nStateId) ? true : false; + + return false; + } + + void AccessibleEditableTextPara::SetState( const sal_Int16 nStateId ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if( pStateSet != NULL && + !pStateSet->contains(nStateId) ) + { + pStateSet->AddState( nStateId ); + GotPropertyEvent( uno::makeAny( nStateId ), AccessibleEventId::STATE_CHANGED ); + } + } + + void AccessibleEditableTextPara::UnSetState( const sal_Int16 nStateId ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if( pStateSet != NULL && + pStateSet->contains(nStateId) ) + { + pStateSet->RemoveState( nStateId ); + LostPropertyEvent( uno::makeAny( nStateId ), AccessibleEventId::STATE_CHANGED ); + } + } + + void AccessibleEditableTextPara::TextChanged() + { + ::rtl::OUString aCurrentString( OCommonAccessibleText::getText() ); + uno::Any aDeleted; + uno::Any aInserted; + if( OCommonAccessibleText::implInitTextChangedEvent( maLastTextString, aCurrentString, + aDeleted, aInserted) ) + { + FireEvent( AccessibleEventId::TEXT_CHANGED, aInserted, aDeleted ); + maLastTextString = aCurrentString; + } + } + + sal_Bool AccessibleEditableTextPara::GetAttributeRun( USHORT& nStartIndex, USHORT& nEndIndex, sal_Int32 nIndex ) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + DBG_ASSERT(nIndex >= 0 && nIndex <= USHRT_MAX, + "AccessibleEditableTextPara::GetAttributeRun: index value overflow"); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getLocale: paragraph index value overflow"); + + return GetTextForwarder().GetAttributeRun( nStartIndex, + nEndIndex, + static_cast< USHORT >(GetParagraphIndex()), + static_cast< USHORT >(nIndex) ); + } + + uno::Any SAL_CALL AccessibleEditableTextPara::queryInterface (const uno::Type & rType) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + uno::Any aRet; + + // must provide XAccesibleText by hand, since it comes publicly inherited by XAccessibleEditableText + if ( rType == ::getCppuType((uno::Reference< XAccessibleText > *)0) ) + { + uno::Reference< XAccessibleText > aAccText = static_cast< XAccessibleEditableText * >(this); + aRet <<= aAccText; + } + else if ( rType == ::getCppuType((uno::Reference< XAccessibleEditableText > *)0) ) + { + uno::Reference< XAccessibleEditableText > aAccEditText = this; + aRet <<= aAccEditText; + } + else + { + aRet = AccessibleTextParaInterfaceBase::queryInterface(rType); + } + + return aRet; + } + + // XAccessible + uno::Reference< XAccessibleContext > SAL_CALL AccessibleEditableTextPara::getAccessibleContext() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + // We implement the XAccessibleContext interface in the same object + return uno::Reference< XAccessibleContext > ( this ); + } + + // XAccessibleContext + sal_Int32 SAL_CALL AccessibleEditableTextPara::getAccessibleChildCount() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + return HaveChildren() ? 1 : 0; + } + + uno::Reference< XAccessible > SAL_CALL AccessibleEditableTextPara::getAccessibleChild( sal_Int32 i ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if( !HaveChildren() ) + throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No childs available")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > (this) ) ); // static_cast: disambiguate hierarchy + + if( i != 0 ) + throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Invalid child index")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > (this) ) ); // static_cast: disambiguate hierarchy + + WeakBullet::HardRefType aChild( maImageBullet.get() ); + + if( !aChild.is() ) + { + // there is no hard reference available, create object then + AccessibleImageBullet* pChild = new AccessibleImageBullet( uno::Reference< XAccessible >( this ) ); + uno::Reference< XAccessible > xChild( static_cast< ::cppu::OWeakObject* > (pChild), uno::UNO_QUERY ); + + if( !xChild.is() ) + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Child creation failed")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > (this) ) ); + + aChild = WeakBullet::HardRefType( xChild, pChild ); + + aChild->SetEditSource( &GetEditSource() ); + aChild->SetParagraphIndex( GetParagraphIndex() ); + aChild->SetIndexInParent( i ); + + maImageBullet = aChild; + } + + return aChild.getRef(); + } + + uno::Reference< XAccessible > SAL_CALL AccessibleEditableTextPara::getAccessibleParent() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + +#ifdef DBG_UTIL + if( !mxParent.is() ) + DBG_TRACE( "AccessibleEditableTextPara::getAccessibleParent: no frontend set, did somebody forgot to call AccessibleTextHelper::SetEventSource()?"); +#endif + + return mxParent; + } + + sal_Int32 SAL_CALL AccessibleEditableTextPara::getAccessibleIndexInParent() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return mnIndexInParent; + } + + sal_Int16 SAL_CALL AccessibleEditableTextPara::getAccessibleRole() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return AccessibleRole::PARAGRAPH; + } + + ::rtl::OUString SAL_CALL AccessibleEditableTextPara::getAccessibleDescription() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + +// ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + return ::rtl::OUString(); + } + + ::rtl::OUString SAL_CALL AccessibleEditableTextPara::getAccessibleName() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + +// ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + return ::rtl::OUString(); + } + + uno::Reference< XAccessibleRelationSet > SAL_CALL AccessibleEditableTextPara::getAccessibleRelationSet() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + // --> OD 2006-01-11 #i27138# - provide relations CONTENT_FLOWS_FROM + // and CONTENT_FLOWS_TO + if ( mpParaManager ) + { + utl::AccessibleRelationSetHelper* pAccRelSetHelper = + new utl::AccessibleRelationSetHelper(); + sal_Int32 nMyParaIndex( GetParagraphIndex() ); + // relation CONTENT_FLOWS_FROM + if ( nMyParaIndex > 0 && + mpParaManager->IsReferencable( nMyParaIndex - 1 ) ) + { + uno::Sequence<uno::Reference<XInterface> > aSequence(1); + aSequence[0] = + mpParaManager->GetChild( nMyParaIndex - 1 ).first.get().getRef(); + AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_FROM, + aSequence ); + pAccRelSetHelper->AddRelation( aAccRel ); + } + + // relation CONTENT_FLOWS_TO + if ( (nMyParaIndex + 1) < (sal_Int32)mpParaManager->GetNum() && + mpParaManager->IsReferencable( nMyParaIndex + 1 ) ) + { + uno::Sequence<uno::Reference<XInterface> > aSequence(1); + aSequence[0] = + mpParaManager->GetChild( nMyParaIndex + 1 ).first.get().getRef(); + AccessibleRelation aAccRel( AccessibleRelationType::CONTENT_FLOWS_TO, + aSequence ); + pAccRelSetHelper->AddRelation( aAccRel ); + } + + return pAccRelSetHelper; + } + else + { + // no relations, therefore empty + return uno::Reference< XAccessibleRelationSet >(); + } + // <-- + } + + uno::Reference< XAccessibleStateSet > SAL_CALL AccessibleEditableTextPara::getAccessibleStateSet() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // Create a copy of the state set and return it. + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + + if( !pStateSet ) + return uno::Reference<XAccessibleStateSet>(); + + return uno::Reference<XAccessibleStateSet>( new ::utl::AccessibleStateSetHelper (*pStateSet) ); + } + + lang::Locale SAL_CALL AccessibleEditableTextPara::getLocale() throw (IllegalAccessibleComponentStateException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + return implGetLocale(); + } + + void SAL_CALL AccessibleEditableTextPara::addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + if( getNotifierClientId() != -1 ) + ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener ); + } + + void SAL_CALL AccessibleEditableTextPara::removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + if( getNotifierClientId() != -1 ) + ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener ); + } + + // XAccessibleComponent + sal_Bool SAL_CALL AccessibleEditableTextPara::containsPoint( const awt::Point& aTmpPoint ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::contains: index value overflow"); + + awt::Rectangle aTmpRect = getBounds(); + Rectangle aRect( Point(aTmpRect.X, aTmpRect.Y), Size(aTmpRect.Width, aTmpRect.Height) ); + Point aPoint( aTmpPoint.X, aTmpPoint.Y ); + + return aRect.IsInside( aPoint ); + } + + uno::Reference< XAccessible > SAL_CALL AccessibleEditableTextPara::getAccessibleAtPoint( const awt::Point& _aPoint ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if( HaveChildren() ) + { + // #103862# No longer need to make given position relative + Point aPoint( _aPoint.X, _aPoint.Y ); + + // respect EditEngine offset to surrounding shape/cell + aPoint -= GetEEOffset(); + + // convert to EditEngine coordinate system + SvxTextForwarder& rCacheTF = GetTextForwarder(); + Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) ); + + EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo( static_cast< USHORT > (GetParagraphIndex()) ); + + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType == SVX_NUM_BITMAP ) + { + Rectangle aRect = aBulletInfo.aBounds; + + if( aRect.IsInside( aLogPoint ) ) + return getAccessibleChild(0); + } + } + + // no children at all, or none at given position + return uno::Reference< XAccessible >(); + } + + awt::Rectangle SAL_CALL AccessibleEditableTextPara::getBounds() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getBounds: index value overflow"); + + SvxTextForwarder& rCacheTF = GetTextForwarder(); + Rectangle aRect = rCacheTF.GetParaBounds( static_cast< USHORT >( GetParagraphIndex() ) ); + + // convert to screen coordinates + Rectangle aScreenRect = AccessibleEditableTextPara::LogicToPixel( aRect, + rCacheTF.GetMapMode(), + GetViewForwarder() ); + + // offset from shape/cell + Point aOffset = GetEEOffset(); + + return awt::Rectangle( aScreenRect.Left() + aOffset.X(), + aScreenRect.Top() + aOffset.Y(), + aScreenRect.GetSize().Width(), + aScreenRect.GetSize().Height() ); + } + + awt::Point SAL_CALL AccessibleEditableTextPara::getLocation( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + awt::Rectangle aRect = getBounds(); + + return awt::Point( aRect.X, aRect.Y ); + } + + awt::Point SAL_CALL AccessibleEditableTextPara::getLocationOnScreen( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // relate us to parent + uno::Reference< XAccessible > xParent = getAccessibleParent(); + if( xParent.is() ) + { + uno::Reference< XAccessibleComponent > xParentComponent( xParent, uno::UNO_QUERY ); + if( xParentComponent.is() ) + { + awt::Point aRefPoint = xParentComponent->getLocationOnScreen(); + awt::Point aPoint = getLocation(); + aPoint.X += aRefPoint.X; + aPoint.Y += aRefPoint.Y; + + return aPoint; + } + } + + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Cannot access parent")), + uno::Reference< uno::XInterface > + ( static_cast< XAccessible* > (this) ) ); // disambiguate hierarchy + } + + awt::Size SAL_CALL AccessibleEditableTextPara::getSize( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + awt::Rectangle aRect = getBounds(); + + return awt::Size( aRect.Width, aRect.Height ); + } + + void SAL_CALL AccessibleEditableTextPara::grabFocus( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + // set cursor to this paragraph + setSelection(0,0); + } + + sal_Int32 SAL_CALL AccessibleEditableTextPara::getForeground( ) throw (::com::sun::star::uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + // #104444# Added to XAccessibleComponent interface + svtools::ColorConfig aColorConfig; + UINT32 nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor; + return static_cast<sal_Int32>(nColor); + } + + sal_Int32 SAL_CALL AccessibleEditableTextPara::getBackground( ) throw (::com::sun::star::uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + // #104444# Added to XAccessibleComponent interface + Color aColor( Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor() ); + + // the background is transparent + aColor.SetTransparency( 0xFF); + + return static_cast<sal_Int32>( aColor.GetColor() ); + } + + // XAccessibleText + sal_Int32 SAL_CALL AccessibleEditableTextPara::getCaretPosition() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if( !HaveEditView() ) + return -1; + + ESelection aSelection; + if( GetEditViewForwarder().GetSelection( aSelection ) && + GetParagraphIndex() == aSelection.nEndPara ) + { + // caret is always nEndPara,nEndPos + return aSelection.nEndPos; + } + + // not within this paragraph + return -1; + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return setSelection(nIndex, nIndex); + } + + sal_Unicode SAL_CALL AccessibleEditableTextPara::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getCharacter: index value overflow"); + + return OCommonAccessibleText::getCharacter( nIndex ); + } + + uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleEditableTextPara::getCharacterAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& rRequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + CheckIndex(nIndex); // may throw IndexOutOfBoundsException + + // get default attribues... + ::comphelper::SequenceAsHashMap aPropHashMap( getDefaultAttributes( rRequestedAttributes ) ); + + // ... and override them with the direct attributes from the specific position + uno::Sequence< beans::PropertyValue > aRunAttribs( getRunAttributes( nIndex, rRequestedAttributes ) ); + sal_Int32 nRunAttribs = aRunAttribs.getLength(); + const beans::PropertyValue *pRunAttrib = aRunAttribs.getConstArray(); + for (sal_Int32 k = 0; k < nRunAttribs; ++k) + { + const beans::PropertyValue &rRunAttrib = pRunAttrib[k]; + aPropHashMap[ rRunAttrib.Name ] = rRunAttrib.Value; //!! should not only be the value !! + } +#ifdef TL_DEBUG + { + uno::Sequence< rtl::OUString > aNames(1); + aNames.getArray()[0] = rtl::OUString::createFromAscii("CharHeight"); + const rtl::OUString *pNames = aNames.getConstArray(); + const uno::Sequence< beans::PropertyValue > aAttribs( getRunAttributes( nIndex, aNames ) ); + const beans::PropertyValue *pAttribs = aAttribs.getConstArray(); + double d1 = -1.0; + float f1 = -1.0; + if (aAttribs.getLength()) + { + uno::Any aAny( pAttribs[0].Value ); + aAny >>= d1; + aAny >>= f1; + } + int i = 3; + } +#endif + + // get resulting sequence + uno::Sequence< beans::PropertyValue > aRes; + aPropHashMap >> aRes; + + // since SequenceAsHashMap ignores property handles and property state + // we have to restore the property state here (property handles are + // of no use to the accessibility API). + sal_Int32 nRes = aRes.getLength(); + beans::PropertyValue *pRes = aRes.getArray(); + for (sal_Int32 i = 0; i < nRes; ++i) + { + beans::PropertyValue &rRes = pRes[i]; + sal_Bool bIsDirectVal = sal_False; + for (sal_Int32 k = 0; k < nRunAttribs && !bIsDirectVal; ++k) + { + if (rRes.Name == pRunAttrib[k].Name) + bIsDirectVal = sal_True; + } + rRes.Handle = -1; + rRes.State = bIsDirectVal ? PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE; + } + + return aRes; + } + + awt::Rectangle SAL_CALL AccessibleEditableTextPara::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getCharacterBounds: index value overflow"); + + // #108900# Have position semantics now for nIndex, as + // one-past-the-end values are legal, too. + CheckPosition( nIndex ); + + SvxTextForwarder& rCacheTF = GetTextForwarder(); + Rectangle aRect = rCacheTF.GetCharBounds( static_cast< USHORT >( GetParagraphIndex() ), static_cast< USHORT >( nIndex ) ); + + // convert to screen + Rectangle aScreenRect = AccessibleEditableTextPara::LogicToPixel( aRect, + rCacheTF.GetMapMode(), + GetViewForwarder() ); + // #109864# offset from parent (paragraph), but in screen + // coordinates. This makes sure the internal text offset in + // the outline view forwarder gets cancelled out here + awt::Rectangle aParaRect( getBounds() ); + aScreenRect.Move( -aParaRect.X, -aParaRect.Y ); + + // offset from shape/cell + Point aOffset = GetEEOffset(); + + return awt::Rectangle( aScreenRect.Left() + aOffset.X(), + aScreenRect.Top() + aOffset.Y(), + aScreenRect.GetSize().Width(), + aScreenRect.GetSize().Height() ); + } + + sal_Int32 SAL_CALL AccessibleEditableTextPara::getCharacterCount() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getCharacterCount: index value overflow"); + + return OCommonAccessibleText::getCharacterCount(); + } + + sal_Int32 SAL_CALL AccessibleEditableTextPara::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + USHORT nPara, nIndex; + + // offset from surrounding cell/shape + Point aOffset( GetEEOffset() ); + Point aPoint( rPoint.X - aOffset.X(), rPoint.Y - aOffset.Y() ); + + // convert to logical coordinates + SvxTextForwarder& rCacheTF = GetTextForwarder(); + Point aLogPoint( GetViewForwarder().PixelToLogic( aPoint, rCacheTF.GetMapMode() ) ); + + // re-offset to parent (paragraph) + Rectangle aParaRect = rCacheTF.GetParaBounds( static_cast< USHORT >( GetParagraphIndex() ) ); + aLogPoint.Move( aParaRect.Left(), aParaRect.Top() ); + + if( rCacheTF.GetIndexAtPoint( aLogPoint, nPara, nIndex ) && + GetParagraphIndex() == nPara ) + { + // #102259# Double-check if we're _really_ on the given character + try + { + awt::Rectangle aRect1( getCharacterBounds(nIndex) ); + Rectangle aRect2( aRect1.X, aRect1.Y, + aRect1.Width + aRect1.X, aRect1.Height + aRect1.Y ); + if( aRect2.IsInside( Point( rPoint.X, rPoint.Y ) ) ) + return nIndex; + else + return -1; + } + catch( const lang::IndexOutOfBoundsException& ) + { + // #103927# Don't throw for invalid nIndex values + return -1; + } + } + else + { + // not within our paragraph + return -1; + } + } + + ::rtl::OUString SAL_CALL AccessibleEditableTextPara::getSelectedText() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getSelectedText: index value overflow"); + + if( !HaveEditView() ) + return ::rtl::OUString(); + + return OCommonAccessibleText::getSelectedText(); + } + + sal_Int32 SAL_CALL AccessibleEditableTextPara::getSelectionStart() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getSelectionStart: index value overflow"); + + if( !HaveEditView() ) + return -1; + + return OCommonAccessibleText::getSelectionStart(); + } + + sal_Int32 SAL_CALL AccessibleEditableTextPara::getSelectionEnd() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getSelectionEnd: index value overflow"); + + if( !HaveEditView() ) + return -1; + + return OCommonAccessibleText::getSelectionEnd(); + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::setSelection: paragraph index value overflow"); + + CheckRange(nStartIndex, nEndIndex); + + try + { + SvxEditViewForwarder& rCacheVF = GetEditViewForwarder( sal_True ); + return rCacheVF.SetSelection( MakeSelection(nStartIndex, nEndIndex) ); + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + ::rtl::OUString SAL_CALL AccessibleEditableTextPara::getText() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getText: paragraph index value overflow"); + + return OCommonAccessibleText::getText(); + } + + ::rtl::OUString SAL_CALL AccessibleEditableTextPara::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getTextRange: paragraph index value overflow"); + + return OCommonAccessibleText::getTextRange(nStartIndex, nEndIndex); + } + + ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getTextAtIndex: paragraph index value overflow"); + + ::com::sun::star::accessibility::TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + + switch( aTextType ) + { + // Not yet handled by OCommonAccessibleText. Missing + // implGetAttributeRunBoundary() method there + case AccessibleTextType::ATTRIBUTE_RUN: + { + const sal_Int32 nTextLen = GetTextForwarder().GetTextLen( static_cast< USHORT >( GetParagraphIndex() ) ); + + if( nIndex == nTextLen ) + { + // #i17014# Special-casing one-behind-the-end character + aResult.SegmentStart = aResult.SegmentEnd = nTextLen; + } + else + { + USHORT nStartIndex, nEndIndex; + + if( GetAttributeRun(nStartIndex, nEndIndex, nIndex) ) + { + aResult.SegmentText = GetTextRange(nStartIndex, nEndIndex); + aResult.SegmentStart = nStartIndex; + aResult.SegmentEnd = nEndIndex; + } + } + break; + } + + default: + aResult = OCommonAccessibleText::getTextAtIndex( nIndex, aTextType ); + break; + } /* end of switch( aTextType ) */ + + return aResult; + } + + ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getTextBeforeIndex: paragraph index value overflow"); + + ::com::sun::star::accessibility::TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + + switch( aTextType ) + { + // Not yet handled by OCommonAccessibleText. Missing + // implGetAttributeRunBoundary() method there + case AccessibleTextType::ATTRIBUTE_RUN: + { + const sal_Int32 nTextLen = GetTextForwarder().GetTextLen( static_cast< USHORT >( GetParagraphIndex() ) ); + USHORT nStartIndex, nEndIndex; + + if( nIndex == nTextLen ) + { + // #i17014# Special-casing one-behind-the-end character + if( nIndex > 0 && + GetAttributeRun(nStartIndex, nEndIndex, nIndex-1) ) + { + aResult.SegmentText = GetTextRange(nStartIndex, nEndIndex); + aResult.SegmentStart = nStartIndex; + aResult.SegmentEnd = nEndIndex; + } + } + else + { + if( GetAttributeRun(nStartIndex, nEndIndex, nIndex) ) + { + // already at the left border? If not, query + // one index further left + if( nStartIndex > 0 && + GetAttributeRun(nStartIndex, nEndIndex, nStartIndex-1) ) + { + aResult.SegmentText = GetTextRange(nStartIndex, nEndIndex); + aResult.SegmentStart = nStartIndex; + aResult.SegmentEnd = nEndIndex; + } + } + } + break; + } + + default: + aResult = OCommonAccessibleText::getTextBeforeIndex( nIndex, aTextType ); + break; + } /* end of switch( aTextType ) */ + + return aResult; + } + + ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getTextBehindIndex: paragraph index value overflow"); + + ::com::sun::star::accessibility::TextSegment aResult; + aResult.SegmentStart = -1; + aResult.SegmentEnd = -1; + + switch( aTextType ) + { + case AccessibleTextType::ATTRIBUTE_RUN: + { + USHORT nStartIndex, nEndIndex; + + if( GetAttributeRun(nStartIndex, nEndIndex, nIndex) ) + { + // already at the right border? + if( nEndIndex < GetTextLen() ) + { + if( GetAttributeRun(nStartIndex, nEndIndex, nEndIndex) ) + { + aResult.SegmentText = GetTextRange(nStartIndex, nEndIndex); + aResult.SegmentStart = nStartIndex; + aResult.SegmentEnd = nEndIndex; + } + } + } + break; + } + + default: + aResult = OCommonAccessibleText::getTextBehindIndex( nIndex, aTextType ); + break; + } /* end of switch( aTextType ) */ + + return aResult; + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + try + { + SvxEditViewForwarder& rCacheVF = GetEditViewForwarder( sal_True ); + #if OSL_DEBUG_LEVEL > 0 + SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + (void)rCacheTF; + #else + GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + #endif + + sal_Bool aRetVal; + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::copyText: index value overflow"); + + CheckRange(nStartIndex, nEndIndex); + + // save current selection + ESelection aOldSelection; + + rCacheVF.GetSelection( aOldSelection ); + rCacheVF.SetSelection( MakeSelection(nStartIndex, nEndIndex) ); + aRetVal = rCacheVF.Copy(); + rCacheVF.SetSelection( aOldSelection ); // restore + + return aRetVal; + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + // XAccessibleEditableText + sal_Bool SAL_CALL AccessibleEditableTextPara::cutText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + try + { + SvxEditViewForwarder& rCacheVF = GetEditViewForwarder( sal_True ); + SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::cutText: index value overflow"); + + CheckRange(nStartIndex, nEndIndex); + + if( !rCacheTF.IsEditable( MakeSelection(nStartIndex, nEndIndex) ) ) + return sal_False; // non-editable area selected + + // don't save selection, might become invalid after cut! + rCacheVF.SetSelection( MakeSelection(nStartIndex, nEndIndex) ); + + return rCacheVF.Cut(); + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::pasteText( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + try + { + SvxEditViewForwarder& rCacheVF = GetEditViewForwarder( sal_True ); + SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::pasteText: index value overflow"); + + CheckPosition(nIndex); + + if( !rCacheTF.IsEditable( MakeSelection(nIndex) ) ) + return sal_False; // non-editable area selected + + // #104400# set empty selection (=> cursor) to given index + rCacheVF.SetSelection( MakeCursor(nIndex) ); + + return rCacheVF.Paste(); + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::deleteText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + try + { + // #102710# Request edit view when doing changes + // AccessibleEmptyEditSource relies on this behaviour + GetEditViewForwarder( sal_True ); + SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::deleteText: index value overflow"); + + CheckRange(nStartIndex, nEndIndex); + + if( !rCacheTF.IsEditable( MakeSelection(nStartIndex, nEndIndex) ) ) + return sal_False; // non-editable area selected + + sal_Bool bRet = rCacheTF.Delete( MakeSelection(nStartIndex, nEndIndex) ); + + GetEditSource().UpdateData(); + + return bRet; + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::insertText( const ::rtl::OUString& sText, sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + try + { + // #102710# Request edit view when doing changes + // AccessibleEmptyEditSource relies on this behaviour + GetEditViewForwarder( sal_True ); + SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::insertText: index value overflow"); + + CheckPosition(nIndex); + + if( !rCacheTF.IsEditable( MakeSelection(nIndex) ) ) + return sal_False; // non-editable area selected + + // #104400# insert given text at empty selection (=> cursor) + sal_Bool bRet = rCacheTF.InsertText( sText, MakeCursor(nIndex) ); + + rCacheTF.QuickFormatDoc(); + GetEditSource().UpdateData(); + + return bRet; + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::replaceText( sal_Int32 nStartIndex, sal_Int32 nEndIndex, const ::rtl::OUString& sReplacement ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + try + { + // #102710# Request edit view when doing changes + // AccessibleEmptyEditSource relies on this behaviour + GetEditViewForwarder( sal_True ); + SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::replaceText: index value overflow"); + + CheckRange(nStartIndex, nEndIndex); + + if( !rCacheTF.IsEditable( MakeSelection(nStartIndex, nEndIndex) ) ) + return sal_False; // non-editable area selected + + // insert given text into given range => replace + sal_Bool bRet = rCacheTF.InsertText( sReplacement, MakeSelection(nStartIndex, nEndIndex) ); + + rCacheTF.QuickFormatDoc(); + GetEditSource().UpdateData(); + + return bRet; + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::setAttributes( sal_Int32 nStartIndex, sal_Int32 nEndIndex, const uno::Sequence< beans::PropertyValue >& aAttributeSet ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + try + { + // #102710# Request edit view when doing changes + // AccessibleEmptyEditSource relies on this behaviour + GetEditViewForwarder( sal_True ); + SvxAccessibleTextAdapter& rCacheTF = GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + USHORT nPara = static_cast< USHORT >( GetParagraphIndex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::setAttributes: index value overflow"); + + CheckRange(nStartIndex, nEndIndex); + + if( !rCacheTF.IsEditable( MakeSelection(nStartIndex, nEndIndex) ) ) + return sal_False; // non-editable area selected + + // do the indices span the whole paragraph? Then use the outliner map + // TODO: hold it as a member? + SvxAccessibleTextPropertySet aPropSet( &GetEditSource(), + 0 == nStartIndex && + rCacheTF.GetTextLen(nPara) == nEndIndex ? + ImplGetSvxUnoOutlinerTextCursorSvxPropertySet() : + ImplGetSvxTextPortionSvxPropertySet() ); + + aPropSet.SetSelection( MakeSelection(nStartIndex, nEndIndex) ); + + // convert from PropertyValue to Any + sal_Int32 i, nLength( aAttributeSet.getLength() ); + const beans::PropertyValue* pPropArray = aAttributeSet.getConstArray(); + for(i=0; i<nLength; ++i) + { + try + { + aPropSet.setPropertyValue(pPropArray->Name, pPropArray->Value); + } + catch( const uno::Exception& ) + { + DBG_ERROR("AccessibleEditableTextPara::setAttributes exception in setPropertyValue"); + } + + ++pPropArray; + } + + rCacheTF.QuickFormatDoc(); + GetEditSource().UpdateData(); + + return sal_True; + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::setText( const ::rtl::OUString& sText ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + return replaceText(0, getCharacterCount(), sText); + } + + // XAccessibleTextAttributes + uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleEditableTextPara::getDefaultAttributes( + const uno::Sequence< ::rtl::OUString >& rRequestedAttributes ) + throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + #if OSL_DEBUG_LEVEL > 0 + SvxAccessibleTextAdapter& rCacheTF = + #endif + GetTextForwarder(); + + #if OSL_DEBUG_LEVEL > 0 + (void)rCacheTF; + #endif + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getCharacterAttributes: index value overflow"); + + // get XPropertySetInfo for paragraph attributes and + // character attributes that span all the paragraphs text. + SvxAccessibleTextPropertySet aPropSet( &GetEditSource(), + ImplGetSvxCharAndParaPropertiesSet() ); + aPropSet.SetSelection( MakeSelection( 0, GetTextLen() ) ); + uno::Reference< beans::XPropertySetInfo > xPropSetInfo = aPropSet.getPropertySetInfo(); + if (!xPropSetInfo.is()) + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Cannot query XPropertySetInfo")), + uno::Reference< uno::XInterface > + ( static_cast< XAccessible* > (this) ) ); // disambiguate hierarchy + + // build sequence of available properties to check + sal_Int32 nLenReqAttr = rRequestedAttributes.getLength(); + uno::Sequence< beans::Property > aProperties; + if (nLenReqAttr) + { + const rtl::OUString *pRequestedAttributes = rRequestedAttributes.getConstArray(); + + aProperties.realloc( nLenReqAttr ); + beans::Property *pProperties = aProperties.getArray(); + sal_Int32 nCurLen = 0; + for (sal_Int32 i = 0; i < nLenReqAttr; ++i) + { + beans::Property aProp; + try + { + aProp = xPropSetInfo->getPropertyByName( pRequestedAttributes[i] ); + } + catch (beans::UnknownPropertyException &) + { + continue; + } + pProperties[ nCurLen++ ] = aProp; + } + aProperties.realloc( nCurLen ); + } + else + aProperties = xPropSetInfo->getProperties(); + + sal_Int32 nLength = aProperties.getLength(); + const beans::Property *pProperties = aProperties.getConstArray(); + + // build resulting sequence + uno::Sequence< beans::PropertyValue > aOutSequence( nLength ); + beans::PropertyValue* pOutSequence = aOutSequence.getArray(); + sal_Int32 nOutLen = 0; + for (sal_Int32 i = 0; i < nLength; ++i) + { + // calling implementation functions: + // _getPropertyState and _getPropertyValue (see below) to provide + // the proper paragraph number when retrieving paragraph attributes + PropertyState eState = aPropSet._getPropertyState( pProperties->Name, mnParagraphIndex ); + if ( eState == PropertyState_AMBIGUOUS_VALUE ) + { + OSL_ENSURE( false, "ambiguous property value encountered" ); + } + + //if (eState == PropertyState_DIRECT_VALUE) + // per definition all paragraph properties and all character + // properties spanning the whole paragraph should be returned + // and declared as default value + { + pOutSequence->Name = pProperties->Name; + pOutSequence->Handle = pProperties->Handle; + pOutSequence->Value = aPropSet._getPropertyValue( pProperties->Name, mnParagraphIndex ); + pOutSequence->State = PropertyState_DEFAULT_VALUE; + + ++pOutSequence; + ++nOutLen; + } + ++pProperties; + } + aOutSequence.realloc( nOutLen ); + + return aOutSequence; + } + + + uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleEditableTextPara::getRunAttributes( + sal_Int32 nIndex, + const uno::Sequence< ::rtl::OUString >& rRequestedAttributes ) + throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + #if OSL_DEBUG_LEVEL > 0 + SvxAccessibleTextAdapter& rCacheTF = + #endif + GetTextForwarder(); + + #if OSL_DEBUG_LEVEL > 0 + (void)rCacheTF; + #endif + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getCharacterAttributes: index value overflow"); + + CheckIndex(nIndex); + + SvxAccessibleTextPropertySet aPropSet( &GetEditSource(), + ImplGetSvxCharAndParaPropertiesSet() ); + aPropSet.SetSelection( MakeSelection( nIndex ) ); + uno::Reference< beans::XPropertySetInfo > xPropSetInfo = aPropSet.getPropertySetInfo(); + if (!xPropSetInfo.is()) + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Cannot query XPropertySetInfo")), + uno::Reference< uno::XInterface > + ( static_cast< XAccessible* > (this) ) ); // disambiguate hierarchy + + // build sequence of available properties to check + sal_Int32 nLenReqAttr = rRequestedAttributes.getLength(); + uno::Sequence< beans::Property > aProperties; + if (nLenReqAttr) + { + const rtl::OUString *pRequestedAttributes = rRequestedAttributes.getConstArray(); + + aProperties.realloc( nLenReqAttr ); + beans::Property *pProperties = aProperties.getArray(); + sal_Int32 nCurLen = 0; + for (sal_Int32 i = 0; i < nLenReqAttr; ++i) + { + beans::Property aProp; + try + { + aProp = xPropSetInfo->getPropertyByName( pRequestedAttributes[i] ); + } + catch (beans::UnknownPropertyException &) + { + continue; + } + pProperties[ nCurLen++ ] = aProp; + } + aProperties.realloc( nCurLen ); + } + else + aProperties = xPropSetInfo->getProperties(); + + sal_Int32 nLength = aProperties.getLength(); + const beans::Property *pProperties = aProperties.getConstArray(); + + // build resulting sequence + uno::Sequence< beans::PropertyValue > aOutSequence( nLength ); + beans::PropertyValue* pOutSequence = aOutSequence.getArray(); + sal_Int32 nOutLen = 0; + for (sal_Int32 i = 0; i < nLength; ++i) + { + // calling 'regular' functions that will operate on the selection + PropertyState eState = aPropSet.getPropertyState( pProperties->Name ); + if (eState == PropertyState_DIRECT_VALUE) + { + pOutSequence->Name = pProperties->Name; + pOutSequence->Handle = pProperties->Handle; + pOutSequence->Value = aPropSet.getPropertyValue( pProperties->Name ); + pOutSequence->State = eState; + + ++pOutSequence; + ++nOutLen; + } + ++pProperties; + } + aOutSequence.realloc( nOutLen ); + + return aOutSequence; + } + + // XAccessibleMultiLineText + sal_Int32 SAL_CALL AccessibleEditableTextPara::getLineNumberAtIndex( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + sal_Int32 nRes = -1; + sal_Int32 nPara = GetParagraphIndex(); + + SvxTextForwarder &rCacheTF = GetTextForwarder(); + const bool bValidPara = 0 <= nPara && nPara < rCacheTF.GetParagraphCount(); + DBG_ASSERT( bValidPara, "getLineNumberAtIndex: current paragraph index out of range" ); + if (bValidPara) + { + // we explicitly allow for the index to point at the character right behind the text + if (0 <= nIndex && nIndex <= rCacheTF.GetTextLen( static_cast< USHORT >(nPara) )) + nRes = rCacheTF.GetLineNumberAtIndex( static_cast< USHORT >(nPara), static_cast< USHORT >(nIndex) ); + else + throw lang::IndexOutOfBoundsException(); + } + return nRes; + } + + // XAccessibleMultiLineText + ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextAtLineNumber( sal_Int32 nLineNo ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::com::sun::star::accessibility::TextSegment aResult; + sal_Int32 nPara = GetParagraphIndex(); + SvxTextForwarder &rCacheTF = GetTextForwarder(); + const bool bValidPara = 0 <= nPara && nPara < rCacheTF.GetParagraphCount(); + DBG_ASSERT( bValidPara, "getTextAtLineNumber: current paragraph index out of range" ); + if (bValidPara) + { + if (0 <= nLineNo && nLineNo < rCacheTF.GetLineCount( static_cast< USHORT >(nPara) )) + { + USHORT nStart = 0, nEnd = 0; + rCacheTF.GetLineBoundaries( nStart, nEnd, static_cast< USHORT >(nPara), static_cast< USHORT >(nLineNo) ); + if (nStart != 0xFFFF && nEnd != 0xFFFF) + { + try + { + aResult.SegmentText = getTextRange( nStart, nEnd ); + aResult.SegmentStart = nStart; + aResult.SegmentEnd = nEnd; + } + catch (lang::IndexOutOfBoundsException) + { + // this is not the exception that should be raised in this function ... + DBG_ASSERT( 0, "unexpected exception" ); + } + } + } + else + throw lang::IndexOutOfBoundsException(); + } + return aResult; + } + + // XAccessibleMultiLineText + ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleEditableTextPara::getTextAtLineWithCaret( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + ::com::sun::star::accessibility::TextSegment aResult; + try + { + aResult = getTextAtLineNumber( getNumberOfLineWithCaret() ); + } + catch (lang::IndexOutOfBoundsException &) + { + // this one needs to be catched since this interface does not allow for it. + } + return aResult; + } + + // XAccessibleMultiLineText + sal_Int32 SAL_CALL AccessibleEditableTextPara::getNumberOfLineWithCaret( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + sal_Int32 nRes = -1; + try + { + nRes = getLineNumberAtIndex( getCaretPosition() ); + } + catch (lang::IndexOutOfBoundsException &) + { + // this one needs to be catched since this interface does not allow for it. + } + return nRes; + } + + + // XServiceInfo + ::rtl::OUString SAL_CALL AccessibleEditableTextPara::getImplementationName (void) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("AccessibleEditableTextPara")); + } + + sal_Bool SAL_CALL AccessibleEditableTextPara::supportsService (const ::rtl::OUString& sServiceName) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + // Iterate over all supported service names and return true if on of them + // matches the given name. + uno::Sequence< ::rtl::OUString> aSupportedServices ( + getSupportedServiceNames ()); + for (int i=0; i<aSupportedServices.getLength(); i++) + if (sServiceName == aSupportedServices[i]) + return sal_True; + return sal_False; + } + + uno::Sequence< ::rtl::OUString> SAL_CALL AccessibleEditableTextPara::getSupportedServiceNames (void) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + const ::rtl::OUString sServiceName( getServiceName() ); + return uno::Sequence< ::rtl::OUString > (&sServiceName, 1); + } + + // XServiceName + ::rtl::OUString SAL_CALL AccessibleEditableTextPara::getServiceName (void) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleEditableTextPara, NULL ); + + // #105185# Using correct service now + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.AccessibleParagraphView")); + } + +} // end of namespace accessibility + +//------------------------------------------------------------------------ diff --git a/editeng/source/accessibility/AccessibleImageBullet.cxx b/editeng/source/accessibility/AccessibleImageBullet.cxx new file mode 100644 index 000000000000..91aff356db6d --- /dev/null +++ b/editeng/source/accessibility/AccessibleImageBullet.cxx @@ -0,0 +1,654 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleImageBullet.cxx,v $ + * $Revision: 1.22 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <tools/gen.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <rtl/ustring.hxx> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleTextType.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <comphelper/accessibleeventnotifier.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <editeng/unolingu.hxx> +#include "editeng/AccessibleEditableTextPara.hxx" +#include "editeng/AccessibleImageBullet.hxx" +#include <editeng/eerdll.hxx> + +#include <editeng/editdata.hxx> +#include <editeng/editeng.hxx> +#include <editeng/outliner.hxx> +#include "editeng.hrc" +#include <svtools/colorcfg.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +namespace accessibility +{ + DBG_NAME( AccessibleImageBullet ) + + AccessibleImageBullet::AccessibleImageBullet ( const uno::Reference< XAccessible >& rParent ) : + mnParagraphIndex( 0 ), + mnIndexInParent( 0 ), + mpEditSource( NULL ), + maEEOffset( 0, 0 ), + mxParent( rParent ), + // well, that's strictly (UNO) exception safe, though not + // really robust. We rely on the fact that this member is + // constructed last, and that the constructor body catches + // exceptions, thus no chance for exceptions once the Id is + // fetched. Nevertheless, normally should employ RAII here... + mnNotifierClientId(::comphelper::AccessibleEventNotifier::registerClient()) + { +#ifdef DBG_UTIL + DBG_CTOR( AccessibleImageBullet, NULL ); + OSL_TRACE( "Received ID: %d", mnNotifierClientId ); +#endif + + try + { + // Create the state set. + ::utl::AccessibleStateSetHelper* pStateSet = new ::utl::AccessibleStateSetHelper (); + mxStateSet = pStateSet; + + // these are always on + pStateSet->AddState( AccessibleStateType::VISIBLE ); + pStateSet->AddState( AccessibleStateType::SHOWING ); + pStateSet->AddState( AccessibleStateType::ENABLED ); + pStateSet->AddState( AccessibleStateType::SENSITIVE ); + } + catch( const uno::Exception& ) {} + } + + AccessibleImageBullet::~AccessibleImageBullet() + { + DBG_DTOR( AccessibleImageBullet, NULL ); + + // sign off from event notifier + if( getNotifierClientId() != -1 ) + { + try + { + ::comphelper::AccessibleEventNotifier::revokeClient( getNotifierClientId() ); +#ifdef DBG_UTIL + OSL_TRACE( "AccessibleImageBullet revoked ID: %d\n", mnNotifierClientId ); +#endif + } + catch( const uno::Exception& ) {} + } + } + + uno::Any SAL_CALL AccessibleImageBullet::queryInterface (const uno::Type & rType) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return AccessibleImageBulletInterfaceBase::queryInterface(rType); + } + + uno::Reference< XAccessibleContext > SAL_CALL AccessibleImageBullet::getAccessibleContext( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + // We implement the XAccessibleContext interface in the same object + return uno::Reference< XAccessibleContext > ( this ); + } + + sal_Int32 SAL_CALL AccessibleImageBullet::getAccessibleChildCount() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return 0; + } + + uno::Reference< XAccessible > SAL_CALL AccessibleImageBullet::getAccessibleChild( sal_Int32 i ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + (void)i; + + throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No childs available")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > (this) ) ); // static_cast: disambiguate hierarchy + } + + uno::Reference< XAccessible > SAL_CALL AccessibleImageBullet::getAccessibleParent() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return mxParent; + } + + sal_Int32 SAL_CALL AccessibleImageBullet::getAccessibleIndexInParent() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return mnIndexInParent; + } + + sal_Int16 SAL_CALL AccessibleImageBullet::getAccessibleRole() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return AccessibleRole::GRAPHIC; + } + + ::rtl::OUString SAL_CALL AccessibleImageBullet::getAccessibleDescription() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // Get the string from the resource for the specified id. + return ::rtl::OUString( String( EditResId (RID_SVXSTR_A11Y_IMAGEBULLET_DESCRIPTION) ) ); + } + + ::rtl::OUString SAL_CALL AccessibleImageBullet::getAccessibleName() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // Get the string from the resource for the specified id. + return ::rtl::OUString( String ( EditResId (RID_SVXSTR_A11Y_IMAGEBULLET_NAME) ) ); + } + + uno::Reference< XAccessibleRelationSet > SAL_CALL AccessibleImageBullet::getAccessibleRelationSet() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + // no relations, therefore empty + return uno::Reference< XAccessibleRelationSet >(); + } + + uno::Reference< XAccessibleStateSet > SAL_CALL AccessibleImageBullet::getAccessibleStateSet() throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // Create a copy of the state set and return it. + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + + if( !pStateSet ) + return uno::Reference<XAccessibleStateSet>(); + + return uno::Reference<XAccessibleStateSet>( new ::utl::AccessibleStateSetHelper (*pStateSet) ); + } + + lang::Locale SAL_CALL AccessibleImageBullet::getLocale() throw (IllegalAccessibleComponentStateException, uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + lang::Locale aLocale; + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleImageBullet::getLocale: paragraph index value overflow"); + + // return locale of first character in the paragraph + return SvxLanguageToLocale(aLocale, GetTextForwarder().GetLanguage( static_cast< USHORT >( GetParagraphIndex() ), 0 )); + } + + void SAL_CALL AccessibleImageBullet::addEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + if( getNotifierClientId() != -1 ) + ::comphelper::AccessibleEventNotifier::addEventListener( getNotifierClientId(), xListener ); + } + + void SAL_CALL AccessibleImageBullet::removeEventListener( const uno::Reference< XAccessibleEventListener >& xListener ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + if( getNotifierClientId() != -1 ) + ::comphelper::AccessibleEventNotifier::removeEventListener( getNotifierClientId(), xListener ); + } + + sal_Bool SAL_CALL AccessibleImageBullet::containsPoint( const awt::Point& rPoint ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::contains: index value overflow"); + + awt::Rectangle aTmpRect = getBounds(); + Rectangle aRect( Point(aTmpRect.X, aTmpRect.Y), Size(aTmpRect.Width, aTmpRect.Height) ); + Point aPoint( rPoint.X, rPoint.Y ); + + return aRect.IsInside( aPoint ); + } + + uno::Reference< XAccessible > SAL_CALL AccessibleImageBullet::getAccessibleAtPoint( const awt::Point& /*aPoint*/ ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + // as we have no children, empty reference + return uno::Reference< XAccessible >(); + } + + awt::Rectangle SAL_CALL AccessibleImageBullet::getBounds( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(GetParagraphIndex() >= 0 && GetParagraphIndex() <= USHRT_MAX, + "AccessibleEditableTextPara::getBounds: index value overflow"); + + SvxTextForwarder& rCacheTF = GetTextForwarder(); + EBulletInfo aBulletInfo = rCacheTF.GetBulletInfo( static_cast< USHORT > (GetParagraphIndex()) ); + Rectangle aParentRect = rCacheTF.GetParaBounds( static_cast< USHORT >( GetParagraphIndex() ) ); + + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType == SVX_NUM_BITMAP ) + { + Rectangle aRect = aBulletInfo.aBounds; + + // subtract paragraph position (bullet pos is absolute in EditEngine/Outliner) + aRect.Move( -aParentRect.Left(), -aParentRect.Top() ); + + // convert to screen coordinates + Rectangle aScreenRect = AccessibleEditableTextPara::LogicToPixel( aRect, + rCacheTF.GetMapMode(), + GetViewForwarder() ); + + // offset from shape/cell + Point aOffset = GetEEOffset(); + + return awt::Rectangle( aScreenRect.Left() + aOffset.X(), + aScreenRect.Top() + aOffset.Y(), + aScreenRect.GetSize().Width(), + aScreenRect.GetSize().Height() ); + } + + return awt::Rectangle(); + } + + awt::Point SAL_CALL AccessibleImageBullet::getLocation( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + awt::Rectangle aRect = getBounds(); + + return awt::Point( aRect.X, aRect.Y ); + } + + awt::Point SAL_CALL AccessibleImageBullet::getLocationOnScreen( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // relate us to parent + uno::Reference< XAccessible > xParent = getAccessibleParent(); + if( xParent.is() ) + { + uno::Reference< XAccessibleComponent > xParentComponent( xParent, uno::UNO_QUERY ); + if( xParentComponent.is() ) + { + awt::Point aRefPoint = xParentComponent->getLocationOnScreen(); + awt::Point aPoint = getLocation(); + aPoint.X += aRefPoint.X; + aPoint.Y += aRefPoint.Y; + + return aPoint; + } + } + + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Cannot access parent")), + uno::Reference< uno::XInterface > + ( static_cast< XAccessible* > (this) ) ); // disambiguate hierarchy + } + + awt::Size SAL_CALL AccessibleImageBullet::getSize( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + awt::Rectangle aRect = getBounds(); + + return awt::Size( aRect.Width, aRect.Height ); + } + + void SAL_CALL AccessibleImageBullet::grabFocus( ) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Not focusable")), + uno::Reference< uno::XInterface > + ( static_cast< XAccessible* > (this) ) ); // disambiguate hierarchy + } + + sal_Int32 SAL_CALL AccessibleImageBullet::getForeground( ) throw (::com::sun::star::uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + // #104444# Added to XAccessibleComponent interface + svtools::ColorConfig aColorConfig; + UINT32 nColor = aColorConfig.GetColorValue( svtools::FONTCOLOR ).nColor; + return static_cast<sal_Int32>(nColor); + } + + sal_Int32 SAL_CALL AccessibleImageBullet::getBackground( ) throw (::com::sun::star::uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + // #104444# Added to XAccessibleComponent interface + Color aColor( Application::GetSettings().GetStyleSettings().GetWindowColor().GetColor() ); + + // the background is transparent + aColor.SetTransparency( 0xFF); + + return static_cast<sal_Int32>( aColor.GetColor() ); + } + + ::rtl::OUString SAL_CALL AccessibleImageBullet::getImplementationName (void) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("AccessibleImageBullet")); + } + + sal_Bool SAL_CALL AccessibleImageBullet::supportsService (const ::rtl::OUString& sServiceName) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + // Iterate over all supported service names and return true if on of them + // matches the given name. + uno::Sequence< ::rtl::OUString> aSupportedServices ( + getSupportedServiceNames ()); + for (int i=0; i<aSupportedServices.getLength(); i++) + if (sServiceName == aSupportedServices[i]) + return sal_True; + return sal_False; + } + + uno::Sequence< ::rtl::OUString> SAL_CALL AccessibleImageBullet::getSupportedServiceNames (void) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + const ::rtl::OUString sServiceName (RTL_CONSTASCII_USTRINGPARAM ("com.sun.star.accessibility.AccessibleContext")); + return uno::Sequence< ::rtl::OUString > (&sServiceName, 1); + } + + ::rtl::OUString SAL_CALL AccessibleImageBullet::getServiceName (void) throw (uno::RuntimeException) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.accessibility.AccessibleContext")); + } + + void AccessibleImageBullet::SetIndexInParent( sal_Int32 nIndex ) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + mnIndexInParent = nIndex; + } + + sal_Int32 AccessibleImageBullet::GetIndexInParent() const + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return mnIndexInParent; + } + + void AccessibleImageBullet::SetEEOffset( const Point& rOffset ) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + maEEOffset = rOffset; + } + + void AccessibleImageBullet::Dispose() + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + int nClientId( getNotifierClientId() ); + + // #108212# drop all references before notifying dispose + mxParent = NULL; + mnNotifierClientId = -1; + mpEditSource = NULL; + + // notify listeners + if( nClientId != -1 ) + { + try + { + uno::Reference < XAccessibleContext > xThis = getAccessibleContext(); + + // #106234# Delegate to EventNotifier + ::comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nClientId, xThis ); +#ifdef DBG_UTIL + OSL_TRACE( "AccessibleImageBullet disposed ID: %d", nClientId ); +#endif + } + catch( const uno::Exception& ) {} + } + } + + void AccessibleImageBullet::SetEditSource( SvxEditSource* pEditSource ) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + mpEditSource = pEditSource; + + if( !mpEditSource ) + { + // going defunc + UnSetState( AccessibleStateType::SHOWING ); + UnSetState( AccessibleStateType::VISIBLE ); + SetState( AccessibleStateType::INVALID ); + SetState( AccessibleStateType::DEFUNC ); + + Dispose(); + } + } + + void AccessibleImageBullet::FireEvent(const sal_Int16 nEventId, const uno::Any& rNewValue, const uno::Any& rOldValue ) const + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + uno::Reference < XAccessibleContext > xThis( const_cast< AccessibleImageBullet* > (this)->getAccessibleContext() ); + + AccessibleEventObject aEvent(xThis, nEventId, rNewValue, rOldValue); + + // #106234# Delegate to EventNotifier + ::comphelper::AccessibleEventNotifier::addEvent( getNotifierClientId(), + aEvent ); + } + + void AccessibleImageBullet::GotPropertyEvent( const uno::Any& rNewValue, const sal_Int16 nEventId ) const + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + FireEvent( nEventId, rNewValue ); + } + + void AccessibleImageBullet::LostPropertyEvent( const uno::Any& rOldValue, const sal_Int16 nEventId ) const + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + FireEvent( nEventId, uno::Any(), rOldValue ); + } + + void AccessibleImageBullet::SetState( const sal_Int16 nStateId ) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if( pStateSet != NULL && + !pStateSet->contains(nStateId) ) + { + pStateSet->AddState( nStateId ); + GotPropertyEvent( uno::makeAny( nStateId ), AccessibleEventId::STATE_CHANGED ); + } + } + + void AccessibleImageBullet::UnSetState( const sal_Int16 nStateId ) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if( pStateSet != NULL && + pStateSet->contains(nStateId) ) + { + pStateSet->RemoveState( nStateId ); + LostPropertyEvent( uno::makeAny( nStateId ), AccessibleEventId::STATE_CHANGED ); + } + } + + int AccessibleImageBullet::getNotifierClientId() const + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return mnNotifierClientId; + } + + void AccessibleImageBullet::SetParagraphIndex( sal_Int32 nIndex ) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + uno::Any aOldDesc; + uno::Any aOldName; + + try + { + aOldDesc <<= getAccessibleDescription(); + aOldName <<= getAccessibleName(); + } + catch( const uno::Exception& ) {} // optional behaviour + + sal_Int32 nOldIndex = mnParagraphIndex; + + mnParagraphIndex = nIndex; + + try + { + if( nOldIndex != nIndex ) + { + // index and therefore description changed + FireEvent( AccessibleEventId::DESCRIPTION_CHANGED, uno::makeAny( getAccessibleDescription() ), aOldDesc ); + FireEvent( AccessibleEventId::NAME_CHANGED, uno::makeAny( getAccessibleName() ), aOldName ); + } + } + catch( const uno::Exception& ) {} // optional behaviour + } + + sal_Int32 AccessibleImageBullet::GetParagraphIndex() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return mnParagraphIndex; + } + + SvxEditSource& AccessibleImageBullet::GetEditSource() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + if( mpEditSource ) + return *mpEditSource; + else + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("No edit source, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleImageBullet* > (this) ) ) ); // disambiguate hierarchy + } + + SvxTextForwarder& AccessibleImageBullet::GetTextForwarder() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + SvxEditSource& rEditSource = GetEditSource(); + SvxTextForwarder* pTextForwarder = rEditSource.GetTextForwarder(); + + if( !pTextForwarder ) + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch text forwarder, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleImageBullet* > (this) ) ) ); // disambiguate hierarchy + + if( pTextForwarder->IsValid() ) + return *pTextForwarder; + else + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Text forwarder is invalid, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleImageBullet* > (this) ) ) ); // disambiguate hierarchy + } + + SvxViewForwarder& AccessibleImageBullet::GetViewForwarder() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + SvxEditSource& rEditSource = GetEditSource(); + SvxViewForwarder* pViewForwarder = rEditSource.GetViewForwarder(); + + if( !pViewForwarder ) + { + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Unable to fetch view forwarder, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleImageBullet* > (this) ) ) ); // disambiguate hierarchy + } + + if( pViewForwarder->IsValid() ) + return *pViewForwarder; + else + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("View forwarder is invalid, object is defunct")), + uno::Reference< uno::XInterface > + ( static_cast< ::cppu::OWeakObject* > + ( const_cast< AccessibleImageBullet* > (this) ) ) ); // disambiguate hierarchy + } + + const Point& AccessibleImageBullet::GetEEOffset() const + { + DBG_CHKTHIS( AccessibleImageBullet, NULL ); + + return maEEOffset; + } + +} // end of namespace accessibility + diff --git a/editeng/source/accessibility/AccessibleParaManager.cxx b/editeng/source/accessibility/AccessibleParaManager.cxx new file mode 100644 index 000000000000..6953c5922ccf --- /dev/null +++ b/editeng/source/accessibility/AccessibleParaManager.cxx @@ -0,0 +1,423 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleParaManager.cxx,v $ + * $Revision: 1.16 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +//------------------------------------------------------------------------ +// +// Global header +// +//------------------------------------------------------------------------ +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <cppuhelper/weakref.hxx> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +//------------------------------------------------------------------------ +// +// Project-local header +// +//------------------------------------------------------------------------ + +#include <editeng/unoedhlp.hxx> +#include <editeng/unopracc.hxx> +#include <editeng/unoedsrc.hxx> +#include "editeng/AccessibleParaManager.hxx" +#include "editeng/AccessibleEditableTextPara.hxx" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + + + +namespace accessibility +{ + AccessibleParaManager::AccessibleParaManager() : + maChildren(1), + maEEOffset( 0, 0 ), + mnFocusedChild( -1 ), + mbActive( sal_False ) + { + } + + AccessibleParaManager::~AccessibleParaManager() + { + // owner is responsible for possible child defuncs + } + + void AccessibleParaManager::SetAdditionalChildStates( const VectorOfStates& rChildStates ) + { + maChildStates = rChildStates; + } + + const AccessibleParaManager::VectorOfStates& AccessibleParaManager::GetAdditionalChildStates() const + { + return maChildStates; + } + + void AccessibleParaManager::SetNum( sal_Int32 nNumParas ) + { + if( (size_t)nNumParas < maChildren.size() ) + Release( nNumParas, maChildren.size() ); + + maChildren.resize( nNumParas ); + + if( mnFocusedChild >= nNumParas ) + mnFocusedChild = -1; + } + + sal_uInt32 AccessibleParaManager::GetNum() const + { + return maChildren.size(); + } + + AccessibleParaManager::VectorOfChildren::iterator AccessibleParaManager::begin() + { + return maChildren.begin(); + } + + AccessibleParaManager::VectorOfChildren::iterator AccessibleParaManager::end() + { + return maChildren.end(); + } + + AccessibleParaManager::VectorOfChildren::const_iterator AccessibleParaManager::begin() const + { + return maChildren.begin(); + } + + AccessibleParaManager::VectorOfChildren::const_iterator AccessibleParaManager::end() const + { + return maChildren.end(); + } + + void AccessibleParaManager::Release( sal_uInt32 nPara ) + { + DBG_ASSERT( maChildren.size() > nPara, "AccessibleParaManager::Release: invalid index" ); + + if( maChildren.size() > nPara ) + { + ShutdownPara( GetChild( nPara ) ); + + // clear reference and rect + maChildren[ nPara ] = WeakChild(); + } + } + + void AccessibleParaManager::FireEvent( sal_uInt32 nPara, + const sal_Int16 nEventId, + const uno::Any& rNewValue, + const uno::Any& rOldValue ) const + { + DBG_ASSERT( maChildren.size() > nPara, "AccessibleParaManager::FireEvent: invalid index" ); + + if( maChildren.size() > nPara ) + { + WeakPara::HardRefType maChild( GetChild( nPara ).first.get() ); + if( maChild.is() ) + maChild->FireEvent( nEventId, rNewValue, rOldValue ); + } + } + + sal_Bool AccessibleParaManager::IsReferencable( WeakPara::HardRefType aChild ) + { + return aChild.is(); + } + + sal_Bool AccessibleParaManager::IsReferencable( sal_uInt32 nChild ) const + { + DBG_ASSERT( maChildren.size() > nChild, "AccessibleParaManager::IsReferencable: invalid index" ); + + if( maChildren.size() > nChild ) + { + // retrieve hard reference from weak one + return IsReferencable( GetChild( nChild ).first.get() ); + } + else + { + return sal_False; + } + } + + AccessibleParaManager::WeakChild AccessibleParaManager::GetChild( sal_uInt32 nParagraphIndex ) const + { + DBG_ASSERT( maChildren.size() > nParagraphIndex, "AccessibleParaManager::GetChild: invalid index" ); + + if( maChildren.size() > nParagraphIndex ) + { + return maChildren[ nParagraphIndex ]; + } + else + { + return WeakChild(); + } + } + + AccessibleParaManager::Child AccessibleParaManager::CreateChild( sal_Int32 nChild, + const uno::Reference< XAccessible >& xFrontEnd, + SvxEditSourceAdapter& rEditSource, + sal_uInt32 nParagraphIndex ) + { + DBG_ASSERT( maChildren.size() > nParagraphIndex, "AccessibleParaManager::CreateChild: invalid index" ); + + if( maChildren.size() > nParagraphIndex ) + { + // retrieve hard reference from weak one + WeakPara::HardRefType aChild( GetChild( nParagraphIndex ).first.get() ); + + if( !IsReferencable( nParagraphIndex ) ) + { + // there is no hard reference available, create object then + // --> OD 2006-01-11 #i27138# + AccessibleEditableTextPara* pChild = new AccessibleEditableTextPara( xFrontEnd, this ); + // <-- + uno::Reference< XAccessible > xChild( static_cast< ::cppu::OWeakObject* > (pChild), uno::UNO_QUERY ); + + if( !xChild.is() ) + throw uno::RuntimeException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Child creation failed")), xFrontEnd); + + aChild = WeakPara::HardRefType( xChild, pChild ); + + InitChild( *aChild, rEditSource, nChild, nParagraphIndex ); + + maChildren[ nParagraphIndex ] = WeakChild( aChild, pChild->getBounds() ); + } + + return Child( aChild.getRef(), GetChild( nParagraphIndex ).second ); + } + else + { + return Child(); + } + } + + void AccessibleParaManager::SetEEOffset( const Point& rOffset ) + { + maEEOffset = rOffset; + + MemFunAdapter< const Point& > aAdapter( &::accessibility::AccessibleEditableTextPara::SetEEOffset, rOffset ); + ::std::for_each( begin(), end(), aAdapter ); + } + + void AccessibleParaManager::SetActive( sal_Bool bActive ) + { + mbActive = bActive; + + if( bActive ) + { + SetState( AccessibleStateType::ACTIVE ); + SetState( AccessibleStateType::EDITABLE ); + } + else + { + UnSetState( AccessibleStateType::ACTIVE ); + UnSetState( AccessibleStateType::EDITABLE ); + } + } + + void AccessibleParaManager::SetFocus( sal_Int32 nChild ) + { + if( mnFocusedChild != -1 ) + UnSetState( mnFocusedChild, AccessibleStateType::FOCUSED ); + + mnFocusedChild = nChild; + + if( mnFocusedChild != -1 ) + SetState( mnFocusedChild, AccessibleStateType::FOCUSED ); + } + + void AccessibleParaManager::InitChild( AccessibleEditableTextPara& rChild, + SvxEditSourceAdapter& rEditSource, + sal_Int32 nChild, + sal_uInt32 nParagraphIndex ) const + { + rChild.SetEditSource( &rEditSource ); + rChild.SetIndexInParent( nChild ); + rChild.SetParagraphIndex( nParagraphIndex ); + + rChild.SetEEOffset( maEEOffset ); + + if( mbActive ) + { + rChild.SetState( AccessibleStateType::ACTIVE ); + rChild.SetState( AccessibleStateType::EDITABLE ); + } + + if( mnFocusedChild == static_cast<sal_Int32>(nParagraphIndex) ) + rChild.SetState( AccessibleStateType::FOCUSED ); + + // add states passed from outside + for( VectorOfStates::const_iterator aIt = maChildStates.begin(), aEnd = maChildStates.end(); aIt != aEnd; ++aIt ) + rChild.SetState( *aIt ); + } + + void AccessibleParaManager::SetState( sal_Int32 nChild, const sal_Int16 nStateId ) + { + MemFunAdapter< const sal_Int16 > aFunc( &AccessibleEditableTextPara::SetState, + nStateId ); + aFunc( GetChild(nChild) ); + } + + void AccessibleParaManager::SetState( const sal_Int16 nStateId ) + { + ::std::for_each( begin(), end(), + MemFunAdapter< const sal_Int16 >( &AccessibleEditableTextPara::SetState, + nStateId ) ); + } + + void AccessibleParaManager::UnSetState( sal_Int32 nChild, const sal_Int16 nStateId ) + { + MemFunAdapter< const sal_Int16 > aFunc( &AccessibleEditableTextPara::UnSetState, + nStateId ); + aFunc( GetChild(nChild) ); + } + + void AccessibleParaManager::UnSetState( const sal_Int16 nStateId ) + { + ::std::for_each( begin(), end(), + MemFunAdapter< const sal_Int16 >( &AccessibleEditableTextPara::UnSetState, + nStateId ) ); + } + + void AccessibleParaManager::SetEditSource( SvxEditSourceAdapter* pEditSource ) + { + MemFunAdapter< SvxEditSourceAdapter* > aAdapter( &::accessibility::AccessibleEditableTextPara::SetEditSource, pEditSource ); + ::std::for_each( begin(), end(), aAdapter ); + } + + // not generic yet, no arguments... + class AccessibleParaManager_DisposeChildren : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void > + { + public: + AccessibleParaManager_DisposeChildren() {} + void operator()( ::accessibility::AccessibleEditableTextPara& rPara ) + { + rPara.Dispose(); + } + }; + + void AccessibleParaManager::Dispose() + { + AccessibleParaManager_DisposeChildren aFunctor; + + ::std::for_each( begin(), end(), + WeakChildAdapter< AccessibleParaManager_DisposeChildren > (aFunctor) ); + } + + // not generic yet, too many method arguments... + class StateChangeEvent : public ::std::unary_function< ::accessibility::AccessibleEditableTextPara&, void > + { + public: + typedef void return_type; + StateChangeEvent( const sal_Int16 nEventId, + const uno::Any& rNewValue, + const uno::Any& rOldValue ) : + mnEventId( nEventId ), + mrNewValue( rNewValue ), + mrOldValue( rOldValue ) {} + void operator()( ::accessibility::AccessibleEditableTextPara& rPara ) + { + rPara.FireEvent( mnEventId, mrNewValue, mrOldValue ); + } + + private: + const sal_Int16 mnEventId; + const uno::Any& mrNewValue; + const uno::Any& mrOldValue; + }; + + void AccessibleParaManager::FireEvent( sal_uInt32 nStartPara, + sal_uInt32 nEndPara, + const sal_Int16 nEventId, + const uno::Any& rNewValue, + const uno::Any& rOldValue ) const + { + DBG_ASSERT( maChildren.size() > nStartPara && + maChildren.size() >= nEndPara , "AccessibleParaManager::FireEvent: invalid index" ); + + if( maChildren.size() > nStartPara && + maChildren.size() >= nEndPara ) + { + VectorOfChildren::const_iterator front = maChildren.begin(); + VectorOfChildren::const_iterator back = front; + + ::std::advance( front, nStartPara ); + ::std::advance( back, nEndPara ); + + StateChangeEvent aFunctor( nEventId, rNewValue, rOldValue ); + + ::std::for_each( front, back, AccessibleParaManager::WeakChildAdapter< StateChangeEvent >( aFunctor ) ); + } + } + + class ReleaseChild : public ::std::unary_function< const AccessibleParaManager::WeakChild&, AccessibleParaManager::WeakChild > + { + public: + AccessibleParaManager::WeakChild operator()( const AccessibleParaManager::WeakChild& rPara ) + { + AccessibleParaManager::ShutdownPara( rPara ); + + // clear reference + return AccessibleParaManager::WeakChild(); + } + }; + + void AccessibleParaManager::Release( sal_uInt32 nStartPara, sal_uInt32 nEndPara ) + { + DBG_ASSERT( maChildren.size() > nStartPara && + maChildren.size() >= nEndPara, "AccessibleParaManager::Release: invalid index" ); + + if( maChildren.size() > nStartPara && + maChildren.size() >= nEndPara ) + { + VectorOfChildren::iterator front = maChildren.begin(); + VectorOfChildren::iterator back = front; + + ::std::advance( front, nStartPara ); + ::std::advance( back, nEndPara ); + + ::std::transform( front, back, front, ReleaseChild() ); + } + } + + void AccessibleParaManager::ShutdownPara( const WeakChild& rChild ) + { + WeakPara::HardRefType aChild( rChild.first.get() ); + + if( IsReferencable( aChild ) ) + aChild->SetEditSource( NULL ); + } + +} + +//------------------------------------------------------------------------ diff --git a/editeng/source/accessibility/AccessibleSelectionBase.cxx b/editeng/source/accessibility/AccessibleSelectionBase.cxx new file mode 100644 index 000000000000..8419be2672aa --- /dev/null +++ b/editeng/source/accessibility/AccessibleSelectionBase.cxx @@ -0,0 +1,111 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleSelectionBase.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/AccessibleSelectionBase.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +namespace accessibility +{ + // --------------------------- + // - AccessibleSelectionBase - + // --------------------------- + + AccessibleSelectionBase::AccessibleSelectionBase() + { + } + + //-------------------------------------------------------------------- + + AccessibleSelectionBase::~AccessibleSelectionBase() + { + } + + //-------------------------------------------------------------------- + + void SAL_CALL AccessibleSelectionBase::selectAccessibleChild( sal_Int32 nChildIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( implGetMutex() ); + OCommonAccessibleSelection::selectAccessibleChild( nChildIndex ); + } + + //-------------------------------------------------------------------- + + sal_Bool SAL_CALL AccessibleSelectionBase::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( implGetMutex() ); + return( OCommonAccessibleSelection::isAccessibleChildSelected( nChildIndex ) ); + } + + //-------------------------------------------------------------------- + + void SAL_CALL AccessibleSelectionBase::clearAccessibleSelection( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( implGetMutex() ); + OCommonAccessibleSelection::clearAccessibleSelection(); + } + + //-------------------------------------------------------------------- + + void SAL_CALL AccessibleSelectionBase::selectAllAccessibleChildren( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( implGetMutex() ); + OCommonAccessibleSelection::selectAllAccessibleChildren(); + } + + //-------------------------------------------------------------------- + + sal_Int32 SAL_CALL AccessibleSelectionBase::getSelectedAccessibleChildCount( ) throw (uno::RuntimeException) + { + ::osl::MutexGuard aGuard( implGetMutex() ); + return( OCommonAccessibleSelection::getSelectedAccessibleChildCount() ); + } + + //-------------------------------------------------------------------- + + uno::Reference< XAccessible > SAL_CALL AccessibleSelectionBase::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( implGetMutex() ); + return( OCommonAccessibleSelection::getSelectedAccessibleChild( nSelectedChildIndex ) ); + } + + //-------------------------------------------------------------------- + + void SAL_CALL AccessibleSelectionBase::deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::osl::MutexGuard aGuard( implGetMutex() ); + OCommonAccessibleSelection::deselectAccessibleChild( nSelectedChildIndex ); + } +} diff --git a/editeng/source/accessibility/AccessibleStaticTextBase.cxx b/editeng/source/accessibility/AccessibleStaticTextBase.cxx new file mode 100644 index 000000000000..c74b44904252 --- /dev/null +++ b/editeng/source/accessibility/AccessibleStaticTextBase.cxx @@ -0,0 +1,1050 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleStaticTextBase.cxx,v $ + * $Revision: 1.27 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +//------------------------------------------------------------------------ +// +// Global header +// +//------------------------------------------------------------------------ + +#include <limits.h> +#include <vector> +#include <algorithm> +#include <boost/bind.hpp> +#include <vos/mutex.hxx> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <comphelper/sequenceasvector.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/awt/Point.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/accessibility/AccessibleTextType.hpp> + +//------------------------------------------------------------------------ +// +// Project-local header +// +//------------------------------------------------------------------------ + +#include <editeng/editdata.hxx> +#include <editeng/unopracc.hxx> +#include "editeng/unoedprx.hxx" +#include <editeng/AccessibleStaticTextBase.hxx> +#include "editeng/AccessibleEditableTextPara.hxx" + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::accessibility; + +/* TODO: + ===== + + - separate adapter functionality from AccessibleStaticText class + + - refactor common loops into templates, using mem_fun + + */ + +namespace accessibility +{ + typedef ::comphelper::SequenceAsVector< beans::PropertyValue > PropertyValueVector; + + class PropertyValueEqualFunctor : public ::std::binary_function< beans::PropertyValue, beans::PropertyValue, bool > + { + public: + PropertyValueEqualFunctor() + {} + bool operator() ( const beans::PropertyValue& lhs, const beans::PropertyValue& rhs ) const + { + return ( lhs.Name == rhs.Name && lhs.Value == rhs.Value ); + } + }; + + //------------------------------------------------------------------------ + // + // Static Helper + // + //------------------------------------------------------------------------ + ESelection MakeSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex, + sal_Int32 nEndPara, sal_Int32 nEndIndex ) + { + DBG_ASSERT(nStartPara >= 0 && nStartPara <= USHRT_MAX && + nStartIndex >= 0 && nStartIndex <= USHRT_MAX && + nEndPara >= 0 && nEndPara <= USHRT_MAX && + nEndIndex >= 0 && nEndIndex <= USHRT_MAX , + "AccessibleStaticTextBase_Impl::MakeSelection: index value overflow"); + + return ESelection( static_cast< USHORT >(nStartPara), static_cast< USHORT >(nStartIndex), + static_cast< USHORT >(nEndPara), static_cast< USHORT >(nEndIndex) ); + } + + //------------------------------------------------------------------------ + // + // AccessibleStaticTextBase_Impl declaration + // + //------------------------------------------------------------------------ + + DBG_NAME( AccessibleStaticTextBase_Impl ); + + /** AccessibleStaticTextBase_Impl + + This class implements the AccessibleStaticTextBase + functionality, mainly by forwarding the calls to an aggregated + AccessibleEditableTextPara. As this is a therefore non-trivial + adapter, factoring out the common functionality from + AccessibleEditableTextPara might be a profitable future task. + */ + class AccessibleStaticTextBase_Impl + { + + public: + + // receive pointer to our frontend class and view window + AccessibleStaticTextBase_Impl(); + ~AccessibleStaticTextBase_Impl(); + + SvxEditSourceAdapter& GetEditSource() const SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + return maEditSource; + } + void SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)); + + void SetEventSource( const uno::Reference< XAccessible >& rInterface ) + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + mxThis = rInterface; + } + uno::Reference< XAccessible > GetEventSource() const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + return mxThis; + } + + void SetOffset( const Point& ); + Point GetOffset() const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + ::osl::MutexGuard aGuard( maMutex ); Point aPoint( maOffset ); + return aPoint; + } + + void UpdateChildren(); + void Dispose(); + +#ifdef DBG_UTIL + void CheckInvariants() const; +#endif + + AccessibleEditableTextPara& GetParagraph( sal_Int32 nPara ) const; + sal_Int32 GetParagraphCount() const; + sal_Int32 GetParagraphIndex() const; + sal_Int32 GetLineCount( sal_Int32 nParagraph ) const; + + EPosition Index2Internal( sal_Int32 nFlatIndex ) const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + return ImpCalcInternal( nFlatIndex, false ); + } + + EPosition Range2Internal( sal_Int32 nFlatIndex ) const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + return ImpCalcInternal( nFlatIndex, true ); + } + + sal_Int32 Internal2Index( EPosition nEEIndex ) const; + + void CorrectTextSegment( TextSegment& aTextSegment, + int nPara ) const; + + sal_Bool SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex, + sal_Int32 nEndPara, sal_Int32 nEndIndex ); + sal_Bool CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex, + sal_Int32 nEndPara, sal_Int32 nEndIndex ); + + Rectangle GetParagraphBoundingBox() const; + + private: + + EPosition ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const; + + // our frontend class (the one implementing the actual + // interface). That's not necessarily the one containing the impl + // pointer + uno::Reference< XAccessible > mxThis; + + // implements our functionality, we're just an adapter (guarded by solar mutex) + mutable AccessibleEditableTextPara* mpTextParagraph; + + uno::Reference< XAccessible > mxParagraph; + + // a wrapper for the text forwarders (guarded by solar mutex) + mutable SvxEditSourceAdapter maEditSource; + + // guard for maOffset + mutable ::osl::Mutex maMutex; + + /// our current offset to the containing shape/cell (guarded by maMutex) + Point maOffset; + + }; + + //------------------------------------------------------------------------ + // + // AccessibleStaticTextBase_Impl implementation + // + //------------------------------------------------------------------------ + + AccessibleStaticTextBase_Impl::AccessibleStaticTextBase_Impl() : + mxThis( NULL ), + mpTextParagraph( new AccessibleEditableTextPara(NULL) ), + mxParagraph( mpTextParagraph ), + maEditSource(), + maMutex(), + maOffset(0,0) + { + DBG_CTOR( AccessibleStaticTextBase_Impl, NULL ); + + // TODO: this is still somewhat of a hack, all the more since + // now the maTextParagraph has an empty parent reference set + } + + AccessibleStaticTextBase_Impl::~AccessibleStaticTextBase_Impl() + { + DBG_DTOR( AccessibleStaticTextBase_Impl, NULL ); + } + + void AccessibleStaticTextBase_Impl::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((uno::RuntimeException)) + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + maEditSource.SetEditSource( pEditSource ); + if( mpTextParagraph ) + mpTextParagraph->SetEditSource( &maEditSource ); + } + + void AccessibleStaticTextBase_Impl::SetOffset( const Point& rPoint ) + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + // guard against non-atomic access to maOffset data structure + { + ::osl::MutexGuard aGuard( maMutex ); + maOffset = rPoint; + } + + if( mpTextParagraph ) + mpTextParagraph->SetEEOffset( rPoint ); + + // in all cases, check visibility afterwards. + UpdateChildren(); + } + + void AccessibleStaticTextBase_Impl::UpdateChildren() + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + // currently no children + } + + void AccessibleStaticTextBase_Impl::Dispose() + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + // we're the owner of the paragraph, so destroy it, too + if( mpTextParagraph ) + mpTextParagraph->Dispose(); + + // drop references + mxParagraph = NULL; + mxThis = NULL; + mpTextParagraph = NULL; + } + +#ifdef DBG_UTIL + void AccessibleStaticTextBase_Impl::CheckInvariants() const + { + // TODO + } +#endif + + AccessibleEditableTextPara& AccessibleStaticTextBase_Impl::GetParagraph( sal_Int32 nPara ) const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + if( !mpTextParagraph ) + throw lang::DisposedException ( + ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")), mxThis ); + + // TODO: Have a differnt method on AccessibleEditableTextPara + // that does not care about state changes + mpTextParagraph->SetParagraphIndex( nPara ); + + return *mpTextParagraph; + } + + sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphCount() const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + if( !mpTextParagraph ) + return 0; + else + return mpTextParagraph->GetTextForwarder().GetParagraphCount(); + } + + sal_Int32 AccessibleStaticTextBase_Impl::GetParagraphIndex() const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + sal_Int32 nIndex = -1; + if( mpTextParagraph ) + nIndex = mpTextParagraph->GetParagraphIndex(); + return nIndex; + } + + sal_Int32 AccessibleStaticTextBase_Impl::GetLineCount( sal_Int32 nParagraph ) const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + sal_Int32 nIndex = 0; + if( mpTextParagraph ) + nIndex = mpTextParagraph->GetTextForwarder().GetLineCount( static_cast< USHORT >(nParagraph) ); + return nIndex; + } + + sal_Int32 AccessibleStaticTextBase_Impl::Internal2Index( EPosition nEEIndex ) const + { + sal_Int32 aRes(0); + int i; + for(i=0; i<nEEIndex.nPara; ++i) + aRes += GetParagraph(i).getCharacterCount(); + + return aRes + nEEIndex.nIndex; + } + + void AccessibleStaticTextBase_Impl::CorrectTextSegment( TextSegment& aTextSegment, + int nPara ) const + { + // Keep 'invalid' values at the TextSegment + if( aTextSegment.SegmentStart != -1 && + aTextSegment.SegmentStart != -1 ) + { + // #112814# Correct TextSegment by paragraph offset + sal_Int32 nOffset(0); + int i; + for(i=0; i<nPara; ++i) + nOffset += GetParagraph(i).getCharacterCount(); + + aTextSegment.SegmentStart += nOffset; + aTextSegment.SegmentEnd += nOffset; + } + } + + EPosition AccessibleStaticTextBase_Impl::ImpCalcInternal( sal_Int32 nFlatIndex, bool bExclusive ) const + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + if( nFlatIndex < 0 ) + throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")), + mxThis); + // gratuitously accepting larger indices here, AccessibleEditableTextPara will throw eventually + + sal_Int32 nCurrPara, nCurrIndex, nParas, nCurrCount; + for( nCurrPara=0, nParas=GetParagraphCount(), nCurrCount=0, nCurrIndex=0; nCurrPara<nParas; ++nCurrPara ) + { + nCurrCount = GetParagraph( nCurrPara ).getCharacterCount(); + nCurrIndex += nCurrCount; + + if( nCurrIndex > nFlatIndex ) + { + // check overflow + DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX && + nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX , + "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow"); + + return EPosition( static_cast< USHORT >(nCurrPara), static_cast< USHORT >(nFlatIndex - nCurrIndex + nCurrCount) ); + } + } + + // #102170# Allow one-past the end for ranges + if( bExclusive && nCurrIndex == nFlatIndex ) + { + // check overflow + DBG_ASSERT(nCurrPara >= 0 && nCurrPara <= USHRT_MAX && + nFlatIndex - nCurrIndex + nCurrCount >= 0 && nFlatIndex - nCurrIndex + nCurrCount <= USHRT_MAX , + "AccessibleStaticTextBase_Impl::Index2Internal: index value overflow"); + + return EPosition( static_cast< USHORT >(nCurrPara-1), static_cast< USHORT >(nFlatIndex - nCurrIndex + nCurrCount) ); + } + + // not found? Out of bounds + throw lang::IndexOutOfBoundsException(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleStaticTextBase_Impl::Index2Internal: character index out of bounds")), + mxThis); + } + + sal_Bool AccessibleStaticTextBase_Impl::SetSelection( sal_Int32 nStartPara, sal_Int32 nStartIndex, + sal_Int32 nEndPara, sal_Int32 nEndIndex ) + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + if( !mpTextParagraph ) + return sal_False; + + try + { + SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True ); + return rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) ); + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + sal_Bool AccessibleStaticTextBase_Impl::CopyText( sal_Int32 nStartPara, sal_Int32 nStartIndex, + sal_Int32 nEndPara, sal_Int32 nEndIndex ) + { + DBG_CHKTHIS( AccessibleStaticTextBase_Impl, NULL ); + + if( !mpTextParagraph ) + return sal_False; + + try + { + SvxEditViewForwarder& rCacheVF = mpTextParagraph->GetEditViewForwarder( sal_True ); + mpTextParagraph->GetTextForwarder(); // MUST be after GetEditViewForwarder(), see method docs + sal_Bool aRetVal; + + // save current selection + ESelection aOldSelection; + + rCacheVF.GetSelection( aOldSelection ); + rCacheVF.SetSelection( MakeSelection(nStartPara, nStartIndex, nEndPara, nEndIndex) ); + aRetVal = rCacheVF.Copy(); + rCacheVF.SetSelection( aOldSelection ); // restore + + return aRetVal; + } + catch( const uno::RuntimeException& ) + { + return sal_False; + } + } + + Rectangle AccessibleStaticTextBase_Impl::GetParagraphBoundingBox() const + { + Rectangle aRect; + if( mpTextParagraph ) + { + awt::Rectangle aAwtRect = mpTextParagraph->getBounds(); + aRect = Rectangle( Point( aAwtRect.X, aAwtRect.Y ), Size( aAwtRect.Width, aAwtRect.Height ) ); + } + else + { + aRect.SetEmpty(); + } + return aRect; + } + + //------------------------------------------------------------------------ + // + // AccessibleStaticTextBase implementation + // + //------------------------------------------------------------------------ + + AccessibleStaticTextBase::AccessibleStaticTextBase( ::std::auto_ptr< SvxEditSource > pEditSource ) : + mpImpl( new AccessibleStaticTextBase_Impl() ) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + SetEditSource( pEditSource ); + } + + AccessibleStaticTextBase::~AccessibleStaticTextBase() + { + } + + const SvxEditSource& AccessibleStaticTextBase::GetEditSource() const SAL_THROW((::com::sun::star::uno::RuntimeException)) + { +#ifdef DBG_UTIL + mpImpl->CheckInvariants(); + + const SvxEditSource& aEditSource = mpImpl->GetEditSource(); + + mpImpl->CheckInvariants(); + + return aEditSource; +#else + return mpImpl->GetEditSource(); +#endif + } + + void AccessibleStaticTextBase::SetEditSource( ::std::auto_ptr< SvxEditSource > pEditSource ) SAL_THROW((::com::sun::star::uno::RuntimeException)) + { +#ifdef DBG_UTIL + // precondition: solar mutex locked + DBG_TESTSOLARMUTEX(); + + mpImpl->CheckInvariants(); + + mpImpl->SetEditSource( pEditSource ); + + mpImpl->CheckInvariants(); +#else + mpImpl->SetEditSource( pEditSource ); +#endif + } + + void AccessibleStaticTextBase::SetEventSource( const uno::Reference< XAccessible >& rInterface ) + { +#ifdef DBG_UTIL + mpImpl->CheckInvariants(); +#endif + + mpImpl->SetEventSource( rInterface ); + +#ifdef DBG_UTIL + mpImpl->CheckInvariants(); +#endif + } + + uno::Reference< XAccessible > AccessibleStaticTextBase::GetEventSource() const + { +#ifdef DBG_UTIL + mpImpl->CheckInvariants(); + + uno::Reference< XAccessible > xRet( mpImpl->GetEventSource() ); + + mpImpl->CheckInvariants(); + + return xRet; +#else + return mpImpl->GetEventSource(); +#endif + } + + void AccessibleStaticTextBase::SetOffset( const Point& rPoint ) + { +#ifdef DBG_UTIL + // precondition: solar mutex locked + DBG_TESTSOLARMUTEX(); + + mpImpl->CheckInvariants(); + + mpImpl->SetOffset( rPoint ); + + mpImpl->CheckInvariants(); +#else + mpImpl->SetOffset( rPoint ); +#endif + } + + Point AccessibleStaticTextBase::GetOffset() const + { +#ifdef DBG_UTIL + mpImpl->CheckInvariants(); + + Point aPoint( mpImpl->GetOffset() ); + + mpImpl->CheckInvariants(); + + return aPoint; +#else + return mpImpl->GetOffset(); +#endif + } + + void AccessibleStaticTextBase::UpdateChildren() SAL_THROW((::com::sun::star::uno::RuntimeException)) + { +#ifdef DBG_UTIL + // precondition: solar mutex locked + DBG_TESTSOLARMUTEX(); + + mpImpl->CheckInvariants(); + + mpImpl->UpdateChildren(); + + mpImpl->CheckInvariants(); +#else + mpImpl->UpdateChildren(); +#endif + } + + void AccessibleStaticTextBase::Dispose() + { +#ifdef DBG_UTIL + mpImpl->CheckInvariants(); +#endif + + mpImpl->Dispose(); + +#ifdef DBG_UTIL + mpImpl->CheckInvariants(); +#endif + } + + // XAccessibleContext + sal_Int32 SAL_CALL AccessibleStaticTextBase::getAccessibleChildCount() throw (uno::RuntimeException) + { + // no children at all + return 0; + } + + uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleChild( sal_Int32 /*i*/ ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + // no children at all + return uno::Reference< XAccessible >(); + } + + uno::Reference< XAccessible > SAL_CALL AccessibleStaticTextBase::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) throw (uno::RuntimeException) + { + // no children at all + return uno::Reference< XAccessible >(); + } + + // XAccessibleText + sal_Int32 SAL_CALL AccessibleStaticTextBase::getCaretPosition() throw (uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + sal_Int32 i, nPos, nParas; + for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) + { + if( (nPos=mpImpl->GetParagraph(i).getCaretPosition()) != -1 ) + return nPos; + } + + return nPos; + } + + sal_Bool SAL_CALL AccessibleStaticTextBase::setCaretPosition( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + return setSelection(nIndex, nIndex); + } + + sal_Unicode SAL_CALL AccessibleStaticTextBase::getCharacter( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + EPosition aPos( mpImpl->Index2Internal(nIndex) ); + + return mpImpl->GetParagraph( aPos.nPara ).getCharacter( aPos.nIndex ); + } + + uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getCharacterAttributes( sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + EPosition aPos( mpImpl->Index2Internal(nIndex) ); + + return mpImpl->GetParagraph( aPos.nPara ).getCharacterAttributes( aPos.nIndex, aRequestedAttributes ); + } + + awt::Rectangle SAL_CALL AccessibleStaticTextBase::getCharacterBounds( sal_Int32 nIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + // #108900# Allow ranges for nIndex, as one-past-the-end + // values are now legal, too. + EPosition aPos( mpImpl->Range2Internal(nIndex) ); + + // #i70916# Text in spread sheet cells return the wrong extents + AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara ); + awt::Rectangle aParaBounds( rPara.getBounds() ); + awt::Rectangle aBounds( rPara.getCharacterBounds( aPos.nIndex ) ); + aBounds.X += aParaBounds.X; + aBounds.Y += aParaBounds.Y; + + return aBounds; + } + + sal_Int32 SAL_CALL AccessibleStaticTextBase::getCharacterCount() throw (uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + sal_Int32 i, nCount, nParas; + for( i=0, nCount=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) + nCount += mpImpl->GetParagraph(i).getCharacterCount(); + + return nCount; + } + + sal_Int32 SAL_CALL AccessibleStaticTextBase::getIndexAtPoint( const awt::Point& rPoint ) throw (uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + const sal_Int32 nParas( mpImpl->GetParagraphCount() ); + sal_Int32 nIndex; + int i; + for( i=0; i<nParas; ++i ) + { + // TODO: maybe exploit the fact that paragraphs are + // ordered vertically for early exit + + // #i70916# Text in spread sheet cells return the wrong extents + AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( i ); + awt::Rectangle aParaBounds( rPara.getBounds() ); + awt::Point aPoint( rPoint ); + aPoint.X -= aParaBounds.X; + aPoint.Y -= aParaBounds.Y; + + // #112814# Use correct index offset + if ( ( nIndex = rPara.getIndexAtPoint( aPoint ) ) != -1 ) + return mpImpl->Internal2Index( EPosition(sal::static_int_cast<USHORT>(i), + sal::static_int_cast<USHORT>(nIndex)) ); + } + + return -1; + } + + ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getSelectedText() throw (uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + sal_Int32 nStart( getSelectionStart() ); + sal_Int32 nEnd( getSelectionEnd() ); + + // #104481# Return the empty string for 'no selection' + if( nStart < 0 || nEnd < 0 ) + return ::rtl::OUString(); + + return getTextRange( nStart, nEnd ); + } + + sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionStart() throw (uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + sal_Int32 i, nPos, nParas; + for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) + { + if( (nPos=mpImpl->GetParagraph(i).getSelectionStart()) != -1 ) + return nPos; + } + + return nPos; + } + + sal_Int32 SAL_CALL AccessibleStaticTextBase::getSelectionEnd() throw (uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + sal_Int32 i, nPos, nParas; + for( i=0, nPos=-1, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) + { + if( (nPos=mpImpl->GetParagraph(i).getSelectionEnd()) != -1 ) + return nPos; + } + + return nPos; + } + + sal_Bool SAL_CALL AccessibleStaticTextBase::setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) ); + EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) ); + + return mpImpl->SetSelection( aStartIndex.nPara, aStartIndex.nIndex, + aEndIndex.nPara, aEndIndex.nIndex ); + } + + ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getText() throw (uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + sal_Int32 i, nParas; + ::rtl::OUString aRes; + for( i=0, nParas=mpImpl->GetParagraphCount(); i<nParas; ++i ) + aRes += mpImpl->GetParagraph(i).getText(); + + return aRes; + } + + ::rtl::OUString SAL_CALL AccessibleStaticTextBase::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if( nStartIndex > nEndIndex ) + ::std::swap(nStartIndex, nEndIndex); + + EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) ); + EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) ); + + // #102170# Special case: start and end paragraph are identical + if( aStartIndex.nPara == aEndIndex.nPara ) + { + return mpImpl->GetParagraph( aStartIndex.nPara ).getTextRange( aStartIndex.nIndex, aEndIndex.nIndex ); + } + else + { + sal_Int32 i( aStartIndex.nPara ); + ::rtl::OUString aRes( mpImpl->GetParagraph(i).getTextRange( aStartIndex.nIndex, + mpImpl->GetParagraph(i).getCharacterCount()-1) ); + ++i; + + // paragraphs inbetween are fully included + for( ; i<aEndIndex.nPara; ++i ) + aRes += mpImpl->GetParagraph(i).getText(); + + if( i<=aEndIndex.nPara ) + aRes += mpImpl->GetParagraph(i).getTextRange( 0, aEndIndex.nIndex ); + + return aRes; + } + } + + ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + EPosition aPos( mpImpl->Range2Internal(nIndex) ); + + ::com::sun::star::accessibility::TextSegment aResult; + + if( AccessibleTextType::PARAGRAPH == aTextType ) + { + // #106393# Special casing one behind last paragraph is + // not necessary, since then, we return the content and + // boundary of that last paragraph. Range2Internal is + // tolerant against that, and returns the last paragraph + // in aPos.nPara. + + // retrieve full text of the paragraph + aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText(); + + // #112814# Adapt the start index with the paragraph offset + aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) ); + aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength(); + } + else + { + // No special handling required, forward to wrapped class + aResult = mpImpl->GetParagraph( aPos.nPara ).getTextAtIndex( aPos.nIndex, aTextType ); + + // #112814# Adapt the start index with the paragraph offset + mpImpl->CorrectTextSegment( aResult, aPos.nPara ); + } + + return aResult; + } + + ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + EPosition aPos( mpImpl->Range2Internal(nIndex) ); + + ::com::sun::star::accessibility::TextSegment aResult; + + if( AccessibleTextType::PARAGRAPH == aTextType ) + { + if( aPos.nIndex == mpImpl->GetParagraph( aPos.nPara ).getCharacterCount() ) + { + // #103589# Special casing one behind the last paragraph + aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara ).getText(); + + // #112814# Adapt the start index with the paragraph offset + aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara, 0 ) ); + } + else if( aPos.nPara > 0 ) + { + aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara - 1 ).getText(); + + // #112814# Adapt the start index with the paragraph offset + aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara - 1, 0 ) ); + } + + aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength(); + } + else + { + // No special handling required, forward to wrapped class + aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBeforeIndex( aPos.nIndex, aTextType ); + + // #112814# Adapt the start index with the paragraph offset + mpImpl->CorrectTextSegment( aResult, aPos.nPara ); + } + + return aResult; + } + + ::com::sun::star::accessibility::TextSegment SAL_CALL AccessibleStaticTextBase::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + EPosition aPos( mpImpl->Range2Internal(nIndex) ); + + ::com::sun::star::accessibility::TextSegment aResult; + + if( AccessibleTextType::PARAGRAPH == aTextType ) + { + // Special casing one behind the last paragraph is not + // necessary, this case is invalid here for + // getTextBehindIndex + if( aPos.nPara + 1 < mpImpl->GetParagraphCount() ) + { + aResult.SegmentText = mpImpl->GetParagraph( aPos.nPara + 1 ).getText(); + + // #112814# Adapt the start index with the paragraph offset + aResult.SegmentStart = mpImpl->Internal2Index( EPosition( aPos.nPara + 1, 0 ) ); + aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength(); + } + } + else + { + // No special handling required, forward to wrapped class + aResult = mpImpl->GetParagraph( aPos.nPara ).getTextBehindIndex( aPos.nIndex, aTextType ); + + // #112814# Adapt the start index with the paragraph offset + mpImpl->CorrectTextSegment( aResult, aPos.nPara ); + } + + return aResult; + } + + sal_Bool SAL_CALL AccessibleStaticTextBase::copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + if( nStartIndex > nEndIndex ) + ::std::swap(nStartIndex, nEndIndex); + + EPosition aStartIndex( mpImpl->Range2Internal(nStartIndex) ); + EPosition aEndIndex( mpImpl->Range2Internal(nEndIndex) ); + + return mpImpl->CopyText( aStartIndex.nPara, aStartIndex.nIndex, + aEndIndex.nPara, aEndIndex.nIndex ); + } + + // XAccessibleTextAttributes + uno::Sequence< beans::PropertyValue > AccessibleStaticTextBase::getDefaultAttributes( const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (uno::RuntimeException) + { + // get the intersection of the default attributes of all paragraphs + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + PropertyValueVector aDefAttrVec( mpImpl->GetParagraph( 0 ).getDefaultAttributes( RequestedAttributes ) ); + + const sal_Int32 nParaCount = mpImpl->GetParagraphCount(); + for ( sal_Int32 nPara = 1; nPara < nParaCount; ++nPara ) + { + uno::Sequence< beans::PropertyValue > aSeq = mpImpl->GetParagraph( nPara ).getDefaultAttributes( RequestedAttributes ); + PropertyValueVector aIntersectionVec; + + PropertyValueVector::const_iterator aEnd = aDefAttrVec.end(); + for ( PropertyValueVector::const_iterator aItr = aDefAttrVec.begin(); aItr != aEnd; ++aItr ) + { + const beans::PropertyValue* pItr = aSeq.getConstArray(); + const beans::PropertyValue* pEnd = pItr + aSeq.getLength(); + const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( *aItr ) ) ); + if ( pFind != pEnd ) + { + aIntersectionVec.push_back( *pFind ); + } + } + + aDefAttrVec.swap( aIntersectionVec ); + + if ( aDefAttrVec.empty() ) + { + break; + } + } + + return aDefAttrVec.getAsConstList(); + } + + uno::Sequence< beans::PropertyValue > SAL_CALL AccessibleStaticTextBase::getRunAttributes( sal_Int32 nIndex, const uno::Sequence< ::rtl::OUString >& RequestedAttributes ) throw (lang::IndexOutOfBoundsException, uno::RuntimeException) + { + // get those default attributes of the paragraph, which are not part + // of the intersection of all paragraphs and add them to the run attributes + + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + + EPosition aPos( mpImpl->Index2Internal( nIndex ) ); + AccessibleEditableTextPara& rPara = mpImpl->GetParagraph( aPos.nPara ); + uno::Sequence< beans::PropertyValue > aDefAttrSeq = rPara.getDefaultAttributes( RequestedAttributes ); + uno::Sequence< beans::PropertyValue > aRunAttrSeq = rPara.getRunAttributes( aPos.nIndex, RequestedAttributes ); + uno::Sequence< beans::PropertyValue > aIntersectionSeq = getDefaultAttributes( RequestedAttributes ); + PropertyValueVector aDiffVec; + + const beans::PropertyValue* pDefAttr = aDefAttrSeq.getConstArray(); + const sal_Int32 nLength = aDefAttrSeq.getLength(); + for ( sal_Int32 i = 0; i < nLength; ++i ) + { + const beans::PropertyValue* pItr = aIntersectionSeq.getConstArray(); + const beans::PropertyValue* pEnd = pItr + aIntersectionSeq.getLength(); + const beans::PropertyValue* pFind = ::std::find_if( pItr, pEnd, ::std::bind2nd( PropertyValueEqualFunctor(), boost::cref( pDefAttr[i] ) ) ); + if ( pFind == pEnd && pDefAttr[i].Handle != 0) + { + aDiffVec.push_back( pDefAttr[i] ); + } + } + + return ::comphelper::concatSequences( aRunAttrSeq, aDiffVec.getAsConstList() ); + } + + Rectangle AccessibleStaticTextBase::GetParagraphBoundingBox() const + { + return mpImpl->GetParagraphBoundingBox(); + } + + sal_Int32 AccessibleStaticTextBase::GetParagraphIndex() const + { + return mpImpl->GetParagraphIndex(); + } + + sal_Int32 AccessibleStaticTextBase::GetParagraphCount() const + { + return mpImpl->GetParagraphCount(); + } + + sal_Int32 AccessibleStaticTextBase::GetLineCount( sal_Int32 nParagraph ) const + { + return mpImpl->GetLineCount( nParagraph ); + } + +} // end of namespace accessibility + +//------------------------------------------------------------------------ diff --git a/editeng/source/accessibility/AccessibleStringWrap.cxx b/editeng/source/accessibility/AccessibleStringWrap.cxx new file mode 100644 index 000000000000..3f9fffaf6982 --- /dev/null +++ b/editeng/source/accessibility/AccessibleStringWrap.cxx @@ -0,0 +1,103 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: AccessibleStringWrap.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <algorithm> +#include <tools/debug.hxx> +#include <vcl/outdev.hxx> + +#include <editeng/svxfont.hxx> +#include <editeng/AccessibleStringWrap.hxx> + +//------------------------------------------------------------------------ +// +// AccessibleStringWrap implementation +// +//------------------------------------------------------------------------ + +AccessibleStringWrap::AccessibleStringWrap( OutputDevice& rDev, SvxFont& rFont, const String& rText ) : + mrDev( rDev ), + mrFont( rFont ), + maText( rText ) +{ +} + +sal_Bool AccessibleStringWrap::GetCharacterBounds( sal_Int32 nIndex, Rectangle& rRect ) +{ + DBG_ASSERT(nIndex >= 0 && nIndex <= USHRT_MAX, + "SvxAccessibleStringWrap::GetCharacterBounds: index value overflow"); + + mrFont.SetPhysFont( &mrDev ); + + // #108900# Handle virtual position one-past-the end of the string + if( nIndex >= maText.Len() ) + { + // create a caret bounding rect that has the height of the + // current font and is one pixel wide. + rRect.Left() = mrDev.GetTextWidth(maText); + rRect.Top() = 0; + rRect.SetSize( Size(mrDev.GetTextHeight(), 1) ); + } + else + { + sal_Int32 aXArray[2]; + mrDev.GetCaretPositions( maText, aXArray, static_cast< USHORT >(nIndex), 1 ); + rRect.Left() = 0; + rRect.Top() = 0; + rRect.SetSize( Size(mrDev.GetTextHeight(), labs(aXArray[0] - aXArray[1])) ); + rRect.Move( ::std::min(aXArray[0], aXArray[1]), 0 ); + } + + if( mrFont.IsVertical() ) + { + // #101701# Rotate to vertical + rRect = Rectangle( Point(-rRect.Top(), rRect.Left()), + Point(-rRect.Bottom(), rRect.Right())); + } + + return sal_True; +} + +sal_Int32 AccessibleStringWrap::GetIndexAtPoint( const Point& rPoint ) +{ + // search for character bounding box containing given point + Rectangle aRect; + sal_Int32 i, nLen = maText.Len(); + for( i=0; i<nLen; ++i ) + { + GetCharacterBounds(i, aRect); + if( aRect.IsInside(rPoint) ) + return i; + } + + return -1; +} diff --git a/editeng/source/accessibility/accessibility.src b/editeng/source/accessibility/accessibility.src new file mode 100644 index 000000000000..430af128e58e --- /dev/null +++ b/editeng/source/accessibility/accessibility.src @@ -0,0 +1,43 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: accessibility.src,v $ + * $Revision: 1.34 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "editeng.hrc" + +String RID_SVXSTR_A11Y_IMAGEBULLET_DESCRIPTION +{ + Text [ en-US ] = "Image bullet in paragraph" ; +}; + +String RID_SVXSTR_A11Y_IMAGEBULLET_NAME +{ + Text [ en-US ] = "Image bullet" ; +}; + + diff --git a/editeng/source/accessibility/makefile.mk b/editeng/source/accessibility/makefile.mk new file mode 100755 index 000000000000..e29b6477f608 --- /dev/null +++ b/editeng/source/accessibility/makefile.mk @@ -0,0 +1,58 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.25 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=editeng +TARGET=accessibility +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES = \ + $(SLO)$/AccessibleStringWrap.obj \ + $(SLO)$/AccessibleContextBase.obj \ + $(SLO)$/AccessibleComponentBase.obj \ + $(SLO)$/AccessibleSelectionBase.obj \ + $(SLO)$/AccessibleStaticTextBase.obj \ + $(SLO)$/AccessibleParaManager.obj \ + $(SLO)$/AccessibleEditableTextPara.obj \ + $(SLO)$/AccessibleImageBullet.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/editeng/source/editeng/editattr.cxx b/editeng/source/editeng/editattr.cxx new file mode 100644 index 000000000000..f55b6d9bab0c --- /dev/null +++ b/editeng/source/editeng/editattr.cxx @@ -0,0 +1,457 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editattr.cxx,v $ + * $Revision: 1.16.212.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +//#include <eeng_pch.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/svxfont.hxx> +#include <editeng/flditem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> + +#include "editattr.hxx" + +DBG_NAME( EE_EditAttrib ) + +// ------------------------------------------------------------------------- +// class EditAttrib +// ------------------------------------------------------------------------- +EditAttrib::EditAttrib( const SfxPoolItem& rAttr ) +{ + DBG_CTOR( EE_EditAttrib, 0 ); + pItem = &rAttr; +} + +EditAttrib::~EditAttrib() +{ + DBG_DTOR( EE_EditAttrib, 0 ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttrib +// ------------------------------------------------------------------------- +EditCharAttrib::EditCharAttrib( const SfxPoolItem& rAttr, USHORT nS, USHORT nE ) + : EditAttrib( rAttr ) +{ + nStart = nS; + nEnd = nE; + bFeature = FALSE; + bEdge = FALSE; + + DBG_ASSERT( ( rAttr.Which() >= EE_ITEMS_START ) && ( rAttr.Which() <= EE_ITEMS_END ), "EditCharAttrib CTOR: Invalid id!" ); + DBG_ASSERT( ( rAttr.Which() < EE_FEATURE_START ) || ( rAttr.Which() > EE_FEATURE_END ) || ( nE == (nS+1) ), "EditCharAttrib CTOR: Invalid feature!" ); +} + +void EditCharAttrib::SetFont( SvxFont&, OutputDevice* ) +{ +} + + +// ------------------------------------------------------------------------- +// class EditCharAttribFont +// ------------------------------------------------------------------------- +EditCharAttribFont::EditCharAttribFont( const SvxFontItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_FONTINFO || rAttr.Which() == EE_CHAR_FONTINFO_CJK || rAttr.Which() == EE_CHAR_FONTINFO_CTL, "Kein Fontattribut!" ); +} + +void EditCharAttribFont::SetFont( SvxFont& rFont, OutputDevice* ) +{ + const SvxFontItem& rAttr = (const SvxFontItem&)(*GetItem()); + + rFont.SetName( rAttr.GetFamilyName() ); + rFont.SetFamily( rAttr.GetFamily() ); + rFont.SetPitch( rAttr.GetPitch() ); + rFont.SetCharSet( rAttr.GetCharSet() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribItalic +// ------------------------------------------------------------------------- +EditCharAttribItalic::EditCharAttribItalic( const SvxPostureItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_ITALIC || rAttr.Which() == EE_CHAR_ITALIC_CJK || rAttr.Which() == EE_CHAR_ITALIC_CTL, "Kein Italicattribut!" ); +} + +void EditCharAttribItalic::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetItalic( ((const SvxPostureItem*)GetItem())->GetPosture() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribWeight +// ------------------------------------------------------------------------- +EditCharAttribWeight::EditCharAttribWeight( const SvxWeightItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_WEIGHT || rAttr.Which() == EE_CHAR_WEIGHT_CJK || rAttr.Which() == EE_CHAR_WEIGHT_CTL, "Kein Weightttribut!" ); +} + +void EditCharAttribWeight::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetWeight( (FontWeight)((const SvxWeightItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribUnderline +// ------------------------------------------------------------------------- +EditCharAttribUnderline::EditCharAttribUnderline( const SvxUnderlineItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_UNDERLINE, "Kein Underlineattribut!" ); +} + +void EditCharAttribUnderline::SetFont( SvxFont& rFont, OutputDevice* pOutDev ) +{ + rFont.SetUnderline( (FontUnderline)((const SvxUnderlineItem*)GetItem())->GetValue() ); + if ( pOutDev ) + pOutDev->SetTextLineColor( ((const SvxUnderlineItem*)GetItem())->GetColor() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribOverline +// ------------------------------------------------------------------------- +EditCharAttribOverline::EditCharAttribOverline( const SvxOverlineItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_OVERLINE, "Kein Overlineattribut!" ); +} + +void EditCharAttribOverline::SetFont( SvxFont& rFont, OutputDevice* pOutDev ) +{ + rFont.SetOverline( (FontUnderline)((const SvxOverlineItem*)GetItem())->GetValue() ); + if ( pOutDev ) + pOutDev->SetOverlineColor( ((const SvxOverlineItem*)GetItem())->GetColor() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribFontHeight +// ------------------------------------------------------------------------- +EditCharAttribFontHeight::EditCharAttribFontHeight( const SvxFontHeightItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_FONTHEIGHT || rAttr.Which() == EE_CHAR_FONTHEIGHT_CJK || rAttr.Which() == EE_CHAR_FONTHEIGHT_CTL, "Kein Heightattribut!" ); +} + +void EditCharAttribFontHeight::SetFont( SvxFont& rFont, OutputDevice* ) +{ + // Prop wird ignoriert + rFont.SetSize( Size( rFont.GetSize().Width(), ((const SvxFontHeightItem*)GetItem())->GetHeight() ) ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribFontWidth +// ------------------------------------------------------------------------- +EditCharAttribFontWidth::EditCharAttribFontWidth( const SvxCharScaleWidthItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_FONTWIDTH, "Kein Widthattribut!" ); +} + +void EditCharAttribFontWidth::SetFont( SvxFont& /*rFont*/, OutputDevice* ) +{ + // must be calculated outside, because f(device)... +} + +// ------------------------------------------------------------------------- +// class EditCharAttribStrikeout +// ------------------------------------------------------------------------- +EditCharAttribStrikeout::EditCharAttribStrikeout( const SvxCrossedOutItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_STRIKEOUT, "Kein Sizeattribut!" ); +} + +void EditCharAttribStrikeout::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetStrikeout( (FontStrikeout)((const SvxCrossedOutItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribColor +// ------------------------------------------------------------------------- +EditCharAttribColor::EditCharAttribColor( const SvxColorItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_COLOR, "Kein Colorattribut!" ); +} + +void EditCharAttribColor::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetColor( ((const SvxColorItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribLanguage +// ------------------------------------------------------------------------- +EditCharAttribLanguage::EditCharAttribLanguage( const SvxLanguageItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( ( rAttr.Which() == EE_CHAR_LANGUAGE ) || ( rAttr.Which() == EE_CHAR_LANGUAGE_CJK ) || ( rAttr.Which() == EE_CHAR_LANGUAGE_CTL ), "Kein Languageattribut!" ); +} + +void EditCharAttribLanguage::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetLanguage( ((const SvxLanguageItem*)GetItem())->GetLanguage() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribShadow +// ------------------------------------------------------------------------- +EditCharAttribShadow::EditCharAttribShadow( const SvxShadowedItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_SHADOW, "Kein Shadowattribut!" ); +} + +void EditCharAttribShadow::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetShadow( (BOOL)((const SvxShadowedItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribEscapement +// ------------------------------------------------------------------------- +EditCharAttribEscapement::EditCharAttribEscapement( const SvxEscapementItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_ESCAPEMENT, "Kein Escapementattribut!" ); +} + +#if defined( WIN ) && !defined( WNT ) +#pragma optimize ("", off) +#endif + +void EditCharAttribEscapement::SetFont( SvxFont& rFont, OutputDevice* ) +{ + USHORT nProp = ((const SvxEscapementItem*)GetItem())->GetProp(); + rFont.SetPropr( (BYTE)nProp ); + + short nEsc = ((const SvxEscapementItem*)GetItem())->GetEsc(); + if ( nEsc == DFLT_ESC_AUTO_SUPER ) + nEsc = 100 - nProp; + else if ( nEsc == DFLT_ESC_AUTO_SUB ) + nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); + rFont.SetEscapement( nEsc ); +} + +#if defined( WIN ) && !defined( WNT ) +#pragma optimize ("", on) +#endif + + +// ------------------------------------------------------------------------- +// class EditCharAttribOutline +// ------------------------------------------------------------------------- +EditCharAttribOutline::EditCharAttribOutline( const SvxContourItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_OUTLINE, "Kein Outlineattribut!" ); +} + +void EditCharAttribOutline::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetOutline( (BOOL)((const SvxContourItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribTab +// ------------------------------------------------------------------------- +EditCharAttribTab::EditCharAttribTab( const SfxVoidItem& rAttr, USHORT nPos ) + : EditCharAttrib( rAttr, nPos, nPos+1 ) +{ + SetFeature( TRUE ); +} + +void EditCharAttribTab::SetFont( SvxFont&, OutputDevice* ) +{ +} + +// ------------------------------------------------------------------------- +// class EditCharAttribLineBreak +// ------------------------------------------------------------------------- +EditCharAttribLineBreak::EditCharAttribLineBreak( const SfxVoidItem& rAttr, USHORT nPos ) + : EditCharAttrib( rAttr, nPos, nPos+1 ) +{ + SetFeature( TRUE ); +} + +void EditCharAttribLineBreak::SetFont( SvxFont&, OutputDevice* ) +{ +} + +// ------------------------------------------------------------------------- +// class EditCharAttribField +// ------------------------------------------------------------------------- +EditCharAttribField::EditCharAttribField( const SvxFieldItem& rAttr, USHORT nPos ) + : EditCharAttrib( rAttr, nPos, nPos+1 ) +{ + SetFeature( TRUE ); // !!! + pTxtColor = 0; + pFldColor = 0; +} + +void EditCharAttribField::SetFont( SvxFont& rFont, OutputDevice* ) +{ + if ( pFldColor ) + { + rFont.SetFillColor( *pFldColor ); + rFont.SetTransparent( FALSE ); + } + if ( pTxtColor ) + rFont.SetColor( *pTxtColor ); +} + +EditCharAttribField::EditCharAttribField( const EditCharAttribField& rAttr ) + : EditCharAttrib( *rAttr.GetItem(), rAttr.GetStart(), rAttr.GetEnd() ), + aFieldValue( rAttr.aFieldValue ) +{ + // Diesen CCTOR nur fuer temporaeres Object verwenden, + // Item wird nicht gepoolt. + pTxtColor = rAttr.pTxtColor ? new Color( *rAttr.pTxtColor ) : 0; + pFldColor = rAttr.pFldColor ? new Color( *rAttr.pFldColor ) : 0; +} + +EditCharAttribField::~EditCharAttribField() +{ + Reset(); +} + +BOOL EditCharAttribField::operator == ( const EditCharAttribField& rAttr ) const +{ + if ( aFieldValue != rAttr.aFieldValue ) + return FALSE; + + if ( ( pTxtColor && !rAttr.pTxtColor ) || ( !pTxtColor && rAttr.pTxtColor ) ) + return FALSE; + if ( ( pTxtColor && rAttr.pTxtColor ) && ( *pTxtColor != *rAttr.pTxtColor ) ) + return FALSE; + + if ( ( pFldColor && !rAttr.pFldColor ) || ( !pFldColor && rAttr.pFldColor ) ) + return FALSE; + if ( ( pFldColor && rAttr.pFldColor ) && ( *pFldColor != *rAttr.pFldColor ) ) + return FALSE; + + return TRUE; +} + +// ------------------------------------------------------------------------- +// class EditCharAttribPairKerning +// ------------------------------------------------------------------------- +EditCharAttribPairKerning::EditCharAttribPairKerning( const SvxAutoKernItem& rAttr, USHORT _nStart, USHORT _nEnd ) +: EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_PAIRKERNING, "Kein PairKerning!" ); +} + +void EditCharAttribPairKerning::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetKerning( ((const SvxAutoKernItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribKerning +// ------------------------------------------------------------------------- +EditCharAttribKerning::EditCharAttribKerning( const SvxKerningItem& rAttr, USHORT _nStart, USHORT _nEnd ) +: EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_KERNING, "Kein Kerning!" ); +} + +void EditCharAttribKerning::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetFixKerning( ((const SvxKerningItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribWordLineMode +// ------------------------------------------------------------------------- +EditCharAttribWordLineMode::EditCharAttribWordLineMode( const SvxWordLineModeItem& rAttr, USHORT _nStart, USHORT _nEnd ) +: EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_WLM, "Kein Kerning!" ); +} + +void EditCharAttribWordLineMode::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetWordLineMode( ((const SvxWordLineModeItem*)GetItem())->GetValue() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribEmphasisMark +// ------------------------------------------------------------------------- +EditCharAttribEmphasisMark::EditCharAttribEmphasisMark( const SvxEmphasisMarkItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_EMPHASISMARK, "Kein Emphasisattribut!" ); +} + +void EditCharAttribEmphasisMark::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetEmphasisMark( ((const SvxEmphasisMarkItem*)GetItem())->GetEmphasisMark() ); +} + +// ------------------------------------------------------------------------- +// class EditCharAttribRelief +// ------------------------------------------------------------------------- +EditCharAttribRelief::EditCharAttribRelief( const SvxCharReliefItem& rAttr, USHORT _nStart, USHORT _nEnd ) + : EditCharAttrib( rAttr, _nStart, _nEnd ) +{ + DBG_ASSERT( rAttr.Which() == EE_CHAR_RELIEF, "Not a relief attribute!" ); +} + +void EditCharAttribRelief::SetFont( SvxFont& rFont, OutputDevice* ) +{ + rFont.SetRelief( (FontRelief)((const SvxCharReliefItem*)GetItem())->GetValue() ); +} diff --git a/editeng/source/editeng/editattr.hxx b/editeng/source/editeng/editattr.hxx new file mode 100644 index 000000000000..7d8913837282 --- /dev/null +++ b/editeng/source/editeng/editattr.hxx @@ -0,0 +1,429 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editattr.hxx,v $ + * $Revision: 1.13.212.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITATTR_HXX +#define _EDITATTR_HXX + +#include <editeng/eeitem.hxx> + +class SvxFont; +class SvxFontItem; +class SvxWeightItem; +class SvxPostureItem; +class SvxShadowedItem; +class SvxEscapementItem; +class SvxContourItem; +class SvxCrossedOutItem; +class SvxUnderlineItem; +class SvxOverlineItem; +class SvxFontHeightItem; +class SvxCharScaleWidthItem; +class SvxColorItem; +class SvxAutoKernItem; +class SvxKerningItem; +class SvxCharSetColorItem; +class SvxWordLineModeItem; +class SvxFieldItem; +class SvxLanguageItem; +class SvxEmphasisMarkItem; +class SvxCharReliefItem; +#include <svl/poolitem.hxx> + + +class SfxVoidItem; + +#define CH_FEATURE_OLD (BYTE) 0xFF +#define CH_FEATURE (sal_Unicode) 0x01 + +// DEF_METRIC: Bei meinem Pool sollte immer die DefMetric bei +// GetMetric( nWhich ) ankommen! +// => Zum ermitteln der DefMetrik einfach ein GetMetric( 0 ) +#define DEF_METRIC 0 + +// ------------------------------------------------------------------------- +// class EditAttrib +// ------------------------------------------------------------------------- +class EditAttrib +{ +private: + EditAttrib() {;} + EditAttrib( const EditAttrib & ) {;} + +protected: + const SfxPoolItem* pItem; + + EditAttrib( const SfxPoolItem& rAttr ); + virtual ~EditAttrib(); + +public: + // RemoveFromPool muss immer vorm DTOR Aufruf erfolgen!! + void RemoveFromPool( SfxItemPool& rPool ); + + USHORT Which() const { return pItem->Which(); } + const SfxPoolItem* GetItem() const { return pItem; } +}; + +// ------------------------------------------------------------------------- +// class EditCharAttrib +// ------------------------------------------------------------------------- +// bFeature: Attribut darf nicht expandieren/schrumfen, Laenge immer 1 +// bEdge: Attribut expandiert nicht, wenn genau an der Kante expandiert werden soll +class EditCharAttrib : public EditAttrib +{ +protected: + + USHORT nStart; + USHORT nEnd; + BOOL bFeature :1; + BOOL bEdge :1; + +public: + EditCharAttrib( const SfxPoolItem& rAttr, USHORT nStart, USHORT nEnd ); + + USHORT& GetStart() { return nStart; } + USHORT& GetEnd() { return nEnd; } + + USHORT GetStart() const { return nStart; } + USHORT GetEnd() const { return nEnd; } + + inline USHORT GetLen() const; + + inline void MoveForward( USHORT nDiff ); + inline void MoveBackward( USHORT nDiff ); + + inline void Expand( USHORT nDiff ); + inline void Collaps( USHORT nDiff ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); + + BOOL IsIn( USHORT nIndex ) + { return ( ( nStart <= nIndex ) && ( nEnd >= nIndex ) ); } + BOOL IsInside( USHORT nIndex ) + { return ( ( nStart < nIndex ) && ( nEnd > nIndex ) ); } + BOOL IsEmpty() + { return nStart == nEnd; } + + BOOL IsFeature() const { return bFeature; } + void SetFeature( BOOL b) { bFeature = b; } + + BOOL IsEdge() const { return bEdge; } + void SetEdge( BOOL b ) { bEdge = b; } +}; + +inline USHORT EditCharAttrib::GetLen() const +{ + DBG_ASSERT( nEnd >= nStart, "EditCharAttrib: nEnd < nStart!" ); + return nEnd-nStart; +} + +inline void EditCharAttrib::MoveForward( USHORT nDiff ) +{ + DBG_ASSERT( ((long)nEnd + nDiff) <= 0xFFFF, "EditCharAttrib: MoveForward?!" ); + nStart = nStart + nDiff; + nEnd = nEnd + nDiff; +} + +inline void EditCharAttrib::MoveBackward( USHORT nDiff ) +{ + DBG_ASSERT( ((long)nStart - nDiff) >= 0, "EditCharAttrib: MoveBackward?!" ); + nStart = nStart - nDiff; + nEnd = nEnd - nDiff; +} + +inline void EditCharAttrib::Expand( USHORT nDiff ) +{ + DBG_ASSERT( ( ((long)nEnd + nDiff) <= (long)0xFFFF ), "EditCharAttrib: Expand?!" ); + DBG_ASSERT( !bFeature, "Bitte keine Features expandieren!" ); + nEnd = nEnd + nDiff; +} + +inline void EditCharAttrib::Collaps( USHORT nDiff ) +{ + DBG_ASSERT( (long)nEnd - nDiff >= (long)nStart, "EditCharAttrib: Collaps?!" ); + DBG_ASSERT( !bFeature, "Bitte keine Features schrumpfen!" ); + nEnd = nEnd - nDiff; +} + +// ------------------------------------------------------------------------- +// class EditCharAttribFont +// ------------------------------------------------------------------------- +class EditCharAttribFont: public EditCharAttrib +{ +public: + EditCharAttribFont( const SvxFontItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribWeight +// ------------------------------------------------------------------------- +class EditCharAttribWeight : public EditCharAttrib +{ +public: + EditCharAttribWeight( const SvxWeightItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; +// ------------------------------------------------------------------------- +// class EditCharAttribItalic +// ------------------------------------------------------------------------- +class EditCharAttribItalic : public EditCharAttrib +{ +public: + EditCharAttribItalic( const SvxPostureItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribShadow +// ------------------------------------------------------------------------- +class EditCharAttribShadow : public EditCharAttrib +{ +public: + EditCharAttribShadow( const SvxShadowedItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribEscapement +// ------------------------------------------------------------------------- +class EditCharAttribEscapement : public EditCharAttrib +{ +public: + EditCharAttribEscapement( const SvxEscapementItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribOutline +// ------------------------------------------------------------------------- +class EditCharAttribOutline : public EditCharAttrib +{ +public: + EditCharAttribOutline( const SvxContourItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribStrikeout +// ------------------------------------------------------------------------- +class EditCharAttribStrikeout : public EditCharAttrib +{ +public: + EditCharAttribStrikeout( const SvxCrossedOutItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribUnderline +// ------------------------------------------------------------------------- +class EditCharAttribUnderline : public EditCharAttrib +{ +public: + EditCharAttribUnderline( const SvxUnderlineItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribOverline +// ------------------------------------------------------------------------- +class EditCharAttribOverline : public EditCharAttrib +{ +public: + EditCharAttribOverline( const SvxOverlineItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribEmphasisMark +// ------------------------------------------------------------------------- +class EditCharAttribEmphasisMark : public EditCharAttrib +{ +public: + EditCharAttribEmphasisMark( const SvxEmphasisMarkItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribRelief +// ------------------------------------------------------------------------- +class EditCharAttribRelief : public EditCharAttrib +{ +public: + EditCharAttribRelief( const SvxCharReliefItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribFontHeight +// ------------------------------------------------------------------------- +class EditCharAttribFontHeight : public EditCharAttrib +{ +public: + EditCharAttribFontHeight( const SvxFontHeightItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribFontWidth +// ------------------------------------------------------------------------- +class EditCharAttribFontWidth : public EditCharAttrib +{ +public: + EditCharAttribFontWidth( const SvxCharScaleWidthItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribColor +// ------------------------------------------------------------------------- +class EditCharAttribColor : public EditCharAttrib +{ +public: + EditCharAttribColor( const SvxColorItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribLanguage +// ------------------------------------------------------------------------- +class EditCharAttribLanguage : public EditCharAttrib +{ +public: + EditCharAttribLanguage( const SvxLanguageItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribTab +// ------------------------------------------------------------------------- +class EditCharAttribTab : public EditCharAttrib +{ +public: + EditCharAttribTab( const SfxVoidItem& rAttr, USHORT nPos ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribLineBreak +// ------------------------------------------------------------------------- +class EditCharAttribLineBreak : public EditCharAttrib +{ +public: + EditCharAttribLineBreak( const SfxVoidItem& rAttr, USHORT nPos ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribField +// ------------------------------------------------------------------------- +class EditCharAttribField: public EditCharAttrib +{ + XubString aFieldValue; + Color* pTxtColor; + Color* pFldColor; + + EditCharAttribField& operator = ( const EditCharAttribField& rAttr ) const; + +public: + EditCharAttribField( const SvxFieldItem& rAttr, USHORT nPos ); + EditCharAttribField( const EditCharAttribField& rAttr ); + ~EditCharAttribField(); + + BOOL operator == ( const EditCharAttribField& rAttr ) const; + BOOL operator != ( const EditCharAttribField& rAttr ) const + { return !(operator == ( rAttr ) ); } + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); + Color*& GetTxtColor() { return pTxtColor; } + Color*& GetFldColor() { return pFldColor; } + + const XubString& GetFieldValue() const { return aFieldValue; } + XubString& GetFieldValue() { return aFieldValue; } + + void Reset() + { + aFieldValue.Erase(); + delete pTxtColor; pTxtColor = 0; + delete pFldColor; pFldColor = 0; + } +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribPairKerning +// ------------------------------------------------------------------------- +class EditCharAttribPairKerning : public EditCharAttrib +{ +public: + EditCharAttribPairKerning( const SvxAutoKernItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribKerning +// ------------------------------------------------------------------------- +class EditCharAttribKerning : public EditCharAttrib +{ +public: + EditCharAttribKerning( const SvxKerningItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + +// ------------------------------------------------------------------------- +// class EditCharAttribWordLineMode +// ------------------------------------------------------------------------- +class EditCharAttribWordLineMode: public EditCharAttrib +{ +public: + EditCharAttribWordLineMode( const SvxWordLineModeItem& rAttr, USHORT nStart, USHORT nEnd ); + + virtual void SetFont( SvxFont& rFont, OutputDevice* pOutDev ); +}; + + +#endif // _EDITATTR_HXX diff --git a/editeng/source/editeng/editdbg.cxx b/editeng/source/editeng/editdbg.cxx new file mode 100644 index 000000000000..88f5fa7062eb --- /dev/null +++ b/editeng/source/editeng/editdbg.cxx @@ -0,0 +1,589 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editdbg.cxx,v $ + * $Revision: 1.22.148.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/lspcitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/frmdiritem.hxx> + +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editdoc.hxx> +#include <editdbg.hxx> + +#if defined( DBG_UTIL ) || ( OSL_DEBUG_LEVEL > 1 ) + +ByteString DbgOutItem( const SfxItemPool& rPool, const SfxPoolItem& rItem ) +{ + ByteString aDebStr; + switch ( rItem.Which() ) + { + case EE_PARA_WRITINGDIR: + aDebStr += "WritingDir="; + aDebStr += ByteString::CreateFromInt32( ((SvxFrameDirectionItem&)rItem).GetValue() ); + break; + case EE_PARA_OUTLLRSPACE: + case EE_PARA_LRSPACE: + aDebStr += "FI="; + aDebStr += ByteString::CreateFromInt32( ((SvxLRSpaceItem&)rItem).GetTxtFirstLineOfst() ); + aDebStr += ", LI="; + aDebStr += ByteString::CreateFromInt32( ((SvxLRSpaceItem&)rItem).GetTxtLeft() ); + aDebStr += ", RI="; + aDebStr += ByteString::CreateFromInt32( ((SvxLRSpaceItem&)rItem).GetRight() ); + break; + case EE_PARA_NUMBULLET: + { + aDebStr += "NumItem "; + for ( USHORT nLevel = 0; nLevel < 3; nLevel++ ) + { + aDebStr += "Level"; + aDebStr += ByteString::CreateFromInt32( nLevel ); + aDebStr += "="; + const SvxNumberFormat* pFmt = ((const SvxNumBulletItem&)rItem).GetNumRule()->Get( nLevel ); + if ( pFmt ) + { + aDebStr += "("; + aDebStr += ByteString::CreateFromInt32( pFmt->GetFirstLineOffset() ); + aDebStr += ","; + aDebStr += ByteString::CreateFromInt32( pFmt->GetAbsLSpace() ); + aDebStr += ","; + if ( pFmt->GetNumberingType() == SVX_NUM_BITMAP ) + { + aDebStr += "Bitmap"; + } + else if( pFmt->GetNumberingType() != SVX_NUM_CHAR_SPECIAL ) + { + aDebStr += "Number"; + } + else + { + aDebStr += "Char=["; + aDebStr += ByteString::CreateFromInt32( pFmt->GetBulletChar() ); + aDebStr += "]"; + } + aDebStr += ") "; + } + } + } + break; + case EE_PARA_BULLETSTATE: + aDebStr += "ShowBullet="; + aDebStr += ByteString::CreateFromInt32( ((SfxBoolItem&)rItem).GetValue() ); + break; + case EE_PARA_HYPHENATE: + aDebStr += "Hyphenate="; + aDebStr += ByteString::CreateFromInt32( ((SfxBoolItem&)rItem).GetValue() ); + break; + case EE_PARA_OUTLLEVEL: + aDebStr += "Level="; + aDebStr += ByteString::CreateFromInt32( ((SfxInt16Item&)rItem).GetValue() ); + break; + case EE_PARA_ULSPACE: + aDebStr += "SB="; + aDebStr += ByteString::CreateFromInt32( ((SvxULSpaceItem&)rItem).GetUpper() ); + aDebStr += ", SA="; + aDebStr += ByteString::CreateFromInt32( ((SvxULSpaceItem&)rItem).GetLower() ); + break; + case EE_PARA_SBL: + aDebStr += "SBL="; + if ( ((SvxLineSpacingItem&)rItem).GetLineSpaceRule() == SVX_LINE_SPACE_MIN ) + { + aDebStr += "Min: "; + aDebStr += ByteString::CreateFromInt32( ((SvxLineSpacingItem&)rItem).GetInterLineSpace() ); + } + else if ( ((SvxLineSpacingItem&)rItem).GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + aDebStr += "Prop: "; + aDebStr += ByteString::CreateFromInt32( (ULONG)((SvxLineSpacingItem&)rItem).GetPropLineSpace() ); + } + else + aDebStr += "Unsupported Type!"; + break; + case EE_PARA_JUST: + aDebStr += "SvxAdust="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxAdjustItem&)rItem).GetAdjust() ); + break; + case EE_PARA_TABS: + { + aDebStr += "Tabs: "; + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) rItem; + aDebStr += ByteString::CreateFromInt32( rTabs.Count() ); + if ( rTabs.Count() ) + { + aDebStr += "( "; + for ( USHORT i = 0; i < rTabs.Count(); i++ ) + { + const SvxTabStop& rTab = rTabs[i]; + aDebStr += ByteString::CreateFromInt32( rTab.GetTabPos() ); + aDebStr += " "; + } + aDebStr += ")"; + } + } + break; + case EE_CHAR_LANGUAGE: + case EE_CHAR_LANGUAGE_CJK: + case EE_CHAR_LANGUAGE_CTL: + aDebStr += "Language="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxLanguageItem&)rItem).GetLanguage() ); + break; + case EE_CHAR_COLOR: + { + aDebStr += "Color= "; + Color aColor( ((SvxColorItem&)rItem).GetValue() ); + aDebStr += ByteString::CreateFromInt32( (USHORT)aColor.GetRed() ); + aDebStr += ", "; + aDebStr += ByteString::CreateFromInt32( (USHORT)aColor.GetGreen() ); + aDebStr += ", "; + aDebStr += ByteString::CreateFromInt32( (USHORT)aColor.GetBlue() ); + } + break; + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + aDebStr += "Font="; + aDebStr += ByteString( ((SvxFontItem&)rItem).GetFamilyName(), RTL_TEXTENCODING_ASCII_US ); + aDebStr += " (CharSet: "; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxFontItem&)rItem).GetCharSet() ); + aDebStr += ')'; + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + aDebStr += "Groesse="; + aDebStr += ByteString::CreateFromInt32( ((SvxFontHeightItem&)rItem).GetHeight() ); + Size aSz( 0, ((SvxFontHeightItem&)rItem).GetHeight() ); + SfxMapUnit eUnit = rPool.GetMetric( rItem.Which() ); + MapMode aItemMapMode( (MapUnit) eUnit ); + MapMode aPntMap( MAP_POINT ); + aSz = OutputDevice::LogicToLogic( aSz, aItemMapMode, aPntMap ); + aDebStr += " Points="; + aDebStr += ByteString::CreateFromInt32( aSz.Height() ); + } + break; + case EE_CHAR_FONTWIDTH: + { + aDebStr += "Breite="; + aDebStr += ByteString::CreateFromInt32( ((SvxCharScaleWidthItem&)rItem).GetValue() ); + aDebStr += "%"; + } + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + aDebStr += "FontWeight="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxWeightItem&)rItem).GetWeight() ); + break; + case EE_CHAR_UNDERLINE: + aDebStr += "FontUnderline="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxUnderlineItem&)rItem).GetLineStyle() ); + break; + case EE_CHAR_OVERLINE: + aDebStr += "FontOverline="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxOverlineItem&)rItem).GetLineStyle() ); + break; + case EE_CHAR_EMPHASISMARK: + aDebStr += "FontUnderline="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxEmphasisMarkItem&)rItem).GetEmphasisMark() ); + break; + case EE_CHAR_RELIEF: + aDebStr += "FontRelief="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxCharReliefItem&)rItem).GetValue() ); + break; + case EE_CHAR_STRIKEOUT: + aDebStr += "FontStrikeout="; + aDebStr +=ByteString::CreateFromInt32( (USHORT)((SvxCrossedOutItem&)rItem).GetStrikeout() ); + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + aDebStr += "FontPosture="; + aDebStr +=ByteString::CreateFromInt32( (USHORT)((SvxPostureItem&)rItem).GetPosture() ); + break; + case EE_CHAR_OUTLINE: + aDebStr += "FontOutline="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxContourItem&)rItem).GetValue() ); + break; + case EE_CHAR_SHADOW: + aDebStr += "FontShadowed="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxShadowedItem&)rItem).GetValue() ); + break; + case EE_CHAR_ESCAPEMENT: + aDebStr += "Escape="; + aDebStr += ByteString::CreateFromInt32( (short)((SvxEscapementItem&)rItem).GetEsc() ); + aDebStr += ", "; + aDebStr += ByteString::CreateFromInt32( (short)((SvxEscapementItem&)rItem).GetProp() ); + break; + case EE_CHAR_PAIRKERNING: + aDebStr += "PairKerning="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxAutoKernItem&)rItem).GetValue() ); + break; + case EE_CHAR_KERNING: + { + aDebStr += "Kerning="; + aDebStr += ByteString::CreateFromInt32( (short)((SvxKerningItem&)rItem).GetValue() ); + Size aSz( 0, (short)((SvxKerningItem&)rItem).GetValue() ); + SfxMapUnit eUnit = rPool.GetMetric( rItem.Which() ); + MapMode aItemMapMode( (MapUnit) eUnit ); + MapMode aPntMap( MAP_POINT ); + aSz = OutputDevice::LogicToLogic( aSz, aItemMapMode, aPntMap ); + aDebStr += " Points="; + aDebStr += ByteString::CreateFromInt32( aSz.Height() ); + } + break; + case EE_CHAR_WLM: + aDebStr += "WordLineMode="; + aDebStr += ByteString::CreateFromInt32( (USHORT)((SvxWordLineModeItem&)rItem).GetValue() ); + break; + case EE_CHAR_XMLATTRIBS: + aDebStr += "XMLAttribs=..."; + break; + } + return aDebStr; +} + +void DbgOutItemSet( FILE* fp, const SfxItemSet& rSet, BOOL bSearchInParent, BOOL bShowALL ) +{ + for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + fprintf( fp, "\nWhich: %i\t", nWhich ); + if ( rSet.GetItemState( nWhich, bSearchInParent ) == SFX_ITEM_OFF ) + fprintf( fp, "ITEM_OFF " ); + else if ( rSet.GetItemState( nWhich, bSearchInParent ) == SFX_ITEM_DONTCARE ) + fprintf( fp, "ITEM_DC " ); + else if ( rSet.GetItemState( nWhich, bSearchInParent ) == SFX_ITEM_ON ) + fprintf( fp, "ITEM_ON *" ); + + if ( !bShowALL && ( rSet.GetItemState( nWhich, bSearchInParent ) != SFX_ITEM_ON ) ) + continue; + + const SfxPoolItem& rItem = rSet.Get( nWhich, bSearchInParent ); + ByteString aDebStr = DbgOutItem( *rSet.GetPool(), rItem ); + fprintf( fp, "%s", aDebStr.GetBuffer() ); + } +} + +void EditDbg::ShowEditEngineData( EditEngine* pEE, BOOL bInfoBox ) +{ +#if defined UNX + FILE* fp = fopen( "/tmp/debug.log", "w" ); +#else + FILE* fp = fopen( "d:\\debug.log", "w" ); +#endif + if ( fp == 0 ) + { + DBG_ERROR( "Log-File konnte nicht angelegt werden!" ); + return; + } + + const SfxItemPool& rPool = *pEE->GetEmptyItemSet().GetPool(); + + fprintf( fp, "================================================================================" ); + fprintf( fp, "\n================== Dokument ================================================" ); + fprintf( fp, "\n================================================================================" ); + for ( USHORT nPortion = 0; nPortion < pEE->pImpEditEngine->GetParaPortions(). Count(); nPortion++) + { + + ParaPortion* pPPortion = pEE->pImpEditEngine->GetParaPortions().GetObject(nPortion ); + fprintf( fp, "\nAbsatz %i: Laenge = %i, Invalid = %i\nText = '%s'", nPortion, pPPortion->GetNode()->Len(), pPPortion->IsInvalid(), ByteString( *pPPortion->GetNode(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + fprintf( fp, "\nVorlage:" ); + SfxStyleSheet* pStyle = pPPortion->GetNode()->GetStyleSheet(); + if ( pStyle ) + fprintf( fp, " %s", ByteString( pStyle->GetName(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + fprintf( fp, "\nAbsatzattribute:" ); + DbgOutItemSet( fp, pPPortion->GetNode()->GetContentAttribs().GetItems(), FALSE, FALSE ); + + fprintf( fp, "\nZeichenattribute:" ); + BOOL bZeroAttr = FALSE; + USHORT z; + for ( z = 0; z < pPPortion->GetNode()->GetCharAttribs().Count(); z++ ) + { + EditCharAttrib* pAttr = pPPortion->GetNode()->GetCharAttribs().GetAttribs().GetObject( z ); + ByteString aCharAttribs; + aCharAttribs += "\nA"; + aCharAttribs += ByteString::CreateFromInt32( nPortion ); + aCharAttribs += ": "; + aCharAttribs += ByteString::CreateFromInt32( pAttr->GetItem()->Which() ); + aCharAttribs += '\t'; + aCharAttribs += ByteString::CreateFromInt32( pAttr->GetStart() ); + aCharAttribs += '\t'; + aCharAttribs += ByteString::CreateFromInt32( pAttr->GetEnd() ); + if ( pAttr->IsEmpty() ) + bZeroAttr = TRUE; + fprintf( fp, "%s => ", aCharAttribs.GetBuffer() ); + + ByteString aDebStr = DbgOutItem( rPool, *pAttr->GetItem() ); + fprintf( fp, "%s", aDebStr.GetBuffer() ); + } + if ( bZeroAttr ) + fprintf( fp, "\nNULL-Attribute!" ); + + USHORT nTextPortions = pPPortion->GetTextPortions().Count(); + ByteString aPortionStr("\nTextportions: #"); + aPortionStr += ByteString::CreateFromInt32( nTextPortions ); + aPortionStr += " \nA"; + aPortionStr += ByteString::CreateFromInt32( nPortion ); + aPortionStr += ": Absatzlaenge = "; + aPortionStr += ByteString::CreateFromInt32( pPPortion->GetNode()->Len() ); + aPortionStr += "\nA"; + aPortionStr += ByteString::CreateFromInt32( nPortion ); + aPortionStr += ": "; + ULONG n = 0; + for ( z = 0; z < nTextPortions; z++ ) + { + TextPortion* pPortion = pPPortion->GetTextPortions().GetObject( z ); + aPortionStr += " "; + aPortionStr += ByteString::CreateFromInt32( pPortion->GetLen() ); + aPortionStr += "("; + aPortionStr += ByteString::CreateFromInt32( pPortion->GetSize().Width() ); + aPortionStr += ")"; + aPortionStr += "["; + aPortionStr += ByteString::CreateFromInt32( (USHORT)pPortion->GetKind() ); + aPortionStr += "]"; + aPortionStr += ";"; + n += pPortion->GetLen(); + } + aPortionStr += "\nA"; + aPortionStr += ByteString::CreateFromInt32( nPortion ); + aPortionStr += ": Gesamtlaenge: "; + aPortionStr += ByteString::CreateFromInt32( n ); + if ( pPPortion->GetNode()->Len() != n ) + aPortionStr += " => Fehler !!!"; + fprintf( fp, "%s", aPortionStr.GetBuffer() ); + + + fprintf( fp, "\n\nZeilen:" ); + // Erstmal die Inhalte... + USHORT nLine; + for ( nLine = 0; nLine < pPPortion->GetLines().Count(); nLine++ ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + + ByteString aLine( *(pPPortion->GetNode()), pLine->GetStart(), pLine->GetEnd() - pLine->GetStart(), RTL_TEXTENCODING_ASCII_US ); + fprintf( fp, "\nZeile %i\t>%s<", nLine, aLine.GetBuffer() ); + } + // dann die internen Daten... + for ( nLine = 0; nLine < pPPortion->GetLines().Count(); nLine++ ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + fprintf( fp, "\nZeile %i:\tStart: %i,\tEnd: %i", nLine, pLine->GetStart(), pLine->GetEnd() ); + fprintf( fp, "\t\tPortions: %i - %i.\tHoehe: %i, Ascent=%i", pLine->GetStartPortion(), pLine->GetEndPortion(), pLine->GetHeight(), pLine->GetMaxAscent() ); + } + + fprintf( fp, "\n-----------------------------------------------------------------------------" ); + } + + if ( pEE->pImpEditEngine->GetStyleSheetPool() ) + { + ULONG nStyles = pEE->pImpEditEngine->GetStyleSheetPool() ? pEE->pImpEditEngine->GetStyleSheetPool()->Count() : 0; + fprintf( fp, "\n\n================================================================================" ); + fprintf( fp, "\n================== Stylesheets =============================================" ); + fprintf( fp, "\n================================================================================" ); + fprintf( fp, "\n#Vorlagen: %lu\n", nStyles ); + SfxStyleSheetIterator aIter( pEE->pImpEditEngine->GetStyleSheetPool(), SFX_STYLE_FAMILY_ALL ); + SfxStyleSheetBase* pStyle = aIter.First(); + while ( pStyle ) + { + fprintf( fp, "\nVorlage: %s", ByteString( pStyle->GetName(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + fprintf( fp, "\nParent: %s", ByteString( pStyle->GetParent(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + fprintf( fp, "\nFollow: %s", ByteString( pStyle->GetFollow(), RTL_TEXTENCODING_ASCII_US ).GetBuffer() ); + DbgOutItemSet( fp, pStyle->GetItemSet(), FALSE, FALSE ); + fprintf( fp, "\n----------------------------------" ); + + pStyle = aIter.Next(); + } + } + + fprintf( fp, "\n\n================================================================================" ); + fprintf( fp, "\n================== Defaults ================================================" ); + fprintf( fp, "\n================================================================================" ); + DbgOutItemSet( fp, pEE->pImpEditEngine->GetEmptyItemSet(), TRUE, TRUE ); + + fprintf( fp, "\n\n================================================================================" ); + fprintf( fp, "\n================== EditEngine & Views ======================================" ); + fprintf( fp, "\n================================================================================" ); + fprintf( fp, "\nControl: %lx", pEE->GetControlWord() ); + fprintf( fp, "\nRefMapMode: %i", pEE->pImpEditEngine->pRefDev->GetMapMode().GetMapUnit() ); + fprintf( fp, "\nPaperSize: %li x %li", pEE->GetPaperSize().Width(), pEE->GetPaperSize().Height() ); + fprintf( fp, "\nMaxAutoPaperSize: %li x %li", pEE->GetMaxAutoPaperSize().Width(), pEE->GetMaxAutoPaperSize().Height() ); + fprintf( fp, "\nMinAutoPaperSize: %li x %li", pEE->GetMinAutoPaperSize().Width(), pEE->GetMinAutoPaperSize().Height() ); + fprintf( fp, "\nUpdate: %i", pEE->GetUpdateMode() ); + fprintf( fp, "\nAnzahl der Views: %i", pEE->GetViewCount() ); + for ( USHORT nView = 0; nView < pEE->GetViewCount(); nView++ ) + { + EditView* pV = pEE->GetView( nView ); + DBG_ASSERT( pV, "View nicht gefunden!" ); + fprintf( fp, "\nView %i: Focus=%i", nView, pV->GetWindow()->HasFocus() ); + Rectangle aR( pV->GetOutputArea() ); + fprintf( fp, "\n OutputArea: nX=%li, nY=%li, dX=%li, dY=%li, MapMode = %i", aR.TopLeft().X(), aR.TopLeft().Y(), aR.GetSize().Width(), aR.GetSize().Height() , pV->GetWindow()->GetMapMode().GetMapUnit() ); + aR = pV->GetVisArea(); + fprintf( fp, "\n VisArea: nX=%li, nY=%li, dX=%li, dY=%li", aR.TopLeft().X(), aR.TopLeft().Y(), aR.GetSize().Width(), aR.GetSize().Height() ); + ESelection aSel = pV->GetSelection(); + fprintf( fp, "\n Selektion: Start=%u,%u, End=%u,%u", aSel.nStartPara, aSel.nStartPos, aSel.nEndPara, aSel.nEndPos ); + } + if ( pEE->GetActiveView() ) + { + fprintf( fp, "\n\n================================================================================" ); + fprintf( fp, "\n================== Aktuelle View ===========================================" ); + fprintf( fp, "\n================================================================================" ); + DbgOutItemSet( fp, pEE->GetActiveView()->GetAttribs(), TRUE, FALSE ); + } + fclose( fp ); + if ( bInfoBox ) + InfoBox(0, String( RTL_CONSTASCII_USTRINGPARAM( "D:\\DEBUG.LOG !" ) ) ).Execute(); +} + +ByteString EditDbg::GetPortionInfo( ParaPortion* pPPortion ) +{ + USHORT z; + + ByteString aDebStr( "Absatzlaenge = " ); + aDebStr += ByteString::CreateFromInt32( pPPortion->GetNode()->Len() ); + + aDebStr += "\nZeichenattribute:"; + for ( z = 0; z < pPPortion->GetNode()->GetCharAttribs().Count(); z++ ) + { + EditCharAttrib* pAttr = pPPortion->GetNode()->GetCharAttribs().GetAttribs().GetObject( z ); + aDebStr += "\n "; + aDebStr += ByteString::CreateFromInt32( pAttr->GetItem()->Which() ); + aDebStr += '\t'; + aDebStr += ByteString::CreateFromInt32( pAttr->GetStart() ); + aDebStr += '\t'; + aDebStr += ByteString::CreateFromInt32( pAttr->GetEnd() ); + } + + aDebStr += "\nTextportions:"; + USHORT n = 0; + for ( z = 0; z < pPPortion->GetTextPortions().Count(); z++ ) + { + TextPortion* pPortion = pPPortion->GetTextPortions().GetObject( z ); + aDebStr += " "; + aDebStr += ByteString::CreateFromInt32( pPortion->GetLen() ); + aDebStr += "("; + aDebStr += ByteString::CreateFromInt32( pPortion->GetSize().Width() ); + aDebStr += ")"; + aDebStr += ";"; + n = n + pPortion->GetLen(); + } + aDebStr += "\nGesamtlaenge: "; + aDebStr += ByteString::CreateFromInt32( n ); + aDebStr += "\nSortiert nach Start:"; + for ( USHORT x = 0; x < pPPortion->GetNode()->GetCharAttribs().Count(); x++ ) + { + EditCharAttrib* pCurAttrib = pPPortion->GetNode()->GetCharAttribs().GetAttribs().GetObject( x ); + aDebStr += "\nStart: "; + aDebStr += ByteString::CreateFromInt32( pCurAttrib->GetStart() ); + aDebStr += "\tEnde: "; + aDebStr += ByteString::CreateFromInt32( pCurAttrib->GetEnd() ); + } + return aDebStr; +} + +ByteString EditDbg::GetTextPortionInfo( TextPortionList& rPortions ) +{ + ByteString aDebStr; + for ( USHORT z = 0; z < rPortions.Count(); z++ ) + { + TextPortion* pPortion = rPortions.GetObject( z ); + aDebStr += " "; + aDebStr += ByteString::CreateFromInt32( pPortion->GetLen() ); + aDebStr += "("; + aDebStr += ByteString::CreateFromInt32( pPortion->GetSize().Width() ); + aDebStr += ")"; + aDebStr += ";"; + } + return aDebStr; +} + +void EditDbg::ShowPortionData( ParaPortion* pPortion ) +{ + ByteString aDebStr( GetPortionInfo( pPortion ) ); + InfoBox( 0, String( aDebStr, RTL_TEXTENCODING_ASCII_US ) ).Execute(); +} + + +BOOL ParaPortion::DbgCheckTextPortions() +{ + // pruefen, ob Portionlaenge ok: + USHORT nXLen = 0; + for ( USHORT nPortion = 0; nPortion < aTextPortionList.Count(); nPortion++ ) + nXLen = nXLen + aTextPortionList[nPortion]->GetLen(); + return nXLen == pNode->Len() ? TRUE : FALSE; +} + +BOOL CheckOrderedList( CharAttribArray& rAttribs, BOOL bStart ) +{ + USHORT nPrev = 0; + for ( USHORT nAttr = 0; nAttr < rAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttribs[nAttr]; + USHORT nCur = bStart ? pAttr->GetStart() : pAttr->GetEnd(); + if ( nCur < nPrev ) + return FALSE; + + nPrev = nCur; + } + return TRUE; +} + +#endif + diff --git a/editeng/source/editeng/editdbg.hxx b/editeng/source/editeng/editdbg.hxx new file mode 100644 index 000000000000..ab51c9ed6ff4 --- /dev/null +++ b/editeng/source/editeng/editdbg.hxx @@ -0,0 +1,60 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editdbg.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITDBG_HXX +#define _EDITDBG_HXX + +#include <svl/solar.hrc> +#include <tools/string.hxx> +#include <stdio.h> + +class EditEngine; +class ParaPortion; +class EditUndoList; +class TextPortionList; +class SfxItemSet; +class SfxItemPool; +class SfxPoolItem; + +ByteString DbgOutItem( const SfxItemPool& rPool, const SfxPoolItem& rItem ); +void DbgOutItemSet( FILE* fp, const SfxItemSet& rSet, BOOL bSearchInParent, BOOL bShowALL ); + +class EditDbg +{ +public: + static void ShowEditEngineData( EditEngine* pEditEngine, BOOL bInfoBox = TRUE ); + static void ShowPortionData( ParaPortion* pPortion ); + static ByteString GetPortionInfo( ParaPortion* pPPortion ); + static ByteString GetTextPortionInfo( TextPortionList& rPortions ); + static ByteString GetUndoDebStr( EditUndoList* pUndoList ); +}; + + +#endif // _EDITDBG_HXX diff --git a/editeng/source/editeng/editdoc.cxx b/editeng/source/editeng/editdoc.cxx new file mode 100644 index 000000000000..1d264b958ac9 --- /dev/null +++ b/editeng/source/editeng/editdoc.cxx @@ -0,0 +1,2317 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editdoc.cxx,v $ + * $Revision: 1.48.148.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/tstpitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/xmlcnitm.hxx> +#include <editeng/editids.hrc> + +#include <editdoc.hxx> +#include <editdbg.hxx> +#include <editeng/eerdll.hxx> +#include <eerdll2.hxx> +#include <tools/stream.hxx> +#include <tools/debug.hxx> +#include <tools/shl.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <stdlib.h> // qsort + +using namespace ::com::sun::star; + + +// ------------------------------------------------------------ + +USHORT GetScriptItemId( USHORT nItemId, short nScriptType ) +{ + USHORT nId = nItemId; + + if ( ( nScriptType == i18n::ScriptType::ASIAN ) || + ( nScriptType == i18n::ScriptType::COMPLEX ) ) + { + switch ( nItemId ) + { + case EE_CHAR_LANGUAGE: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_LANGUAGE_CJK : EE_CHAR_LANGUAGE_CTL; + break; + case EE_CHAR_FONTINFO: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK : EE_CHAR_FONTINFO_CTL; + break; + case EE_CHAR_FONTHEIGHT: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_FONTHEIGHT_CJK : EE_CHAR_FONTHEIGHT_CTL; + break; + case EE_CHAR_WEIGHT: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_WEIGHT_CJK : EE_CHAR_WEIGHT_CTL; + break; + case EE_CHAR_ITALIC: + nId = ( nScriptType == i18n::ScriptType::ASIAN ) ? EE_CHAR_ITALIC_CJK : EE_CHAR_ITALIC_CTL; + break; + } + } + + return nId; +} + +BOOL IsScriptItemValid( USHORT nItemId, short nScriptType ) +{ + BOOL bValid = TRUE; + + switch ( nItemId ) + { + case EE_CHAR_LANGUAGE: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_LANGUAGE_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_LANGUAGE_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_FONTINFO: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_FONTINFO_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_FONTINFO_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_FONTHEIGHT: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_FONTHEIGHT_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_FONTHEIGHT_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_WEIGHT: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_WEIGHT_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_WEIGHT_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + case EE_CHAR_ITALIC: + bValid = nScriptType == i18n::ScriptType::LATIN; + break; + case EE_CHAR_ITALIC_CJK: + bValid = nScriptType == i18n::ScriptType::ASIAN; + break; + case EE_CHAR_ITALIC_CTL: + bValid = nScriptType == i18n::ScriptType::COMPLEX; + break; + } + + return bValid; +} + + +// ------------------------------------------------------------ + +// Sollte spaeter zentral nach TOOLS/STRING (Aktuell: 303) +// fuer Grep: WS_TARGET + +DBG_NAME( EE_TextPortion ); +DBG_NAME( EE_EditLine ); +DBG_NAME( EE_ContentNode ); +DBG_NAME( EE_CharAttribList ); + +SfxItemInfo aItemInfos[EDITITEMCOUNT] = { + { SID_ATTR_FRAMEDIRECTION, SFX_ITEM_POOLABLE }, // EE_PARA_WRITINGDIR + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_XMLATTRIBS + { SID_ATTR_PARA_HANGPUNCTUATION, SFX_ITEM_POOLABLE }, // EE_PARA_HANGINGPUNCTUATION + { SID_ATTR_PARA_FORBIDDEN_RULES, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_SCRIPTSPACE, SFX_ITEM_POOLABLE }, // EE_PARA_ASIANCJKSPACING + { SID_ATTR_NUMBERING_RULE, SFX_ITEM_POOLABLE }, // EE_PARA_NUMBULL + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_HYPHENATE + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_BULLETSTATE + { 0, SFX_ITEM_POOLABLE }, // EE_PARA_OUTLLRSPACE + { SID_ATTR_PARA_OUTLLEVEL, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_BULLET, SFX_ITEM_POOLABLE }, + { SID_ATTR_LRSPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_ULSPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_LINESPACE, SFX_ITEM_POOLABLE }, + { SID_ATTR_PARA_ADJUST, SFX_ITEM_POOLABLE }, + { SID_ATTR_TABSTOP, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_COLOR, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_SCALEWIDTH, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_UNDERLINE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_STRIKEOUT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CONTOUR, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_SHADOWED, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_ESCAPEMENT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_AUTOKERN, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_KERNING, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_WORDLINEMODE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_LANGUAGE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_FONT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_FONTHEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_WEIGHT, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CJK_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_CTL_POSTURE, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_EMPHASISMARK, SFX_ITEM_POOLABLE }, + { SID_ATTR_CHAR_RELIEF, SFX_ITEM_POOLABLE }, + { 0, SFX_ITEM_POOLABLE }, // EE_CHAR_RUBI_DUMMY + { 0, SFX_ITEM_POOLABLE }, // EE_CHAR_XMLATTRIBS + { SID_ATTR_CHAR_OVERLINE, SFX_ITEM_POOLABLE }, + { 0, SFX_ITEM_POOLABLE }, // EE_FEATURE_TAB + { 0, SFX_ITEM_POOLABLE }, // EE_FEATURE_LINEBR + { SID_ATTR_CHAR_CHARSETCOLOR, SFX_ITEM_POOLABLE }, // EE_FEATURE_NOTCONV + { SID_FIELD, SFX_ITEM_POOLABLE } +}; + +USHORT aV1Map[] = { + 3999, 4001, 4002, 4003, 4004, 4005, 4006, + 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4017, 4018, 4019 // MI: 4019? +}; + +USHORT aV2Map[] = { + 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, + 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4018, 4019, 4020 +}; + +USHORT aV3Map[] = { + 3997, 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, + 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, + 4020, 4021 +}; + +USHORT aV4Map[] = { + 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, + 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, + 4014, 4015, 4016, 4017, 4018, + /* CJK Items inserted here: EE_CHAR_LANGUAGE - EE_CHAR_XMLATTRIBS */ + 4034, 4035, 4036, 4037 +}; + +USHORT aV5Map[] = { + 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 4002, 4003, + 4004, 4005, 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, + 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, + 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, + /* EE_CHAR_OVERLINE inserted here */ + 4035, 4036, 4037, 4038 +}; + +SV_IMPL_PTRARR( DummyContentList, ContentNode* ); +SV_IMPL_VARARR( ScriptTypePosInfos, ScriptTypePosInfo ); +SV_IMPL_VARARR( WritingDirectionInfos, WritingDirectionInfo ); +// SV_IMPL_VARARR( ExtraCharInfos, ExtraCharInfo ); + + +int SAL_CALL CompareStart( const void* pFirst, const void* pSecond ) +{ + if ( (*((EditCharAttrib**)pFirst))->GetStart() < (*((EditCharAttrib**)pSecond))->GetStart() ) + return (-1); + else if ( (*((EditCharAttrib**)pFirst))->GetStart() > (*((EditCharAttrib**)pSecond))->GetStart() ) + return (1); + return 0; +} + +EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, USHORT nS, USHORT nE ) +{ + // das neue Attribut im Pool anlegen + const SfxPoolItem& rNew = rPool.Put( rAttr ); + + EditCharAttrib* pNew = 0; + switch( rNew.Which() ) + { + case EE_CHAR_LANGUAGE: + case EE_CHAR_LANGUAGE_CJK: + case EE_CHAR_LANGUAGE_CTL: + { + pNew = new EditCharAttribLanguage( (const SvxLanguageItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_COLOR: + { + pNew = new EditCharAttribColor( (const SvxColorItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + pNew = new EditCharAttribFont( (const SvxFontItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + pNew = new EditCharAttribFontHeight( (const SvxFontHeightItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_FONTWIDTH: + { + pNew = new EditCharAttribFontWidth( (const SvxCharScaleWidthItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + pNew = new EditCharAttribWeight( (const SvxWeightItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_UNDERLINE: + { + pNew = new EditCharAttribUnderline( (const SvxUnderlineItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_OVERLINE: + { + pNew = new EditCharAttribOverline( (const SvxOverlineItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_EMPHASISMARK: + { + pNew = new EditCharAttribEmphasisMark( (const SvxEmphasisMarkItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_RELIEF: + { + pNew = new EditCharAttribRelief( (const SvxCharReliefItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_STRIKEOUT: + { + pNew = new EditCharAttribStrikeout( (const SvxCrossedOutItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + pNew = new EditCharAttribItalic( (const SvxPostureItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_OUTLINE: + { + pNew = new EditCharAttribOutline( (const SvxContourItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_SHADOW: + { + pNew = new EditCharAttribShadow( (const SvxShadowedItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_ESCAPEMENT: + { + pNew = new EditCharAttribEscapement( (const SvxEscapementItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_PAIRKERNING: + { + pNew = new EditCharAttribPairKerning( (const SvxAutoKernItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_KERNING: + { + pNew = new EditCharAttribKerning( (const SvxKerningItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_WLM: + { + pNew = new EditCharAttribWordLineMode( (const SvxWordLineModeItem&)rNew, nS, nE ); + } + break; + case EE_CHAR_XMLATTRIBS: + { + pNew = new EditCharAttrib( rNew, nS, nE ); // Attrib is only for holding XML information... + } + break; + case EE_FEATURE_TAB: + { + pNew = new EditCharAttribTab( (const SfxVoidItem&)rNew, nS ); + } + break; + case EE_FEATURE_LINEBR: + { + pNew = new EditCharAttribLineBreak( (const SfxVoidItem&)rNew, nS ); + } + break; + case EE_FEATURE_FIELD: + { + pNew = new EditCharAttribField( (const SvxFieldItem&)rNew, nS ); + } + break; + default: + { + DBG_ERROR( "Ungueltiges Attribut!" ); + } + } + return pNew; +} + +// ------------------------------------------------------------------------- +// class EditLine +// ------------------------------------------------------------------------- + +EditLine::EditLine() +{ + DBG_CTOR( EE_EditLine, 0 ); + + nStart = nEnd = 0; + nStartPortion = 0; // damit in ungueltiger Zeile ohne Portions von einer gueltigen Zeile mit der Portion Nr0 unterscieden werden kann. + nEndPortion = 0; + nHeight = 0; + nStartPosX = 0; + nTxtHeight = 0; + nTxtWidth = 0; + nCrsrHeight = 0; + nMaxAscent = 0; + bHangingPunctuation = FALSE; + bInvalid = TRUE; +} + +EditLine::EditLine( const EditLine& r ) +{ + DBG_CTOR( EE_EditLine, 0 ); + + nEnd = r.nEnd; + nStart = r.nStart; + nStartPortion = r.nStartPortion; + nEndPortion = r.nEndPortion; + bHangingPunctuation = r.bHangingPunctuation; + + nHeight = 0; + nStartPosX = 0; + nTxtHeight = 0; + nTxtWidth = 0; + nCrsrHeight = 0; + nMaxAscent = 0; + bInvalid = TRUE; +} + +EditLine::~EditLine() +{ + DBG_DTOR( EE_EditLine, 0 ); +} + +EditLine* EditLine::Clone() const +{ + EditLine* pL = new EditLine; + if ( aPositions.Count() ) + { + pL->aPositions.Insert (aPositions.GetData(), aPositions.Count(), 0); + } + pL->nStartPosX = nStartPosX; + pL->nStart = nStart; + pL->nEnd = nEnd; + pL->nStartPortion = nStartPortion; + pL->nEndPortion = nEndPortion; + pL->nHeight = nHeight; + pL->nTxtWidth = nTxtWidth; + pL->nTxtHeight = nTxtHeight; + pL->nCrsrHeight = nCrsrHeight; + pL->nMaxAscent = nMaxAscent; + + return pL; +} + +BOOL operator == ( const EditLine& r1, const EditLine& r2 ) +{ + if ( r1.nStart != r2.nStart ) + return FALSE; + + if ( r1.nEnd != r2.nEnd ) + return FALSE; + + if ( r1.nStartPortion != r2.nStartPortion ) + return FALSE; + + if ( r1.nEndPortion != r2.nEndPortion ) + return FALSE; + + return TRUE; +} + +EditLine& EditLine::operator = ( const EditLine& r ) +{ + nEnd = r.nEnd; + nStart = r.nStart; + nEndPortion = r.nEndPortion; + nStartPortion = r.nStartPortion; + return *this; +} + + +BOOL operator != ( const EditLine& r1, const EditLine& r2 ) +{ + return !( r1 == r2 ); +} + +Size EditLine::CalcTextSize( ParaPortion& rParaPortion ) +{ + Size aSz; + Size aTmpSz; + TextPortion* pPortion; + + USHORT nIndex = GetStart(); + + DBG_ASSERT( rParaPortion.GetTextPortions().Count(), "GetTextSize vor CreatePortions !" ); + + for ( USHORT n = nStartPortion; n <= nEndPortion; n++ ) + { + pPortion = rParaPortion.GetTextPortions().GetObject(n); + switch ( pPortion->GetKind() ) + { + case PORTIONKIND_TEXT: + case PORTIONKIND_FIELD: + case PORTIONKIND_HYPHENATOR: + { + aTmpSz = pPortion->GetSize(); + aSz.Width() += aTmpSz.Width(); + if ( aSz.Height() < aTmpSz.Height() ) + aSz.Height() = aTmpSz.Height(); + } + break; + case PORTIONKIND_TAB: +// case PORTIONKIND_EXTRASPACE: + { + aSz.Width() += pPortion->GetSize().Width(); + } + break; + } + nIndex = nIndex + pPortion->GetLen(); + } + + SetHeight( (USHORT)aSz.Height() ); + return aSz; +} + +// ------------------------------------------------------------------------- +// class EditLineList +// ------------------------------------------------------------------------- +EditLineList::EditLineList() +{ +} + +EditLineList::~EditLineList() +{ + Reset(); +} + +void EditLineList::Reset() +{ + for ( USHORT nLine = 0; nLine < Count(); nLine++ ) + delete GetObject(nLine); + Remove( 0, Count() ); +} + +void EditLineList::DeleteFromLine( USHORT nDelFrom ) +{ + DBG_ASSERT( nDelFrom <= (Count() - 1), "DeleteFromLine: Out of range" ); + for ( USHORT nL = nDelFrom; nL < Count(); nL++ ) + delete GetObject(nL); + Remove( nDelFrom, Count()-nDelFrom ); +} + +USHORT EditLineList::FindLine( USHORT nChar, BOOL bInclEnd ) +{ + for ( USHORT nLine = 0; nLine < Count(); nLine++ ) + { + EditLine* pLine = GetObject( nLine ); + if ( ( bInclEnd && ( pLine->GetEnd() >= nChar ) ) || + ( pLine->GetEnd() > nChar ) ) + { + return nLine; + } + } + + DBG_ASSERT( !bInclEnd, "Zeile nicht gefunden: FindLine" ); + return ( Count() - 1 ); +} + +// ------------------------------------------------------------------------- +// class EditSelection +// ------------------------------------------------------------------------- +BOOL EditPaM::DbgIsBuggy( EditDoc& rDoc ) +{ + if ( !pNode ) + return TRUE; + if ( rDoc.GetPos( pNode ) >= rDoc.Count() ) + return TRUE; + if ( nIndex > pNode->Len() ) + return TRUE; + + return FALSE; +} + +BOOL EditSelection::DbgIsBuggy( EditDoc& rDoc ) +{ + if ( aStartPaM.DbgIsBuggy( rDoc ) ) + return TRUE; + if ( aEndPaM.DbgIsBuggy( rDoc ) ) + return TRUE; + + return FALSE; +} + +EditSelection::EditSelection() +{ +} + +EditSelection::EditSelection( const EditPaM& rStartAndAnd ) +{ + // koennte noch optimiert werden! + // nicht erst Def-CTOR vom PaM rufen! + aStartPaM = rStartAndAnd; + aEndPaM = rStartAndAnd; +} + +EditSelection::EditSelection( const EditPaM& rStart, const EditPaM& rEnd ) +{ + // koennte noch optimiert werden! + aStartPaM = rStart; + aEndPaM = rEnd; +} + +EditSelection& EditSelection::operator = ( const EditPaM& rPaM ) +{ + aStartPaM = rPaM; + aEndPaM = rPaM; + return *this; +} + +BOOL EditSelection::IsInvalid() const +{ + EditPaM aEmptyPaM; + + if ( aStartPaM == aEmptyPaM ) + return TRUE; + + if ( aEndPaM == aEmptyPaM ) + return TRUE; + + return FALSE; +} + +BOOL EditSelection::Adjust( const ContentList& rNodes ) +{ + DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index im Wald in Adjust(1)" ); + DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index im Wald in Adjust(2)" ); + + ContentNode* pStartNode = aStartPaM.GetNode(); + ContentNode* pEndNode = aEndPaM.GetNode(); + + USHORT nStartNode = rNodes.GetPos( pStartNode ); + USHORT nEndNode = rNodes.GetPos( pEndNode ); + + DBG_ASSERT( nStartNode != USHRT_MAX, "Node im Wald in Adjust(1)" ); + DBG_ASSERT( nEndNode != USHRT_MAX, "Node im Wald in Adjust(2)" ); + + BOOL bSwap = FALSE; + if ( nStartNode > nEndNode ) + bSwap = TRUE; + else if ( ( nStartNode == nEndNode ) && ( aStartPaM.GetIndex() > aEndPaM.GetIndex() ) ) + bSwap = TRUE; + + if ( bSwap ) + { + EditPaM aTmpPaM( aStartPaM ); + aStartPaM = aEndPaM; + aEndPaM = aTmpPaM; + } + + return bSwap; +} + + +// ------------------------------------------------------------------------- +// class EditPaM +// ------------------------------------------------------------------------- +BOOL operator == ( const EditPaM& r1, const EditPaM& r2 ) +{ + if ( r1.GetNode() != r2.GetNode() ) + return FALSE; + + if ( r1.GetIndex() != r2.GetIndex() ) + return FALSE; + + return TRUE; +} + +EditPaM& EditPaM::operator = ( const EditPaM& rPaM ) +{ + nIndex = rPaM.nIndex; + pNode = rPaM.pNode; + return *this; +} + +BOOL operator != ( const EditPaM& r1, const EditPaM& r2 ) +{ + return !( r1 == r2 ); +} + + +// ------------------------------------------------------------------------- +// class ContentNode +// ------------------------------------------------------------------------- +ContentNode::ContentNode( SfxItemPool& rPool ) : aContentAttribs( rPool ) +{ + DBG_CTOR( EE_ContentNode, 0 ); + pWrongList = NULL; +} + +ContentNode::ContentNode( const XubString& rStr, const ContentAttribs& rContentAttribs ) : + XubString( rStr ), aContentAttribs( rContentAttribs ) +{ + DBG_CTOR( EE_ContentNode, 0 ); + pWrongList = NULL; +} + +ContentNode::~ContentNode() +{ + DBG_DTOR( EE_ContentNode, 0 ); +#ifndef SVX_LIGHT + delete pWrongList; +#endif +} + +void ContentNode::ExpandAttribs( USHORT nIndex, USHORT nNew, SfxItemPool& rItemPool ) +{ + if ( !nNew ) + return; + + // Da Features anders behandelt werden als normale Zeichenattribute, + // kann sich hier auch die Sortierung der Start-Liste aendern! + // In jedem if..., in dem weiter (n) Moeglichkeiten aufgrund von + // bFeature oder Spezialfall existieren, + // muessen (n-1) Moeglichkeiten mit bResort versehen werden. + // Die wahrscheinlichste Moeglichkeit erhaelt kein bResort, + // so dass nicht neu sortiert wird, wenn sich alle Attribute + // gleich verhalten. + BOOL bResort = FALSE; + BOOL bExpandedEmptyAtIndexNull = FALSE; + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + while ( pAttrib ) + { + if ( pAttrib->GetEnd() >= nIndex ) + { + // Alle Attribute hinter der Einfuegeposition verschieben... + if ( pAttrib->GetStart() > nIndex ) + { + pAttrib->MoveForward( nNew ); + } + // 0: Leeres Attribut expandieren, wenn an Einfuegestelle + else if ( pAttrib->IsEmpty() ) + { + // Index nicht pruefen, leeres durfte nur dort liegen. + // Wenn spaeter doch Ueberpruefung: + // Spezialfall: Start == 0; AbsLen == 1, nNew = 1 => Expand, weil durch Absatzumbruch! + // Start <= nIndex, End >= nIndex => Start=End=nIndex! +// if ( pAttrib->GetStart() == nIndex ) + pAttrib->Expand( nNew ); + if ( pAttrib->GetStart() == 0 ) + bExpandedEmptyAtIndexNull = TRUE; + } + // 1: Attribut startet davor, geht bis Index... + else if ( pAttrib->GetEnd() == nIndex ) // Start muss davor liegen + { + // Nur expandieren, wenn kein Feature, + // und wenn nicht in ExcludeListe! + // Sonst geht z.B. ein UL bis zum neuen ULDB, beide expandieren +// if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( pAttrib->Which() ) ) + if ( !pAttrib->IsFeature() && !aCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) ) + { + if ( !pAttrib->IsEdge() ) + pAttrib->Expand( nNew ); + } + else + bResort = TRUE; + } + // 2: Attribut startet davor, geht hinter Index... + else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) + { + DBG_ASSERT( !pAttrib->IsFeature(), "Grosses Feature?!" ); + pAttrib->Expand( nNew ); + } + // 3: Attribut startet auf Index... + else if ( pAttrib->GetStart() == nIndex ) + { + if ( pAttrib->IsFeature() ) + { + pAttrib->MoveForward( nNew ); + bResort = TRUE; + } + else + { + BOOL bExpand = FALSE; + if ( nIndex == 0 ) + { + bExpand = TRUE; + if( bExpandedEmptyAtIndexNull ) + { + // Check if this kind of attribut was empty and expanded here... + USHORT nW = pAttrib->GetItem()->Which(); + for ( USHORT nA = 0; nA < nAttr; nA++ ) + { + EditCharAttrib* pA = aCharAttribList.GetAttribs()[nA]; + if ( ( pA->GetStart() == 0 ) && ( pA->GetItem()->Which() == nW ) ) + { + bExpand = FALSE; + break; + } + } + + } + } + if ( bExpand ) + { + pAttrib->Expand( nNew ); + bResort = TRUE; + } + else + { + pAttrib->MoveForward( nNew ); + } + } + } + } + + if ( pAttrib->IsEdge() ) + pAttrib->SetEdge( FALSE ); + + DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" ); + + DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: Attribut verdreht!" ); + DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attrib groesser als Absatz!" ); + if ( pAttrib->IsEmpty() ) + { + DBG_ERROR( "Leeres Attribut nach ExpandAttribs?" ); + bResort = TRUE; + aCharAttribList.GetAttribs().Remove( nAttr ); + rItemPool.Remove( *pAttrib->GetItem() ); + delete pAttrib; + nAttr--; + } + nAttr++; + pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + } + + if ( bResort ) + aCharAttribList.ResortAttribs(); + +#ifndef SVX_LIGHT + if ( pWrongList ) + { + BOOL bSep = ( GetChar( nIndex ) == ' ' ) || IsFeature( nIndex ); + pWrongList->TextInserted( nIndex, nNew, bSep ); + } +#endif // !SVX_LIGHT + +#ifdef EDITDEBUG + DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), TRUE ), "Expand: Start-Liste verdreht" ); +#endif +} + +void ContentNode::CollapsAttribs( USHORT nIndex, USHORT nDeleted, SfxItemPool& rItemPool ) +{ + if ( !nDeleted ) + return; + + // Da Features anders behandelt werden als normale Zeichenattribute, + // kann sich hier auch die Sortierung der Start-Liste aendern! + BOOL bResort = FALSE; + BOOL bDelAttr = FALSE; + USHORT nEndChanges = nIndex+nDeleted; + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + while ( pAttrib ) + { + bDelAttr = FALSE; + if ( pAttrib->GetEnd() >= nIndex ) + { + // Alles Attribute hinter der Einfuegeposition verschieben... + if ( pAttrib->GetStart() >= nEndChanges ) + { + pAttrib->MoveBackward( nDeleted ); + } + // 1. Innenliegende Attribute loeschen... + else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() <= nEndChanges ) ) + { + // Spezialfall: Attrubt deckt genau den Bereich ab + // => als leeres Attribut behalten. + if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex ) && ( pAttrib->GetEnd() == nEndChanges ) ) + pAttrib->GetEnd() = nIndex; // leer + else + bDelAttr = TRUE; + } + // 2. Attribut beginnt davor, endet drinnen oder dahinter... + else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() > nIndex ) ) + { + DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" ); + if ( pAttrib->GetEnd() <= nEndChanges ) // endet drinnen + pAttrib->GetEnd() = nIndex; + else + pAttrib->Collaps( nDeleted ); // endet dahinter + } + // 3. Attribut beginnt drinnen, endet dahinter... + else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() > nEndChanges ) ) + { + // Features duerfen nicht expandieren! + if ( pAttrib->IsFeature() ) + { + pAttrib->MoveBackward( nDeleted ); + bResort = TRUE; + } + else + { + pAttrib->GetStart() = nEndChanges; + pAttrib->MoveBackward( nDeleted ); + } + } + } + DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), "Expand: FeaturesLen != 1" ); + + DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collaps: Attribut verdreht!" ); + DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collaps: Attrib groesser als Absatz!" ); + if ( bDelAttr /* || pAttrib->IsEmpty() */ ) + { + bResort = TRUE; + aCharAttribList.GetAttribs().Remove( nAttr ); + rItemPool.Remove( *pAttrib->GetItem() ); + delete pAttrib; + nAttr--; + } + else if ( pAttrib->IsEmpty() ) + aCharAttribList.HasEmptyAttribs() = TRUE; + + nAttr++; + pAttrib = GetAttrib( aCharAttribList.GetAttribs(), nAttr ); + } + + if ( bResort ) + aCharAttribList.ResortAttribs(); + +#ifndef SVX_LIGHT + if ( pWrongList ) + pWrongList->TextDeleted( nIndex, nDeleted ); +#endif // !SVX_LIGHT + +#ifdef EDITDEBUG + DBG_ASSERT( CheckOrderedList( aCharAttribList.GetAttribs(), TRUE ), "Collaps: Start-Liste verdreht" ); +#endif +} + +void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, BOOL bKeepEndingAttribs ) +{ + DBG_ASSERT( pPrevNode, "kopieren von Attributen auf einen NULL-Pointer ?" ); + + xub_StrLen nCut = pPrevNode->Len(); + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttrib ) + { + if ( pAttrib->GetEnd() < nCut ) + { + // bleiben unveraendert.... + ; + } + else if ( pAttrib->GetEnd() == nCut ) + { + // muessen als leeres Attribut kopiert werden. + if ( bKeepEndingAttribs && !pAttrib->IsFeature() && !aCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) ) + { + EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, 0 ); + DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" ); + aCharAttribList.InsertAttrib( pNewAttrib ); + } + } + else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() && !pAttrib->IsFeature() ) ) + { + // Wenn ganz vorne gecuttet wird, muss das Attribut erhalten bleiben! + // muessen kopiert und geaendert werden + EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, *(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut ); + DBG_ASSERT( pNewAttrib, "MakeCharAttrib fehlgeschlagen!" ); + aCharAttribList.InsertAttrib( pNewAttrib ); + // stutzen: + pAttrib->GetEnd() = nCut; + } + else + { + // alle dahinter verschieben in den neuen Node (this) +// pPrevNode->GetCharAttribs().RemoveAttrib( pAttrib ); + pPrevNode->GetCharAttribs().GetAttribs().Remove( nAttr ); + aCharAttribList.InsertAttrib( pAttrib ); + DBG_ASSERT( pAttrib->GetStart() >= nCut, "Start < nCut!" ); + DBG_ASSERT( pAttrib->GetEnd() >= nCut, "End < nCut!" ); + pAttrib->GetStart() = pAttrib->GetStart() - nCut; + pAttrib->GetEnd() = pAttrib->GetEnd() - nCut; + nAttr--; + } + nAttr++; + pAttrib = GetAttrib( pPrevNode->GetCharAttribs().GetAttribs(), nAttr ); + } +} + +void ContentNode::AppendAttribs( ContentNode* pNextNode ) +{ + DBG_ASSERT( pNextNode, "kopieren von Attributen von einen NULL-Pointer ?" ); + + USHORT nNewStart = Len(); + +#ifdef EDITDEBUG + DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute VOR AppendAttribs kaputt" ); +#endif + + USHORT nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttrib ) + { + // alle Attribute verschieben in den aktuellen Node (this) + BOOL bMelted = FALSE; + if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) ) + { + // Evtl koennen Attribute zusammengefasst werden: + USHORT nTmpAttr = 0; + EditCharAttrib* pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr ); + while ( !bMelted && pTmpAttrib ) + { + if ( pTmpAttrib->GetEnd() == nNewStart ) + { + if ( ( pTmpAttrib->Which() == pAttrib->Which() ) && + ( *(pTmpAttrib->GetItem()) == *(pAttrib->GetItem() ) ) ) + { + pTmpAttrib->GetEnd() = + pTmpAttrib->GetEnd() + pAttrib->GetLen(); + pNextNode->GetCharAttribs().GetAttribs().Remove( nAttr ); + // Vom Pool abmelden ?! + delete pAttrib; + bMelted = TRUE; + } + } + ++nTmpAttr; + pTmpAttrib = GetAttrib( aCharAttribList.GetAttribs(), nTmpAttr ); + } + } + + if ( !bMelted ) + { + pAttrib->GetStart() = pAttrib->GetStart() + nNewStart; + pAttrib->GetEnd() = pAttrib->GetEnd() + nNewStart; + aCharAttribList.InsertAttrib( pAttrib ); + ++nAttr; + } + pAttrib = GetAttrib( pNextNode->GetCharAttribs().GetAttribs(), nAttr ); + } + // Fuer die Attribute, die nur ruebergewandert sind: + pNextNode->GetCharAttribs().Clear(); + +#ifdef EDITDEBUG + DBG_ASSERT( aCharAttribList.DbgCheckAttribs(), "Attribute NACH AppendAttribs kaputt" ); +#endif +} + +void ContentNode::CreateDefFont() +{ + // Erst alle Informationen aus dem Style verwenden... + SfxStyleSheet* pS = aContentAttribs.GetStyleSheet(); + if ( pS ) + CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() ); + + // ... dann die harte Absatzformatierung rueberbuegeln... + CreateFont( GetCharAttribs().GetDefFont(), + GetContentAttribs().GetItems(), pS == NULL ); +} + +void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle ) +{ + aContentAttribs.SetStyleSheet( pS ); + + // Erst alle Informationen aus dem Style verwenden... + GetCharAttribs().GetDefFont() = rFontFromStyle; + // ... dann die harte Absatzformatierung rueberbuegeln... + CreateFont( GetCharAttribs().GetDefFont(), + GetContentAttribs().GetItems(), pS == NULL ); +} + +void ContentNode::SetStyleSheet( SfxStyleSheet* pS, BOOL bRecalcFont ) +{ + aContentAttribs.SetStyleSheet( pS ); + if ( bRecalcFont ) + CreateDefFont(); +} + +void ContentNode::DestroyWrongList() +{ +#ifndef SVX_LIGHT + delete pWrongList; +#endif + pWrongList = NULL; +} + +void ContentNode::CreateWrongList() +{ + DBG_ASSERT( !pWrongList, "WrongList existiert schon!" ); +#ifndef SVX_LIGHT + pWrongList = new WrongList; +#endif +} + +void ContentNode::SetWrongList( WrongList* p ) +{ + DBG_ASSERT( !pWrongList, "WrongList existiert schon!" ); + pWrongList = p; +} + +// ------------------------------------------------------------------------- +// class ContentAttribs +// ------------------------------------------------------------------------- +ContentAttribs::ContentAttribs( SfxItemPool& rPool ) : + aAttribSet( rPool, EE_PARA_START, EE_CHAR_END ) +{ + pStyle = 0; +} + +ContentAttribs::ContentAttribs( const ContentAttribs& rRef ) : + aAttribSet( rRef.aAttribSet ) +{ + pStyle = rRef.pStyle; +} + +ContentAttribs::~ContentAttribs() +{ +} + +SvxTabStop ContentAttribs::FindTabStop( long nCurPos, USHORT nDefTab ) +{ + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) GetItem( EE_PARA_TABS ); + for ( USHORT i = 0; i < rTabs.Count(); i++ ) + { + const SvxTabStop& rTab = rTabs[i]; + if ( rTab.GetTabPos() > nCurPos ) + return rTab; + } + + // DefTab ermitteln... + SvxTabStop aTabStop; + long x = nCurPos / nDefTab + 1; + aTabStop.GetTabPos() = nDefTab * x; + return aTabStop; +} + +void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS ) +{ + BOOL bStyleChanged = ( pStyle != pS ); + pStyle = pS; + // #104799# Only when other style sheet, not when current style sheet modified + if ( pStyle && bStyleChanged ) + { + // Gezielt die Attribute aus der Absatzformatierung entfernen, die im Style + // spezifiziert sind, damit die Attribute des Styles wirken koennen. + const SfxItemSet& rStyleAttribs = pStyle->GetItemSet(); + for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + // #99635# Don't change bullet on/off + if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON ) ) + aAttribSet.ClearItem( nWhich ); + } + } +} + +const SfxPoolItem& ContentAttribs::GetItem( USHORT nWhich ) +{ + // Harte Absatzattribute haben Vorrang! + SfxItemSet* pTakeFrom = &aAttribSet; + if ( pStyle && ( aAttribSet.GetItemState( nWhich, FALSE ) != SFX_ITEM_ON ) ) + pTakeFrom = &pStyle->GetItemSet(); + + return pTakeFrom->Get( nWhich ); +} + +BOOL ContentAttribs::HasItem( USHORT nWhich ) +{ + BOOL bHasItem = FALSE; + if ( aAttribSet.GetItemState( nWhich, FALSE ) == SFX_ITEM_ON ) + bHasItem = TRUE; + else if ( pStyle && pStyle->GetItemSet().GetItemState( nWhich ) == SFX_ITEM_ON ) + bHasItem = TRUE; + + return bHasItem; +} + + + +// ---------------------------------------------------------------------- +// class ItemList +// ---------------------------------------------------------------------- +const SfxPoolItem* ItemList::FindAttrib( USHORT nWhich ) +{ + const SfxPoolItem* pItem = First(); + while ( pItem && ( pItem->Which() != nWhich ) ) + pItem = Next(); + + return pItem; +} + +// ------------------------------------------------------------------------- +// class EditDoc +// ------------------------------------------------------------------------- +EditDoc::EditDoc( SfxItemPool* pPool ) +{ + if ( pPool ) + { + pItemPool = pPool; + bOwnerOfPool = FALSE; + } + else + { + pItemPool = new EditEngineItemPool( FALSE ); + bOwnerOfPool = TRUE; + } + + nDefTab = DEFTAB; + bIsVertical = FALSE; + bIsFixedCellHeight = FALSE; + + // Don't create a empty node, Clear() will be called in EditEngine-CTOR + + SetModified( FALSE ); +}; + +EditDoc::~EditDoc() +{ + ImplDestroyContents(); + if ( bOwnerOfPool ) + SfxItemPool::Free(pItemPool); +} + +void EditDoc::ImplDestroyContents() +{ + for ( USHORT nNode = Count(); nNode; ) + RemoveItemsFromPool( GetObject( --nNode ) ); + DeleteAndDestroy( 0, Count() ); +} + +void EditDoc::RemoveItemsFromPool( ContentNode* pNode ) +{ + for ( USHORT nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ ) + { + EditCharAttrib* pAttr = pNode->GetCharAttribs().GetAttribs()[nAttr]; + GetItemPool().Remove( *pAttr->GetItem() ); + } +} + +void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent, short nScriptType ) +{ + Font aPrevFont( rFont ); + rFont.SetAlign( ALIGN_BASELINE ); + rFont.SetTransparent( TRUE ); + + USHORT nWhich_FontInfo = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ); + USHORT nWhich_Language = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); + USHORT nWhich_FontHeight = GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ); + USHORT nWhich_Weight = GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ); + USHORT nWhich_Italic = GetScriptItemId( EE_CHAR_ITALIC, nScriptType ); + + if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontInfo ) == SFX_ITEM_ON ) ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)rSet.Get( nWhich_FontInfo ); + rFont.SetName( rFontItem.GetFamilyName() ); + rFont.SetFamily( rFontItem.GetFamily() ); + rFont.SetPitch( rFontItem.GetPitch() ); + rFont.SetCharSet( rFontItem.GetCharSet() ); + } + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Language ) == SFX_ITEM_ON ) ) + rFont.SetLanguage( ((const SvxLanguageItem&)rSet.Get( nWhich_Language )).GetLanguage() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_COLOR ) == SFX_ITEM_ON ) ) + rFont.SetColor( ((const SvxColorItem&)rSet.Get( EE_CHAR_COLOR )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_FontHeight ) == SFX_ITEM_ON ) ) + rFont.SetSize( Size( rFont.GetSize().Width(), ((const SvxFontHeightItem&)rSet.Get( nWhich_FontHeight ) ).GetHeight() ) ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Weight ) == SFX_ITEM_ON ) ) + rFont.SetWeight( ((const SvxWeightItem&)rSet.Get( nWhich_Weight )).GetWeight() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_UNDERLINE ) == SFX_ITEM_ON ) ) + rFont.SetUnderline( ((const SvxUnderlineItem&)rSet.Get( EE_CHAR_UNDERLINE )).GetLineStyle() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OVERLINE ) == SFX_ITEM_ON ) ) + rFont.SetOverline( ((const SvxOverlineItem&)rSet.Get( EE_CHAR_OVERLINE )).GetLineStyle() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_STRIKEOUT ) == SFX_ITEM_ON ) ) + rFont.SetStrikeout( ((const SvxCrossedOutItem&)rSet.Get( EE_CHAR_STRIKEOUT )).GetStrikeout() ); + if ( bSearchInParent || ( rSet.GetItemState( nWhich_Italic ) == SFX_ITEM_ON ) ) + rFont.SetItalic( ((const SvxPostureItem&)rSet.Get( nWhich_Italic )).GetPosture() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_OUTLINE ) == SFX_ITEM_ON ) ) + rFont.SetOutline( ((const SvxContourItem&)rSet.Get( EE_CHAR_OUTLINE )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_SHADOW ) == SFX_ITEM_ON ) ) + rFont.SetShadow( ((const SvxShadowedItem&)rSet.Get( EE_CHAR_SHADOW )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_ESCAPEMENT ) == SFX_ITEM_ON ) ) + { + const SvxEscapementItem& rEsc = (const SvxEscapementItem&) rSet.Get( EE_CHAR_ESCAPEMENT ); + + USHORT nProp = rEsc.GetProp(); + rFont.SetPropr( (BYTE)nProp ); + + short nEsc = rEsc.GetEsc(); + if ( nEsc == DFLT_ESC_AUTO_SUPER ) + nEsc = 100 - nProp; + else if ( nEsc == DFLT_ESC_AUTO_SUB ) + nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); + rFont.SetEscapement( nEsc ); + } + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_PAIRKERNING ) == SFX_ITEM_ON ) ) + rFont.SetKerning( ((const SvxAutoKernItem&)rSet.Get( EE_CHAR_PAIRKERNING )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_KERNING ) == SFX_ITEM_ON ) ) + rFont.SetFixKerning( ((const SvxKerningItem&)rSet.Get( EE_CHAR_KERNING )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_WLM ) == SFX_ITEM_ON ) ) + rFont.SetWordLineMode( ((const SvxWordLineModeItem&)rSet.Get( EE_CHAR_WLM )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_EMPHASISMARK ) == SFX_ITEM_ON ) ) + rFont.SetEmphasisMark( ((const SvxEmphasisMarkItem&)rSet.Get( EE_CHAR_EMPHASISMARK )).GetValue() ); + if ( bSearchInParent || ( rSet.GetItemState( EE_CHAR_RELIEF ) == SFX_ITEM_ON ) ) + rFont.SetRelief( (FontRelief)((const SvxCharReliefItem&)rSet.Get( EE_CHAR_RELIEF )).GetValue() ); + + // Ob ich jetzt den ganzen Font vergleiche, oder vor jeder Aenderung + // pruefe, ob der Wert sich aendert, bleibt sich relativ gleich. + // So ggf ein MakeUniqFont im Font mehr, dafuer bei Aenderung schnellerer + // Abbruch der Abfrage, oder ich musste noch jedesmal ein bChanged pflegen. + if ( rFont == aPrevFont ) + rFont = aPrevFont; // => Gleicher ImpPointer fuer IsSameInstance +} + +void EditDoc::CreateDefFont( BOOL bUseStyles ) +{ + SfxItemSet aTmpSet( GetItemPool(), EE_PARA_START, EE_CHAR_END ); + CreateFont( aDefFont, aTmpSet ); + aDefFont.SetVertical( IsVertical() ); + aDefFont.SetOrientation( IsVertical() ? 2700 : 0 ); + + for ( USHORT nNode = 0; nNode < Count(); nNode++ ) + { + ContentNode* pNode = GetObject( nNode ); + pNode->GetCharAttribs().GetDefFont() = aDefFont; + if ( bUseStyles ) + pNode->CreateDefFont(); + } +} + +static const sal_Unicode aCR[] = { 0x0d, 0x00 }; +static const sal_Unicode aLF[] = { 0x0a, 0x00 }; +static const sal_Unicode aCRLF[] = { 0x0d, 0x0a, 0x00 }; + +XubString EditDoc::GetSepStr( LineEnd eEnd ) +{ + XubString aSep; + if ( eEnd == LINEEND_CR ) + aSep = aCR; + else if ( eEnd == LINEEND_LF ) + aSep = aLF; + else + aSep = aCRLF; + return aSep; +} + +XubString EditDoc::GetText( LineEnd eEnd ) const +{ + ULONG nLen = GetTextLen(); + USHORT nNodes = Count(); + + String aSep = EditDoc::GetSepStr( eEnd ); + USHORT nSepSize = aSep.Len(); + + if ( nSepSize ) + nLen += nNodes * nSepSize; + if ( nLen > 0xFFFb / sizeof(xub_Unicode) ) + { + DBG_ERROR( "Text zu gross fuer String" ); + return XubString(); + } + xub_Unicode* pStr = new xub_Unicode[nLen+1]; + xub_Unicode* pCur = pStr; + USHORT nLastNode = nNodes-1; + for ( USHORT nNode = 0; nNode < nNodes; nNode++ ) + { + XubString aTmp( GetParaAsString( GetObject(nNode) ) ); + memcpy( pCur, aTmp.GetBuffer(), aTmp.Len()*sizeof(sal_Unicode) ); + pCur += aTmp.Len(); + if ( nSepSize && ( nNode != nLastNode ) ) + { + memcpy( pCur, aSep.GetBuffer(), nSepSize*sizeof(sal_Unicode ) ); + pCur += nSepSize; + } + } + *pCur = '\0'; + XubString aASCIIText( pStr ); + delete[] pStr; + return aASCIIText; +} + +XubString EditDoc::GetParaAsString( USHORT nNode ) const +{ + return GetParaAsString( SaveGetObject( nNode ) ); +} + +XubString EditDoc::GetParaAsString( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, BOOL bResolveFields ) const +{ + if ( nEndPos > pNode->Len() ) + nEndPos = pNode->Len(); + + DBG_ASSERT( nStartPos <= nEndPos, "Start und Ende vertauscht?" ); + + USHORT nIndex = nStartPos; + XubString aStr; + EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex ); + while ( nIndex < nEndPos ) + { + USHORT nEnd = nEndPos; + if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) ) + nEnd = pNextFeature->GetStart(); + else + pNextFeature = 0; // Feature interessiert unten nicht + + DBG_ASSERT( nEnd >= nIndex, "Ende vorm Index?" ); + //!! beware of sub string length of -1 which is also defined as STRING_LEN and + //!! thus would result in adding the whole sub string up to the end of the node !! + if (nEnd > nIndex) + aStr += XubString( *pNode, nIndex, nEnd - nIndex ); + + if ( pNextFeature ) + { + switch ( pNextFeature->GetItem()->Which() ) + { + case EE_FEATURE_TAB: aStr += '\t'; + break; + case EE_FEATURE_LINEBR: aStr += '\x0A'; + break; + case EE_FEATURE_FIELD: if ( bResolveFields ) + aStr += ((EditCharAttribField*)pNextFeature)->GetFieldValue(); + break; + default: DBG_ERROR( "Was fuer ein Feature ?" ); + } + pNextFeature = pNode->GetCharAttribs().FindFeature( ++nEnd ); + } + nIndex = nEnd; + } + return aStr; +} + +ULONG EditDoc::GetTextLen() const +{ + ULONG nLen = 0; + for ( USHORT nNode = 0; nNode < Count(); nNode++ ) + { + ContentNode* pNode = GetObject( nNode ); + nLen += pNode->Len(); + // Felder k”nnen laenger sein als der Platzhalter im Node. + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( USHORT nAttr = rAttrs.Count(); nAttr; ) + { + EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + USHORT nFieldLen = ((EditCharAttribField*)pAttr)->GetFieldValue().Len(); + if ( !nFieldLen ) + nLen--; + else + nLen += nFieldLen-1; + } + } + } + return nLen; +} + +EditPaM EditDoc::Clear() +{ + ImplDestroyContents(); + + ContentNode* pNode = new ContentNode( GetItemPool() ); + Insert( pNode, 0 ); + + CreateDefFont( FALSE ); + + SetModified( FALSE ); + + EditPaM aPaM( pNode, 0 ); + return aPaM; +} + +void EditDoc::SetModified( BOOL b ) +{ + bModified = b; + if ( bModified ) + { + aModifyHdl.Call( NULL ); + } +} + +EditPaM EditDoc::RemoveText() +{ + // Das alte ItemSetmerken, damit z.B. im Chart Font behalten bleibt + ContentNode* pPrevFirstNode = GetObject(0); + SfxStyleSheet* pPrevStyle = pPrevFirstNode->GetStyleSheet(); + SfxItemSet aPrevSet( pPrevFirstNode->GetContentAttribs().GetItems() ); + Font aPrevFont( pPrevFirstNode->GetCharAttribs().GetDefFont() ); + + ImplDestroyContents(); + + ContentNode* pNode = new ContentNode( GetItemPool() ); + Insert( pNode, 0 ); + + pNode->SetStyleSheet( pPrevStyle, FALSE ); + pNode->GetContentAttribs().GetItems().Set( aPrevSet ); + pNode->GetCharAttribs().GetDefFont() = aPrevFont; + + SetModified( TRUE ); + + EditPaM aPaM( pNode, 0 ); + return aPaM; +} + +void EditDoc::InsertText( const EditPaM& rPaM, xub_Unicode c ) +{ + DBG_ASSERT( c != 0x0A, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( c != 0x0D, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( c != '\t', "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + + rPaM.GetNode()->Insert( c, rPaM.GetIndex() ); + rPaM.GetNode()->ExpandAttribs( rPaM.GetIndex(), 1, GetItemPool() ); + + SetModified( TRUE ); +} + +EditPaM EditDoc::InsertText( EditPaM aPaM, const XubString& rStr ) +{ + DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( '\t' ) == STRING_NOTFOUND, "EditDoc::InsertText: Zeilentrenner in Absatz nicht erlaubt!" ); + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertText1" ); + + aPaM.GetNode()->Insert( rStr, aPaM.GetIndex() ); + aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), rStr.Len(), GetItemPool() ); + aPaM.GetIndex() = aPaM.GetIndex() + rStr.Len(); + + SetModified( TRUE ); + + return aPaM; +} + +EditPaM EditDoc::InsertParaBreak( EditPaM aPaM, BOOL bKeepEndingAttribs ) +{ + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertParaBreak" ); + ContentNode* pCurNode = aPaM.GetNode(); + USHORT nPos = GetPos( pCurNode ); + XubString aStr = aPaM.GetNode()->Copy( aPaM.GetIndex() ); + aPaM.GetNode()->Erase( aPaM.GetIndex() ); + + // the paragraph attributes... + ContentAttribs aContentAttribs( aPaM.GetNode()->GetContentAttribs() ); + + // for a new paragraph we like to have the bullet/numbering visible by default + aContentAttribs.GetItems().Put( SfxBoolItem( EE_PARA_BULLETSTATE, TRUE), EE_PARA_BULLETSTATE ); + + // ContenNode-CTOR kopiert auch die Absatzattribute + ContentNode* pNode = new ContentNode( aStr, aContentAttribs ); + + // Den Default-Font kopieren + pNode->GetCharAttribs().GetDefFont() = aPaM.GetNode()->GetCharAttribs().GetDefFont(); + SfxStyleSheet* pStyle = aPaM.GetNode()->GetStyleSheet(); + if ( pStyle ) + { + XubString aFollow( pStyle->GetFollow() ); + if ( aFollow.Len() && ( aFollow != pStyle->GetName() ) ) + { + SfxStyleSheetBase* pNext = pStyle->GetPool().Find( aFollow, pStyle->GetFamily() ); + pNode->SetStyleSheet( (SfxStyleSheet*)pNext ); + } + } + + // Zeichenattribute muessen ggf. kopiert bzw gestutzt werden: + pNode->CopyAndCutAttribs( aPaM.GetNode(), GetItemPool(), bKeepEndingAttribs ); + + Insert( pNode, nPos+1 ); + + SetModified( TRUE ); + + aPaM.SetNode( pNode ); + aPaM.SetIndex( 0 ); + return aPaM; +} + +EditPaM EditDoc::InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem ) +{ + DBG_ASSERT( aPaM.GetNode(), "Blinder PaM in EditDoc::InsertFeature" ); + + aPaM.GetNode()->Insert( CH_FEATURE, aPaM.GetIndex() ); + aPaM.GetNode()->ExpandAttribs( aPaM.GetIndex(), 1, GetItemPool() ); + + // Fuer das Feature ein Feature-Attribut anlegen... + EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rItem, aPaM.GetIndex(), aPaM.GetIndex()+1 ); + DBG_ASSERT( pAttrib, "Warum kann ich kein Feature anlegen ?" ); + aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttrib ); + + SetModified( TRUE ); + + aPaM.GetIndex()++; + return aPaM; +} + +EditPaM EditDoc::ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight ) +{ + const EditPaM aPaM( pLeft, pLeft->Len() ); + + // Erst die Attribute, da sonst nLen nicht stimmt! + pLeft->AppendAttribs( pRight ); + // Dann den Text... + *pLeft += *pRight; + + // der rechte verschwindet. + RemoveItemsFromPool( pRight ); + USHORT nRight = GetPos( pRight ); + Remove( nRight ); + delete pRight; + + SetModified( TRUE ); + + return aPaM; +} + +EditPaM EditDoc::RemoveChars( EditPaM aPaM, USHORT nChars ) +{ + // Evtl. Features entfernen! + aPaM.GetNode()->Erase( aPaM.GetIndex(), nChars ); + aPaM.GetNode()->CollapsAttribs( aPaM.GetIndex(), nChars, GetItemPool() ); + + SetModified( TRUE ); + + return aPaM; +} + +void EditDoc::InsertAttribInSelection( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ) +{ + DBG_ASSERT( pNode, "Wohin mit dem Attribut?" ); + DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" ); + + // fuer Optimierung: + // dieses endet am Anfang der Selektion => kann erweitert werden + EditCharAttrib* pEndingAttrib = 0; + // dieses startet am Ende der Selektion => kann erweitert werden + EditCharAttrib* pStartingAttrib = 0; + + DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" ); + + RemoveAttribs( pNode, nStart, nEnd, pStartingAttrib, pEndingAttrib, rPoolItem.Which() ); + + if ( pStartingAttrib && pEndingAttrib && + ( *(pStartingAttrib->GetItem()) == rPoolItem ) && + ( *(pEndingAttrib->GetItem()) == rPoolItem ) ) + { + // wird ein groesses Attribut. + pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd(); + GetItemPool().Remove( *(pStartingAttrib->GetItem()) ); + pNode->GetCharAttribs().GetAttribs().Remove( pNode->GetCharAttribs().GetAttribs().GetPos( pStartingAttrib ) ); + delete pStartingAttrib; + } + else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) ) + pStartingAttrib->GetStart() = nStart; + else if ( pEndingAttrib && ( *(pEndingAttrib->GetItem()) == rPoolItem ) ) + pEndingAttrib->GetEnd() = nEnd; + else + InsertAttrib( rPoolItem, pNode, nStart, nEnd ); + + if ( pStartingAttrib ) + pNode->GetCharAttribs().ResortAttribs(); + + SetModified( TRUE ); +} + +BOOL EditDoc::RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, USHORT nWhich ) +{ + EditCharAttrib* pStarting; + EditCharAttrib* pEnding; + return RemoveAttribs( pNode, nStart, nEnd, pStarting, pEnding, nWhich ); +} + +BOOL EditDoc::RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, USHORT nWhich ) +{ + DBG_ASSERT( pNode, "Wohin mit dem Attribut?" ); + DBG_ASSERT( nEnd <= pNode->Len(), "InsertAttrib: Attribut zu gross!" ); + + // dieses endet am Anfang der Selektion => kann erweitert werden + rpEnding = 0; + // dieses startet am Ende der Selektion => kann erweitert werden + rpStarting = 0; + + BOOL bChanged = FALSE; + + DBG_ASSERT( nStart <= nEnd, "Kleiner Rechenfehler in InsertAttribInSelection" ); + + // ueber die Attribute iterieren... + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr ) + { + BOOL bRemoveAttrib = FALSE; + // MT 11.9.97: + // Ich denke dass in dieser Methode generell keine Features geloescht + // werden sollen. + // => Dann koennen die Feature-Abfragen weiter unten entfallen + USHORT nAttrWhich = pAttr->Which(); + if ( ( nAttrWhich < EE_FEATURE_START ) && ( !nWhich || ( nAttrWhich == nWhich ) ) ) + { + // Attribut beginnt in Selection + if ( ( pAttr->GetStart() >= nStart ) && ( pAttr->GetStart() <= nEnd ) ) + { + bChanged = TRUE; + if ( pAttr->GetEnd() > nEnd ) + { + pAttr->GetStart() = nEnd; // dann faengt es dahinter an + rpStarting = pAttr; + if ( nWhich ) + break; // es kann kein weiteres Attrib hier liegen + } + else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) ) + { + // Feature nur loeschen, wenn genau an der Stelle + bRemoveAttrib = TRUE; + } + } + + // Attribut endet in Selection + else if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetEnd() <= nEnd ) ) + { + bChanged = TRUE; + if ( ( pAttr->GetStart() < nStart ) && !pAttr->IsFeature() ) + { + pAttr->GetEnd() = nStart; // dann hoert es hier auf + rpEnding = pAttr; + } + else if ( !pAttr->IsFeature() || ( pAttr->GetStart() == nStart ) ) + { + // Feature nur loeschen, wenn genau an der Stelle + bRemoveAttrib = TRUE; + } + } + // Attribut ueberlappt die Selektion + else if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) ) + { + bChanged = TRUE; + if ( pAttr->GetStart() == nStart ) + { + pAttr->GetStart() = nEnd; + rpStarting = pAttr; + if ( nWhich ) + break; // es kann weitere Attribute geben! + } + else if ( pAttr->GetEnd() == nEnd ) + { + pAttr->GetEnd() = nStart; + rpEnding = pAttr; + if ( nWhich ) + break; // es kann weitere Attribute geben! + } + else // Attribut muss gesplittet werden... + { + USHORT nOldEnd = pAttr->GetEnd(); + pAttr->GetEnd() = nStart; + rpEnding = pAttr; + InsertAttrib( *pAttr->GetItem(), pNode, nEnd, nOldEnd ); + if ( nWhich ) + break; // es kann weitere Attribute geben! + } + } + } + if ( bRemoveAttrib ) + { + DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Loeschen und behalten des gleichen Attributs ?" ); + DBG_ASSERT( !pAttr->IsFeature(), "RemoveAttribs: Remove a feature?!" ); + pNode->GetCharAttribs().GetAttribs().Remove(nAttr); + GetItemPool().Remove( *pAttr->GetItem() ); + delete pAttr; + nAttr--; + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + + if ( bChanged ) + { + // char attributes need to be sorted by start again + pNode->GetCharAttribs().ResortAttribs(); + + SetModified( TRUE ); + } + + return bChanged; +} + +void EditDoc::InsertAttrib( const SfxPoolItem& rPoolItem, ContentNode* pNode, USHORT nStart, USHORT nEnd ) +{ + // Diese Methode prueft nicht mehr, ob ein entspr. Attribut + // schon an der Stelle existiert! + + EditCharAttrib* pAttrib = MakeCharAttrib( GetItemPool(), rPoolItem, nStart, nEnd ); + DBG_ASSERT( pAttrib, "MakeCharAttrib fehlgeschlagen!" ); + pNode->GetCharAttribs().InsertAttrib( pAttrib ); + + SetModified( TRUE ); +} + +void EditDoc::InsertAttrib( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ) +{ + if ( nStart != nEnd ) + { + InsertAttribInSelection( pNode, nStart, nEnd, rPoolItem ); + } + else + { + // Pruefen, ob schon ein neues Attribut mit der WhichId an der Stelle: + EditCharAttrib* pAttr = pNode->GetCharAttribs().FindEmptyAttrib( rPoolItem.Which(), nStart ); + if ( pAttr ) + { + // Attribut entfernen.... + pNode->GetCharAttribs().GetAttribs().Remove( + pNode->GetCharAttribs().GetAttribs().GetPos( pAttr ) ); + } + + // pruefen, ob ein 'gleiches' Attribut an der Stelle liegt. + pAttr = pNode->GetCharAttribs().FindAttrib( rPoolItem.Which(), nStart ); + if ( pAttr ) + { + if ( pAttr->IsInside( nStart ) ) // splitten + { + // ??????????????????????????????? + // eigentlich noch pruefen, ob wirklich splittet, oder return ! + // ??????????????????????????????? + USHORT nOldEnd = pAttr->GetEnd(); + pAttr->GetEnd() = nStart; + pAttr = MakeCharAttrib( GetItemPool(), *(pAttr->GetItem()), nStart, nOldEnd ); + pNode->GetCharAttribs().InsertAttrib( pAttr ); + } + else if ( pAttr->GetEnd() == nStart ) + { + DBG_ASSERT( !pAttr->IsEmpty(), "Doch noch ein leeres Attribut?" ); + // pruefen, ob genau das gleiche Attribut + if ( *(pAttr->GetItem()) == rPoolItem ) + return; + } + } + InsertAttrib( rPoolItem, pNode, nStart, nStart ); + } + + SetModified( TRUE ); +} + +void EditDoc::FindAttribs( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, SfxItemSet& rCurSet ) +{ + DBG_ASSERT( pNode, "Wo soll ich suchen ?" ); + DBG_ASSERT( nStartPos <= nEndPos, "Ungueltiger Bereich!" ); + + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + // keine Selection... + if ( nStartPos == nEndPos ) + { + while ( pAttr && ( pAttr->GetStart() <= nEndPos) ) + { + const SfxPoolItem* pItem = 0; + // Attribut liegt dadrueber... + if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() > nStartPos ) ) + pItem = pAttr->GetItem(); + // Attribut endet hier, ist nicht leer + else if ( ( pAttr->GetStart() < nStartPos ) && ( pAttr->GetEnd() == nStartPos ) ) + { + if ( !pNode->GetCharAttribs().FindEmptyAttrib( pAttr->GetItem()->Which(), nStartPos ) ) + pItem = pAttr->GetItem(); + } + // Attribut endet hier, ist leer + else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() == nStartPos ) ) + { + pItem = pAttr->GetItem(); + } + // Attribut beginnt hier + else if ( ( pAttr->GetStart() == nStartPos ) && ( pAttr->GetEnd() > nStartPos ) ) + { + if ( nStartPos == 0 ) // Sonderfall + pItem = pAttr->GetItem(); + } + + if ( pItem ) + { + USHORT nWhich = pItem->Which(); + if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + rCurSet.Put( *pItem ); + } + else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = rCurSet.Get( nWhich ); + if ( rItem != *pItem ) + { + rCurSet.InvalidateItem( nWhich ); + } + } + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + } + else // Selektion + { + while ( pAttr && ( pAttr->GetStart() < nEndPos) ) + { + const SfxPoolItem* pItem = 0; + // Attribut liegt dadrueber... + if ( ( pAttr->GetStart() <= nStartPos ) && ( pAttr->GetEnd() >= nEndPos ) ) + pItem = pAttr->GetItem(); + // Attribut startet mitten drin... + else if ( pAttr->GetStart() >= nStartPos ) + { + // !!! pItem = pAttr->GetItem(); + // einfach nur pItem reicht nicht, da ich z.B. bei Shadow + // niemals ein ungleiches Item finden wuerde, da ein solche + // seine Anwesenheit durch Abwesenheit repraesentiert! + // if ( ... ) + // Es muesste geprueft werden, on genau das gleiche Attribut + // an der Bruchstelle aufsetzt, was recht aufwendig ist. + // Da ich beim Einfuegen von Attributen aber etwas optimiere + // tritt der Fall nicht so schnell auf... + // Also aus Geschwindigkeitsgruenden: + rCurSet.InvalidateItem( pAttr->GetItem()->Which() ); + + } + // Attribut endet mitten drin... + else if ( pAttr->GetEnd() > nStartPos ) + { + // pItem = pAttr->GetItem(); + // s.o. + /*-----------------31.05.95 16:01------------------- + Ist falsch, wenn das gleiche Attribut sofort wieder + eingestellt wird! + => Sollte am besten nicht vorkommen, also gleich beim + Setzen von Attributen richtig machen! + --------------------------------------------------*/ + rCurSet.InvalidateItem( pAttr->GetItem()->Which() ); + } + + if ( pItem ) + { + USHORT nWhich = pItem->Which(); + if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + rCurSet.Put( *pItem ); + } + else if ( rCurSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = rCurSet.Get( nWhich ); + if ( rItem != *pItem ) + { + rCurSet.InvalidateItem( nWhich ); + } + } + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + } +} + + +// ------------------------------------------------------------------------- +// class EditCharAttribList +// ------------------------------------------------------------------------- + +CharAttribList::CharAttribList() +{ + DBG_CTOR( EE_CharAttribList, 0 ); + bHasEmptyAttribs = FALSE; +} + +CharAttribList::~CharAttribList() +{ + DBG_DTOR( EE_CharAttribList, 0 ); + + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr ) + { + delete pAttr; + ++nAttr; + pAttr = GetAttrib( aAttribs, nAttr ); + } + Clear(); +} + +void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib ) +{ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// optimieren: binaere Suche ? ! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + // MT: 26.11.98 + // Vielleicht aber auch einfach nur rueckwaerts iterieren: + // Der haeufigste und kritischste Fall: Attribute kommen bereits + // sortiert an (InsertBinTextObject!) + // Hier waere auch binaere Suche nicht optimal. + // => Wuerde einiges bringen! + + const USHORT nCount = Count(); + const USHORT nStart = pAttrib->GetStart(); // vielleicht besser fuer Comp.Opt. + + if ( pAttrib->IsEmpty() ) + bHasEmptyAttribs = TRUE; + + BOOL bInserted = FALSE; + for ( USHORT x = 0; x < nCount; x++ ) + { + EditCharAttribPtr pCurAttrib = aAttribs[x]; + if ( pCurAttrib->GetStart() > nStart ) + { + aAttribs.Insert( pAttrib, x ); + bInserted = TRUE; + break; + } + } + if ( !bInserted ) + aAttribs.Insert( pAttrib, nCount ); +} + +void CharAttribList::ResortAttribs() +{ + if ( Count() ) + { +#if defined __SUNPRO_CC +#pragma disable_warn +#endif + qsort( (void*)aAttribs.GetData(), aAttribs.Count(), sizeof( EditCharAttrib* ), CompareStart ); +#if defined __SUNPRO_CC +#pragma enable_warn +#endif + } +} + +void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool ) +{ + for ( USHORT n = 0; n < aAttribs.Count(); n++ ) + { + EditCharAttrib* pAttr = aAttribs.GetObject( n ); + for ( USHORT nNext = n+1; nNext < aAttribs.Count(); nNext++ ) + { + EditCharAttrib* p = aAttribs.GetObject( nNext ); + if ( !pAttr->IsFeature() && ( p->GetStart() == pAttr->GetEnd() ) && ( p->Which() == pAttr->Which() ) ) + { + if ( *p->GetItem() == *pAttr->GetItem() ) + { + pAttr->GetEnd() = p->GetEnd(); + aAttribs.Remove( nNext ); + rItemPool.Remove( *p->GetItem() ); + delete p; + } + break; // only 1 attr with same which can start here. + } + else if ( p->GetStart() > pAttr->GetEnd() ) + { + break; + } + } + } +} + +EditCharAttrib* CharAttribList::FindAttrib( USHORT nWhich, USHORT nPos ) +{ + // Rueckwaerts, falls eins dort endet, das naechste startet. + // => Das startende gilt... + USHORT nAttr = aAttribs.Count()-1; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr ) + { + if ( ( pAttr->Which() == nWhich ) && pAttr->IsIn(nPos) ) + return pAttr; + pAttr = GetAttrib( aAttribs, --nAttr ); + } + return 0; +} + +EditCharAttrib* CharAttribList::FindNextAttrib( USHORT nWhich, USHORT nFromPos ) const +{ + DBG_ASSERT( nWhich, "FindNextAttrib: Which?" ); + const USHORT nAttribs = aAttribs.Count(); + for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[ nAttr ]; + if ( ( pAttr->GetStart() >= nFromPos ) && ( pAttr->Which() == nWhich ) ) + return pAttr; + } + return 0; +} + +BOOL CharAttribList::HasAttrib( USHORT nWhich ) const +{ + for ( USHORT nAttr = aAttribs.Count(); nAttr; ) + { + const EditCharAttrib* pAttr = aAttribs[--nAttr]; + if ( pAttr->Which() == nWhich ) + return TRUE; + } + return FALSE; +} + +BOOL CharAttribList::HasAttrib( USHORT nStartPos, USHORT nEndPos ) const +{ + BOOL bAttr = FALSE; + for ( USHORT nAttr = aAttribs.Count(); nAttr && !bAttr; ) + { + const EditCharAttrib* pAttr = aAttribs[--nAttr]; + if ( ( pAttr->GetStart() < nEndPos ) && ( pAttr->GetEnd() > nStartPos ) ) + return bAttr = TRUE; + } + return bAttr; +} + + +BOOL CharAttribList::HasBoundingAttrib( USHORT nBound ) +{ + // Rueckwaerts, falls eins dort endet, das naechste startet. + // => Das startende gilt... + USHORT nAttr = aAttribs.Count()-1; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr && ( pAttr->GetEnd() >= nBound ) ) + { + if ( ( pAttr->GetStart() == nBound ) || ( pAttr->GetEnd() == nBound ) ) + return TRUE; + pAttr = GetAttrib( aAttribs, --nAttr ); + } + return FALSE; +} + +EditCharAttrib* CharAttribList::FindEmptyAttrib( USHORT nWhich, USHORT nPos ) +{ + if ( !bHasEmptyAttribs ) + return 0; + USHORT nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( aAttribs, nAttr ); + while ( pAttr && ( pAttr->GetStart() <= nPos ) ) + { + if ( ( pAttr->GetStart() == nPos ) && ( pAttr->GetEnd() == nPos ) && ( pAttr->Which() == nWhich ) ) + return pAttr; + nAttr++; + pAttr = GetAttrib( aAttribs, nAttr ); + } + return 0; +} + +EditCharAttrib* CharAttribList::FindFeature( USHORT nPos ) const +{ + + USHORT nAttr = 0; + EditCharAttrib* pNextAttrib = GetAttrib( aAttribs, nAttr ); + + // erstmal zur gewuenschten Position... + while ( pNextAttrib && ( pNextAttrib->GetStart() < nPos ) ) + { + nAttr++; + pNextAttrib = GetAttrib( aAttribs, nAttr ); + } + + // jetzt das Feature suchen... + while ( pNextAttrib && !pNextAttrib->IsFeature() ) + { + nAttr++; + pNextAttrib = GetAttrib( aAttribs, nAttr ); + } + + return pNextAttrib; +} + + +void CharAttribList::DeleteEmptyAttribs( SfxItemPool& rItemPool ) +{ + for ( USHORT nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[nAttr]; + if ( pAttr->IsEmpty() ) + { + rItemPool.Remove( *pAttr->GetItem() ); + aAttribs.Remove( nAttr ); + delete pAttr; + nAttr--; + } + } + bHasEmptyAttribs = FALSE; +} + +BOOL CharAttribList::DbgCheckAttribs() +{ +#ifdef DBG_UTIL + BOOL bOK = TRUE; + for ( USHORT nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = aAttribs[nAttr]; + if ( pAttr->GetStart() > pAttr->GetEnd() ) + { + bOK = FALSE; + DBG_ERROR( "Attr verdreht" ); + } + else if ( pAttr->IsFeature() && ( pAttr->GetLen() != 1 ) ) + { + bOK = FALSE; + DBG_ERROR( "Feature, Len != 1" ); + } + } + return bOK; +#else + return TRUE; +#endif +} + + + +SvxFontTable::SvxFontTable() +{ +} + +SvxFontTable::~SvxFontTable() +{ + SvxFontItem* pItem = First(); + while( pItem ) + { + delete pItem; + pItem = Next(); + } +} + +ULONG SvxFontTable::GetId( const SvxFontItem& rFontItem ) +{ + SvxFontItem* pItem = First(); + while ( pItem ) + { + if ( *pItem == rFontItem ) + return GetCurKey(); + pItem = Next(); + } + DBG_WARNING( "Font nicht gefunden: GetId()" ); + return 0; +} + +SvxColorList::SvxColorList() +{ +} + +SvxColorList::~SvxColorList() +{ + SvxColorItem* pItem = First(); + while( pItem ) + { + delete pItem; + pItem = Next(); + } +} + +ULONG SvxColorList::GetId( const SvxColorItem& rColorItem ) +{ + SvxColorItem* pItem = First(); + while ( pItem ) + { + if ( *pItem == rColorItem ) + return GetCurPos(); + pItem = Next(); + } + DBG_WARNING( "Color nicht gefunden: GetId()" ); + return 0; +} + +EditEngineItemPool::EditEngineItemPool( BOOL bPersistenRefCounts ) + : SfxItemPool( String( "EditEngineItemPool", RTL_TEXTENCODING_ASCII_US ), EE_ITEMS_START, EE_ITEMS_END, + aItemInfos, 0, bPersistenRefCounts ) +{ + SetVersionMap( 1, 3999, 4015, aV1Map ); + SetVersionMap( 2, 3999, 4019, aV2Map ); + SetVersionMap( 3, 3997, 4020, aV3Map ); + SetVersionMap( 4, 3994, 4022, aV4Map ); + SetVersionMap( 5, 3994, 4037, aV5Map ); + + DBG_ASSERT( EE_DLL(), "EditDLL?!" ); + SfxPoolItem** ppDefItems = EE_DLL()->GetGlobalData()->GetDefItems(); + SetDefaults( ppDefItems ); +} + +EditEngineItemPool::~EditEngineItemPool() +{ +} + +SvStream& EditEngineItemPool::Store( SvStream& rStream ) const +{ + // Bei einem 3.1-Export muess ein Hack eingebaut werden, da BUG im + // SfxItemSet::Load, aber nicht nachtraeglich in 3.1 fixbar. + + // Der eingestellte Range muss nach Store erhalten bleiben, weil dann + // erst die ItemSets gespeichert werden... + + long nVersion = rStream.GetVersion(); + BOOL b31Format = ( nVersion && ( nVersion <= SOFFICE_FILEFORMAT_31 ) ) + ? TRUE : FALSE; + + EditEngineItemPool* pThis = (EditEngineItemPool*)this; + if ( b31Format ) + pThis->SetStoringRange( 3997, 4022 ); + else + pThis->SetStoringRange( EE_ITEMS_START, EE_ITEMS_END ); + + return SfxItemPool::Store( rStream ); +} diff --git a/editeng/source/editeng/editdoc.hxx b/editeng/source/editeng/editdoc.hxx new file mode 100644 index 000000000000..d1eebda99baa --- /dev/null +++ b/editeng/source/editeng/editdoc.hxx @@ -0,0 +1,805 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editdoc.hxx,v $ + * $Revision: 1.29 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITDOC_HXX +#define _EDITDOC_HXX + +#ifndef _COM_SUN_STAR_I18N_XEXTENDEDINPUTSEQUENCECHECKER_HDL_ +#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp> +#endif + +#include <editattr.hxx> +#include <edtspell.hxx> +#include <editeng/svxfont.hxx> +#include <svl/itemset.hxx> +#include <svl/style.hxx> +#include <svl/itempool.hxx> +#include <tools/table.hxx> + +class ImpEditEngine; +class SvxTabStop; +class SvtCTLOptions; + +DBG_NAMEEX( EE_TextPortion ) + +#define CHARPOSGROW 16 +#define DEFTAB 720 + +void CreateFont( SvxFont& rFont, const SfxItemSet& rSet, bool bSearchInParent = true, short nScriptType = 0 ); +USHORT GetScriptItemId( USHORT nItemId, short nScriptType ); +BOOL IsScriptItemValid( USHORT nItemId, short nScriptType ); + +EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, USHORT nS, USHORT nE ); + +class ContentNode; +class EditDoc; + +struct EPaM +{ + USHORT nPara; + USHORT nIndex; + + EPaM() { nPara = 0; nIndex = 0; } + EPaM( USHORT nP, USHORT nI ) { nPara = nP; nIndex = nI; } + EPaM( const EPaM& r) { nPara = r.nPara; nIndex = r.nIndex; } + EPaM& operator = ( const EPaM& r ) { nPara = r.nPara; nIndex = r.nIndex; return *this; } + inline BOOL operator == ( const EPaM& r ) const; + inline BOOL operator < ( const EPaM& r ) const; +}; + +inline BOOL EPaM::operator < ( const EPaM& r ) const +{ + return ( ( nPara < r.nPara ) || + ( ( nPara == r.nPara ) && nIndex < r.nIndex ) ) ? TRUE : FALSE; +} + +inline BOOL EPaM::operator == ( const EPaM& r ) const +{ + return ( ( nPara == r.nPara ) && ( nIndex == r.nIndex ) ) ? TRUE : FALSE; +} + +struct ScriptTypePosInfo +{ + short nScriptType; + USHORT nStartPos; + USHORT nEndPos; + + ScriptTypePosInfo( short _Type, USHORT _Start, USHORT _End ) + { + nScriptType = _Type; + nStartPos = _Start; + nEndPos = _End; + } +}; + +SV_DECL_VARARR( ScriptTypePosInfos, ScriptTypePosInfo, 0, 4 ) + +struct WritingDirectionInfo +{ + BYTE nType; + USHORT nStartPos; + USHORT nEndPos; + + WritingDirectionInfo( BYTE _Type, USHORT _Start, USHORT _End ) + { + nType = _Type; + nStartPos = _Start; + nEndPos = _End; + } +}; + +SV_DECL_VARARR( WritingDirectionInfos, WritingDirectionInfo, 0, 4 ) + +typedef EditCharAttrib* EditCharAttribPtr; +SV_DECL_PTRARR( CharAttribArray, EditCharAttribPtr, 0, 4 ) + +class ContentAttribsInfo +{ +private: + SfxItemSet aPrevParaAttribs; + CharAttribArray aPrevCharAttribs; + +public: + ContentAttribsInfo( const SfxItemSet& rParaAttribs ); + + const SfxItemSet& GetPrevParaAttribs() const { return aPrevParaAttribs; } + const CharAttribArray& GetPrevCharAttribs() const { return aPrevCharAttribs; } + + CharAttribArray& GetPrevCharAttribs() { return aPrevCharAttribs; } +}; + +typedef ContentAttribsInfo* ContentAttribsInfoPtr; +SV_DECL_PTRARR( ContentInfoArray, ContentAttribsInfoPtr, 1, 1 ) + +// ---------------------------------------------------------------------- +// class SvxFontTable +// ---------------------------------------------------------------------- +DECLARE_TABLE( DummyFontTable, SvxFontItem* ) +class SvxFontTable : public DummyFontTable +{ +public: + SvxFontTable(); + ~SvxFontTable(); + + ULONG GetId( const SvxFontItem& rFont ); +}; + +// ---------------------------------------------------------------------- +// class SvxColorList +// ---------------------------------------------------------------------- +typedef ContentNode* ContentNodePtr; +DECLARE_LIST( DummyColorList, SvxColorItem* ) +class SvxColorList : public DummyColorList +{ +public: + SvxColorList(); + ~SvxColorList(); + + ULONG GetId( const SvxColorItem& rColor ); +}; + +// ---------------------------------------------------------------------- +// class ItemList +// ---------------------------------------------------------------------- +typedef const SfxPoolItem* ConstPoolItemPtr; +DECLARE_LIST( DummyItemList, ConstPoolItemPtr ) +class ItemList : public DummyItemList +{ +public: + const SfxPoolItem* FindAttrib( USHORT nWhich ); +}; + +// ------------------------------------------------------------------------- +// class ContentAttribs +// ------------------------------------------------------------------------- +class ContentAttribs +{ +private: + SfxStyleSheet* pStyle; + SfxItemSet aAttribSet; + +public: + ContentAttribs( SfxItemPool& rItemPool ); + ContentAttribs( const ContentAttribs& ); + ~ContentAttribs(); // erst bei umfangreicheren Tabs + + SvxTabStop FindTabStop( long nCurPos, USHORT nDefTab ); + SfxItemSet& GetItems() { return aAttribSet; } + SfxStyleSheet* GetStyleSheet() const { return pStyle; } + void SetStyleSheet( SfxStyleSheet* pS ); + + const SfxPoolItem& GetItem( USHORT nWhich ); + BOOL HasItem( USHORT nWhich ); +}; + +// ------------------------------------------------------------------------- +// class CharAttribList +// ------------------------------------------------------------------------- +class CharAttribList +{ +private: + CharAttribArray aAttribs; + SvxFont aDefFont; // schneller, als jedesmal vom Pool! + BOOL bHasEmptyAttribs; + + CharAttribList( const CharAttribList& ) {;} + +public: + CharAttribList(); + ~CharAttribList(); + + void DeleteEmptyAttribs( SfxItemPool& rItemPool ); + void RemoveItemsFromPool( SfxItemPool* pItemPool ); + + EditCharAttrib* FindAttrib( USHORT nWhich, USHORT nPos ); + EditCharAttrib* FindNextAttrib( USHORT nWhich, USHORT nFromPos ) const; + EditCharAttrib* FindEmptyAttrib( USHORT nWhich, USHORT nPos ); + EditCharAttrib* FindFeature( USHORT nPos ) const; + + + void ResortAttribs(); + void OptimizeRanges( SfxItemPool& rItemPool ); + + USHORT Count() { return aAttribs.Count(); } + void Clear() { aAttribs.Remove( 0, aAttribs.Count()); } + void InsertAttrib( EditCharAttrib* pAttrib ); + + SvxFont& GetDefFont() { return aDefFont; } + + BOOL HasEmptyAttribs() const { return bHasEmptyAttribs; } + BOOL& HasEmptyAttribs() { return bHasEmptyAttribs; } + BOOL HasBoundingAttrib( USHORT nBound ); + BOOL HasAttrib( USHORT nWhich ) const; + BOOL HasAttrib( USHORT nStartPos, USHORT nEndPos ) const; + + CharAttribArray& GetAttribs() { return aAttribs; } + const CharAttribArray& GetAttribs() const { return aAttribs; } + + // Debug: + BOOL DbgCheckAttribs(); +}; + +// ------------------------------------------------------------------------- +// class ContentNode +// ------------------------------------------------------------------------- +class ContentNode : public XubString +{ +private: + ContentAttribs aContentAttribs; + CharAttribList aCharAttribList; + WrongList* pWrongList; + +public: + ContentNode( SfxItemPool& rItemPool ); + ContentNode( const XubString& rStr, const ContentAttribs& rContentAttribs ); + ~ContentNode(); + + ContentAttribs& GetContentAttribs() { return aContentAttribs; } + CharAttribList& GetCharAttribs() { return aCharAttribList; } + + void ExpandAttribs( USHORT nIndex, USHORT nNewChars, SfxItemPool& rItemPool ); + void CollapsAttribs( USHORT nIndex, USHORT nDelChars, SfxItemPool& rItemPool ); + void AppendAttribs( ContentNode* pNextNode ); + void CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& rPool, BOOL bKeepEndingAttribs ); + + void SetStyleSheet( SfxStyleSheet* pS, BOOL bRecalcFont = TRUE ); + void SetStyleSheet( SfxStyleSheet* pS, const SvxFont& rFontFromStyle ); + SfxStyleSheet* GetStyleSheet() { return aContentAttribs.GetStyleSheet(); } + + void CreateDefFont(); + + WrongList* GetWrongList() { return pWrongList; } + void SetWrongList( WrongList* p ); + + void CreateWrongList(); + void DestroyWrongList(); + + BOOL IsFeature( USHORT nPos ) const { return ( GetChar( nPos ) == CH_FEATURE ); } +}; + +typedef ContentNode* ContentNodePtr; +SV_DECL_PTRARR( DummyContentList, ContentNodePtr, 0, 4 ) + +class ContentList : public DummyContentList +{ + USHORT nLastCache; +public: + ContentList() : DummyContentList( 0, 4 ), nLastCache(0) {} + USHORT GetPos( const ContentNodePtr &rPtr ) const; +}; + +// ------------------------------------------------------------------------- +// class EditPaM +// ------------------------------------------------------------------------- +class EditPaM +{ +private: + ContentNode* pNode; + USHORT nIndex; + +public: + EditPaM() { pNode = NULL; nIndex = 0; } + EditPaM( ContentNode* p, USHORT n ) { pNode = p; nIndex = n; } + + ContentNode* GetNode() const { return pNode; } + void SetNode( ContentNode* p) { pNode = p; } + + USHORT GetIndex() const { return nIndex; } + USHORT& GetIndex() { return nIndex; } + void SetIndex( USHORT n ) { nIndex = n; } + + BOOL IsParaStart() const { return nIndex == 0; } + BOOL IsParaEnd() const { return nIndex == pNode->Len(); } + + BOOL DbgIsBuggy( EditDoc& rDoc ); + + EditPaM& operator = ( const EditPaM& rPaM ); + friend BOOL operator == ( const EditPaM& r1, const EditPaM& r2 ); + friend BOOL operator != ( const EditPaM& r1, const EditPaM& r2 ); +}; + +#define PORTIONKIND_TEXT 0 +#define PORTIONKIND_TAB 1 +#define PORTIONKIND_LINEBREAK 2 +#define PORTIONKIND_FIELD 3 +#define PORTIONKIND_HYPHENATOR 4 +// #define PORTIONKIND_EXTRASPACE 5 + +#define DELMODE_SIMPLE 0 +#define DELMODE_RESTOFWORD 1 +#define DELMODE_RESTOFCONTENT 2 + +#define CHAR_NORMAL 0x00 +#define CHAR_KANA 0x01 +#define CHAR_PUNCTUATIONLEFT 0x02 +#define CHAR_PUNCTUATIONRIGHT 0x04 + +// ------------------------------------------------------------------------- +// struct ExtraPortionInfos +// ------------------------------------------------------------------------- +struct ExtraPortionInfo +{ + long nOrgWidth; + long nWidthFullCompression; + + long nPortionOffsetX; + + USHORT nMaxCompression100thPercent; + + BYTE nAsianCompressionTypes; + BOOL bFirstCharIsRightPunktuation; + BOOL bCompressed; + + sal_Int32* pOrgDXArray; + + + ExtraPortionInfo(); + ~ExtraPortionInfo(); + + void SaveOrgDXArray( const sal_Int32* pDXArray, USHORT nLen ); + void DestroyOrgDXArray(); +}; + + +// ------------------------------------------------------------------------- +// class TextPortion +// ------------------------------------------------------------------------- +class TextPortion +{ +private: + ExtraPortionInfo* pExtraInfos; + USHORT nLen; + Size aOutSz; + BYTE nKind; + BYTE nRightToLeft; + sal_Unicode nExtraValue; + + + TextPortion() { DBG_CTOR( EE_TextPortion, 0 ); + pExtraInfos = NULL; nLen = 0; nKind = PORTIONKIND_TEXT; nExtraValue = 0; nRightToLeft = FALSE;} + +public: + TextPortion( USHORT nL ) : aOutSz( -1, -1 ) + { DBG_CTOR( EE_TextPortion, 0 ); + pExtraInfos = NULL; nLen = nL; nKind = PORTIONKIND_TEXT; nExtraValue = 0; nRightToLeft = FALSE;} + TextPortion( const TextPortion& r ) : aOutSz( r.aOutSz ) + { DBG_CTOR( EE_TextPortion, 0 ); + pExtraInfos = NULL; nLen = r.nLen; nKind = r.nKind; nExtraValue = r.nExtraValue; nRightToLeft = r.nRightToLeft; } + + ~TextPortion() { DBG_DTOR( EE_TextPortion, 0 ); delete pExtraInfos; } + + USHORT GetLen() const { return nLen; } + USHORT& GetLen() { return nLen; } + void SetLen( USHORT nL ) { nLen = nL; } + + Size& GetSize() { return aOutSz; } + Size GetSize() const { return aOutSz; } + + BYTE& GetKind() { return nKind; } + BYTE GetKind() const { return nKind; } + + void SetRightToLeft( BYTE b ) { nRightToLeft = b; } + BYTE GetRightToLeft() const { return nRightToLeft; } + BOOL IsRightToLeft() const { return (nRightToLeft&1); } + + sal_Unicode GetExtraValue() const { return nExtraValue; } + void SetExtraValue( sal_Unicode n ) { nExtraValue = n; } + + BOOL HasValidSize() const { return aOutSz.Width() != (-1); } + + ExtraPortionInfo* GetExtraInfos() const { return pExtraInfos; } + void SetExtraInfos( ExtraPortionInfo* p ) { delete pExtraInfos; pExtraInfos = p; } +}; + +// ------------------------------------------------------------------------- +// class TextPortionList +// ------------------------------------------------------------------------- +typedef TextPortion* TextPortionPtr; +SV_DECL_PTRARR( TextPortionArray, TextPortionPtr, 0, 8 ) + +class TextPortionList : public TextPortionArray +{ +public: + TextPortionList(); + ~TextPortionList(); + + void Reset(); + USHORT FindPortion( USHORT nCharPos, USHORT& rPortionStart, BOOL bPreferStartingPortion = FALSE ); + USHORT GetStartPos( USHORT nPortion ); + void DeleteFromPortion( USHORT nDelFrom ); +}; + +class ParaPortion; + +SV_DECL_VARARR( CharPosArray, sal_Int32, 0, CHARPOSGROW ) + +// ------------------------------------------------------------------------ +// class EditLine +// ------------------------------------------------------------------------- +class EditLine +{ +private: + CharPosArray aPositions; + long nTxtWidth; + USHORT nStartPosX; + USHORT nStart; // koennte durch nStartPortion ersetzt werden + USHORT nEnd; // koennte durch nEndPortion ersetzt werden + USHORT nStartPortion; + USHORT nEndPortion; + USHORT nHeight; // Gesamthoehe der Zeile + USHORT nTxtHeight; // Reine Texthoehe + USHORT nCrsrHeight; // Bei Konturfluss hohe Zeilen => Cursor zu groá. + USHORT nMaxAscent; + BOOL bHangingPunctuation; + BOOL bInvalid; // fuer geschickte Formatierung + +public: + EditLine(); + EditLine( const EditLine& ); + ~EditLine(); + + BOOL IsIn( USHORT nIndex ) const + { return ( (nIndex >= nStart ) && ( nIndex < nEnd ) ); } + + BOOL IsIn( USHORT nIndex, BOOL bInclEnd ) const + { return ( ( nIndex >= nStart ) && ( bInclEnd ? ( nIndex <= nEnd ) : ( nIndex < nEnd ) ) ); } + + void SetStart( USHORT n ) { nStart = n; } + USHORT GetStart() const { return nStart; } + USHORT& GetStart() { return nStart; } + + void SetEnd( USHORT n ) { nEnd = n; } + USHORT GetEnd() const { return nEnd; } + USHORT& GetEnd() { return nEnd; } + + void SetStartPortion( USHORT n ) { nStartPortion = n; } + USHORT GetStartPortion() const { return nStartPortion; } + USHORT& GetStartPortion() { return nStartPortion; } + + void SetEndPortion( USHORT n ) { nEndPortion = n; } + USHORT GetEndPortion() const { return nEndPortion; } + USHORT& GetEndPortion() { return nEndPortion; } + + void SetHeight( USHORT nH, USHORT nTxtH = 0, USHORT nCrsrH = 0 ) + { nHeight = nH; + nTxtHeight = ( nTxtH ? nTxtH : nH ); + nCrsrHeight = ( nCrsrH ? nCrsrH : nTxtHeight ); + } + USHORT GetHeight() const { return nHeight; } + USHORT GetTxtHeight() const { return nTxtHeight; } + USHORT GetCrsrHeight() const { return nCrsrHeight; } + + void SetTextWidth( long n ) { nTxtWidth = n; } + long GetTextWidth() const { return nTxtWidth; } + + void SetMaxAscent( USHORT n ) { nMaxAscent = n; } + USHORT GetMaxAscent() const { return nMaxAscent; } + + void SetHangingPunctuation( BOOL b ) { bHangingPunctuation = b; } + BOOL IsHangingPunctuation() const { return bHangingPunctuation; } + + USHORT GetLen() const { return nEnd - nStart; } + + USHORT GetStartPosX() const { return nStartPosX; } + void SetStartPosX( USHORT start ) { nStartPosX = start; } + + Size CalcTextSize( ParaPortion& rParaPortion ); + + BOOL IsInvalid() const { return bInvalid; } + BOOL IsValid() const { return !bInvalid; } + void SetInvalid() { bInvalid = TRUE; } + void SetValid() { bInvalid = FALSE; } + + BOOL IsEmpty() const { return (nEnd > nStart) ? FALSE : TRUE; } + + CharPosArray& GetCharPosArray() { return aPositions; } + + EditLine* Clone() const; + + EditLine& operator = ( const EditLine& rLine ); + friend BOOL operator == ( const EditLine& r1, const EditLine& r2 ); + friend BOOL operator != ( const EditLine& r1, const EditLine& r2 ); +}; + + +// ------------------------------------------------------------------------- +// class LineList +// ------------------------------------------------------------------------- +typedef EditLine* EditLinePtr; +SV_DECL_PTRARR( LineArray, EditLinePtr, 0, 4 ) + +class EditLineList : public LineArray +{ +public: + EditLineList(); + ~EditLineList(); + + void Reset(); + void DeleteFromLine( USHORT nDelFrom ); + USHORT FindLine( USHORT nChar, BOOL bInclEnd ); +}; + +// ------------------------------------------------------------------------- +// class ParaPortion +// ------------------------------------------------------------------------- +class ParaPortion +{ + friend class ImpEditEngine; // zum Einstellen der Hoehe +private: + EditLineList aLineList; + TextPortionList aTextPortionList; + ContentNode* pNode; + long nHeight; + + ScriptTypePosInfos aScriptInfos; + WritingDirectionInfos aWritingDirectionInfos; + + USHORT nInvalidPosStart; + USHORT nFirstLineOffset; // Fuer Writer-LineSpacing-Interpretation + USHORT nBulletX; + short nInvalidDiff; + + BOOL bInvalid : 1; + BOOL bSimple : 1; // nur lineares Tippen + BOOL bVisible : 1; // MT 05/00: Gehoert an den Node!!! + BOOL bForceRepaint : 1; + + ParaPortion( const ParaPortion& ); + +public: + ParaPortion( ContentNode* pNode ); + ~ParaPortion(); + + USHORT GetLineNumber( USHORT nIndex ); + + EditLineList& GetLines() { return aLineList; } + + BOOL IsInvalid() const { return bInvalid; } + BOOL IsSimpleInvalid() const { return bSimple; } + void SetValid() { bInvalid = FALSE; bSimple = TRUE;} + + BOOL MustRepaint() const { return bForceRepaint; } + void SetMustRepaint( BOOL bRP ) { bForceRepaint = bRP; } + + USHORT GetBulletX() const { return nBulletX; } + void SetBulletX( USHORT n ) { nBulletX = n; } + + void MarkInvalid( USHORT nStart, short nDiff); + void MarkSelectionInvalid( USHORT nStart, USHORT nEnd ); + + void SetVisible( BOOL bVisible ); + BOOL IsVisible() { return bVisible; } + + long GetHeight() const { return ( bVisible ? nHeight : 0 ); } + USHORT GetFirstLineOffset() const { return ( bVisible ? nFirstLineOffset : 0 ); } + void ResetHeight() { nHeight = 0; nFirstLineOffset = 0; } + + ContentNode* GetNode() const { return pNode; } + TextPortionList& GetTextPortions() { return aTextPortionList; } + + USHORT GetInvalidPosStart() const { return nInvalidPosStart; } + short GetInvalidDiff() const { return nInvalidDiff; } + + void CorrectValuesBehindLastFormattedLine( USHORT nLastFormattedLine ); + + BOOL DbgCheckTextPortions(); +}; + +typedef ParaPortion* ParaPortionPtr; +SV_DECL_PTRARR( DummyParaPortionList, ParaPortionPtr, 0, 4 ) + +// ------------------------------------------------------------------------- +// class ParaPortionList +// ------------------------------------------------------------------------- +class ParaPortionList : public DummyParaPortionList +{ + USHORT nLastCache; +public: + ParaPortionList(); + ~ParaPortionList(); + + void Reset(); + long GetYOffset( ParaPortion* pPPortion ); + USHORT FindParagraph( long nYOffset ); + + inline ParaPortion* SaveGetObject( USHORT nPos ) const + { return ( nPos < Count() ) ? GetObject( nPos ) : 0; } + + USHORT GetPos( const ParaPortionPtr &rPtr ) const; + + // temporaer: + void DbgCheck( EditDoc& rDoc ); +}; + +// ------------------------------------------------------------------------- +// class EditSelection +// ------------------------------------------------------------------------- +class EditSelection +{ +private: + EditPaM aStartPaM; + EditPaM aEndPaM; + +public: + EditSelection(); // kein CCTOR und DTOR, geht autom. richtig! + EditSelection( const EditPaM& rStartAndAnd ); + EditSelection( const EditPaM& rStart, const EditPaM& rEnd ); + + EditPaM& Min() { return aStartPaM; } + EditPaM& Max() { return aEndPaM; } + + const EditPaM& Min() const { return aStartPaM; } + const EditPaM& Max() const { return aEndPaM; } + + BOOL HasRange() const { return aStartPaM != aEndPaM; } + BOOL IsInvalid() const; + BOOL DbgIsBuggy( EditDoc& rDoc ); + + BOOL Adjust( const ContentList& rNodes ); + + EditSelection& operator = ( const EditPaM& r ); + BOOL operator == ( const EditSelection& r ) const + { return ( ( aStartPaM == r.aStartPaM ) && ( aEndPaM == r.aEndPaM ) ) + ? TRUE : FALSE; } + BOOL operator != ( const EditSelection& r ) const { return !( r == *this ); } +}; + +// ------------------------------------------------------------------------- +// class DeletedNodeInfo +// ------------------------------------------------------------------------- +class DeletedNodeInfo +{ +private: + ULONG nInvalidAdressPtr; + USHORT nInvalidParagraph; + +public: + DeletedNodeInfo( ULONG nInvAdr, USHORT nPos ) + { nInvalidAdressPtr = nInvAdr; + nInvalidParagraph = nPos; } + + ULONG GetInvalidAdress() { return nInvalidAdressPtr; } + USHORT GetPosition() { return nInvalidParagraph; } +}; + +typedef DeletedNodeInfo* DeletedNodeInfoPtr; +SV_DECL_PTRARR( DeletedNodesList, DeletedNodeInfoPtr, 0, 4 ) + +// ------------------------------------------------------------------------- +// class EditDoc +// ------------------------------------------------------------------------- +class EditDoc : public ContentList +{ +private: + SfxItemPool* pItemPool; + Link aModifyHdl; + + SvxFont aDefFont; //schneller, als jedesmal vom Pool! + USHORT nDefTab; + BOOL bIsVertical; + BOOL bIsFixedCellHeight; + + BOOL bOwnerOfPool; + BOOL bModified; + +protected: + void ImplDestroyContents(); + +public: + EditDoc( SfxItemPool* pItemPool ); + ~EditDoc(); + + BOOL IsModified() const { return bModified; } + void SetModified( BOOL b ); + + void SetModifyHdl( const Link& rLink ) { aModifyHdl = rLink; } + Link GetModifyHdl() const { return aModifyHdl; } + + void CreateDefFont( BOOL bUseStyles ); + const SvxFont& GetDefFont() { return aDefFont; } + + void SetDefTab( USHORT nTab ) { nDefTab = nTab ? nTab : DEFTAB; } + USHORT GetDefTab() const { return nDefTab; } + + void SetVertical( BOOL bVertical ) { bIsVertical = bVertical; } + BOOL IsVertical() const { return bIsVertical; } + + void SetFixedCellHeight( BOOL bUseFixedCellHeight ) { bIsFixedCellHeight = bUseFixedCellHeight; } + BOOL IsFixedCellHeight() const { return bIsFixedCellHeight; } + + EditPaM Clear(); + EditPaM RemoveText(); + EditPaM RemoveChars( EditPaM aPaM, USHORT nChars ); + void InsertText( const EditPaM& rPaM, xub_Unicode c ); + EditPaM InsertText( EditPaM aPaM, const XubString& rStr ); + EditPaM InsertParaBreak( EditPaM aPaM, BOOL bKeepEndingAttribs ); + EditPaM InsertFeature( EditPaM aPaM, const SfxPoolItem& rItem ); + EditPaM ConnectParagraphs( ContentNode* pLeft, ContentNode* pRight ); + + String GetText( LineEnd eEnd ) const; + ULONG GetTextLen() const; + + XubString GetParaAsString( USHORT nNode ) const; + XubString GetParaAsString( ContentNode* pNode, USHORT nStartPos = 0, USHORT nEndPos = 0xFFFF, BOOL bResolveFields = TRUE ) const; + + inline EditPaM GetStartPaM() const; + inline EditPaM GetEndPaM() const; + + SfxItemPool& GetItemPool() { return *pItemPool; } + const SfxItemPool& GetItemPool() const { return *pItemPool; } + + void RemoveItemsFromPool( ContentNode* pNode ); + + void InsertAttrib( const SfxPoolItem& rItem, ContentNode* pNode, USHORT nStart, USHORT nEnd ); + void InsertAttrib( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ); + void InsertAttribInSelection( ContentNode* pNode, USHORT nStart, USHORT nEnd, const SfxPoolItem& rPoolItem ); + BOOL RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, USHORT nWhich = 0 ); + BOOL RemoveAttribs( ContentNode* pNode, USHORT nStart, USHORT nEnd, EditCharAttrib*& rpStarting, EditCharAttrib*& rpEnding, USHORT nWhich = 0 ); + void FindAttribs( ContentNode* pNode, USHORT nStartPos, USHORT nEndPos, SfxItemSet& rCurSet ); + + USHORT GetPos( ContentNode* pNode ) const { return ContentList::GetPos(pNode); } + ContentNode* SaveGetObject( USHORT nPos ) const { return ( nPos < Count() ) ? GetObject( nPos ) : 0; } + + static XubString GetSepStr( LineEnd eEnd ); +}; + +inline EditPaM EditDoc::GetStartPaM() const +{ + return EditPaM( GetObject( 0 ), 0 ); +} + +inline EditPaM EditDoc::GetEndPaM() const +{ + ContentNode* pLastNode = GetObject( Count()-1 ); + return EditPaM( pLastNode, pLastNode->Len() ); +} + +inline EditCharAttrib* GetAttrib( const CharAttribArray& rAttribs, USHORT nAttr ) +{ + return ( nAttr < rAttribs.Count() ) ? rAttribs[nAttr] : 0; +} + +BOOL CheckOrderedList( CharAttribArray& rAttribs, BOOL bStart ); + +// ------------------------------------------------------------------------- +// class EditEngineItemPool +// ------------------------------------------------------------------------- +class EditEngineItemPool : public SfxItemPool +{ +public: + EditEngineItemPool( BOOL bPersistenRefCounts ); +protected: + virtual ~EditEngineItemPool(); +public: + + virtual SvStream& Store( SvStream& rStream ) const; +}; + +#endif // _EDITDOC_HXX diff --git a/editeng/source/editeng/editdoc2.cxx b/editeng/source/editeng/editdoc2.cxx new file mode 100644 index 000000000000..9db4ef26b912 --- /dev/null +++ b/editeng/source/editeng/editdoc2.cxx @@ -0,0 +1,547 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editdoc2.cxx,v $ + * $Revision: 1.19 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <svl/smplhint.hxx> + +#include <tools/rtti.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> + +#include <editdoc.hxx> +#include <impedit.hxx> +#include <editdbg.hxx> + +#include <editeng/numitem.hxx> + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/charscaleitem.hxx> + +#include <vcl/svapp.hxx> // Fuer AppWindow... + +DBG_NAME( EE_ParaPortion ) + +SV_IMPL_VARARR( CharPosArray, sal_Int32 ); + +/* + +BOOL EditStyleSheet::HasStyleAsAnyParent( SfxStyleSheet& rStyle ) +{ + if ( GetParent() == rStyle.GetName() ) + return TRUE; + + if ( GetParent().Len() && ( GetParent() != GetName() ) ) + { + EditStyleSheet* pS = (EditStyleSheet*)GetPool().Find( GetParent(), rStyle.GetFamily() ); + if ( pS ) + return pS->HasStyleAsAnyParent( rStyle ); + } + return FALSE; +} + +*/ + +// ------------------------------------------------------------------------- +// class TextPortionList +// ------------------------------------------------------------------------- +TextPortionList::TextPortionList() +{ +} + +TextPortionList::~TextPortionList() +{ + Reset(); +} + +void TextPortionList::Reset() +{ + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + delete GetObject( nPortion ); + Remove( 0, Count() ); +} + +void TextPortionList::DeleteFromPortion( USHORT nDelFrom ) +{ + DBG_ASSERT( ( nDelFrom < Count() ) || ( (nDelFrom == 0) && (Count() == 0) ), "DeleteFromPortion: Out of range" ); + for ( USHORT nP = nDelFrom; nP < Count(); nP++ ) + delete GetObject( nP ); + Remove( nDelFrom, Count()-nDelFrom ); +} + +USHORT TextPortionList::FindPortion( USHORT nCharPos, USHORT& nPortionStart, BOOL bPreferStartingPortion ) +{ + // Bei nCharPos an Portion-Grenze wird die linke Portion gefunden + USHORT nTmpPos = 0; + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + { + TextPortion* pPortion = GetObject( nPortion ); + nTmpPos = nTmpPos + pPortion->GetLen(); + if ( nTmpPos >= nCharPos ) + { + // take this one if we don't prefer the starting portion, or if it's the last one + if ( ( nTmpPos != nCharPos ) || !bPreferStartingPortion || ( nPortion == Count() - 1 ) ) + { + nPortionStart = nTmpPos - pPortion->GetLen(); + return nPortion; + } + } + } + DBG_ERROR( "FindPortion: Nicht gefunden!" ); + return ( Count() - 1 ); +} + +USHORT TextPortionList::GetStartPos( USHORT nPortion ) +{ + USHORT nPos = 0; + for ( USHORT n = 0; n < nPortion; n++ ) + { + TextPortion* pPortion = GetObject( n ); + nPos = nPos + pPortion->GetLen(); + } + return nPos; +} + + +// ------------------------------------------------------------------------- +// class ExtraPortionInfo +// ------------------------------------------------------------------------- + +ExtraPortionInfo::ExtraPortionInfo() +{ + nOrgWidth = 0; + nWidthFullCompression = 0; + nMaxCompression100thPercent = 0; + nAsianCompressionTypes = 0; + nPortionOffsetX = 0; + bFirstCharIsRightPunktuation = FALSE; + bCompressed = FALSE; + pOrgDXArray = NULL; +} + +ExtraPortionInfo::~ExtraPortionInfo() +{ + delete[] pOrgDXArray; +} + +void ExtraPortionInfo::SaveOrgDXArray( const sal_Int32* pDXArray, USHORT nLen ) +{ + delete[] pOrgDXArray; + pOrgDXArray = new sal_Int32[nLen]; + memcpy( pOrgDXArray, pDXArray, nLen*sizeof(sal_Int32) ); +} + +void ExtraPortionInfo::DestroyOrgDXArray() +{ + delete[] pOrgDXArray; + pOrgDXArray = NULL; +} + + +// ------------------------------------------------------------------------- +// class ParaPortion +// ------------------------------------------------------------------------- +ParaPortion::ParaPortion( ContentNode* pN ) +{ + DBG_CTOR( EE_ParaPortion, 0 ); + + pNode = pN; + bInvalid = TRUE; + bVisible = TRUE; + bSimple = FALSE; + bForceRepaint = FALSE; + nInvalidPosStart = 0; + nInvalidDiff = 0; + nHeight = 0; + nFirstLineOffset = 0; + nBulletX = 0; +} + +ParaPortion::~ParaPortion() +{ + DBG_DTOR( EE_ParaPortion, 0 ); +} + +void ParaPortion::MarkInvalid( USHORT nStart, short nDiff ) +{ + if ( bInvalid == FALSE ) + { +// nInvalidPosEnd = nStart; // ??? => CreateLines + nInvalidPosStart = ( nDiff >= 0 ) ? nStart : ( nStart + nDiff ); + nInvalidDiff = nDiff; + } + else + { + // Einfaches hintereinander tippen + if ( ( nDiff > 0 ) && ( nInvalidDiff > 0 ) && + ( ( nInvalidPosStart+nInvalidDiff ) == nStart ) ) + { + nInvalidDiff = nInvalidDiff + nDiff; + } + // Einfaches hintereinander loeschen + else if ( ( nDiff < 0 ) && ( nInvalidDiff < 0 ) && ( nInvalidPosStart == nStart ) ) + { + nInvalidPosStart = nInvalidPosStart + nDiff; + nInvalidDiff = nInvalidDiff + nDiff; + } + else + { +// nInvalidPosEnd = pNode->Len(); + DBG_ASSERT( ( nDiff >= 0 ) || ( (nStart+nDiff) >= 0 ), "MarkInvalid: Diff out of Range" ); + nInvalidPosStart = Min( nInvalidPosStart, (USHORT) ( nDiff < 0 ? nStart+nDiff : nDiff ) ); + nInvalidDiff = 0; + bSimple = FALSE; + } + } + bInvalid = TRUE; + aScriptInfos.Remove( 0, aScriptInfos.Count() ); + aWritingDirectionInfos.Remove( 0, aWritingDirectionInfos.Count() ); +// aExtraCharInfos.Remove( 0, aExtraCharInfos.Count() ); +} + +void ParaPortion::MarkSelectionInvalid( USHORT nStart, USHORT /* nEnd */ ) +{ + if ( bInvalid == FALSE ) + { + nInvalidPosStart = nStart; +// nInvalidPosEnd = nEnd; + } + else + { + nInvalidPosStart = Min( nInvalidPosStart, nStart ); +// nInvalidPosEnd = pNode->Len(); + } + nInvalidDiff = 0; + bInvalid = TRUE; + bSimple = FALSE; + aScriptInfos.Remove( 0, aScriptInfos.Count() ); + aWritingDirectionInfos.Remove( 0, aWritingDirectionInfos.Count() ); +// aExtraCharInfos.Remove( 0, aExtraCharInfos.Count() ); +} + +USHORT ParaPortion::GetLineNumber( USHORT nIndex ) +{ + DBG_ASSERTWARNING( aLineList.Count(), "Leere ParaPortion in GetLine!" ); + DBG_ASSERT( bVisible, "Wozu GetLine() bei einem unsichtbaren Absatz?" ); + + for ( USHORT nLine = 0; nLine < aLineList.Count(); nLine++ ) + { + if ( aLineList[nLine]->IsIn( nIndex ) ) + return nLine; + } + + // Dann sollte es am Ende der letzten Zeile sein! + DBG_ASSERT( nIndex == aLineList[ aLineList.Count() - 1 ]->GetEnd(), "Index voll daneben!" ); + return (aLineList.Count()-1); +} + +void ParaPortion::SetVisible( BOOL bMakeVisible ) +{ + bVisible = bMakeVisible; +} + +void ParaPortion::CorrectValuesBehindLastFormattedLine( USHORT nLastFormattedLine ) +{ + USHORT nLines = aLineList.Count(); + DBG_ASSERT( nLines, "CorrectPortionNumbersFromLine: Leere Portion?" ); + if ( nLastFormattedLine < ( nLines - 1 ) ) + { + const EditLine* pLastFormatted = aLineList[ nLastFormattedLine ]; + const EditLine* pUnformatted = aLineList[ nLastFormattedLine+1 ]; + short nPortionDiff = pUnformatted->GetStartPortion() - pLastFormatted->GetEndPortion(); + short nTextDiff = pUnformatted->GetStart() - pLastFormatted->GetEnd(); + nTextDiff++; // LastFormatted->GetEnd() war incl. => 1 zuviel abgezogen! + + // Die erste unformatierte muss genau eine Portion hinter der letzten der + // formatierten beginnen: + // Wenn in der geaenderten Zeile eine Portion gesplittet wurde, + // kann nLastEnd > nNextStart sein! + int nPDiff = -( nPortionDiff-1 ); + int nTDiff = -( nTextDiff-1 ); + if ( nPDiff || nTDiff ) + { + for ( USHORT nL = nLastFormattedLine+1; nL < nLines; nL++ ) + { + EditLine* pLine = aLineList[ nL ]; + + pLine->GetStartPortion() = sal::static_int_cast< USHORT >( + pLine->GetStartPortion() + nPDiff); + pLine->GetEndPortion() = sal::static_int_cast< USHORT >( + pLine->GetEndPortion() + nPDiff); + + pLine->GetStart() = sal::static_int_cast< USHORT >( + pLine->GetStart() + nTDiff); + pLine->GetEnd() = sal::static_int_cast< USHORT >( + pLine->GetEnd() + nTDiff); + + pLine->SetValid(); + } + } + } + DBG_ASSERT( aLineList[ aLineList.Count()-1 ]->GetEnd() == pNode->Len(), "CorrectLines: Ende stimmt nicht!" ); +} + +// Shared reverse lookup acceleration pieces ... + +static USHORT FastGetPos( const VoidPtr *pPtrArray, USHORT nPtrArrayLen, + VoidPtr pPtr, USHORT &rLastPos ) +{ + // Through certain filter code-paths we do a lot of appends, which in + // turn call GetPos - creating some N^2 nightmares. If we have a + // non-trivially large list, do a few checks from the end first. + if( rLastPos > 16 ) + { + USHORT nEnd; + if (rLastPos > nPtrArrayLen - 2) + nEnd = nPtrArrayLen; + else + nEnd = rLastPos + 2; + + for( USHORT nIdx = rLastPos - 2; nIdx < nEnd; nIdx++ ) + { + if( pPtrArray[ nIdx ] == pPtr ) + { + rLastPos = nIdx; + return nIdx; + } + } + } + // The world's lamest linear search from svarray ... + for( USHORT nIdx = 0; nIdx < nPtrArrayLen; nIdx++ ) + if (pPtrArray[ nIdx ] == pPtr ) + return rLastPos = nIdx; + return USHRT_MAX; +} + +// ------------------------------------------------------------------------- +// class ParaPortionList +// ------------------------------------------------------------------------- +ParaPortionList::ParaPortionList() : nLastCache( 0 ) +{ +} + +ParaPortionList::~ParaPortionList() +{ + Reset(); +} + +USHORT ParaPortionList::GetPos( const ParaPortionPtr &rPtr ) const +{ + return FastGetPos( reinterpret_cast<const VoidPtr *>( GetData() ), + Count(), static_cast<VoidPtr>( rPtr ), + ((ParaPortionList *)this)->nLastCache ); +} + +USHORT ContentList::GetPos( const ContentNodePtr &rPtr ) const +{ + return FastGetPos( reinterpret_cast<const VoidPtr *>( GetData() ), + Count(), static_cast<VoidPtr>( rPtr ), + ((ContentList *)this)->nLastCache ); +} + +void ParaPortionList::Reset() +{ + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + delete GetObject( nPortion ); + Remove( 0, Count() ); +} + +long ParaPortionList::GetYOffset( ParaPortion* pPPortion ) +{ + long nHeight = 0; + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + { + ParaPortion* pTmpPortion = GetObject(nPortion); + if ( pTmpPortion == pPPortion ) + return nHeight; + nHeight += pTmpPortion->GetHeight(); + } + DBG_ERROR( "GetYOffset: Portion nicht gefunden" ); + return nHeight; +} + +USHORT ParaPortionList::FindParagraph( long nYOffset ) +{ + long nY = 0; + for ( USHORT nPortion = 0; nPortion < Count(); nPortion++ ) + { + nY += GetObject(nPortion)->GetHeight(); // sollte auch bei !bVisible richtig sein! + if ( nY > nYOffset ) + return nPortion; + } + return 0xFFFF; // solte mal ueber EE_PARA_NOT_FOUND erreicht werden! +} + +void ParaPortionList::DbgCheck( EditDoc& +#ifdef DBG_UTIL + rDoc +#endif + ) +{ +#ifdef DBG_UTIL + DBG_ASSERT( Count() == rDoc.Count(), "ParaPortionList::DbgCheck() - Count() ungleich!" ); + for ( USHORT i = 0; i < Count(); i++ ) + { + DBG_ASSERT( SaveGetObject(i), "ParaPortionList::DbgCheck() - Null-Pointer in Liste!" ); + DBG_ASSERT( GetObject(i)->GetNode(), "ParaPortionList::DbgCheck() - Null-Pointer in Liste(2)!" ); + DBG_ASSERT( GetObject(i)->GetNode() == rDoc.GetObject(i), "ParaPortionList::DbgCheck() - Eintraege kreuzen sich!" ); + } +#endif +} + + +ContentAttribsInfo::ContentAttribsInfo( const SfxItemSet& rParaAttribs ) : + aPrevParaAttribs( rParaAttribs) +{ +} + + +void ConvertItem( SfxPoolItem& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit ) +{ + DBG_ASSERT( eSourceUnit != eDestUnit, "ConvertItem - Why?!" ); + + switch ( rPoolItem.Which() ) + { + case EE_PARA_LRSPACE: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLRSpaceItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxLRSpaceItem& rItem = (SvxLRSpaceItem&)rPoolItem; + rItem.SetTxtFirstLineOfst( sal::static_int_cast< short >( OutputDevice::LogicToLogic( rItem.GetTxtFirstLineOfst(), eSourceUnit, eDestUnit ) ) ); + rItem.SetTxtLeft( OutputDevice::LogicToLogic( rItem.GetTxtLeft(), eSourceUnit, eDestUnit ) ); +// rItem.SetLeft( OutputDevice::LogicToLogic( rItem.GetLeft(), eSourceUnit, eDestUnit ) ); // #96298# SetLeft manipulates nTxtLeft! + rItem.SetRight( OutputDevice::LogicToLogic( rItem.GetRight(), eSourceUnit, eDestUnit ) ); + } + break; + case EE_PARA_ULSPACE: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxULSpaceItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxULSpaceItem& rItem = (SvxULSpaceItem&)rPoolItem; + rItem.SetUpper( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetUpper(), eSourceUnit, eDestUnit ) ) ); + rItem.SetLower( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetLower(), eSourceUnit, eDestUnit ) ) ); + } + break; + case EE_PARA_SBL: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxLineSpacingItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxLineSpacingItem& rItem = (SvxLineSpacingItem&)rPoolItem; + // #96298# SetLineHeight changes also eLineSpace! + if ( rItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN ) + rItem.SetLineHeight( sal::static_int_cast< USHORT >( OutputDevice::LogicToLogic( rItem.GetLineHeight(), eSourceUnit, eDestUnit ) ) ); + } + break; + case EE_PARA_TABS: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxTabStopItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxTabStopItem& rItem = (SvxTabStopItem&)rPoolItem; + SvxTabStopItem aNewItem( EE_PARA_TABS ); + for ( USHORT i = 0; i < rItem.Count(); i++ ) + { + const SvxTabStop& rTab = rItem[i]; + SvxTabStop aNewStop( OutputDevice::LogicToLogic( rTab.GetTabPos(), eSourceUnit, eDestUnit ), rTab.GetAdjustment(), rTab.GetDecimal(), rTab.GetFill() ); + aNewItem.Insert( aNewStop ); + } + rItem = aNewItem; + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + DBG_ASSERT( rPoolItem.IsA( TYPE( SvxFontHeightItem ) ), "ConvertItem: Ungueltiges Item!" ); + SvxFontHeightItem& rItem = (SvxFontHeightItem&)rPoolItem; + rItem.SetHeight( OutputDevice::LogicToLogic( rItem.GetHeight(), eSourceUnit, eDestUnit ) ); + } + break; + } +} + +void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit, const MapUnit* pDestUnit ) +{ + const SfxItemPool* pSourcePool = rSource.GetPool(); + const SfxItemPool* pDestPool = rDest.GetPool(); + + for ( USHORT nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + // Wenn moeglich ueber SlotID gehen... + + USHORT nSourceWhich = nWhich; + USHORT nSlot = pDestPool->GetTrueSlotId( nWhich ); + if ( nSlot ) + { + USHORT nW = pSourcePool->GetTrueWhich( nSlot ); + if ( nW ) + nSourceWhich = nW; + } + + if ( rSource.GetItemState( nSourceWhich, FALSE ) == SFX_ITEM_ON ) + { + MapUnit eSourceUnit = pSourceUnit ? *pSourceUnit : (MapUnit)pSourcePool->GetMetric( nSourceWhich ); + MapUnit eDestUnit = pDestUnit ? *pDestUnit : (MapUnit)pDestPool->GetMetric( nWhich ); + if ( eSourceUnit != eDestUnit ) + { + SfxPoolItem* pItem = rSource.Get( nSourceWhich ).Clone(); +// pItem->SetWhich( nWhich ); + ConvertItem( *pItem, eSourceUnit, eDestUnit ); + rDest.Put( *pItem, nWhich ); + delete pItem; + } + else + { + rDest.Put( rSource.Get( nSourceWhich ), nWhich ); + } + } + else + { + // MT 3.3.99: Waere so eigentlich richtig, aber schon seit Jahren nicht so... +// rDest.ClearItem( nWhich ); + } + } +} + diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx new file mode 100644 index 000000000000..e3aac4fe8c1a --- /dev/null +++ b/editeng/source/editeng/editeng.cxx @@ -0,0 +1,2944 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editeng.cxx,v $ + * $Revision: 1.117.12.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#define USE_SVXFONT + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> +#include <svl/ctloptions.hxx> +#include <svtools/ctrltool.hxx> + +#include <editeng/svxfont.hxx> +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/editstat.hxx> +#include <editdbg.hxx> +#include <eerdll2.hxx> +#include <editeng/eerdll.hxx> +#include <editeng.hrc> +#include <editeng/flditem.hxx> +#include <editeng/txtrange.hxx> +#include <vcl/graph.hxx> + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> + +#include <sot/exchange.hxx> +#include <sot/formats.hxx> + +#include <editeng/numitem.hxx> +#include <editeng/bulitem.hxx> +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <i18npool/mslangid.hxx> +#include <vcl/help.hxx> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/i18n/InputSequenceCheckMode.hpp> + +#include <svl/srchdefs.hxx> + +#if OSL_DEBUG_LEVEL > 1 +#include <editeng/frmdiritem.hxx> +#endif +#include <basegfx/polygon/b2dpolygon.hxx> + +// Spaeter -> TOOLS\STRING.H (fuer Grep: WS_TARGET) + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; + + +DBG_NAME( EditEngine ) +DBG_NAMEEX( EditView ) + +#if (OSL_DEBUG_LEVEL > 1) || defined ( DBG_UTIL ) +static sal_Bool bDebugPaint = sal_False; +#endif + +SV_IMPL_VARARR( EECharAttribArray, EECharAttrib ); + +static SfxItemPool* pGlobalPool=0; + +// ---------------------------------------------------------------------- +// EditEngine +// ---------------------------------------------------------------------- +EditEngine::EditEngine( SfxItemPool* pItemPool ) +{ + DBG_CTOR( EditEngine, 0 ); + pImpEditEngine = new ImpEditEngine( this, pItemPool ); +} + +EditEngine::~EditEngine() +{ + DBG_DTOR( EditEngine, 0 ); + delete pImpEditEngine; +} + +void EditEngine::EnableUndo( sal_Bool bEnable ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EnableUndo( bEnable ); +} + +sal_Bool EditEngine::IsUndoEnabled() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsUndoEnabled(); +} + +sal_Bool EditEngine::IsInUndo() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsInUndo(); +} + +SfxUndoManager& EditEngine::GetUndoManager() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetUndoManager(); +} + +void EditEngine::UndoActionStart( sal_uInt16 nId ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( !pImpEditEngine->IsInUndo(), "Aufruf von UndoActionStart im Undomodus!" ); + if ( !pImpEditEngine->IsInUndo() ) + pImpEditEngine->UndoActionStart( nId ); +} + +void EditEngine::UndoActionEnd( sal_uInt16 nId ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( !pImpEditEngine->IsInUndo(), "Aufruf von UndoActionEnd im Undomodus!" ); + if ( !pImpEditEngine->IsInUndo() ) + pImpEditEngine->UndoActionEnd( nId ); +} + +BOOL EditEngine::HasTriedMergeOnLastAddUndo() const +{ + return pImpEditEngine->mbLastTryMerge; +} + +void EditEngine::SetRefDevice( OutputDevice* pRefDev ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetRefDevice( pRefDev ); +} + +OutputDevice* EditEngine::GetRefDevice() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetRefDevice(); +} + +void EditEngine::SetRefMapMode( const MapMode& rMapMode ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetRefMapMode( rMapMode ); +} + +MapMode EditEngine::GetRefMapMode() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetRefMapMode(); +} + +void EditEngine::SetBackgroundColor( const Color& rColor ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetBackgroundColor( rColor ); +} + +Color EditEngine::GetBackgroundColor() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetBackgroundColor(); +} + +Color EditEngine::GetAutoColor() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetAutoColor(); +} + +void EditEngine::EnableAutoColor( BOOL b ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EnableAutoColor( b ); +} + +BOOL EditEngine::IsAutoColorEnabled() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsAutoColorEnabled(); +} + +void EditEngine::ForceAutoColor( BOOL b ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->ForceAutoColor( b ); +} + +BOOL EditEngine::IsForceAutoColor() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsForceAutoColor(); +} + +const SfxItemSet& EditEngine::GetEmptyItemSet() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEmptyItemSet(); +} + +void EditEngine::Draw( OutputDevice* pOutDev, const Rectangle& rOutRect ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + Draw( pOutDev, rOutRect, Point( 0, 0 ) ); +} + +void EditEngine::Draw( OutputDevice* pOutDev, const Point& rStartPos, short nOrientation ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + // Mit 2 Punkten erzeugen, da bei Positivem Punkt, LONGMAX als Size + // Bottom und Right im Bereich > LONGMAX landen. + Rectangle aBigRec( -0x3FFFFFFF, -0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF ); + if( pOutDev->GetConnectMetaFile() ) + pOutDev->Push(); + Point aStartPos( rStartPos ); + if ( IsVertical() ) + { + aStartPos.X() += GetPaperSize().Width(); + aStartPos = Rotate( aStartPos, nOrientation, rStartPos ); + } + pImpEditEngine->Paint( pOutDev, aBigRec, aStartPos, sal_False, nOrientation ); + if( pOutDev->GetConnectMetaFile() ) + pOutDev->Pop(); +} + +void EditEngine::Draw( OutputDevice* pOutDev, const Rectangle& rOutRect, const Point& rStartDocPos ) +{ + Draw( pOutDev, rOutRect, rStartDocPos, sal_True ); +} + +void EditEngine::Draw( OutputDevice* pOutDev, const Rectangle& rOutRect, const Point& rStartDocPos, sal_Bool bClip ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + +#if defined( DBG_UTIL ) || (OSL_DEBUG_LEVEL > 1) + if ( bDebugPaint ) + EditDbg::ShowEditEngineData( this, sal_False ); +#endif + + // Auf Pixelgrenze ausrichten, damit genau das gleiche + // wie bei Paint(). + Rectangle aOutRect( pOutDev->LogicToPixel( rOutRect ) ); + aOutRect = pOutDev->PixelToLogic( aOutRect ); + + Point aStartPos; + if ( !IsVertical() ) + { + aStartPos.X() = aOutRect.Left() - rStartDocPos.X(); + aStartPos.Y() = aOutRect.Top() - rStartDocPos.Y(); + } + else + { + aStartPos.X() = aOutRect.Right() + rStartDocPos.Y(); + aStartPos.Y() = aOutRect.Top() - rStartDocPos.X(); + } + + sal_Bool bClipRegion = pOutDev->IsClipRegion(); + sal_Bool bMetafile = pOutDev->GetConnectMetaFile() ? sal_True : sal_False; + Region aOldRegion = pOutDev->GetClipRegion(); + +#ifdef EDIT_PRINTER_LOG + if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER ) + { + SvFileStream aLog( "d:\\editprn.log", STREAM_WRITE ); + aLog.Seek( STREAM_SEEK_TO_END ); + aLog << '' << endl << "Printing: "; + aLog << GetText( "\n\r" ).GetStr(); + aLog << endl << endl; + aLog << "Ref-Device: " << String( (sal_uInt32)GetRefDevice() ).GetStr() << " Type=" << String( (sal_uInt16)GetRefDevice()->GetOutDevType() ).GetStr() << ", MapX=" << String( GetRefDevice()->GetMapMode().GetScaleX().GetNumerator() ).GetStr() << "/" << String( GetRefDevice()->GetMapMode().GetScaleX().GetDenominator() ).GetStr() <<endl; + aLog << "Paper-Width: " << String( GetPaperSize().Width() ).GetStr() << ",\tOut-Width: " << String( rOutRect.GetWidth() ).GetStr() << ",\tCalculated: " << String( CalcTextWidth() ).GetStr() << endl; + aLog << "Paper-Height: " << String( GetPaperSize().Height() ).GetStr() << ",\tOut-Height: " << String( rOutRect.GetHeight() ).GetStr() << ",\tCalculated: " << String( GetTextHeight() ).GetStr() << endl; + + aLog << endl; + } +#endif + + // Wenn es eine gab => Schnittmenge ! + // Bei der Metafileaufzeichnung Push/Pop verwenden. + if ( bMetafile ) + pOutDev->Push(); + + // Immer die Intersect-Methode, weil beim Metafile ein Muss! + if ( bClip ) + { + // Clip only if neccesary... + if ( !rStartDocPos.X() && !rStartDocPos.Y() && + ( rOutRect.GetHeight() >= (long)GetTextHeight() ) && + ( rOutRect.GetWidth() >= (long)CalcTextWidth() ) ) + { + bClip = FALSE; + } + else + { + // Einige Druckertreiber bereiten Probleme, wenn Buchstaben die + // ClipRegion streifen, deshalb lieber ein Pixel mehr... + Rectangle aClipRect( aOutRect ); + if ( pOutDev->GetOutDevType() == OUTDEV_PRINTER ) + { + Size aPixSz( 1, 0 ); + aPixSz = pOutDev->PixelToLogic( aPixSz ); + aClipRect.Right() += aPixSz.Width(); + aClipRect.Bottom() += aPixSz.Width(); + } + pOutDev->IntersectClipRegion( aClipRect ); + } + } + + pImpEditEngine->Paint( pOutDev, aOutRect, aStartPos ); + + if ( bMetafile ) + pOutDev->Pop(); + else if ( bClipRegion ) + pOutDev->SetClipRegion( aOldRegion ); + else + pOutDev->SetClipRegion(); +} + +void EditEngine::InsertView( EditView* pEditView, sal_uInt16 nIndex ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_CHKOBJ( pEditView, EditView, 0 ); + + if ( nIndex > pImpEditEngine->GetEditViews().Count() ) + nIndex = pImpEditEngine->GetEditViews().Count(); + + pImpEditEngine->GetEditViews().Insert( pEditView, nIndex ); + EditSelection aStartSel; + aStartSel = pImpEditEngine->GetEditDoc().GetStartPaM(); + pEditView->pImpEditView->SetEditSelection( aStartSel ); + if ( !pImpEditEngine->GetActiveView() ) + pImpEditEngine->SetActiveView( pEditView ); + + pEditView->pImpEditView->AddDragAndDropListeners(); +} + +EditView* EditEngine::RemoveView( EditView* pView ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_CHKOBJ( pView, EditView, 0 ); + + pView->HideCursor(); + EditView* pRemoved = 0; + sal_uInt16 nPos = pImpEditEngine->GetEditViews().GetPos( pView ); + DBG_ASSERT( nPos != USHRT_MAX, "RemoveView mit ungueltigem Index" ); + if ( nPos != USHRT_MAX ) + { + pRemoved = pImpEditEngine->GetEditViews().GetObject( nPos ); + pImpEditEngine->GetEditViews().Remove( nPos ); + if ( pImpEditEngine->GetActiveView() == pView ) + { + pImpEditEngine->SetActiveView( 0 ); + pImpEditEngine->GetSelEngine().SetCurView( 0 ); + } + pView->pImpEditView->RemoveDragAndDropListeners(); + + } + return pRemoved; +} + +EditView* EditEngine::RemoveView( sal_uInt16 nIndex ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditView* pView = pImpEditEngine->GetEditViews().GetObject( nIndex ); + if ( pView ) + return RemoveView( pView ); + return NULL; +} + +EditView* EditEngine::GetView( sal_uInt16 nIndex ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditViews().GetObject( nIndex ); +} + +sal_uInt16 EditEngine::GetViewCount() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditViews().Count(); +} + +sal_Bool EditEngine::HasView( EditView* pView ) const +{ + return pImpEditEngine->GetEditViews().GetPos( pView ) != USHRT_MAX; +} + +EditView* EditEngine::GetActiveView() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetActiveView(); +} + +void EditEngine::SetActiveView( EditView* pView ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( pView ) + { + DBG_CHKOBJ( pView, EditView, 0 ); + } + pImpEditEngine->SetActiveView( pView ); +} + +void EditEngine::SetDefTab( sal_uInt16 nDefTab ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->GetEditDoc().SetDefTab( nDefTab ); + if ( pImpEditEngine->IsFormatted() ) + { + pImpEditEngine->FormatFullDoc(); + pImpEditEngine->UpdateViews( (EditView*) 0 ); + } +} + +sal_uInt16 EditEngine::GetDefTab() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditDoc().GetDefTab(); +} + +void EditEngine::SetPaperSize( const Size& rNewSize ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + Size aOldSize( pImpEditEngine->GetPaperSize() ); + pImpEditEngine->SetValidPaperSize( rNewSize ); + Size aNewSize( pImpEditEngine->GetPaperSize() ); + + sal_Bool bAutoPageSize = pImpEditEngine->GetStatus().AutoPageSize(); + if ( bAutoPageSize || ( aNewSize.Width() != aOldSize.Width() ) ) + { + for ( sal_uInt16 nView = 0; nView < pImpEditEngine->aEditViews.Count(); nView++ ) + { + EditView* pView = pImpEditEngine->aEditViews[nView]; + DBG_CHKOBJ( pView, EditView, 0 ); + if ( bAutoPageSize ) + pView->pImpEditView->RecalcOutputArea(); + else if ( pView->pImpEditView->DoAutoSize() ) + { + pView->pImpEditView->ResetOutputArea( Rectangle( + pView->pImpEditView->GetOutputArea().TopLeft(), aNewSize ) ); + } + } + + if ( bAutoPageSize || pImpEditEngine->IsFormatted() ) + { + // Aendern der Breite hat bei AutoPageSize keine Wirkung, da durch + // Textbreite bestimmt. + // Optimierung erst nach Vobis-Auslieferung aktivieren... +// if ( !bAutoPageSize ) + pImpEditEngine->FormatFullDoc(); +// else +// { +// pImpEditEngine->FormatDoc(); // PageSize, falls Aenderung +// pImpEditEngine->CheckAutoPageSize(); // Falls nichts formatiert wurde +// } + + pImpEditEngine->UpdateViews( pImpEditEngine->GetActiveView() ); + + if ( pImpEditEngine->GetUpdateMode() && pImpEditEngine->GetActiveView() ) + pImpEditEngine->pActiveView->ShowCursor( sal_False, sal_False ); + } + } +} + +const Size& EditEngine::GetPaperSize() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetPaperSize(); +} + +void EditEngine::SetVertical( BOOL bVertical ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetVertical( bVertical ); +} + +BOOL EditEngine::IsVertical() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsVertical(); +} + +void EditEngine::SetFixedCellHeight( BOOL bUseFixedCellHeight ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetFixedCellHeight( bUseFixedCellHeight ); +} + +BOOL EditEngine::IsFixedCellHeight() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsFixedCellHeight(); +} + +void EditEngine::SetDefaultHorizontalTextDirection( EEHorizontalTextDirection eHTextDir ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetDefaultHorizontalTextDirection( eHTextDir ); +} + +EEHorizontalTextDirection EditEngine::GetDefaultHorizontalTextDirection() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetDefaultHorizontalTextDirection(); +} + +USHORT EditEngine::GetScriptType( const ESelection& rSelection ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine->CreateSel( rSelection ) ); + return pImpEditEngine->GetScriptType( aSel ); +} + +LanguageType EditEngine::GetLanguage( USHORT nPara, USHORT nPos ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERT( pNode, "GetLanguage - nPara is invalid!" ); + return pNode ? pImpEditEngine->GetLanguage( EditPaM( pNode, nPos ) ) : LANGUAGE_DONTKNOW; +} + + +void EditEngine::TransliterateText( const ESelection& rSelection, sal_Int32 nTransliterationMode ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditEngine->TransliterateText( pImpEditEngine->CreateSel( rSelection ), nTransliterationMode ); +} + +void EditEngine::SetAsianCompressionMode( USHORT n ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditEngine->SetAsianCompressionMode( n ); +} + +USHORT EditEngine::GetAsianCompressionMode() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditEngine->GetAsianCompressionMode(); +} + +void EditEngine::SetKernAsianPunctuation( BOOL b ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditEngine->SetKernAsianPunctuation( b ); +} + +BOOL EditEngine::IsKernAsianPunctuation() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditEngine->IsKernAsianPunctuation(); +} + +void EditEngine::SetAddExtLeading( BOOL b ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetAddExtLeading( b ); +} + +BOOL EditEngine::IsAddExtLeading() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsAddExtLeading(); +} + +void EditEngine::SetPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + SetPolygon( rPolyPolygon, 0L ); +} + +void EditEngine::SetPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DPolyPolygon* pLinePolyPolygon) +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_Bool bSimple(sal_False); + + if(pLinePolyPolygon && 1L == rPolyPolygon.count()) + { + if(rPolyPolygon.getB2DPolygon(0L).isClosed()) + { + // open polygon + bSimple = sal_True; + } + } + + TextRanger* pRanger = new TextRanger( rPolyPolygon, pLinePolyPolygon, 30, 2, 2, bSimple, sal_True ); + pImpEditEngine->SetTextRanger( pRanger ); + pImpEditEngine->SetPaperSize( pRanger->GetBoundRect().GetSize() ); +} + +void EditEngine::ClearPolygon() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetTextRanger( 0 ); +} + +const PolyPolygon* EditEngine::GetPolygon() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetTextRanger() ? + &pImpEditEngine->GetTextRanger()->GetPolyPolygon() : NULL; +} + +const Size& EditEngine::GetMinAutoPaperSize() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetMinAutoPaperSize(); +} + +void EditEngine::SetMinAutoPaperSize( const Size& rSz ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetMinAutoPaperSize( rSz ); +} + +const Size& EditEngine::GetMaxAutoPaperSize() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetMaxAutoPaperSize(); +} + +void EditEngine::SetMaxAutoPaperSize( const Size& rSz ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetMaxAutoPaperSize( rSz ); +} + +XubString EditEngine::GetText( LineEnd eEnd ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditDoc().GetText( eEnd ); +} + +XubString EditEngine::GetText( const ESelection& rESelection, const LineEnd eEnd ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine->CreateSel( rESelection ) ); + return pImpEditEngine->GetSelected( aSel, eEnd ); +} + +sal_uInt32 EditEngine::GetTextLen() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditDoc().GetTextLen(); +} + +sal_uInt16 EditEngine::GetParagraphCount() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aEditDoc.Count(); +} + +sal_uInt16 EditEngine::GetLineCount( sal_uInt16 nParagraph ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineCount( nParagraph ); +} + +sal_uInt16 EditEngine::GetLineLen( sal_uInt16 nParagraph, sal_uInt16 nLine ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineLen( nParagraph, nLine ); +} + +void EditEngine::GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nParagraph, USHORT nLine ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineBoundaries( rStart, rEnd, nParagraph, nLine ); +} + +USHORT EditEngine::GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineNumberAtIndex( nPara, nIndex ); +} + +sal_uInt32 EditEngine::GetLineHeight( sal_uInt16 nParagraph, sal_uInt16 nLine ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + // Falls jemand mit einer leeren Engine ein GetLineHeight() macht. + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + return pImpEditEngine->GetLineHeight( nParagraph, nLine ); +} + +sal_uInt16 EditEngine::GetFirstLineOffset( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nParagraph ); + return ( pPortion ? pPortion->GetFirstLineOffset() : 0 ); +} + +sal_uInt32 EditEngine::GetTextHeight( sal_uInt16 nParagraph ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + sal_uInt32 nHeight = pImpEditEngine->GetParaHeight( nParagraph ); + return nHeight; +} + +XubString EditEngine::GetWord( sal_uInt16 nPara, sal_uInt16 nIndex ) +{ + ESelection aESel( nPara, nIndex, nPara, nIndex ); + EditSelection aSel( pImpEditEngine->CreateSel( aESel ) ); + aSel = pImpEditEngine->SelectWord( aSel ); + return pImpEditEngine->GetSelected( aSel ); +} + +ESelection EditEngine::GetWord( const ESelection& rSelection, USHORT nWordType ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->SelectWord( aSel, nWordType ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +ESelection EditEngine::WordLeft( const ESelection& rSelection, USHORT nWordType ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->WordLeft( aSel.Min(), nWordType ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +ESelection EditEngine::WordRight( const ESelection& rSelection, USHORT nWordType ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->WordRight( aSel.Max(), nWordType ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +ESelection EditEngine::CursorLeft( const ESelection& rSelection, USHORT nCharacterIteratorMode ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->CursorLeft( aSel.Min(), nCharacterIteratorMode ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +ESelection EditEngine::CursorRight( const ESelection& rSelection, USHORT nCharacterIteratorMode ) const +{ + // ImpEditEngine-Iteration-Methods should be const! + EditEngine* pE = (EditEngine*)this; + + EditSelection aSel( pE->pImpEditEngine->CreateSel( rSelection ) ); + aSel = pE->pImpEditEngine->CursorRight( aSel.Max(), nCharacterIteratorMode ); + return pE->pImpEditEngine->CreateESel( aSel ); +} + +sal_Bool EditEngine::PostKeyEvent( const KeyEvent& rKeyEvent, EditView* pEditView ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_CHKOBJ( pEditView, EditView, 0 ); + DBG_ASSERT( pEditView, "Keine View - keine Kekse !" ); + + sal_Bool bDone = sal_True; + + sal_Bool bModified = sal_False; + sal_Bool bMoved = sal_False; + sal_Bool bAllowIdle = sal_True; + sal_Bool bReadOnly = pEditView->IsReadOnly(); + + USHORT nNewCursorFlags = 0; + BOOL bSetCursorFlags = TRUE; + + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + DBG_ASSERT( !aCurSel.IsInvalid(), "Blinde Selection in EditEngine::PostKeyEvent" ); + + String aAutoText( pImpEditEngine->GetAutoCompleteText() ); + if ( pImpEditEngine->GetAutoCompleteText().Len() ) + pImpEditEngine->SetAutoCompleteText( String(), sal_True ); + + sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); + KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_UNDO: + { + if ( !bReadOnly ) + pEditView->Undo(); + return sal_True; + } + // break; + case KEYFUNC_REDO: + { + if ( !bReadOnly ) + pEditView->Redo(); + return sal_True; + } + // break; + + default: // wird dann evtl. unten bearbeitet. + eFunc = KEYFUNC_DONTKNOW; + } + } + + pImpEditEngine->EnterBlockNotifications(); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_INPUT_START ); + aNotify.pEditEngine = this; + pImpEditEngine->CallNotify( aNotify ); + } + + if ( eFunc == KEYFUNC_DONTKNOW ) + { + switch ( nCode ) + { + #if defined( DBG_UTIL ) || (OSL_DEBUG_LEVEL > 1) + case KEY_F1: + { + if ( rKeyEvent.GetKeyCode().IsMod1() && rKeyEvent.GetKeyCode().IsMod2() ) + { + USHORT nParas = GetParagraphCount(); + Point aPos; + Point aViewStart( pEditView->GetOutputArea().TopLeft() ); + long n20 = 40 * pImpEditEngine->nOnePixelInRef; + for ( USHORT n = 0; n < nParas; n++ ) + { + long nH = GetTextHeight( n ); + Point P1( aViewStart.X() + n20 + n20*(n%2), aViewStart.Y() + aPos.Y() ); + Point P2( P1 ); + P2.X() += n20; + P2.Y() += nH; + pEditView->GetWindow()->SetLineColor(); + pEditView->GetWindow()->SetFillColor( Color( (n%2) ? COL_YELLOW : COL_LIGHTGREEN ) ); + pEditView->GetWindow()->DrawRect( Rectangle( P1, P2 ) ); + aPos.Y() += nH; + } + } + bDone = FALSE; + } + break; + case KEY_F11: + { + if ( rKeyEvent.GetKeyCode().IsMod1() && rKeyEvent.GetKeyCode().IsMod2() ) + { + bDebugPaint = !bDebugPaint; + ByteString aInfo( "DebugPaint: " ); + aInfo += bDebugPaint ? "On" : "Off"; + InfoBox( NULL, String( aInfo, RTL_TEXTENCODING_ASCII_US ) ).Execute(); + } + bDone = FALSE; + } + break; + case KEY_F12: + { + if ( rKeyEvent.GetKeyCode().IsMod1() && rKeyEvent.GetKeyCode().IsMod2() ) + { + EditDbg::ShowEditEngineData( this ); + #ifdef EDIT_PRINTER_LOG + SvFileStream aLog( "d:\\editprn.log", STREAM_WRITE ); + aLog.Seek( STREAM_SEEK_TO_END ); + aLog << '' << endl << "Debug: "; + aLog << GetText( "\n\r" ).GetStr(); + aLog << endl << endl; + aLog << "Ref-Device: " << String( (sal_uInt32)GetRefDevice() ).GetStr() << " Type=" << String( (sal_uInt16)GetRefDevice()->GetOutDevType() ).GetStr() << ", MapX=" << String( GetRefDevice()->GetMapMode().GetScaleX().GetNumerator() ).GetStr() << "/" << String( GetRefDevice()->GetMapMode().GetScaleX().GetDenominator() ).GetStr() <<endl; + aLog << "Paper-Width: " << String( GetPaperSize().Width() ).GetStr() << ",\tCalculated: " << String( CalcTextWidth() ).GetStr() << endl; + aLog << "Paper-Height: " << String( GetPaperSize().Height() ).GetStr() << ",\tCalculated: " << String( GetTextHeight() ).GetStr() << endl; + aLog << endl; + #endif + } + bDone = FALSE; + } + break; + #endif + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_HOME: + case KEY_END: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + case com::sun::star::awt::Key::MOVE_WORD_FORWARD: + case com::sun::star::awt::Key::SELECT_WORD_FORWARD: + case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: + case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: + case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: + case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: + case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: + case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: + case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: + case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: + { + if ( !rKeyEvent.GetKeyCode().IsMod2() || ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) + { + if ( pImpEditEngine->DoVisualCursorTraveling( aCurSel.Max().GetNode() ) && ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) /* || ( nCode == KEY_HOME ) || ( nCode == KEY_END ) */ ) ) + bSetCursorFlags = FALSE; // Will be manipulated within visual cursor move + + aCurSel = pImpEditEngine->MoveCursor( rKeyEvent, pEditView ); + + if ( aCurSel.HasRange() ) { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aSelection(pEditView->GetWindow()->GetPrimarySelection()); + pEditView->pImpEditView->CutCopy( aSelection, FALSE ); + } + + bMoved = sal_True; + if ( nCode == KEY_HOME ) + nNewCursorFlags |= GETCRSR_STARTOFLINE; + else if ( nCode == KEY_END ) + nNewCursorFlags |= GETCRSR_ENDOFLINE; + + } +#if OSL_DEBUG_LEVEL > 1 + GetLanguage( pImpEditEngine->GetEditDoc().GetPos( aCurSel.Max().GetNode() ), aCurSel.Max().GetIndex() ); +#endif + } + break; + case KEY_BACKSPACE: + case KEY_DELETE: + case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: + case com::sun::star::awt::Key::DELETE_WORD_FORWARD: + case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH: + case com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH: + { + if ( !bReadOnly && !rKeyEvent.GetKeyCode().IsMod2() ) + { + // check if we are behind a bullet and using the backspace key + ContentNode *pNode = aCurSel.Min().GetNode(); + const SvxNumberFormat *pFmt = pImpEditEngine->GetNumberFormat( pNode ); + if (pFmt && nCode == KEY_BACKSPACE && + !aCurSel.HasRange() && aCurSel.Min().GetIndex() == 0) + { + // if the bullet is still visible just do not paint it from + // now on and that will be all. Otherwise continue as usual. + // ... + + USHORT nPara = pImpEditEngine->GetEditDoc().GetPos( pNode ); + SfxBoolItem aBulletState( (const SfxBoolItem&) pImpEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE ) ); + bool bBulletIsVisible = aBulletState.GetValue() ? true : false; + + // just toggling EE_PARA_BULLETSTATE should be fine for both cases... + aBulletState.SetValue( !bBulletIsVisible ); + SfxItemSet aSet( pImpEditEngine->GetParaAttribs( nPara ) ); + aSet.Put( aBulletState ); + pImpEditEngine->SetParaAttribs( nPara, aSet ); + + // have this and the following paragraphs formatted and repainted. + // (not painting a numbering in the list may cause the following + // numberings to have different numbers than before and thus the + // length may have changed as well ) + pImpEditEngine->FormatAndUpdate( pImpEditEngine->GetActiveView() ); + + if (bBulletIsVisible) // bullet just turned invisible... + break; + } + + BYTE nDel = 0, nMode = 0; + switch( nCode ) + { + case com::sun::star::awt::Key::DELETE_WORD_BACKWARD: + nMode = DELMODE_RESTOFWORD; + nDel = DEL_LEFT; + break; + case com::sun::star::awt::Key::DELETE_WORD_FORWARD: + nMode = DELMODE_RESTOFWORD; + nDel = DEL_RIGHT; + break; + case com::sun::star::awt::Key::DELETE_TO_BEGIN_OF_PARAGRAPH: + nMode = DELMODE_RESTOFCONTENT; + nDel = DEL_LEFT; + break; + case com::sun::star::awt::Key::DELETE_TO_END_OF_PARAGRAPH: + nMode = DELMODE_RESTOFCONTENT; + nDel = DEL_RIGHT; + break; + default: + nDel = ( nCode == KEY_DELETE ) ? DEL_RIGHT : DEL_LEFT; + nMode = rKeyEvent.GetKeyCode().IsMod1() ? DELMODE_RESTOFWORD : DELMODE_SIMPLE; + if ( ( nMode == DELMODE_RESTOFWORD ) && rKeyEvent.GetKeyCode().IsShift() ) + nMode = DELMODE_RESTOFCONTENT; + break; + } + + pEditView->pImpEditView->DrawSelection(); + pImpEditEngine->UndoActionStart( EDITUNDO_DELETE ); + aCurSel = pImpEditEngine->DeleteLeftOrRight( aCurSel, nDel, nMode ); + pImpEditEngine->UndoActionEnd( EDITUNDO_DELETE ); + bModified = sal_True; + bAllowIdle = sal_False; + } + } + break; + case KEY_TAB: + { + if ( !bReadOnly && !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + { + sal_Bool bShift = rKeyEvent.GetKeyCode().IsShift(); + if ( pImpEditEngine->GetStatus().DoTabIndenting() && + ( aCurSel.Min().GetNode() != aCurSel.Max().GetNode() ) ) + { + pImpEditEngine->IndentBlock( pEditView, !bShift ); + } + else if ( !bShift ) + { + sal_Bool bSel = pEditView->HasSelection(); + if ( bSel ) + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + if ( pImpEditEngine->GetStatus().DoAutoCorrect() ) + aCurSel = pImpEditEngine->AutoCorrect( aCurSel, 0, !pEditView->IsInsertMode() ); + aCurSel = pImpEditEngine->InsertTab( aCurSel ); + if ( bSel ) + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + bModified = sal_True; + } + } + else + bDone = sal_False; + } + break; + case KEY_RETURN: + { + if ( !bReadOnly ) + { + pEditView->pImpEditView->DrawSelection(); + if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + { + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + if ( rKeyEvent.GetKeyCode().IsShift() ) + { + aCurSel = pImpEditEngine->AutoCorrect( aCurSel, 0, !pEditView->IsInsertMode() ); + aCurSel = pImpEditEngine->InsertLineBreak( aCurSel ); + } + else + { + if ( !aAutoText.Len() ) + { + if ( pImpEditEngine->GetStatus().DoAutoCorrect() ) + aCurSel = pImpEditEngine->AutoCorrect( aCurSel, 0, !pEditView->IsInsertMode() ); + aCurSel = pImpEditEngine->InsertParaBreak( aCurSel ); + } + else + { + DBG_ASSERT( !aCurSel.HasRange(), "Selektion bei Complete?!" ); + EditPaM aStart( pImpEditEngine->WordLeft( aCurSel.Max() ) ); + aCurSel = pImpEditEngine->InsertText( + EditSelection( aStart, aCurSel.Max() ), aAutoText ); + pImpEditEngine->SetAutoCompleteText( String(), sal_True ); + } + } + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + bModified = sal_True; + } + } + } + break; + case KEY_INSERT: + { + if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + pEditView->SetInsertMode( !pEditView->IsInsertMode() ); + } + break; + default: + { + #if (OSL_DEBUG_LEVEL > 1) && defined(DBG_UTIL) + if ( ( nCode == KEY_W ) && rKeyEvent.GetKeyCode().IsMod1() && rKeyEvent.GetKeyCode().IsMod2() ) + { + SfxItemSet aAttribs = pEditView->GetAttribs(); + const SvxFrameDirectionItem& rCurrentWritingMode = (const SvxFrameDirectionItem&)aAttribs.Get( EE_PARA_WRITINGDIR ); + SvxFrameDirectionItem aNewItem( FRMDIR_HORI_LEFT_TOP, EE_PARA_WRITINGDIR ); + if ( rCurrentWritingMode.GetValue() != FRMDIR_HORI_RIGHT_TOP ) + aNewItem.SetValue( FRMDIR_HORI_RIGHT_TOP ); + aAttribs.Put( aNewItem ); + pEditView->SetAttribs( aAttribs ); + } + #endif + if ( !bReadOnly && IsSimpleCharInput( rKeyEvent ) ) + { + xub_Unicode nCharCode = rKeyEvent.GetCharCode(); + pEditView->pImpEditView->DrawSelection(); + // Autokorrektur ? + if ( ( pImpEditEngine->GetStatus().DoAutoCorrect() ) && + ( ( nCharCode == ' ' ) || ( nCharCode == '*' ) || + ( nCharCode == '\"' ) || ( nCharCode == '\'' ) || + ( nCharCode == '_' ) )) + { + aCurSel = pImpEditEngine->AutoCorrect( aCurSel, nCharCode, !pEditView->IsInsertMode() ); + } + else + { + aCurSel = pImpEditEngine->InsertText( (const EditSelection&)aCurSel, nCharCode, !pEditView->IsInsertMode(), sal_True ); + } + // AutoComplete ??? + if ( pImpEditEngine->GetStatus().DoAutoComplete() && ( nCharCode != ' ' ) ) + { + // Aber nur wenn Wort-Ende... + sal_uInt16 nIndex = aCurSel.Max().GetIndex(); + if ( ( nIndex >= aCurSel.Max().GetNode()->Len() ) || + ( pImpEditEngine->aWordDelimiters.Search( aCurSel.Max().GetNode()->GetChar( nIndex ) ) != STRING_NOTFOUND ) ) + { + EditPaM aStart( pImpEditEngine->WordLeft( aCurSel.Max() ) ); + String aWord = pImpEditEngine->GetSelected( EditSelection( aStart, aCurSel.Max() ) ); + if ( aWord.Len() >= 3 ) + { + String aComplete; + + LanguageType eLang = pImpEditEngine->GetLanguage( EditPaM( aStart.GetNode(), aStart.GetIndex()+1)); + lang::Locale aLocale( MsLangId::convertLanguageToLocale( eLang)); + + if (!pImpEditEngine->xLocaleDataWrapper.isInitialized()) + pImpEditEngine->xLocaleDataWrapper.init( SvtSysLocale().GetLocaleData().getServiceFactory(), aLocale, eLang); + else + pImpEditEngine->xLocaleDataWrapper.changeLocale( aLocale, eLang); + + if (!pImpEditEngine->xTransliterationWrapper.isInitialized()) + pImpEditEngine->xTransliterationWrapper.init( SvtSysLocale().GetLocaleData().getServiceFactory(), eLang, i18n::TransliterationModules_IGNORE_CASE); + else + pImpEditEngine->xTransliterationWrapper.changeLocale( eLang); + + const ::utl::TransliterationWrapper* pTransliteration = pImpEditEngine->xTransliterationWrapper.get(); + Sequence< i18n::CalendarItem > xItem = pImpEditEngine->xLocaleDataWrapper->getDefaultCalendarDays(); + sal_Int32 nCount = xItem.getLength(); + const i18n::CalendarItem* pArr = xItem.getArray(); + for( sal_Int32 n = 0; n <= nCount; ++n ) + { + const ::rtl::OUString& rDay = pArr[n].FullName; + if( pTransliteration->isMatch( aWord, rDay) ) + { + aComplete = rDay; + break; + } + } + + if ( !aComplete.Len() ) + { + xItem = pImpEditEngine->xLocaleDataWrapper->getDefaultCalendarMonths(); + sal_Int32 nMonthCount = xItem.getLength(); + const i18n::CalendarItem* pMonthArr = xItem.getArray(); + for( sal_Int32 n = 0; n <= nMonthCount; ++n ) + { + const ::rtl::OUString& rMon = pMonthArr[n].FullName; + if( pTransliteration->isMatch( aWord, rMon) ) + { + aComplete = rMon; + break; + } + } + } + + if( aComplete.Len() && ( ( aWord.Len() + 1 ) < aComplete.Len() ) ) + { + pImpEditEngine->SetAutoCompleteText( aComplete, sal_False ); + Point aPos = pImpEditEngine->PaMtoEditCursor( aCurSel.Max() ).TopLeft(); + aPos = pEditView->pImpEditView->GetWindowPos( aPos ); + aPos = pEditView->pImpEditView->GetWindow()->LogicToPixel( aPos ); + aPos = pEditView->GetWindow()->OutputToScreenPixel( aPos ); + aPos.Y() -= 3; + Help::ShowQuickHelp( pEditView->GetWindow(), Rectangle( aPos, Size( 1, 1 ) ), aComplete, QUICKHELP_BOTTOM|QUICKHELP_LEFT ); + } + } + } + } + bModified = sal_True; + } + else + bDone = sal_False; + } + } + } + + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pImpEditEngine->UpdateSelections(); + + if ( ( !IsVertical() && ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) ) || + ( IsVertical() && ( nCode != KEY_LEFT ) && ( nCode != KEY_RIGHT ) )) + { + pEditView->pImpEditView->nTravelXPos = TRAVEL_X_DONTKNOW; + } + + if ( /* ( nCode != KEY_HOME ) && ( nCode != KEY_END ) && */ + ( !IsVertical() && ( nCode != KEY_LEFT ) && ( nCode != KEY_RIGHT ) ) || + ( IsVertical() && ( nCode != KEY_UP ) && ( nCode != KEY_DOWN ) )) + { + pEditView->pImpEditView->SetCursorBidiLevel( 0xFFFF ); + } + + if ( bSetCursorFlags ) + pEditView->pImpEditView->nExtraCursorFlags = nNewCursorFlags; + + if ( bModified ) + { + DBG_ASSERT( !bReadOnly, "ReadOnly but modified???" ); + // Idle-Formatter nur, wenn AnyInput. + if ( bAllowIdle && pImpEditEngine->GetStatus().UseIdleFormatter() + && Application::AnyInput( INPUT_KEYBOARD) ) + pImpEditEngine->IdleFormatAndUpdate( pEditView ); + else + pImpEditEngine->FormatAndUpdate( pEditView ); + } + else if ( bMoved ) + { + sal_Bool bGotoCursor = pEditView->pImpEditView->DoAutoScroll(); + pEditView->pImpEditView->ShowCursor( bGotoCursor, sal_True ); + pImpEditEngine->CallStatusHdl(); + } + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_INPUT_END ); + aNotify.pEditEngine = this; + pImpEditEngine->CallNotify( aNotify ); + } + + pImpEditEngine->LeaveBlockNotifications(); + + return bDone; +} + +sal_uInt32 EditEngine::GetTextHeight() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + sal_uInt32 nHeight = !IsVertical() ? pImpEditEngine->GetTextHeight() : pImpEditEngine->CalcTextWidth( TRUE ); + return nHeight; +} + +sal_uInt32 EditEngine::CalcTextWidth() +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + sal_uInt32 nWidth = !IsVertical() ? pImpEditEngine->CalcTextWidth( TRUE ) : pImpEditEngine->GetTextHeight(); + return nWidth; +} + +void EditEngine::SetUpdateMode( sal_Bool bUpdate ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetUpdateMode( bUpdate ); + if ( pImpEditEngine->pActiveView ) + pImpEditEngine->pActiveView->ShowCursor( sal_False, sal_False ); +} + +sal_Bool EditEngine::GetUpdateMode() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetUpdateMode(); +} + +void EditEngine::Clear() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->Clear(); +} + +void EditEngine::SetText( const XubString& rText ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetText( rText ); + if ( rText.Len() ) + pImpEditEngine->FormatAndUpdate(); +} + +ULONG EditEngine::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, SvKeyValueIterator* pHTTPHeaderAttrs /* = NULL */ ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_Bool bUndoEnabled = pImpEditEngine->IsUndoEnabled(); + pImpEditEngine->EnableUndo( sal_False ); + pImpEditEngine->SetText( XubString() ); + EditPaM aPaM( pImpEditEngine->GetEditDoc().GetStartPaM() ); + pImpEditEngine->Read( rInput, rBaseURL, eFormat, EditSelection( aPaM, aPaM ), pHTTPHeaderAttrs ); + pImpEditEngine->EnableUndo( bUndoEnabled ); + return rInput.GetError(); +} + +ULONG EditEngine::Write( SvStream& rOutput, EETextFormat eFormat ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditPaM aStartPaM( pImpEditEngine->GetEditDoc().GetStartPaM() ); + EditPaM aEndPaM( pImpEditEngine->GetEditDoc().GetEndPaM() ); + pImpEditEngine->Write( rOutput, eFormat, EditSelection( aStartPaM, aEndPaM ) ); + return rOutput.GetError(); +} + +EditTextObject* EditEngine::CreateTextObject() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->CreateTextObject(); +} + +EditTextObject* EditEngine::CreateTextObject( const ESelection& rESelection ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine->CreateSel( rESelection ) ); + return pImpEditEngine->CreateTextObject( aSel ); +} + +void EditEngine::SetText( const EditTextObject& rTextObject ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EnterBlockNotifications(); + pImpEditEngine->SetText( rTextObject ); + pImpEditEngine->FormatAndUpdate(); + pImpEditEngine->LeaveBlockNotifications(); +} + +void EditEngine::ShowParagraph( sal_uInt16 nParagraph, sal_Bool bShow ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->ShowParagraph( nParagraph, bShow ); +} + +sal_Bool EditEngine::IsParagraphVisible( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsParagraphVisible( nParagraph ); +} + +void EditEngine::SetNotifyHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetNotifyHdl( rLink ); +} + +Link EditEngine::GetNotifyHdl() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetNotifyHdl(); +} + +void EditEngine::SetStatusEventHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetStatusEventHdl( rLink ); +} + +Link EditEngine::GetStatusEventHdl() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStatusEventHdl(); +} + +void EditEngine::SetImportHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aImportHdl = rLink; +} + +Link EditEngine::GetImportHdl() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aImportHdl; +} + +void EditEngine::SetBeginMovingParagraphsHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aBeginMovingParagraphsHdl = rLink; +} + +void EditEngine::SetEndMovingParagraphsHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aEndMovingParagraphsHdl = rLink; +} + +void EditEngine::SetBeginPasteOrDropHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + pImpEditEngine->aBeginPasteOrDropHdl = rLink; +} + +void EditEngine::SetEndPasteOrDropHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aEndPasteOrDropHdl = rLink; +} + +EditTextObject* EditEngine::CreateTextObject( sal_uInt16 nPara, sal_uInt16 nParas ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( nPara < pImpEditEngine->GetEditDoc().Count(), "CreateTextObject: Startpara out of Range" ); + DBG_ASSERT( nPara+nParas-1 < pImpEditEngine->GetEditDoc().Count(), "CreateTextObject: Endpara out of Range" ); + + ContentNode* pStartNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + ContentNode* pEndNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara+nParas-1 ); + DBG_ASSERT( pStartNode, "Start-Absatz existiert nicht: CreateTextObject" ); + DBG_ASSERT( pEndNode, "End-Absatz existiert nicht: CreateTextObject" ); + + if ( pStartNode && pEndNode ) + { + EditSelection aTmpSel; + aTmpSel.Min() = EditPaM( pStartNode, 0 ); + aTmpSel.Max() = EditPaM( pEndNode, pEndNode->Len() ); + return pImpEditEngine->CreateTextObject( aTmpSel ); + } + return 0; +} + +void EditEngine::RemoveParagraph( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( pImpEditEngine->GetEditDoc().Count() > 1, "Der erste Absatz darf nicht geloescht werden!" ); + if( pImpEditEngine->GetEditDoc().Count() <= 1 ) + return; + + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + DBG_ASSERT( pPortion && pNode, "Absatz nicht gefunden: RemoveParagraph" ); + if ( pNode && pPortion ) + { + // Keine Undokappselung noetig. + pImpEditEngine->ImpRemoveParagraph( nPara ); + pImpEditEngine->InvalidateFromParagraph( nPara ); + pImpEditEngine->UpdateSelections(); + pImpEditEngine->FormatAndUpdate(); + } +} + +sal_uInt16 EditEngine::GetTextLen( sal_uInt16 nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERT( pNode, "Absatz nicht gefunden: GetTextLen" ); + if ( pNode ) + return pNode->Len(); + return 0; +} + +XubString EditEngine::GetText( sal_uInt16 nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + XubString aStr; + if ( nPara < pImpEditEngine->GetEditDoc().Count() ) + aStr = pImpEditEngine->GetEditDoc().GetParaAsString( nPara ); + return aStr; +} + +void EditEngine::SetModifyHdl( const Link& rLink ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetModifyHdl( rLink ); +} + +Link EditEngine::GetModifyHdl() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetModifyHdl(); +} + + +void EditEngine::ClearModifyFlag() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetModifyFlag( sal_False ); +} + +void EditEngine::SetModified() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetModifyFlag( sal_True ); +} + +sal_Bool EditEngine::IsModified() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsModified(); +} + +sal_Bool EditEngine::IsInSelectionMode() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return ( pImpEditEngine->IsInSelectionMode() || + pImpEditEngine->GetSelEngine().IsInSelection() ); +} + +void EditEngine::StopSelectionMode() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->StopSelectionMode(); +} + +void EditEngine::InsertParagraph( sal_uInt16 nPara, const EditTextObject& rTxtObj ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( nPara > GetParagraphCount() ) + { + DBG_ASSERTWARNING( nPara == USHRT_MAX, "AbsatzNr zu Gro???, aber nicht LIST_APPEND! " ); + nPara = GetParagraphCount(); + } + + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + + // Keine Undoklammerung noetig. + EditPaM aPaM( pImpEditEngine->InsertParagraph( nPara ) ); + // Bei einem InsertParagraph von aussen sollen keine Harten + // Attribute uebernommen werden ! + pImpEditEngine->RemoveCharAttribs( nPara ); + pImpEditEngine->InsertText( rTxtObj, EditSelection( aPaM, aPaM ) ); + + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + + pImpEditEngine->FormatAndUpdate(); +} + +void EditEngine::InsertParagraph( sal_uInt16 nPara, const XubString& rTxt ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( nPara > GetParagraphCount() ) + { + DBG_ASSERTWARNING( nPara == USHRT_MAX, "AbsatzNr zu Gro???, aber nicht LIST_APPEND! " ); + nPara = GetParagraphCount(); + } + + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + EditPaM aPaM( pImpEditEngine->InsertParagraph( nPara ) ); + // Bei einem InsertParagraph von aussen sollen keine Harten + // Attribute uebernommen werden ! + pImpEditEngine->RemoveCharAttribs( nPara ); + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + pImpEditEngine->ImpInsertText( EditSelection( aPaM, aPaM ), rTxt ); + pImpEditEngine->FormatAndUpdate(); +} + +void EditEngine::SetText( sal_uInt16 nPara, const EditTextObject& rTxtObj ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection* pSel = pImpEditEngine->SelectParagraph( nPara ); + if ( pSel ) + { + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + pImpEditEngine->InsertText( rTxtObj, *pSel ); + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + pImpEditEngine->FormatAndUpdate(); + delete pSel; + } +} + +void EditEngine::SetText( sal_uInt16 nPara, const XubString& rTxt ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection* pSel = pImpEditEngine->SelectParagraph( nPara ); + if ( pSel ) + { + pImpEditEngine->UndoActionStart( EDITUNDO_INSERT ); + pImpEditEngine->ImpInsertText( *pSel, rTxt ); + pImpEditEngine->UndoActionEnd( EDITUNDO_INSERT ); + pImpEditEngine->FormatAndUpdate(); + delete pSel; + } +} + +void EditEngine::SetParaAttribs( sal_uInt16 nPara, const SfxItemSet& rSet ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + // Keine Undoklammerung noetig. + pImpEditEngine->SetParaAttribs( nPara, rSet ); + pImpEditEngine->FormatAndUpdate(); +} + +const SfxItemSet& EditEngine::GetParaAttribs( sal_uInt16 nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetParaAttribs( nPara ); +} + +sal_Bool EditEngine::HasParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->HasParaAttrib( nPara, nWhich ); +} + +const SfxPoolItem& EditEngine::GetParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetParaAttrib( nPara, nWhich ); +} + +void EditEngine::GetCharAttribs( sal_uInt16 nPara, EECharAttribArray& rLst ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->GetCharAttribs( nPara, rLst ); +} + +SfxItemSet EditEngine::GetAttribs( const ESelection& rSel, BOOL bOnlyHardAttrib ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + return pImpEditEngine->GetAttribs( aSel, bOnlyHardAttrib ); +} + +SfxItemSet EditEngine::GetAttribs( USHORT nPara, USHORT nStart, USHORT nEnd, sal_uInt8 nFlags ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetAttribs( nPara, nStart, nEnd, nFlags ); +} + +void EditEngine::RemoveAttribs( const ESelection& rSelection, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + pImpEditEngine->UndoActionStart( EDITUNDO_RESETATTRIBS ); + EditSelection aSel( pImpEditEngine->ConvertSelection( rSelection.nStartPara, rSelection.nStartPos, rSelection.nEndPara, rSelection.nEndPos ) ); + pImpEditEngine->RemoveCharAttribs( aSel, bRemoveParaAttribs, nWhich ); + pImpEditEngine->UndoActionEnd( EDITUNDO_RESETATTRIBS ); + pImpEditEngine->FormatAndUpdate(); +} + +// MT: Can be removed after 6.x? +Font EditEngine::GetStandardFont( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return GetStandardSvxFont( nPara ); +} + +SvxFont EditEngine::GetStandardSvxFont( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + return pNode->GetCharAttribs().GetDefFont(); +} + +void EditEngine::StripPortions() +{ + DBG_CHKTHIS( EditEngine, 0 ); + VirtualDevice aTmpDev; + Rectangle aBigRec( Point( 0, 0 ), Size( 0x7FFFFFFF, 0x7FFFFFFF ) ); + if ( IsVertical() ) + { + aBigRec.Right() = 0; + aBigRec.Left() = -0x7FFFFFFF; + } + pImpEditEngine->Paint( &aTmpDev, aBigRec, Point(), sal_True ); +} + +void EditEngine::GetPortions( sal_uInt16 nPara, SvUShorts& rList ) +{ + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatFullDoc(); + + ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + if ( pParaPortion ) + { + sal_uInt16 nEnd = 0; + sal_uInt16 nTextPortions = pParaPortion->GetTextPortions().Count(); + for ( sal_uInt16 n = 0; n < nTextPortions; n++ ) + { + nEnd = nEnd + pParaPortion->GetTextPortions()[n]->GetLen(); + rList.Insert( nEnd, rList.Count() ); + } + } +} + +void EditEngine::SetFlatMode( sal_Bool bFlat) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetFlatMode( bFlat ); +} + +sal_Bool EditEngine::IsFlatMode() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return !( pImpEditEngine->aStatus.UseCharAttribs() ); +} + +void EditEngine::SetControlWord( sal_uInt32 nWord ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( nWord != pImpEditEngine->aStatus.GetControlWord() ) + { + sal_uInt32 nPrev = pImpEditEngine->aStatus.GetControlWord(); + pImpEditEngine->aStatus.GetControlWord() = nWord; + + sal_uInt32 nChanges = nPrev ^ nWord; + if ( pImpEditEngine->IsFormatted() ) + { + // ggf. neu formatieren: + if ( ( nChanges & EE_CNTRL_USECHARATTRIBS ) || + ( nChanges & EE_CNTRL_USEPARAATTRIBS ) || + ( nChanges & EE_CNTRL_ONECHARPERLINE ) || + ( nChanges & EE_CNTRL_STRETCHING ) || + ( nChanges & EE_CNTRL_OUTLINER ) || + ( nChanges & EE_CNTRL_NOCOLORS ) || + ( nChanges & EE_CNTRL_OUTLINER2 ) ) + { + if ( ( nChanges & EE_CNTRL_USECHARATTRIBS ) || + ( nChanges & EE_CNTRL_USEPARAATTRIBS ) ) + { + sal_Bool bUseCharAttribs = ( nWord & EE_CNTRL_USECHARATTRIBS ) ? sal_True : sal_False; + pImpEditEngine->GetEditDoc().CreateDefFont( bUseCharAttribs ); + } + + pImpEditEngine->FormatFullDoc(); + pImpEditEngine->UpdateViews( pImpEditEngine->GetActiveView() ); + } + } + + sal_Bool bSpellingChanged = nChanges & EE_CNTRL_ONLINESPELLING ? sal_True : sal_False; + + if ( bSpellingChanged ) + { + pImpEditEngine->StopOnlineSpellTimer(); + if ( bSpellingChanged && ( nWord & EE_CNTRL_ONLINESPELLING ) ) + { + // WrongListen anlegen, Timer starten... + sal_uInt16 nNodes = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( n ); + pNode->CreateWrongList(); + } + pImpEditEngine->StartOnlineSpellTimer(); + } + else + { + long nY = 0; + sal_uInt16 nNodes = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( n ); + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().GetObject( n ); + sal_Bool bWrongs = ( bSpellingChanged || ( nWord & EE_CNTRL_ONLINESPELLING ) ) ? pNode->GetWrongList()->HasWrongs() : sal_False; + if ( bSpellingChanged ) // Also aus + pNode->DestroyWrongList(); // => vorm Paint weghaun. + if ( bWrongs ) + { + pImpEditEngine->aInvalidRec.Left() = 0; + pImpEditEngine->aInvalidRec.Right() = pImpEditEngine->GetPaperSize().Width(); + pImpEditEngine->aInvalidRec.Top() = nY+1; + pImpEditEngine->aInvalidRec.Bottom() = nY+pPortion->GetHeight()-1; + pImpEditEngine->UpdateViews( pImpEditEngine->pActiveView ); + } + nY += pPortion->GetHeight(); + } + } + } + } +} + +sal_uInt32 EditEngine::GetControlWord() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aStatus.GetControlWord(); +} + +long EditEngine::GetFirstLineStartX( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + long nX = 0; + ParaPortion* pPPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nParagraph ); + if ( pPPortion ) + { + DBG_ASSERT( pImpEditEngine->IsFormatted() || !pImpEditEngine->IsFormatting(), "GetFirstLineStartX: Doc not formatted - unable to format!" ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + EditLine* pFirstLine = pPPortion->GetLines()[0]; + nX = pFirstLine->GetStartPosX(); + } + return nX; +} + +Point EditEngine::GetDocPos( const Point& rPaperPos ) const +{ + Point aDocPos( rPaperPos ); + if ( IsVertical() ) + { + aDocPos.X() = rPaperPos.Y(); + aDocPos.Y() = GetPaperSize().Width() - rPaperPos.X(); + } + return aDocPos; +} + +Point EditEngine::GetDocPosTopLeft( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + ParaPortion* pPPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetWindowPosTopLeft" ); + Point aPoint; + if ( pPPortion ) + { + // Falls jemand mit einer leeren Engine ein GetLineHeight() macht. + DBG_ASSERT( pImpEditEngine->IsFormatted() || !pImpEditEngine->IsFormatting(), "GetDocPosTopLeft: Doc not formatted - unable to format!" ); + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatAndUpdate(); + if ( pPPortion->GetLines().Count() ) + { + // So richtiger, falls grosses Bullet. + EditLine* pFirstLine = pPPortion->GetLines()[0]; + aPoint.X() = pFirstLine->GetStartPosX(); + } + else + { + const SvxLRSpaceItem& rLRItem = pImpEditEngine->GetLRSpaceItem( pPPortion->GetNode() ); +// TL_NF_LR aPoint.X() = pImpEditEngine->GetXValue( (short)(rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst()) ); + sal_Int32 nSpaceBefore = 0; + pImpEditEngine->GetSpaceBeforeAndMinLabelWidth( pPPortion->GetNode(), &nSpaceBefore ); + short nX = (short)(rLRItem.GetTxtLeft() + + rLRItem.GetTxtFirstLineOfst() + + nSpaceBefore); + aPoint.X() = pImpEditEngine->GetXValue( nX + ); + } + aPoint.Y() = pImpEditEngine->GetParaPortions().GetYOffset( pPPortion ); + } + return aPoint; +} + +const SvxNumberFormat* EditEngine::GetNumberFormat( USHORT nPara ) const +{ + // derived objects may overload this function to give access to + // bullet information (see Outliner) + (void) nPara; + return 0; +} + +BOOL EditEngine::IsRightToLeft( USHORT nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->IsRightToLeft( nPara ); +} + +sal_Bool EditEngine::IsTextPos( const Point& rPaperPos, sal_uInt16 nBorder ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + sal_Bool bTextPos = sal_False; + // #90780# take unrotated positions for calculation here + Point aDocPos = GetDocPos( rPaperPos ); + + if ( ( aDocPos.Y() > 0 ) && ( aDocPos.Y() < (long)pImpEditEngine->GetTextHeight() ) ) + { + EditPaM aPaM = pImpEditEngine->GetPaM( aDocPos, sal_False ); + if ( aPaM.GetNode() ) + { + ParaPortion* pParaPortion = pImpEditEngine->FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pParaPortion, "ParaPortion?" ); + + sal_uInt16 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex() ); + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + Range aLineXPosStartEnd = pImpEditEngine->GetLineXPosStartEnd( pParaPortion, pLine ); + if ( ( aDocPos.X() >= aLineXPosStartEnd.Min() - nBorder ) && + ( aDocPos.X() <= aLineXPosStartEnd.Max() + nBorder ) ) + { + bTextPos = sal_True; + } + } + } + return bTextPos; +} + +void EditEngine::SetEditTextObjectPool( SfxItemPool* pPool ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetEditTextObjectPool( pPool ); +} + +SfxItemPool* EditEngine::GetEditTextObjectPool() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetEditTextObjectPool(); +} + +void EditEngine::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->SetAttribs( aSel, rSet ); +} + +void EditEngine::QuickMarkInvalid( const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( rSel.nStartPara < pImpEditEngine->GetEditDoc().Count(), "MarkInvalid: Start out of Range!" ); + DBG_ASSERT( rSel.nEndPara < pImpEditEngine->GetEditDoc().Count(), "MarkInvalid: End out of Range!" ); + for ( sal_uInt16 nPara = rSel.nStartPara; nPara <= rSel.nEndPara; nPara++ ) + { + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + if ( pPortion ) + pPortion->MarkSelectionInvalid( 0, pPortion->GetNode()->Len() ); + } +} + +void EditEngine::QuickInsertText( const XubString& rText, const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->ImpInsertText( aSel, rText ); +} + +void EditEngine::QuickDelete( const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->ImpDeleteSelection( aSel ); +} + +void EditEngine::QuickMarkToBeRepainted( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + ParaPortion* pPortion = pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + if ( pPortion ) + pPortion->SetMustRepaint( sal_True ); +} + +void EditEngine::QuickInsertLineBreak( const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->InsertLineBreak( aSel ); +} + +void EditEngine::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + EditSelection aSel( pImpEditEngine-> + ConvertSelection( rSel.nStartPara, rSel.nStartPos, rSel.nEndPara, rSel.nEndPos ) ); + + pImpEditEngine->ImpInsertFeature( aSel, rFld ); +} + +void EditEngine::QuickFormatDoc( sal_Bool bFull ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( bFull ) + pImpEditEngine->FormatFullDoc(); + else + pImpEditEngine->FormatDoc(); + + // #111072# Don't pass active view, maybe selection is not updated yet... + pImpEditEngine->UpdateViews( NULL ); +} + +void EditEngine::QuickRemoveCharAttribs( sal_uInt16 nPara, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->RemoveCharAttribs( nPara, nWhich ); +} + +void EditEngine::SetStyleSheet( sal_uInt16 nPara, SfxStyleSheet* pStyle ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetStyleSheet( nPara, pStyle ); +} + +SfxStyleSheet* EditEngine::GetStyleSheet( sal_uInt16 nPara ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStyleSheet( nPara ); +} + +void EditEngine::SetStyleSheetPool( SfxStyleSheetPool* pSPool ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetStyleSheetPool( pSPool ); +} + +SfxStyleSheetPool* EditEngine::GetStyleSheetPool() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStyleSheetPool(); +} + +void EditEngine::SetWordDelimiters( const XubString& rDelimiters ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->aWordDelimiters = rDelimiters; + if ( pImpEditEngine->aWordDelimiters.Search( CH_FEATURE ) == STRING_NOTFOUND ) + pImpEditEngine->aWordDelimiters.Insert( CH_FEATURE ); +} + +XubString EditEngine::GetWordDelimiters() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aWordDelimiters; +} + +void EditEngine::SetGroupChars( const XubString& rChars ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + DBG_ASSERT( ( rChars.Len() % 2 ) == 0, "SetGroupChars: Ungerade Anzahl!" ); + pImpEditEngine->aGroupChars = rChars; +} + +XubString EditEngine::GetGroupChars() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->aGroupChars; +} + +void EditEngine::EnablePasteSpecial( sal_Bool bEnable ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( bEnable ) + pImpEditEngine->GetStatus().TurnOnFlags( EE_CNTRL_PASTESPECIAL ); + else + pImpEditEngine->GetStatus().TurnOffFlags( EE_CNTRL_PASTESPECIAL ); +} + +sal_Bool EditEngine::IsPasteSpecialEnabled() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStatus().AllowPasteSpecial(); +} + +void EditEngine::EnableIdleFormatter( sal_Bool bEnable ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( bEnable ) + pImpEditEngine->GetStatus().TurnOnFlags( EE_CNTRL_DOIDLEFORMAT ); + else + pImpEditEngine->GetStatus().TurnOffFlags( EE_CNTRL_DOIDLEFORMAT); +} + +sal_Bool EditEngine::IsIdleFormatterEnabled() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetStatus().UseIdleFormatter(); +} + +void EditEngine::EraseVirtualDevice() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EraseVirtualDevice(); +} + +void EditEngine::SetSpeller( Reference< XSpellChecker1 > &xSpeller ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetSpeller( xSpeller ); +} +Reference< XSpellChecker1 > EditEngine::GetSpeller() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetSpeller(); +} +Reference< XHyphenator > EditEngine::GetHyphenator() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetHyphenator(); +} + +void EditEngine::SetHyphenator( Reference< XHyphenator > & xHyph ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetHyphenator( xHyph ); +} + +void EditEngine::SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetForbiddenCharsTable( xForbiddenChars ); +} + +vos::ORef<SvxForbiddenCharactersTable> EditEngine::GetForbiddenCharsTable() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetForbiddenCharsTable( FALSE ); +} + + +void EditEngine::SetDefaultLanguage( LanguageType eLang ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetDefaultLanguage( eLang ); +} + +LanguageType EditEngine::GetDefaultLanguage() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetDefaultLanguage(); +} + +sal_Bool __EXPORT EditEngine::SpellNextDocument() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return sal_False; +} + +EESpellState EditEngine::HasSpellErrors() +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( !pImpEditEngine->GetSpeller().is() ) + return EE_SPELL_NOSPELLER; + + return pImpEditEngine->HasSpellErrors(); +} +/*-- 13.10.2003 16:56:23--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void EditEngine::StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->StartSpelling(rEditView, bMultipleDoc); +} +/*-- 13.10.2003 16:56:23--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void EditEngine::EndSpelling() +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->EndSpelling(); +} + +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +bool EditEngine::SpellSentence(EditView& rView, ::svx::SpellPortions& rToFill, bool bIsGrammarChecking ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->SpellSentence( rView, rToFill, bIsGrammarChecking ); +} +/*-- 08.09.2008 11:38:32--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void EditEngine::PutSpellingToSentenceStart( EditView& rEditView ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->PutSpellingToSentenceStart( rEditView ); +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void EditEngine::ApplyChangedSentence(EditView& rEditView, const ::svx::SpellPortions& rNewPortions, bool bIsGrammarChecking ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->ApplyChangedSentence( rEditView, rNewPortions, bIsGrammarChecking ); +} + +sal_Bool EditEngine::HasConvertibleTextPortion( LanguageType nLang ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->HasConvertibleTextPortion( nLang ); +} + +sal_Bool __EXPORT EditEngine::ConvertNextDocument() +{ + DBG_CHKTHIS( EditEngine, 0 ); + return sal_False; +} + +sal_Bool EditEngine::HasText( const SvxSearchItem& rSearchItem ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->HasText( rSearchItem ); +} + +void EditEngine::SetGlobalCharStretching( sal_uInt16 nX, sal_uInt16 nY ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetCharStretching( nX, nY ); +} + +void EditEngine::GetGlobalCharStretching( sal_uInt16& rX, sal_uInt16& rY ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->GetCharStretching( rX, rY ); +} + +void EditEngine::DoStretchChars( sal_uInt16 nX, sal_uInt16 nY ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->DoStretchChars( nX, nY ); +} + +void EditEngine::SetBigTextObjectStart( sal_uInt16 nStartAtPortionCount ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + pImpEditEngine->SetBigTextObjectStart( nStartAtPortionCount ); +} + +sal_uInt16 EditEngine::GetBigTextObjectStart() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + return pImpEditEngine->GetBigTextObjectStart(); +} + +sal_Bool EditEngine::ShouldCreateBigTextObject() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_uInt16 nTextPortions = 0; + sal_uInt16 nParas = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 nPara = 0; nPara < nParas; nPara++ ) + { + ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions()[nPara]; + nTextPortions = nTextPortions + pParaPortion->GetTextPortions().Count(); + } + return ( nTextPortions >= pImpEditEngine->GetBigTextObjectStart() ) ? sal_True : sal_False; +} + +USHORT EditEngine::GetFieldCount( USHORT nPara ) const +{ + USHORT nFields = 0; + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + if ( pNode ) + { + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( sal_uInt16 nAttr = 0; nAttr < rAttrs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttrs[nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + nFields++; + } + } + + return nFields; +} + +EFieldInfo EditEngine::GetFieldInfo( USHORT nPara, USHORT nField ) const +{ + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + if ( pNode ) + { + USHORT nCurrentField = 0; + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( sal_uInt16 nAttr = 0; nAttr < rAttrs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttrs[nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + if ( nCurrentField == nField ) + { + EFieldInfo aInfo( *(const SvxFieldItem*)pAttr->GetItem(), nPara, pAttr->GetStart() ); + aInfo.aCurrentText = ((EditCharAttribField*)pAttr)->GetFieldValue(); + return aInfo; + } + + nCurrentField++; + } + } + } + return EFieldInfo(); +} + + +sal_Bool EditEngine::UpdateFields() +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_Bool bChanges = pImpEditEngine->UpdateFields(); + if ( bChanges ) + pImpEditEngine->FormatAndUpdate(); + return bChanges; +} + +void EditEngine::RemoveFields( sal_Bool bKeepFieldText, TypeId aType ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( bKeepFieldText ) + pImpEditEngine->UpdateFields(); + + sal_uInt16 nParas = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 nPara = 0; nPara < nParas; nPara++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( nPara ); + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( sal_uInt16 nAttr = rAttrs.Count(); nAttr; ) + { + const EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + const SvxFieldData* pFldData = ((const SvxFieldItem*)pAttr->GetItem())->GetField(); + if ( pFldData && ( !aType || ( pFldData->IsA( aType ) ) ) ) + { + DBG_ASSERT( pAttr->GetItem()->ISA( SvxFieldItem ), "Kein FeldItem..." ); + EditSelection aSel( EditPaM( pNode, pAttr->GetStart() ), EditPaM( pNode, pAttr->GetEnd() ) ); + String aFieldText = ((EditCharAttribField*)pAttr)->GetFieldValue(); + pImpEditEngine->ImpInsertText( aSel, aFieldText ); + } + } + } + } +} + +sal_Bool EditEngine::HasOnlineSpellErrors() const +{ + DBG_CHKTHIS( EditEngine, 0 ); + sal_uInt16 nNodes = pImpEditEngine->GetEditDoc().Count(); + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( n ); + if ( pNode->GetWrongList() && pNode->GetWrongList()->Count() ) + return sal_True; + } + return sal_False; +} + +void EditEngine::CompleteOnlineSpelling() +{ + DBG_CHKTHIS( EditEngine, 0 ); + if ( pImpEditEngine->GetStatus().DoOnlineSpelling() ) + { + if( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatAndUpdate(); + + pImpEditEngine->StopOnlineSpellTimer(); + pImpEditEngine->DoOnlineSpelling( 0, sal_True, sal_False ); + } +} + +USHORT EditEngine::FindParagraph( long nDocPosY ) +{ + return pImpEditEngine->GetParaPortions().FindParagraph( nDocPosY ); +} + +EPosition EditEngine::FindDocPosition( const Point& rDocPos ) const +{ + EPosition aPos; + // From the point of the API, this is const.... + EditPaM aPaM = ((EditEngine*)this)->pImpEditEngine->GetPaM( rDocPos, FALSE ); + if ( aPaM.GetNode() ) + { + aPos.nPara = pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + aPos.nIndex = aPaM.GetIndex(); + } + return aPos; +} + +Rectangle EditEngine::GetCharacterBounds( const EPosition& rPos ) const +{ + Rectangle aBounds; + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( rPos.nPara ); + + // #109151# Check against index, not paragraph + if ( pNode && ( rPos.nIndex < pNode->Len() ) ) + { + aBounds = pImpEditEngine->PaMtoEditCursor( EditPaM( pNode, rPos.nIndex ), GETCRSR_TXTONLY ); + Rectangle aR2 = pImpEditEngine->PaMtoEditCursor( EditPaM( pNode, rPos.nIndex+1 ), GETCRSR_TXTONLY|GETCRSR_ENDOFLINE ); + if ( aR2.Right() > aBounds.Right() ) + aBounds.Right() = aR2.Right(); + } + return aBounds; +} + +ParagraphInfos EditEngine::GetParagraphInfos( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + // Funktioniert nur, wenn nicht bereits in der Formatierung... + if ( !pImpEditEngine->IsFormatted() ) + pImpEditEngine->FormatDoc(); + + ParagraphInfos aInfos; + aInfos.bValid = pImpEditEngine->IsFormatted(); + if ( pImpEditEngine->IsFormatted() ) + { + ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions()[nPara]; + EditLine* pLine = (pParaPortion && pParaPortion->GetLines().Count()) ? + pParaPortion->GetLines().GetObject( 0 ) : NULL; + DBG_ASSERT( pParaPortion && pLine, "GetParagraphInfos - Paragraph out of range" ); + if ( pParaPortion && pLine ) + { + aInfos.nParaHeight = (USHORT)pParaPortion->GetHeight(); + aInfos.nLines = pParaPortion->GetLines().Count(); + aInfos.nFirstLineStartX = pLine->GetStartPosX(); + aInfos.nFirstLineOffset = pParaPortion->GetFirstLineOffset(); + aInfos.nFirstLineHeight = pLine->GetHeight(); + aInfos.nFirstLineTextHeight = pLine->GetTxtHeight(); + aInfos.nFirstLineMaxAscent = pLine->GetMaxAscent(); + } + } + return aInfos; +} + +::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > + EditEngine::CreateTransferable( const ESelection& rSelection ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + EditSelection aSel( pImpEditEngine->CreateSel( rSelection ) ); + return pImpEditEngine->CreateTransferable( aSel ); +} + +// ===================================================================== +// ====================== Virtuelle Methoden ======================= +// ===================================================================== +void __EXPORT EditEngine::DrawingText( const Point&, const XubString&, USHORT, USHORT, + const sal_Int32*, const SvxFont&, sal_uInt16, sal_uInt16, BYTE, + const EEngineData::WrongSpellVector*, const SvxFieldData*, bool, bool, bool, + const ::com::sun::star::lang::Locale*, const Color&, const Color&) + +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::PaintingFirstLine( sal_uInt16, const Point&, long, const Point&, short, OutputDevice* ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::ParagraphInserted( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_PARAGRAPHINSERTED ); + aNotify.pEditEngine = this; + aNotify.nParagraph = nPara; + pImpEditEngine->CallNotify( aNotify ); + } +} + +void __EXPORT EditEngine::ParagraphDeleted( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_PARAGRAPHREMOVED ); + aNotify.pEditEngine = this; + aNotify.nParagraph = nPara; + pImpEditEngine->CallNotify( aNotify ); + } +} +void EditEngine::ParagraphConnected( USHORT /*nLeftParagraph*/, USHORT /*nRightParagraph*/ ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +sal_Bool __EXPORT EditEngine::FormattingParagraph( sal_uInt16 ) +{ + // return sal_True, wenn die Attribute geaendert wurden... + DBG_CHKTHIS( EditEngine, 0 ); + return sal_False; +} + +void __EXPORT EditEngine::ParaAttribsChanged( sal_uInt16 /* nParagraph */ ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::StyleSheetChanged( SfxStyleSheet* /* pStyle */ ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::ParagraphHeightChanged( sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_TEXTHEIGHTCHANGED ); + aNotify.pEditEngine = this; + aNotify.nParagraph = nPara; + pImpEditEngine->CallNotify( aNotify ); + } +} + +XubString __EXPORT EditEngine::GetUndoComment( sal_uInt16 nId ) const +{ + DBG_CHKTHIS( EditEngine, 0 ); + XubString aComment; + switch ( nId ) + { + case EDITUNDO_REMOVECHARS: + case EDITUNDO_CONNECTPARAS: + case EDITUNDO_REMOVEFEATURE: + case EDITUNDO_DELCONTENT: + case EDITUNDO_DELETE: + case EDITUNDO_CUT: + aComment = XubString( EditResId( RID_EDITUNDO_DEL ) ); + break; + case EDITUNDO_MOVEPARAGRAPHS: + case EDITUNDO_MOVEPARAS: + case EDITUNDO_DRAGANDDROP: + aComment = XubString( EditResId( RID_EDITUNDO_MOVE ) ); + break; + case EDITUNDO_INSERTFEATURE: + case EDITUNDO_SPLITPARA: + case EDITUNDO_INSERTCHARS: + case EDITUNDO_PASTE: + case EDITUNDO_INSERT: + case EDITUNDO_READ: + aComment = XubString( EditResId( RID_EDITUNDO_INSERT ) ); + break; + case EDITUNDO_SRCHANDREPL: + case EDITUNDO_REPLACEALL: + aComment = XubString( EditResId( RID_EDITUNDO_REPLACE ) ); + break; + case EDITUNDO_ATTRIBS: + case EDITUNDO_PARAATTRIBS: + case EDITUNDO_STRETCH: + aComment = XubString( EditResId( RID_EDITUNDO_SETATTRIBS ) ); + break; + case EDITUNDO_RESETATTRIBS: + aComment = XubString( EditResId( RID_EDITUNDO_RESETATTRIBS ) ); + break; + case EDITUNDO_STYLESHEET: + aComment = XubString( EditResId( RID_EDITUNDO_SETSTYLE ) ); + break; + case EDITUNDO_TRANSLITERATE: + aComment = XubString( EditResId( RID_EDITUNDO_TRANSLITERATE ) ); + break; + case EDITUNDO_INDENTBLOCK: + case EDITUNDO_UNINDENTBLOCK: + aComment = XubString( EditResId( RID_EDITUNDO_INDENT ) ); + break; + } + return aComment; +} + +Rectangle EditEngine::GetBulletArea( sal_uInt16 ) +{ + return Rectangle( Point(), Point() ); +} + +XubString __EXPORT EditEngine::CalcFieldValue( const SvxFieldItem&, sal_uInt16, sal_uInt16, Color*&, Color*& ) +{ + DBG_CHKTHIS( EditEngine, 0 ); + return ' '; +} + +void __EXPORT EditEngine::FieldClicked( const SvxFieldItem&, sal_uInt16, sal_uInt16 ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +void __EXPORT EditEngine::FieldSelected( const SvxFieldItem&, sal_uInt16, sal_uInt16 ) +{ + DBG_CHKTHIS( EditEngine, 0 ); +} + +// ===================================================================== +// ====================== Statische Methoden ======================= +// ===================================================================== +SfxItemPool* EditEngine::CreatePool( sal_Bool bPersistentRefCounts ) +{ + SfxItemPool* pPool = new EditEngineItemPool( bPersistentRefCounts ); + return pPool; +} + +SfxItemPool& EditEngine::GetGlobalItemPool() +{ + if ( !pGlobalPool ) + pGlobalPool = CreatePool(); + return *pGlobalPool; +} + +sal_uInt32 EditEngine::RegisterClipboardFormatName() +{ + static sal_uInt32 nFormat = 0; + if ( !nFormat ) + nFormat = SotExchange::RegisterFormatName( String( RTL_CONSTASCII_USTRINGPARAM( "EditEngineFormat" ) ) ); + return nFormat; +} + +sal_uInt16 EditEngine::GetAvailableSearchOptions() +{ + return SEARCH_OPTIONS_SEARCH | SEARCH_OPTIONS_REPLACE | + SEARCH_OPTIONS_REPLACE_ALL | SEARCH_OPTIONS_WHOLE_WORDS | + SEARCH_OPTIONS_BACKWARDS | SEARCH_OPTIONS_REG_EXP | + SEARCH_OPTIONS_EXACT | SEARCH_OPTIONS_SELECTION; +} + +void EditEngine::SetFontInfoInItemSet( SfxItemSet& rSet, const Font& rFont ) +{ + SvxFont aSvxFont( rFont ); + SetFontInfoInItemSet( rSet, aSvxFont ); + +} + +void EditEngine::SetFontInfoInItemSet( SfxItemSet& rSet, const SvxFont& rFont ) +{ + rSet.Put( SvxLanguageItem( rFont.GetLanguage(), EE_CHAR_LANGUAGE ) ); + rSet.Put( SvxFontItem( rFont.GetFamily(), rFont.GetName(), XubString(), rFont.GetPitch(), rFont.GetCharSet(), EE_CHAR_FONTINFO ) ); + rSet.Put( SvxFontHeightItem( rFont.GetSize().Height(), 100, EE_CHAR_FONTHEIGHT ) ); + rSet.Put( SvxCharScaleWidthItem( 100, EE_CHAR_FONTWIDTH ) ); + rSet.Put( SvxShadowedItem( rFont.IsShadow(), EE_CHAR_SHADOW ) ); + rSet.Put( SvxEscapementItem( rFont.GetEscapement(), rFont.GetPropr(), EE_CHAR_ESCAPEMENT ) ); + rSet.Put( SvxWeightItem( rFont.GetWeight(), EE_CHAR_WEIGHT ) ); + rSet.Put( SvxColorItem( rFont.GetColor(), EE_CHAR_COLOR ) ); + rSet.Put( SvxUnderlineItem( rFont.GetUnderline(), EE_CHAR_UNDERLINE ) ); + rSet.Put( SvxOverlineItem( rFont.GetOverline(), EE_CHAR_OVERLINE ) ); + rSet.Put( SvxCrossedOutItem( rFont.GetStrikeout(), EE_CHAR_STRIKEOUT ) ); + rSet.Put( SvxPostureItem( rFont.GetItalic(), EE_CHAR_ITALIC ) ); + rSet.Put( SvxContourItem( rFont.IsOutline(), EE_CHAR_OUTLINE ) ); + rSet.Put( SvxAutoKernItem( rFont.IsKerning(), EE_CHAR_PAIRKERNING ) ); + rSet.Put( SvxKerningItem( rFont.GetFixKerning(), EE_CHAR_KERNING ) ); + rSet.Put( SvxWordLineModeItem( rFont.IsWordLineMode(), EE_CHAR_WLM ) ); + rSet.Put( SvxEmphasisMarkItem( rFont.GetEmphasisMark(), EE_CHAR_EMPHASISMARK ) ); + rSet.Put( SvxCharReliefItem( rFont.GetRelief(), EE_CHAR_RELIEF ) ); +} + +Font EditEngine::CreateFontFromItemSet( const SfxItemSet& rItemSet, USHORT nScriptType ) +{ + SvxFont aFont; + CreateFont( aFont, rItemSet, true, nScriptType ); + return aFont; +} + +// Maybe we can remove the next two methods, check after 6.x +Font EditEngine::CreateFontFromItemSet( const SfxItemSet& rItemSet ) +{ + return CreateSvxFontFromItemSet( rItemSet ); +} + +SvxFont EditEngine::CreateSvxFontFromItemSet( const SfxItemSet& rItemSet ) +{ + SvxFont aFont; + CreateFont( aFont, rItemSet ); + return aFont; +} + +sal_Bool EditEngine::DoesKeyMoveCursor( const KeyEvent& rKeyEvent ) +{ + sal_Bool bDoesMove = sal_False; + + switch ( rKeyEvent.GetKeyCode().GetCode() ) + { + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + case KEY_HOME: + case KEY_END: + case KEY_PAGEUP: + case KEY_PAGEDOWN: + { + if ( !rKeyEvent.GetKeyCode().IsMod2() ) + bDoesMove = sal_True; + } + break; + } + return bDoesMove; +} + +sal_Bool EditEngine::DoesKeyChangeText( const KeyEvent& rKeyEvent ) +{ + sal_Bool bDoesChange = sal_False; + + KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_UNDO: + case KEYFUNC_REDO: + case KEYFUNC_CUT: + case KEYFUNC_PASTE: bDoesChange = sal_True; + break; + default: // wird dann evtl. unten bearbeitet. + eFunc = KEYFUNC_DONTKNOW; + } + } + if ( eFunc == KEYFUNC_DONTKNOW ) + { + switch ( rKeyEvent.GetKeyCode().GetCode() ) + { + case KEY_DELETE: + case KEY_BACKSPACE: bDoesChange = sal_True; + break; + case KEY_RETURN: + case KEY_TAB: + { + if ( !rKeyEvent.GetKeyCode().IsMod1() && !rKeyEvent.GetKeyCode().IsMod2() ) + bDoesChange = sal_True; + } + break; + default: + { + bDoesChange = IsSimpleCharInput( rKeyEvent ); + } + } + } + return bDoesChange; +} + +sal_Bool EditEngine::IsSimpleCharInput( const KeyEvent& rKeyEvent ) +{ + if( EditEngine::IsPrintable( rKeyEvent.GetCharCode() ) && + ( KEY_MOD2 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT ) ) && + ( KEY_MOD1 != (rKeyEvent.GetKeyCode().GetModifier() & ~KEY_SHIFT ) ) ) + { + return sal_True; + } + return sal_False; +} + +// Mal in den Outliner schieben... +void EditEngine::ImportBulletItem( SvxNumBulletItem& /*rNumBullet*/, sal_uInt16 /*nLevel*/, + const SvxBulletItem* /*pOldBullet*/, const SvxLRSpaceItem* /*pOldLRSpace*/ ) +{ +/* TL_NFLR + if ( pOldBullet || pOldLRSpace ) + { + // Numberformat dynamisch, weil Zuweisungsoperator nicht implementiert. + + // Altes NumBulletItem nur uebernehmen, wenn kein altes BulletItem + const SvxNumberFormat* pFmt = ( !pOldBullet && ( rNumBullet.GetNumRule()->GetLevelCount() > nLevel ) ) ? + rNumBullet.GetNumRule()->Get( nLevel ) : NULL; + SvxNumberFormat* pNumberFormat = pFmt + ? new SvxNumberFormat( *pFmt ) + : new SvxNumberFormat( SVX_NUM_NUMBER_NONE ); + if ( pOldBullet ) + { + // Style + SvxExtNumType eNumType; + switch( pOldBullet->GetStyle() ) + { + case BS_BMP: eNumType = SVX_NUM_BITMAP; break; + case BS_BULLET: eNumType = SVX_NUM_CHAR_SPECIAL; break; + case BS_ROMAN_BIG: eNumType = SVX_NUM_ROMAN_UPPER; break; + case BS_ROMAN_SMALL: eNumType = SVX_NUM_ROMAN_LOWER; break; + case BS_ABC_BIG: eNumType = SVX_NUM_CHARS_UPPER_LETTER; break; + case BS_ABC_SMALL: eNumType = SVX_NUM_CHARS_LOWER_LETTER; break; + case BS_123: eNumType = SVX_NUM_ARABIC; break; + default: eNumType = SVX_NUM_NUMBER_NONE; break; + } + pNumberFormat->SetNumberingType( + sal::static_int_cast< sal_Int16 >( eNumType ) ); + + // Justification + SvxAdjust eAdjust; + switch( pOldBullet->GetJustification() & (BJ_HRIGHT|BJ_HCENTER|BJ_HLEFT) ) + { + case BJ_HRIGHT: eAdjust = SVX_ADJUST_RIGHT; break; + case BJ_HCENTER: eAdjust = SVX_ADJUST_CENTER; break; + default: eAdjust = SVX_ADJUST_LEFT; break; + } + pNumberFormat->SetNumAdjust(eAdjust); + + // Prefix/Suffix + pNumberFormat->SetPrefix( pOldBullet->GetPrevText() ); + pNumberFormat->SetSuffix( pOldBullet->GetFollowText() ); + + //Font + if ( eNumType != SVX_NUM_BITMAP ) + { + Font aTmpFont = pOldBullet->GetFont(); + pNumberFormat->SetBulletFont( &aTmpFont ); + } + + // Color + pNumberFormat->SetBulletColor( pOldBullet->GetFont().GetColor() ); + + // Start + pNumberFormat->SetStart( pOldBullet->GetStart() ); + + // Scale + pNumberFormat->SetBulletRelSize( pOldBullet->GetScale() ); + + // Bullet/Bitmap + if( eNumType == SVX_NUM_CHAR_SPECIAL ) + { + pNumberFormat->SetBulletChar( pOldBullet->GetSymbol() ); + } + else if( eNumType == SVX_NUM_BITMAP ) + { + SvxBrushItem aBItem( Graphic( pOldBullet->GetBitmap() ), GPOS_NONE, SID_ATTR_BRUSH ); + pNumberFormat->SetGraphicBrush( &aBItem ); + } + } + + // Einzug und Erstzeileneinzug +//TL_NFLR if ( pOldLRSpace ) +//TL_NFLR { +//TL_NFLR short nLSpace = (short)pOldLRSpace->GetTxtLeft(); +//TL_NFLR pNumberFormat->SetLSpace( nLSpace ); +//TL_NFLR pNumberFormat->SetAbsLSpace( nLSpace ); +//TL_NFLR pNumberFormat->SetFirstLineOffset( pOldLRSpace->GetTxtFirstLineOfst() ); +//TL_NFLR } + + rNumBullet.GetNumRule()->SetLevel( nLevel, *pNumberFormat ); + delete pNumberFormat; + } +*/ +} + +BOOL EditEngine::HasValidData( const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& rTransferable ) +{ + BOOL bValidData = FALSE; + + if ( rTransferable.is() ) + { + // Every application that copies rtf or any other text format also copies plain text into the clipboard.... + datatransfer::DataFlavor aFlavor; + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); + bValidData = rTransferable->isDataFlavorSupported( aFlavor ); + } + + return bValidData; +} + +/** sets a link that is called at the beginning of a drag operation at an edit view */ +void EditEngine::SetBeginDropHdl( const Link& rLink ) +{ + pImpEditEngine->SetBeginDropHdl( rLink ); +} + +Link EditEngine::GetBeginDropHdl() const +{ + return pImpEditEngine->GetBeginDropHdl(); +} + +/** sets a link that is called at the end of a drag operation at an edit view */ +void EditEngine::SetEndDropHdl( const Link& rLink ) +{ + pImpEditEngine->SetEndDropHdl( rLink ); +} + +Link EditEngine::GetEndDropHdl() const +{ + return pImpEditEngine->GetEndDropHdl(); +} + +void EditEngine::SetFirstWordCapitalization( BOOL bCapitalize ) +{ + pImpEditEngine->SetFirstWordCapitalization( bCapitalize ); +} + +BOOL EditEngine::IsFirstWordCapitalization() const +{ + return pImpEditEngine->IsFirstWordCapitalization(); +} + + +// --------------------------------------------------- + + +EFieldInfo::EFieldInfo() +{ + pFieldItem = NULL; +} + + +EFieldInfo::EFieldInfo( const SvxFieldItem& rFieldItem, USHORT nPara, USHORT nPos ) : aPosition( nPara, nPos ) +{ + pFieldItem = new SvxFieldItem( rFieldItem ); +} + +EFieldInfo::~EFieldInfo() +{ + delete pFieldItem; +} + +EFieldInfo::EFieldInfo( const EFieldInfo& rFldInfo ) +{ + *this = rFldInfo; +} + +EFieldInfo& EFieldInfo::operator= ( const EFieldInfo& rFldInfo ) +{ + if( this == &rFldInfo ) + return *this; + + pFieldItem = rFldInfo.pFieldItem ? new SvxFieldItem( *rFldInfo.pFieldItem ) : 0; + aCurrentText = rFldInfo.aCurrentText; + aPosition = rFldInfo.aPosition; + + return *this; +} diff --git a/editeng/source/editeng/editeng.src b/editeng/source/editeng/editeng.src new file mode 100644 index 000000000000..24c366e63ccc --- /dev/null +++ b/editeng/source/editeng/editeng.src @@ -0,0 +1,127 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editeng.src,v $ + * $Revision: 1.47 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <editeng.hrc> +#include <helpid.hrc> + +String RID_EDITUNDO_DEL +{ + Text [ en-US ] = "Delete" ; +}; + +String RID_EDITUNDO_MOVE +{ + Text [ en-US ] = "Move" ; +}; + +String RID_EDITUNDO_INSERT +{ + Text [ en-US ] = "Insert" ; +}; + +String RID_EDITUNDO_REPLACE +{ + Text [ en-US ] = "Replace" ; +}; + +String RID_EDITUNDO_SETATTRIBS +{ + Text [ en-US ] = "Apply attributes" ; +}; + +String RID_EDITUNDO_RESETATTRIBS +{ + Text [ en-US ] = "Reset attributes" ; +}; + +String RID_EDITUNDO_INDENT +{ + Text [ en-US ] = "Indent" ; +}; + +String RID_EDITUNDO_SETSTYLE +{ + Text [ en-US ] = "Apply Styles" ; +}; + +String RID_EDITUNDO_TRANSLITERATE +{ + Text [ en-US ] = "Case/Characters"; +}; + + +Menu RID_MENU_SPELL +{ + ItemList = + { + MenuItem + { + Identifier = MN_SPELLING ; + HelpId = HID_EDITENG_SPELLER_START; + Text [ en-US ] = "~Spellcheck..." ; + }; + MenuItem + { + Identifier = MN_INSERT ; + HelpId = HID_EDITENG_SPELLER_ADDWORD; + SubMenu = Menu + { + }; + Text [ en-US ] = "~Add" ; + }; + MenuItem + { + Identifier = MN_IGNORE ; + HelpId = HID_EDITENG_SPELLER_IGNORE; + Text [ en-US ] = "Ignore All" ; + }; + MenuItem + { + Identifier = MN_AUTOCORR ; + HelpId = HID_EDITENG_SPELLER_AUTOCORRECT; + SubMenu = Menu + { + }; + Text [ en-US ] = "AutoCorrect" ; + }; + }; +}; + + +String RID_STR_WORD +{ + Text [ en-US ] = "Word is %x"; +}; + +String RID_STR_PARAGRAPH +{ + Text [ en-US ] = "Paragraph is %x"; +}; + diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx new file mode 100644 index 000000000000..76615727aa5f --- /dev/null +++ b/editeng/source/editeng/editobj.cxx @@ -0,0 +1,1728 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editobj.cxx,v $ + * $Revision: 1.30 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#define ENABLE_STRING_STREAM_OPERATORS +#include <tools/stream.hxx> + +#include <editobj2.hxx> +#include <editeng/editdata.hxx> +#include <editattr.hxx> +#include <editeng/editeng.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/bulitem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/brshitem.hxx> +#include <vcl/graph.hxx> +#include <svl/intitem.hxx> +#include <unotools/fontcvt.hxx> +#include <tools/tenccvt.hxx> + +DBG_NAME( EE_EditTextObject ) +DBG_NAME( XEditAttribute ) + +//-------------------------------------------------------------- + +BOOL lcl_CreateBulletItem( const SvxNumBulletItem& rNumBullet, USHORT nLevel, SvxBulletItem& rBullet ) +{ + const SvxNumberFormat* pFmt = rNumBullet.GetNumRule()->Get( nLevel ); + if ( pFmt ) + { + rBullet.SetWidth( (-pFmt->GetFirstLineOffset()) + pFmt->GetCharTextDistance() ); + rBullet.SetSymbol( pFmt->GetBulletChar() ); + rBullet.SetPrevText( pFmt->GetPrefix() ); + rBullet.SetFollowText( pFmt->GetSuffix() ); + rBullet.SetStart( pFmt->GetStart() ); + rBullet.SetScale( pFmt->GetBulletRelSize() ); + + Font aBulletFont( rBullet.GetFont() ); + if ( pFmt->GetBulletFont() ) + aBulletFont = *pFmt->GetBulletFont(); + aBulletFont.SetColor( pFmt->GetBulletColor() ); + rBullet.SetFont( aBulletFont ); + + if ( pFmt->GetBrush() && pFmt->GetBrush()->GetGraphic() ) + { + Bitmap aBmp( pFmt->GetBrush()->GetGraphic()->GetBitmap() ); + aBmp.SetPrefSize( pFmt->GetGraphicSize() ); + aBmp.SetPrefMapMode( MAP_100TH_MM ); + rBullet.SetBitmap( aBmp ); + } + + switch ( pFmt->GetNumberingType() ) + { + case SVX_NUM_CHARS_UPPER_LETTER: + case SVX_NUM_CHARS_UPPER_LETTER_N: + rBullet.SetStyle( BS_ABC_BIG ); + break; + case SVX_NUM_CHARS_LOWER_LETTER: + case SVX_NUM_CHARS_LOWER_LETTER_N: + rBullet.SetStyle( BS_ABC_SMALL ); + break; + case SVX_NUM_ROMAN_UPPER: + rBullet.SetStyle( BS_ROMAN_BIG ); + break; + case SVX_NUM_ROMAN_LOWER: + rBullet.SetStyle( BS_ROMAN_SMALL ); + break; + case SVX_NUM_ARABIC: + rBullet.SetStyle( BS_123 ); + break; + case SVX_NUM_NUMBER_NONE: + rBullet.SetStyle( BS_NONE ); + break; + case SVX_NUM_CHAR_SPECIAL: + rBullet.SetStyle( BS_BULLET ); + break; + case SVX_NUM_PAGEDESC: + DBG_ERROR( "Unknown: SVX_NUM_PAGEDESC" ); + rBullet.SetStyle( BS_BULLET ); + break; + case SVX_NUM_BITMAP: + rBullet.SetStyle( BS_BMP ); + break; + default: + DBG_ERROR( "Unknown NumType" ); + } + + switch ( pFmt->GetNumAdjust() ) + { + case SVX_ADJUST_LEFT: + rBullet.SetJustification( BJ_VCENTER|BJ_HLEFT ); + break; + case SVX_ADJUST_RIGHT: + rBullet.SetJustification( BJ_VCENTER|BJ_HRIGHT ); + break; + case SVX_ADJUST_CENTER: + rBullet.SetJustification( BJ_VCENTER|BJ_HCENTER ); + break; + default: + DBG_ERROR( "Unknown or invalid NumAdjust" ); + } + } + return pFmt ? TRUE : FALSE; +} + + +XEditAttribute* MakeXEditAttribute( SfxItemPool& rPool, const SfxPoolItem& rItem, USHORT nStart, USHORT nEnd ) +{ + // das neue Attribut im Pool anlegen + const SfxPoolItem& rNew = rPool.Put( rItem ); + + XEditAttribute* pNew = new XEditAttribute( rNew, nStart, nEnd ); + return pNew; +} + + +XEditAttribute::XEditAttribute( const SfxPoolItem& rAttr ) +{ + DBG_CTOR( XEditAttribute, 0 ); + pItem = &rAttr; + nStart = 0; + nEnd = 0; +} + +XEditAttribute::XEditAttribute( const SfxPoolItem& rAttr, USHORT nS, USHORT nE ) +{ + DBG_CTOR( XEditAttribute, 0 ); + pItem = &rAttr; + nStart = nS; + nEnd = nE; +} + +XEditAttribute::~XEditAttribute() +{ + DBG_DTOR( XEditAttribute, 0 ); + pItem = 0; // Gehoert dem Pool. +} + +XEditAttribute* XEditAttributeList::FindAttrib( USHORT _nWhich, USHORT nChar ) const +{ + for ( USHORT n = Count(); n; ) + { + XEditAttribute* pAttr = GetObject( --n ); + if( ( pAttr->GetItem()->Which() == _nWhich ) && ( pAttr->GetStart() <= nChar ) && ( pAttr->GetEnd() > nChar ) ) + return pAttr; + } + return NULL; +} + +ContentInfo::ContentInfo( SfxItemPool& rPool ) : aParaAttribs( rPool, EE_PARA_START, EE_CHAR_END ) +{ + eFamily = SFX_STYLE_FAMILY_PARA; + pWrongs = NULL; +/* cl removed because not needed anymore since binfilter + pTempLoadStoreInfos = NULL; +*/ +} + +// Richtiger CopyCTOR unsinning, weil ich mit einem anderen Pool arbeiten muss! +ContentInfo::ContentInfo( const ContentInfo& rCopyFrom, SfxItemPool& rPoolToUse ) + : aParaAttribs( rPoolToUse, EE_PARA_START, EE_CHAR_END ) +{ + pWrongs = NULL; +/* cl removed because not needed anymore since binfilter + pTempLoadStoreInfos = NULL; +*/ + if ( rCopyFrom.GetWrongList() ) + pWrongs = rCopyFrom.GetWrongList()->Clone(); + // So sollten die Items im richtigen Pool landen! + aParaAttribs.Set( rCopyFrom.GetParaAttribs() ); + aText = rCopyFrom.GetText(); + aStyle = rCopyFrom.GetStyle(); + eFamily = rCopyFrom.GetFamily(); + + // Attribute kopieren... + for ( USHORT n = 0; n < rCopyFrom.GetAttribs().Count(); n++ ) + { + XEditAttribute* pAttr = rCopyFrom.GetAttribs().GetObject( n ); + XEditAttribute* pMyAttr = MakeXEditAttribute( rPoolToUse, *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() ); + aAttribs.Insert( pMyAttr, aAttribs.Count() ); + } + + // Wrongs + pWrongs = NULL; +#ifndef SVX_LIGHT + if ( rCopyFrom.GetWrongList() ) + pWrongs = rCopyFrom.GetWrongList()->Clone(); +#endif // !SVX_LIGHT +} + +ContentInfo::~ContentInfo() +{ + for ( USHORT nAttr = 0; nAttr < aAttribs.Count(); nAttr++ ) + { + XEditAttribute* pAttr = aAttribs.GetObject(nAttr); + // Item aus Pool entfernen! + aParaAttribs.GetPool()->Remove( *pAttr->GetItem() ); + delete pAttr; + } + aAttribs.Remove( 0, aAttribs.Count() ); +#ifndef SVX_LIGHT + delete pWrongs; +#endif +} + +/* cl removed because not needed anymore since binfilter +void ContentInfo::CreateLoadStoreTempInfos() +{ + delete pTempLoadStoreInfos; + pTempLoadStoreInfos = new LoadStoreTempInfos; +} + +void ContentInfo::DestroyLoadStoreTempInfos() +{ + delete pTempLoadStoreInfos; + pTempLoadStoreInfos = NULL; +} +*/ + +// #i102062# +bool ContentInfo::isWrongListEqual(const ContentInfo& rCompare) const +{ + if(GetWrongList() == rCompare.GetWrongList()) + return true; + + if(!GetWrongList() || !rCompare.GetWrongList()) + return false; + + return (*GetWrongList() == *rCompare.GetWrongList()); +} + +bool ContentInfo::operator==( const ContentInfo& rCompare ) const +{ + if( (aText == rCompare.aText) && + (aStyle == rCompare.aStyle ) && + (aAttribs.Count() == rCompare.aAttribs.Count() ) && + (eFamily == rCompare.eFamily ) && + (aParaAttribs == rCompare.aParaAttribs ) ) + { + const USHORT nCount = aAttribs.Count(); + if( nCount == rCompare.aAttribs.Count() ) + { + USHORT n; + for( n = 0; n < nCount; n++ ) + { + if( !(*aAttribs.GetObject(n) == *rCompare.aAttribs.GetObject(n)) ) + return false; + } + + return true; + } + } + + return false; +} + +EditTextObject::EditTextObject( USHORT n) +{ + DBG_CTOR( EE_EditTextObject, 0 ); + nWhich = n; +} + +EditTextObject::EditTextObject( const EditTextObject& r ) +{ + DBG_CTOR( EE_EditTextObject, 0 ); + nWhich = r.nWhich; +} + +__EXPORT EditTextObject::~EditTextObject() +{ + DBG_DTOR( EE_EditTextObject, 0 ); +} + +USHORT EditTextObject::GetParagraphCount() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +XubString EditTextObject::GetText( USHORT /* nParagraph */ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return XubString(); +} + +void EditTextObject::Insert( const EditTextObject& /* rObj */, USHORT /* nPara */) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +EditTextObject* EditTextObject::CreateTextObject( USHORT /*nPara*/, USHORT /*nParas*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +void EditTextObject::RemoveParagraph( USHORT /*nPara*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::HasPortionInfo() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void EditTextObject::ClearPortionInfo() +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::HasOnlineSpellErrors() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +BOOL EditTextObject::HasCharAttribs( USHORT ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void EditTextObject::GetCharAttribs( USHORT /*nPara*/, EECharAttribArray& /*rLst*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +void EditTextObject::MergeParaAttribs( const SfxItemSet& /*rAttribs*/, USHORT /*nStart*/, USHORT /*nEnd*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::IsFieldObject() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +const SvxFieldItem* EditTextObject::GetField() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +BOOL EditTextObject::HasField( TypeId /*aType*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +SfxItemSet EditTextObject::GetParaAttribs( USHORT /*nPara*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return SfxItemSet( *(SfxItemPool*)NULL ); +} + +void EditTextObject::SetParaAttribs( USHORT /*nPara*/, const SfxItemSet& /*rAttribs*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::RemoveCharAttribs( USHORT /*nWhich*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +BOOL EditTextObject::RemoveParaAttribs( USHORT /*nWhich*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +BOOL EditTextObject::HasStyleSheet( const XubString& /*rName*/, SfxStyleFamily /*eFamily*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void EditTextObject::GetStyleSheet( USHORT /*nPara*/, XubString& /*rName*/, SfxStyleFamily& /*eFamily*/ ) const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +void EditTextObject::SetStyleSheet( USHORT /*nPara*/, const XubString& /*rName*/, const SfxStyleFamily& /*eFamily*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL __EXPORT EditTextObject::ChangeStyleSheets( const XubString&, SfxStyleFamily, + const XubString&, SfxStyleFamily ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void __EXPORT EditTextObject::ChangeStyleSheetName( SfxStyleFamily /*eFamily*/, + const XubString& /*rOldName*/, const XubString& /*rNewName*/ ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +USHORT EditTextObject::GetUserType() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +void EditTextObject::SetUserType( USHORT ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +ULONG EditTextObject::GetObjectSettings() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +void EditTextObject::SetObjectSettings( ULONG ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); +} + +BOOL EditTextObject::IsVertical() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return FALSE; +} + +void EditTextObject::SetVertical( BOOL bVertical ) +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + ((BinTextObject*)this)->SetVertical( bVertical ); +} + +USHORT EditTextObject::GetScriptType() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return ((const BinTextObject*)this)->GetScriptType(); +} + + +BOOL EditTextObject::Store( SvStream& rOStream ) const +{ + if ( rOStream.GetError() ) + return FALSE; + + // Vorspann: + sal_Size nStartPos = rOStream.Tell(); + + rOStream << (USHORT)Which(); + + sal_uInt32 nStructSz = 0; + rOStream << nStructSz; + + // Eigene Daten: + StoreData( rOStream ); + + // Nachspann: + sal_Size nEndPos = rOStream.Tell(); + nStructSz = nEndPos - nStartPos - sizeof( nWhich ) - sizeof( nStructSz ); + rOStream.Seek( nStartPos + sizeof( nWhich ) ); + rOStream << nStructSz; + rOStream.Seek( nEndPos ); + + return rOStream.GetError() ? FALSE : TRUE; +} + +EditTextObject* EditTextObject::Create( SvStream& rIStream, SfxItemPool* pGlobalTextObjectPool ) +{ + ULONG nStartPos = rIStream.Tell(); + + // Ertmal sehen, was fuer ein Object... + USHORT nWhich; + rIStream >> nWhich; + + sal_uInt32 nStructSz; + rIStream >> nStructSz; + + DBG_ASSERT( ( nWhich == 0x22 /*EE_FORMAT_BIN300*/ ) || ( nWhich == EE_FORMAT_BIN ), "CreateTextObject: Unbekanntes Objekt!" ); + + if ( rIStream.GetError() ) + return NULL; + + EditTextObject* pTxtObj = NULL; + switch ( nWhich ) + { + case 0x22 /*BIN300*/: pTxtObj = new BinTextObject( 0 ); + ((BinTextObject*)pTxtObj)->CreateData300( rIStream ); + break; + case EE_FORMAT_BIN: pTxtObj = new BinTextObject( pGlobalTextObjectPool ); + pTxtObj->CreateData( rIStream ); + break; + default: + { + // Wenn ich das Format nicht kenne, ueberlese ich den Inhalt: + rIStream.SetError( EE_READWRITE_WRONGFORMAT ); + } + } + + // Sicherstellen, dass der Stream an der richtigen Stelle hinterlassen wird. + sal_Size nFullSz = sizeof( nWhich ) + sizeof( nStructSz ) + nStructSz; + rIStream.Seek( nStartPos + nFullSz ); + return pTxtObj; +} + +void EditTextObject::Skip( SvStream& rIStream ) +{ + sal_Size nStartPos = rIStream.Tell(); + + USHORT _nWhich; + rIStream >> _nWhich; + + sal_uInt32 nStructSz; + rIStream >> nStructSz; + + sal_Size nFullSz = sizeof( _nWhich ) + sizeof( nStructSz ) + nStructSz; + rIStream.Seek( nStartPos + nFullSz ); +} + +void __EXPORT EditTextObject::StoreData( SvStream& ) const +{ + DBG_ERROR( "StoreData: Basisklasse!" ); +} + +void __EXPORT EditTextObject::CreateData( SvStream& ) +{ + DBG_ERROR( "CreateData: Basisklasse!" ); +} + +USHORT EditTextObject::GetVersion() const +{ + DBG_ERROR( "V-Methode direkt vom EditTextObject!" ); + return 0; +} + +bool EditTextObject::operator==( const EditTextObject& rCompare ) const +{ + return static_cast< const BinTextObject* >( this )->operator==( static_cast< const BinTextObject& >( rCompare ) ); +} + +// #i102062# +bool EditTextObject::isWrongListEqual(const EditTextObject& rCompare) const +{ + return static_cast< const BinTextObject* >(this)->isWrongListEqual(static_cast< const BinTextObject& >(rCompare)); +} + +// from SfxItemPoolUser +void BinTextObject::ObjectInDestruction(const SfxItemPool& rSfxItemPool) +{ + if(!bOwnerOfPool && pPool && pPool == &rSfxItemPool) + { + // The pool we are based on gets destructed; get owner of pool by creating own one. + // No need to call RemoveSfxItemPoolUser(), this is done from the pool's destructor + // Base new pool on EditEnginePool; it would also be possible to clone the used + // pool if needed, but only text attributes should be used. + SfxItemPool* pNewPool = EditEngine::CreatePool(); + + if(pPool) + { + pNewPool->SetDefaultMetric(pPool->GetMetric(DEF_METRIC)); + } + + for(sal_uInt16 n(0); n < aContents.Count(); n++) + { + // clone ContentInfos for new pool + ContentInfo* pOrg = aContents.GetObject(n); + DBG_ASSERT(pOrg, "NULL-Pointer in ContentList!"); + + ContentInfo* pNew = new ContentInfo(*pOrg, *pNewPool); + aContents.Replace(pNew, n); + delete pOrg; + } + + // set local variables + pPool = pNewPool; + bOwnerOfPool = TRUE; + } +} + +EditEngineItemPool* getEditEngineItemPool(SfxItemPool* pPool) +{ + EditEngineItemPool* pRetval = dynamic_cast< EditEngineItemPool* >(pPool); + + while(!pRetval && pPool && pPool->GetSecondaryPool()) + { + pPool = pPool->GetSecondaryPool(); + + if(pPool) + { + pRetval = dynamic_cast< EditEngineItemPool* >(pPool); + } + } + + return pRetval; +} + +BinTextObject::BinTextObject( SfxItemPool* pP ) : + EditTextObject( EE_FORMAT_BIN ), + SfxItemPoolUser() +{ + nVersion = 0; + nMetric = 0xFFFF; + nUserType = 0; + nObjSettings = 0; + pPortionInfo = 0; + + // #i101239# ensure target is a EditEngineItemPool, else + // fallback to pool ownership. This is needed to ensure that at + // pool destruction time of an alien pool, the pool is still alive. + // When registering would happen at an alien pool which just uses an + // EditEngineItemPool as some sub-pool, that pool could already + // be decoupled and deleted whcih would lead to crashes. + pPool = getEditEngineItemPool(pP); + + if ( pPool ) + { + bOwnerOfPool = FALSE; + } + else + { + pPool = EditEngine::CreatePool(); + bOwnerOfPool = TRUE; + } + + if(!bOwnerOfPool && pPool) + { + // it is sure now that the pool is an EditEngineItemPool + pPool->AddSfxItemPoolUser(*this); + } + + bVertical = FALSE; + bStoreUnicodeStrings = FALSE; + nScriptType = 0; +} + +BinTextObject::BinTextObject( const BinTextObject& r ) : + EditTextObject( r ), + SfxItemPoolUser() +{ + nVersion = r.nVersion; + nMetric = r.nMetric; + nUserType = r.nUserType; + nObjSettings = r.nObjSettings; + bVertical = r.bVertical; + nScriptType = r.nScriptType; + pPortionInfo = NULL; // PortionInfo nicht kopieren + bStoreUnicodeStrings = FALSE; + + if ( !r.bOwnerOfPool ) + { + // reuse alien pool; this must be a EditEngineItemPool + // since there is no other way to construct a BinTextObject + // than it's regular constructor where that is ensured + pPool = r.pPool; + bOwnerOfPool = FALSE; + } + else + { + pPool = EditEngine::CreatePool(); + bOwnerOfPool = TRUE; + + } + + if(!bOwnerOfPool && pPool) + { + // it is sure now that the pool is an EditEngineItemPool + pPool->AddSfxItemPoolUser(*this); + } + + if ( bOwnerOfPool && pPool && r.pPool ) + pPool->SetDefaultMetric( r.pPool->GetMetric( DEF_METRIC ) ); + + for ( USHORT n = 0; n < r.aContents.Count(); n++ ) + { + ContentInfo* pOrg = r.aContents.GetObject( n ); + DBG_ASSERT( pOrg, "NULL-Pointer in ContentList!" ); + ContentInfo* pNew = new ContentInfo( *pOrg, *pPool ); + aContents.Insert( pNew, aContents.Count() ); + } +} + +__EXPORT BinTextObject::~BinTextObject() +{ + if(!bOwnerOfPool && pPool) + { + pPool->RemoveSfxItemPoolUser(*this); + } + + ClearPortionInfo(); + DeleteContents(); + if ( bOwnerOfPool ) + { + // Nicht mehr, wegen 1xDefItems. + // siehe auch ~EditDoc(). +// pPool->ReleaseDefaults( TRUE /* bDelete */ ); + SfxItemPool::Free(pPool); + } +} + +USHORT BinTextObject::GetUserType() const +{ + return nUserType; +} + +void BinTextObject::SetUserType( USHORT n ) +{ + nUserType = n; +} + +ULONG BinTextObject::GetObjectSettings() const +{ + return nObjSettings; +} + +void BinTextObject::SetObjectSettings( ULONG n ) +{ + nObjSettings = n; +} + +BOOL BinTextObject::IsVertical() const +{ + return bVertical; +} + +void BinTextObject::SetVertical( BOOL b ) +{ + if ( b != bVertical ) + { + bVertical = b; + ClearPortionInfo(); + } +} + +USHORT BinTextObject::GetScriptType() const +{ + return nScriptType; +} + +void BinTextObject::SetScriptType( USHORT nType ) +{ + nScriptType = nType; +} + + +void BinTextObject::DeleteContents() +{ + for ( USHORT n = 0; n < aContents.Count(); n++ ) + { + ContentInfo* p = aContents.GetObject( n ); + DBG_ASSERT( p, "NULL-Pointer in ContentList!" ); + delete p; + } + aContents.Remove( 0, aContents.Count() ); +} + +EditTextObject* __EXPORT BinTextObject::Clone() const +{ + return new BinTextObject( *this ); +} + +XEditAttribute* BinTextObject::CreateAttrib( const SfxPoolItem& rItem, USHORT nStart, USHORT nEnd ) +{ + return MakeXEditAttribute( *pPool, rItem, nStart, nEnd ); +} + +void BinTextObject::DestroyAttrib( XEditAttribute* pAttr ) +{ + pPool->Remove( *pAttr->GetItem() ); + delete pAttr; +} + +ContentInfo* BinTextObject::CreateAndInsertContent() +{ + ContentInfo* pC = new ContentInfo( *pPool ); + aContents.Insert( pC, aContents.Count() ); + return pC; +} + +USHORT BinTextObject::GetParagraphCount() const +{ + return aContents.Count(); +} + +XubString BinTextObject::GetText( USHORT nPara ) const +{ + DBG_ASSERT( nPara < aContents.Count(), "BinTextObject::GetText: Absatz existiert nicht!" ); + if ( nPara < aContents.Count() ) + { + ContentInfo* pC = aContents[ nPara ]; + return pC->GetText(); + } + return XubString(); +} + +void BinTextObject::Insert( const EditTextObject& rObj, USHORT nDestPara ) +{ + DBG_ASSERT( rObj.Which() == EE_FORMAT_BIN, "UTO: Unbekanntes Textobjekt" ); + + const BinTextObject& rBinObj = (const BinTextObject&)rObj; + + if ( nDestPara > aContents.Count() ) + nDestPara = aContents.Count(); + + const USHORT nParas = rBinObj.GetContents().Count(); + for ( USHORT nP = 0; nP < nParas; nP++ ) + { + ContentInfo* pC = rBinObj.GetContents()[ nP ]; + ContentInfo* pNew = new ContentInfo( *pC, *GetPool() ); + aContents.Insert( pNew, nDestPara+nP ); + } + ClearPortionInfo(); +} + +EditTextObject* BinTextObject::CreateTextObject( USHORT nPara, USHORT nParas ) const +{ + if ( ( nPara >= aContents.Count() ) || !nParas ) + return NULL; + + // Pool nur teilen, wenn von aussen eingestellter Pool. + BinTextObject* pObj = new BinTextObject( bOwnerOfPool ? 0 : pPool ); + if ( bOwnerOfPool && pPool ) + pObj->GetPool()->SetDefaultMetric( pPool->GetMetric( DEF_METRIC ) ); + + // If complete text is only one ScriptType, this is valid. + // If text contains different ScriptTypes, this shouldn't be a problem... + pObj->nScriptType = nScriptType; + + const USHORT nEndPara = nPara+nParas-1; + for ( USHORT nP = nPara; nP <= nEndPara; nP++ ) + { + ContentInfo* pC = aContents[ nP ]; + ContentInfo* pNew = new ContentInfo( *pC, *pObj->GetPool() ); + pObj->GetContents().Insert( pNew, pObj->GetContents().Count() ); + } + return pObj; +} + +void BinTextObject::RemoveParagraph( USHORT nPara ) +{ + DBG_ASSERT( nPara < aContents.Count(), "BinTextObject::GetText: Absatz existiert nicht!" ); + if ( nPara < aContents.Count() ) + { + ContentInfo* pC = aContents[ nPara ]; + aContents.Remove( nPara ); + delete pC; + ClearPortionInfo(); + } +} + +BOOL BinTextObject::HasPortionInfo() const +{ + return pPortionInfo ? TRUE : FALSE; +} + +void BinTextObject::ClearPortionInfo() +{ + if ( pPortionInfo ) + { + for ( USHORT n = pPortionInfo->Count(); n; ) + delete pPortionInfo->GetObject( --n ); + delete pPortionInfo; + pPortionInfo = NULL; + } +} + +BOOL BinTextObject::HasOnlineSpellErrors() const +{ +#ifndef SVX_LIGHT + for ( USHORT n = 0; n < aContents.Count(); n++ ) + { + ContentInfo* p = aContents.GetObject( n ); + if ( p->GetWrongList() && p->GetWrongList()->Count() ) + return TRUE; + } +#endif // !SVX_LIGHT + return FALSE; + +} + +BOOL BinTextObject::HasCharAttribs( USHORT _nWhich ) const +{ + for ( USHORT nPara = GetContents().Count(); nPara; ) + { + ContentInfo* pC = GetContents().GetObject( --nPara ); + + USHORT nAttribs = pC->GetAttribs().Count(); + if ( nAttribs && !_nWhich ) + return TRUE; + + for ( USHORT nAttr = nAttribs; nAttr; ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( --nAttr ); + if ( pX->GetItem()->Which() == _nWhich ) + return TRUE; + } + } + return FALSE; +} + +void BinTextObject::GetCharAttribs( USHORT nPara, EECharAttribArray& rLst ) const +{ + rLst.Remove( 0, rLst.Count() ); + ContentInfo* pC = GetContents().GetObject( nPara ); + if ( pC ) + { + for ( USHORT nAttr = 0; nAttr < pC->GetAttribs().Count(); nAttr++ ) + { + XEditAttribute* pAttr = pC->GetAttribs().GetObject( nAttr ); + EECharAttrib aEEAttr; + aEEAttr.pAttr = pAttr->GetItem(); + aEEAttr.nPara = nPara; + aEEAttr.nStart = pAttr->GetStart(); + aEEAttr.nEnd = pAttr->GetEnd(); + rLst.Insert( aEEAttr, rLst.Count() ); + } + } +} + +void BinTextObject::MergeParaAttribs( const SfxItemSet& rAttribs, USHORT nStart, USHORT nEnd ) +{ + BOOL bChanged = FALSE; + + for ( USHORT nPara = GetContents().Count(); nPara; ) + { + ContentInfo* pC = GetContents().GetObject( --nPara ); + + for ( USHORT nW = nStart; nW <= nEnd; nW++ ) + { + if ( ( pC->GetParaAttribs().GetItemState( nW, FALSE ) != SFX_ITEM_ON ) + && ( rAttribs.GetItemState( nW, FALSE ) == SFX_ITEM_ON ) ) + { + pC->GetParaAttribs().Put( rAttribs.Get( nW ) ); + bChanged = TRUE; + } + } + } + + if ( bChanged ) + ClearPortionInfo(); +} + +BOOL BinTextObject::IsFieldObject() const +{ + return BinTextObject::GetField() ? TRUE : FALSE; +} + +const SvxFieldItem* BinTextObject::GetField() const +{ + if ( GetContents().Count() == 1 ) + { + ContentInfo* pC = GetContents()[0]; + if ( pC->GetText().Len() == 1 ) + { + USHORT nAttribs = pC->GetAttribs().Count(); + for ( USHORT nAttr = nAttribs; nAttr; ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( --nAttr ); + if ( pX->GetItem()->Which() == EE_FEATURE_FIELD ) + return (const SvxFieldItem*)pX->GetItem(); + } + } + } + return 0; +} + +BOOL BinTextObject::HasField( TypeId aType ) const +{ + USHORT nParagraphs = GetContents().Count(); + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + USHORT nAttrs = pC->GetAttribs().Count(); + for ( USHORT nAttr = 0; nAttr < nAttrs; nAttr++ ) + { + XEditAttribute* pAttr = pC->GetAttribs()[nAttr]; + if ( pAttr->GetItem()->Which() == EE_FEATURE_FIELD ) + { + if ( !aType ) + return TRUE; + + const SvxFieldData* pFldData = ((const SvxFieldItem*)pAttr->GetItem())->GetField(); + if ( pFldData && pFldData->IsA( aType ) ) + return TRUE; + } + } + } + return FALSE; +} + +SfxItemSet BinTextObject::GetParaAttribs( USHORT nPara ) const +{ + ContentInfo* pC = GetContents().GetObject( nPara ); + return pC->GetParaAttribs(); +} + +void BinTextObject::SetParaAttribs( USHORT nPara, const SfxItemSet& rAttribs ) +{ + ContentInfo* pC = GetContents().GetObject( nPara ); + pC->GetParaAttribs().Set( rAttribs ); + ClearPortionInfo(); +} + +BOOL BinTextObject::RemoveCharAttribs( USHORT _nWhich ) +{ + BOOL bChanged = FALSE; + + for ( USHORT nPara = GetContents().Count(); nPara; ) + { + ContentInfo* pC = GetContents().GetObject( --nPara ); + + for ( USHORT nAttr = pC->GetAttribs().Count(); nAttr; ) + { + XEditAttribute* pAttr = pC->GetAttribs().GetObject( --nAttr ); + if ( !_nWhich || ( pAttr->GetItem()->Which() == _nWhich ) ) + { + pC->GetAttribs().Remove( nAttr ); + DestroyAttrib( pAttr ); + bChanged = TRUE; + } + } + } + + if ( bChanged ) + ClearPortionInfo(); + + return bChanged; +} + +BOOL BinTextObject::RemoveParaAttribs( USHORT _nWhich ) +{ + BOOL bChanged = FALSE; + + for ( USHORT nPara = GetContents().Count(); nPara; ) + { + ContentInfo* pC = GetContents().GetObject( --nPara ); + + if ( !_nWhich ) + { + if( pC->GetParaAttribs().Count() ) + bChanged = TRUE; + pC->GetParaAttribs().ClearItem(); + } + else + { + if ( pC->GetParaAttribs().GetItemState( _nWhich ) == SFX_ITEM_ON ) + { + pC->GetParaAttribs().ClearItem( _nWhich ); + bChanged = TRUE; + } + } + } + + if ( bChanged ) + ClearPortionInfo(); + + return bChanged; +} + +BOOL BinTextObject::HasStyleSheet( const XubString& rName, SfxStyleFamily eFamily ) const +{ + USHORT nParagraphs = GetContents().Count(); + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + if ( ( pC->GetFamily() == eFamily ) && ( pC->GetStyle() == rName ) ) + return TRUE; + } + return FALSE; +} + +void BinTextObject::GetStyleSheet( USHORT nPara, XubString& rName, SfxStyleFamily& rFamily ) const +{ + if ( nPara < aContents.Count() ) + { + ContentInfo* pC = aContents[ nPara ]; + rName = pC->GetStyle(); + rFamily = pC->GetFamily(); + } +} + +void BinTextObject::SetStyleSheet( USHORT nPara, const XubString& rName, const SfxStyleFamily& rFamily ) +{ + if ( nPara < aContents.Count() ) + { + ContentInfo* pC = aContents[ nPara ]; + pC->GetStyle() = rName; + pC->GetFamily() = rFamily; + } +} + +BOOL BinTextObject::ImpChangeStyleSheets( + const XubString& rOldName, SfxStyleFamily eOldFamily, + const XubString& rNewName, SfxStyleFamily eNewFamily ) +{ + const USHORT nParagraphs = GetContents().Count(); + BOOL bChanges = FALSE; + + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + if ( pC->GetFamily() == eOldFamily ) + { + if ( pC->GetStyle() == rOldName ) + { + pC->GetStyle() = rNewName; + pC->GetFamily() = eNewFamily; + bChanges = TRUE; + } + } + } + return bChanges; +} + +BOOL __EXPORT BinTextObject::ChangeStyleSheets( + const XubString& rOldName, SfxStyleFamily eOldFamily, + const XubString& rNewName, SfxStyleFamily eNewFamily ) +{ + BOOL bChanges = ImpChangeStyleSheets( rOldName, eOldFamily, rNewName, eNewFamily ); + if ( bChanges ) + ClearPortionInfo(); + + return bChanges; +} + +void __EXPORT BinTextObject::ChangeStyleSheetName( SfxStyleFamily eFamily, + const XubString& rOldName, const XubString& rNewName ) +{ + ImpChangeStyleSheets( rOldName, eFamily, rNewName, eFamily ); +} + +void __EXPORT BinTextObject::StoreData( SvStream& rOStream ) const +{ + USHORT nVer = 602; + rOStream << nVer; + + rOStream << bOwnerOfPool; + + // Erst den Pool speichern, spaeter nur noch Surregate + if ( bOwnerOfPool ) + { + GetPool()->SetFileFormatVersion( SOFFICE_FILEFORMAT_50 ); + GetPool()->Store( rOStream ); + } + + // Aktuelle Zeichensatz speichern... + // #90477# GetSOStoreTextEncoding: Bug in 5.2, when default char set is multi byte text encoding + rtl_TextEncoding eEncoding = GetSOStoreTextEncoding( gsl_getSystemTextEncoding(), (USHORT) rOStream.GetVersion() ); + rOStream << (USHORT) eEncoding; + + // Die Anzahl der Absaetze... + USHORT nParagraphs = GetContents().Count(); + rOStream << nParagraphs; + + char cFeatureConverted = ByteString( CH_FEATURE, eEncoding ).GetChar(0); + + // Die einzelnen Absaetze... + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + + // Text... + ByteString aText( pC->GetText(), eEncoding ); + + // Symbols? + BOOL bSymbolPara = FALSE; + if ( pC->GetParaAttribs().GetItemState( EE_CHAR_FONTINFO ) == SFX_ITEM_ON ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)pC->GetParaAttribs().Get( EE_CHAR_FONTINFO ); + if ( rFontItem.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) + { + aText = ByteString( pC->GetText(), RTL_TEXTENCODING_SYMBOL ); + bSymbolPara = TRUE; + } + } + for ( USHORT nA = 0; nA < pC->GetAttribs().Count(); nA++ ) + { + XEditAttribute* pAttr = pC->GetAttribs().GetObject( nA ); + + if ( pAttr->GetItem()->Which() == EE_CHAR_FONTINFO ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)*pAttr->GetItem(); + if ( ( !bSymbolPara && ( rFontItem.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) ) + || ( bSymbolPara && ( rFontItem.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) ) + { + // Not correctly converted + String aPart( pC->GetText(), pAttr->GetStart(), pAttr->GetEnd() - pAttr->GetStart() ); + ByteString aNew( aPart, rFontItem.GetCharSet() ); + aText.Erase( pAttr->GetStart(), pAttr->GetEnd() - pAttr->GetStart() ); + aText.Insert( aNew, pAttr->GetStart() ); + } + + // #88414# Convert StarSymbol back to StarBats + FontToSubsFontConverter hConv = CreateFontToSubsFontConverter( rFontItem.GetFamilyName(), FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS ); + if ( hConv ) + { + // Don't create a new Attrib with StarBats font, MBR changed the + // SvxFontItem::Store() to store StarBats instead of StarSymbol! + for ( USHORT nChar = pAttr->GetStart(); nChar < pAttr->GetEnd(); nChar++ ) + { + sal_Unicode cOld = pC->GetText().GetChar( nChar ); + char cConv = ByteString::ConvertFromUnicode( ConvertFontToSubsFontChar( hConv, cOld ), RTL_TEXTENCODING_SYMBOL ); + if ( cConv ) + aText.SetChar( nChar, cConv ); + } + + DestroyFontToSubsFontConverter( hConv ); + } + } + } + + // #88414# Convert StarSymbol back to StarBats + // StarSymbol as paragraph attribute or in StyleSheet? + + FontToSubsFontConverter hConv = NULL; + if ( pC->GetParaAttribs().GetItemState( EE_CHAR_FONTINFO ) == SFX_ITEM_ON ) + { + hConv = CreateFontToSubsFontConverter( ((const SvxFontItem&)pC->GetParaAttribs().Get( EE_CHAR_FONTINFO )).GetFamilyName(), FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS ); + } +/* cl removed because not needed anymore since binfilter + + else if ( pC->GetStyle().Len() && pC->GetLoadStoreTempInfos() ) + { + hConv = pC->GetLoadStoreTempInfos()->hOldSymbolConv_Store; + } +*/ + if ( hConv ) + { + for ( USHORT nChar = 0; nChar < pC->GetText().Len(); nChar++ ) + { + if ( !pC->GetAttribs().FindAttrib( EE_CHAR_FONTINFO, nChar ) ) + { + sal_Unicode cOld = pC->GetText().GetChar( nChar ); + char cConv = ByteString::ConvertFromUnicode( ConvertFontToSubsFontChar( hConv, cOld ), RTL_TEXTENCODING_SYMBOL ); + if ( cConv ) + aText.SetChar( nChar, cConv ); + } + } + + DestroyFontToSubsFontConverter( hConv ); + + } + + + // Convert CH_FEATURE to CH_FEATURE_OLD + aText.SearchAndReplaceAll( cFeatureConverted, CH_FEATURE_OLD ); + rOStream.WriteByteString( aText ); + + // StyleName und Family... + rOStream.WriteByteString( ByteString( pC->GetStyle(), eEncoding ) ); + rOStream << (USHORT)pC->GetFamily(); + + // Absatzattribute... + pC->GetParaAttribs().Store( rOStream ); + + // Die Anzahl der Attribute... + USHORT nAttribs = pC->GetAttribs().Count(); + rOStream << nAttribs; + + // Und die einzelnen Attribute + // Items als Surregate => immer 8 Byte pro Attrib + // Which = 2; Surregat = 2; Start = 2; End = 2; + for ( USHORT nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( nAttr ); + + rOStream << pX->GetItem()->Which(); + GetPool()->StoreSurrogate( rOStream, pX->GetItem() ); + rOStream << pX->GetStart(); + rOStream << pX->GetEnd(); + } + } + + // Ab 400: + rOStream << nMetric; + + // Ab 600 + rOStream << nUserType; + rOStream << nObjSettings; + + // Ab 601 + rOStream << bVertical; + + // Ab 602 + rOStream << nScriptType; + + rOStream << bStoreUnicodeStrings; + if ( bStoreUnicodeStrings ) + { + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + USHORT nL = pC->GetText().Len(); + rOStream << nL; + rOStream.Write( pC->GetText().GetBuffer(), nL*sizeof(sal_Unicode) ); + + // #91575# StyleSheetName must be Unicode too! + // Copy/Paste from EA3 to BETA or from BETA to EA3 not possible, not needed... + // If needed, change nL back to ULONG and increase version... + nL = pC->GetStyle().Len(); + rOStream << nL; + rOStream.Write( pC->GetStyle().GetBuffer(), nL*sizeof(sal_Unicode) ); + } + } +} + +void __EXPORT BinTextObject::CreateData( SvStream& rIStream ) +{ + rIStream >> nVersion; + + // Das Textobject wurde erstmal mit der aktuellen Einstellung + // von pTextObjectPool erzeugt. + BOOL bOwnerOfCurrent = bOwnerOfPool; + rIStream >> bOwnerOfPool; + + if ( bOwnerOfCurrent && !bOwnerOfPool ) + { + // Es wurde ein globaler Pool verwendet, mir jetzt nicht uebergeben, + // aber ich brauche ihn! + DBG_ERROR( "Man gebe mir den globalen TextObjectPool!" ); + return; + } + else if ( !bOwnerOfCurrent && bOwnerOfPool ) + { + // Es soll ein globaler Pool verwendet werden, aber dieses + // Textobject hat einen eigenen. + pPool = EditEngine::CreatePool(); + } + + if ( bOwnerOfPool ) + GetPool()->Load( rIStream ); + + // CharSet, in dem gespeichert wurde: + USHORT nCharSet; + rIStream >> nCharSet; + + rtl_TextEncoding eSrcEncoding = GetSOLoadTextEncoding( (rtl_TextEncoding)nCharSet, (USHORT)rIStream.GetVersion() ); + + // Die Anzahl der Absaetze... + USHORT nParagraphs; + rIStream >> nParagraphs; + + // Die einzelnen Absaetze... + for ( ULONG nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = CreateAndInsertContent(); + + // Der Text... + ByteString aByteString; + rIStream.ReadByteString( aByteString ); + pC->GetText() = String( aByteString, eSrcEncoding ); + + // StyleName und Family... + rIStream.ReadByteString( pC->GetStyle(), eSrcEncoding ); + USHORT nStyleFamily; + rIStream >> nStyleFamily; + pC->GetFamily() = (SfxStyleFamily)nStyleFamily; + + // Absatzattribute... + pC->GetParaAttribs().Load( rIStream ); + + // Die Anzahl der Attribute... + USHORT nAttribs; + rIStream >> nAttribs; + + // Und die einzelnen Attribute + // Items als Surregate => immer 8 Byte pro Attrib + // Which = 2; Surregat = 2; Start = 2; End = 2; + USHORT nAttr; + for ( nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + USHORT _nWhich, nStart, nEnd; + const SfxPoolItem* pItem; + + rIStream >> _nWhich; + _nWhich = pPool->GetNewWhich( _nWhich ); + pItem = pPool->LoadSurrogate( rIStream, _nWhich, 0 ); + rIStream >> nStart; + rIStream >> nEnd; + if ( pItem ) + { + if ( pItem->Which() == EE_FEATURE_NOTCONV ) + { + pC->GetText().SetChar( nStart, ByteString::ConvertToUnicode( aByteString.GetChar( nStart ), ((SvxCharSetColorItem*)pItem)->GetCharSet() ) ); + } + else + { + XEditAttribute* pAttr = new XEditAttribute( *pItem, nStart, nEnd ); + pC->GetAttribs().Insert( pAttr, pC->GetAttribs().Count() ); + + if ( ( _nWhich >= EE_FEATURE_START ) && ( _nWhich <= EE_FEATURE_END ) ) + { + // Convert CH_FEATURE to CH_FEATURE_OLD + DBG_ASSERT( (BYTE) aByteString.GetChar( nStart ) == CH_FEATURE_OLD, "CreateData: CH_FEATURE expected!" ); + if ( (BYTE) aByteString.GetChar( nStart ) == CH_FEATURE_OLD ) + pC->GetText().SetChar( nStart, CH_FEATURE ); + } + } + } + } + + // But check for paragraph and character symbol attribs here, + // FinishLoad will not be called in OpenOffice Calc, no StyleSheets... + + BOOL bSymbolPara = FALSE; + if ( pC->GetParaAttribs().GetItemState( EE_CHAR_FONTINFO ) == SFX_ITEM_ON ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)pC->GetParaAttribs().Get( EE_CHAR_FONTINFO ); + if ( rFontItem.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) + { + pC->GetText() = String( aByteString, RTL_TEXTENCODING_SYMBOL ); + bSymbolPara = TRUE; + } + } + + for ( nAttr = pC->GetAttribs().Count(); nAttr; ) + { + XEditAttribute* pAttr = pC->GetAttribs().GetObject( --nAttr ); + if ( pAttr->GetItem()->Which() == EE_CHAR_FONTINFO ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)*pAttr->GetItem(); + if ( ( !bSymbolPara && ( rFontItem.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) ) + || ( bSymbolPara && ( rFontItem.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) ) + { + // Not correctly converted + ByteString aPart( aByteString, pAttr->GetStart(), pAttr->GetEnd()-pAttr->GetStart() ); + String aNew( aPart, rFontItem.GetCharSet() ); + pC->GetText().Erase( pAttr->GetStart(), pAttr->GetEnd()-pAttr->GetStart() ); + pC->GetText().Insert( aNew, pAttr->GetStart() ); + } + + // #88414# Convert StarMath and StarBats to StarSymbol + FontToSubsFontConverter hConv = CreateFontToSubsFontConverter( rFontItem.GetFamilyName(), FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS ); + if ( hConv ) + { + SvxFontItem aNewFontItem( rFontItem ); + aNewFontItem.GetFamilyName() = GetFontToSubsFontName( hConv ); + + pC->GetAttribs().Remove( nAttr ); + XEditAttribute* pNewAttr = CreateAttrib( aNewFontItem, pAttr->GetStart(), pAttr->GetEnd() ); + pC->GetAttribs().Insert( pNewAttr, nAttr ); + DestroyAttrib( pAttr ); + + for ( USHORT nChar = pNewAttr->GetStart(); nChar < pNewAttr->GetEnd(); nChar++ ) + { + sal_Unicode cOld = pC->GetText().GetChar( nChar ); + DBG_ASSERT( cOld >= 0xF000, "cOld not converted?!" ); + sal_Unicode cConv = ConvertFontToSubsFontChar( hConv, cOld ); + if ( cConv ) + pC->GetText().SetChar( nChar, cConv ); + } + + DestroyFontToSubsFontConverter( hConv ); + } + } + } + + + // #88414# Convert StarMath and StarBats to StarSymbol + // Maybe old symbol font as paragraph attribute? + if ( pC->GetParaAttribs().GetItemState( EE_CHAR_FONTINFO ) == SFX_ITEM_ON ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)pC->GetParaAttribs().Get( EE_CHAR_FONTINFO ); + FontToSubsFontConverter hConv = CreateFontToSubsFontConverter( rFontItem.GetFamilyName(), FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS ); + if ( hConv ) + { + SvxFontItem aNewFontItem( rFontItem ); + aNewFontItem.GetFamilyName() = GetFontToSubsFontName( hConv ); + pC->GetParaAttribs().Put( aNewFontItem ); + + for ( USHORT nChar = 0; nChar < pC->GetText().Len(); nChar++ ) + { + if ( !pC->GetAttribs().FindAttrib( EE_CHAR_FONTINFO, nChar ) ) + { + sal_Unicode cOld = pC->GetText().GetChar( nChar ); + DBG_ASSERT( cOld >= 0xF000, "cOld not converted?!" ); + sal_Unicode cConv = ConvertFontToSubsFontChar( hConv, cOld ); + if ( cConv ) + pC->GetText().SetChar( nChar, cConv ); + } + } + + DestroyFontToSubsFontConverter( hConv ); + } + } + } + + // Ab 400 auch die DefMetric: + if ( nVersion >= 400 ) + { + USHORT nTmpMetric; + rIStream >> nTmpMetric; + if ( nVersion >= 401 ) + { + // In der 400 gab es noch einen Bug bei Textobjekten mit eigenem + // Pool, deshalb erst ab 401 auswerten. + nMetric = nTmpMetric; + if ( bOwnerOfPool && pPool && ( nMetric != 0xFFFF ) ) + pPool->SetDefaultMetric( (SfxMapUnit)nMetric ); + } + } + + if ( nVersion >= 600 ) + { + rIStream >> nUserType; + rIStream >> nObjSettings; + } + + if ( nVersion >= 601 ) + { + rIStream >> bVertical; + } + + if ( nVersion >= 602 ) + { + rIStream >> nScriptType; + + BOOL bUnicodeStrings; + rIStream >> bUnicodeStrings; + if ( bUnicodeStrings ) + { + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = GetContents().GetObject( nPara ); + USHORT nL; + + // Text + rIStream >> nL; + if ( nL ) + { + pC->GetText().AllocBuffer( nL ); + rIStream.Read( pC->GetText().GetBufferAccess(), nL*sizeof(sal_Unicode) ); + pC->GetText().ReleaseBufferAccess( (USHORT)nL ); + } + + // StyleSheetName + rIStream >> nL; + if ( nL ) + { + pC->GetStyle().AllocBuffer( nL ); + rIStream.Read( pC->GetStyle().GetBufferAccess(), nL*sizeof(sal_Unicode) ); + pC->GetStyle().ReleaseBufferAccess( (USHORT)nL ); + } + } + } + } + + + // Ab 500 werden die Tabs anders interpretiert: TabPos + LI, vorher nur TabPos. + // Wirkt nur wenn auch Tab-Positionen eingestellt wurden, nicht beim DefTab. + if ( nVersion < 500 ) + { + for ( USHORT n = 0; n < aContents.Count(); n++ ) + { + ContentInfo* pC = aContents.GetObject( n ); + const SvxLRSpaceItem& rLRSpace = (const SvxLRSpaceItem&) pC->GetParaAttribs().Get( EE_PARA_LRSPACE ); + if ( rLRSpace.GetTxtLeft() && ( pC->GetParaAttribs().GetItemState( EE_PARA_TABS ) == SFX_ITEM_ON ) ) + { + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) pC->GetParaAttribs().Get( EE_PARA_TABS ); + SvxTabStopItem aNewTabs( 0, 0, SVX_TAB_ADJUST_LEFT, EE_PARA_TABS ); + for ( USHORT t = 0; t < rTabs.Count(); t++ ) + { + const SvxTabStop& rT = rTabs[ t ]; + aNewTabs.Insert( SvxTabStop( rT.GetTabPos() - rLRSpace.GetTxtLeft(), + rT.GetAdjustment(), rT.GetDecimal(), rT.GetFill() ) ); + } + pC->GetParaAttribs().Put( aNewTabs ); + } + } + } +} + +USHORT BinTextObject::GetVersion() const +{ + return nVersion; +} + +bool BinTextObject::operator==( const BinTextObject& rCompare ) const +{ + if( this == &rCompare ) + return true; + + if( ( aContents.Count() != rCompare.aContents.Count() ) || + ( pPool != rCompare.pPool ) || + ( nMetric != rCompare.nMetric ) || + ( nUserType!= rCompare.nUserType ) || + ( nScriptType != rCompare.nScriptType ) || + ( bVertical != rCompare.bVertical ) ) + return false; + + USHORT n; + for( n = 0; n < aContents.Count(); n++ ) + { + if( !( *aContents.GetObject( n ) == *rCompare.aContents.GetObject( n ) ) ) + return false; + } + + return true; +} + +// #i102062# +bool BinTextObject::isWrongListEqual(const BinTextObject& rCompare) const +{ + if(GetContents().Count() != rCompare.GetContents().Count()) + { + return false; + } + + for(USHORT a(0); a < GetContents().Count(); a++) + { + const ContentInfo& rCandA(*GetContents().GetObject(a)); + const ContentInfo& rCandB(*rCompare.GetContents().GetObject(a)); + + if(!rCandA.isWrongListEqual(rCandB)) + { + return false; + } + } + + return true; +} + +#define CHARSETMARKER 0x9999 + +void __EXPORT BinTextObject::CreateData300( SvStream& rIStream ) +{ + // Fuer Aufwaertskompatibilitaet. + + // Erst den Pool laden... + // Ist in der 300 immer gespeichert worden! + GetPool()->Load( rIStream ); + + // Die Anzahl der Absaetze... + sal_uInt32 nParagraphs; + rIStream >> nParagraphs; + + // Die einzelnen Absaetze... + for ( ULONG nPara = 0; nPara < nParagraphs; nPara++ ) + { + ContentInfo* pC = CreateAndInsertContent(); + + // Der Text... + rIStream.ReadByteString( pC->GetText() ); + + // StyleName und Family... + rIStream.ReadByteString( pC->GetStyle() ); + USHORT nStyleFamily; + rIStream >> nStyleFamily; + pC->GetFamily() = (SfxStyleFamily)nStyleFamily; + + // Absatzattribute... + pC->GetParaAttribs().Load( rIStream ); + + // Die Anzahl der Attribute... + sal_uInt32 nAttribs; + rIStream >> nAttribs; + + // Und die einzelnen Attribute + // Items als Surregate => immer 8 Byte pro Attrib + // Which = 2; Surregat = 2; Start = 2; End = 2; + for ( ULONG nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + USHORT _nWhich, nStart, nEnd; + const SfxPoolItem* pItem; + + rIStream >> _nWhich; + _nWhich = pPool->GetNewWhich( _nWhich ); + pItem = pPool->LoadSurrogate( rIStream, _nWhich, 0 ); + rIStream >> nStart; + rIStream >> nEnd; + if ( pItem ) + { + XEditAttribute* pAttr = new XEditAttribute( *pItem, nStart, nEnd ); + pC->GetAttribs().Insert( pAttr, pC->GetAttribs().Count() ); + } + } + } + + // Prueffen, ob ein Zeichensatz gespeichert wurde + USHORT nCharSetMarker; + rIStream >> nCharSetMarker; + if ( nCharSetMarker == CHARSETMARKER ) + { + USHORT nCharSet; + rIStream >> nCharSet; + } +} diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx new file mode 100644 index 000000000000..e5947656f6f6 --- /dev/null +++ b/editeng/source/editeng/editobj2.hxx @@ -0,0 +1,312 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editobj2.hxx,v $ + * $Revision: 1.14 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITOBJ2_HXX +#define _EDITOBJ2_HXX + +#include <editeng/editobj.hxx> +#include <editdoc.hxx> + +#include <unotools/fontcvt.hxx> + + +class SfxStyleSheetPool; + +class XEditAttribute +{ + friend class ContentInfo; // fuer DTOR + friend class BinTextObject; // fuer DTOR + +private: + const SfxPoolItem* pItem; + USHORT nStart; + USHORT nEnd; + + XEditAttribute(); + XEditAttribute( const XEditAttribute& rCopyFrom ); + + ~XEditAttribute(); + +public: + XEditAttribute( const SfxPoolItem& rAttr ); + XEditAttribute( const SfxPoolItem& rAttr, USHORT nStart, USHORT nEnd ); + + const SfxPoolItem* GetItem() const { return pItem; } + + USHORT& GetStart() { return nStart; } + USHORT& GetEnd() { return nEnd; } + + USHORT GetStart() const { return nStart; } + USHORT GetEnd() const { return nEnd; } + + USHORT GetLen() const { return nEnd-nStart; } + + inline BOOL IsFeature(); + + inline bool operator==( const XEditAttribute& rCompare ); +}; + +inline bool XEditAttribute::operator==( const XEditAttribute& rCompare ) +{ + return (nStart == rCompare.nStart) && + (nEnd == rCompare.nEnd) && + ( (pItem == rCompare.pItem) || + ( pItem->Which() != rCompare.pItem->Which()) || + (*pItem == *rCompare.pItem)); +} + +inline BOOL XEditAttribute::IsFeature() +{ + USHORT nWhich = pItem->Which(); + return ( ( nWhich >= EE_FEATURE_START ) && + ( nWhich <= EE_FEATURE_END ) ); +} + +typedef XEditAttribute* XEditAttributePtr; +SV_DECL_PTRARR( XEditAttributeListImpl, XEditAttributePtr, 0, 4 ) + +class XEditAttributeList : public XEditAttributeListImpl +{ +public: + XEditAttribute* FindAttrib( USHORT nWhich, USHORT nChar ) const; +}; + +struct XParaPortion +{ + long nHeight; + USHORT nFirstLineOffset; + + EditLineList aLines; + TextPortionList aTextPortions; +}; + +typedef XParaPortion* XParaPortionPtr; +SV_DECL_PTRARR( XBaseParaPortionList, XParaPortionPtr, 0, 4 ) + +class XParaPortionList : public XBaseParaPortionList +{ + ULONG nRefDevPtr; + OutDevType eRefDevType; + MapMode aRefMapMode; + ULONG nPaperWidth; + + +public: + XParaPortionList( OutputDevice* pRefDev, ULONG nPW ) : + aRefMapMode( pRefDev->GetMapMode() ) + { + nRefDevPtr = (ULONG)pRefDev; nPaperWidth = nPW; + eRefDevType = pRefDev->GetOutDevType(); + } + + ULONG GetRefDevPtr() const { return nRefDevPtr; } + ULONG GetPaperWidth() const { return nPaperWidth; } + OutDevType GetRefDevType() const { return eRefDevType; } + const MapMode& GetRefMapMode() const { return aRefMapMode; } +}; + +/* cl removed because not needed anymore since binfilter +struct LoadStoreTempInfos +{ + ByteString aOrgString_Load; + + FontToSubsFontConverter hOldSymbolConv_Store; + BOOL bSymbolParagraph_Store; + + + LoadStoreTempInfos() { bSymbolParagraph_Store = FALSE; hOldSymbolConv_Store = NULL; } +}; +*/ + +class ContentInfo +{ + friend class BinTextObject; + +private: + String aText; + String aStyle; + XEditAttributeList aAttribs; + SfxStyleFamily eFamily; + SfxItemSet aParaAttribs; + WrongList* pWrongs; + +/* cl removed because not needed anymore since binfilter + LoadStoreTempInfos* pTempLoadStoreInfos; +*/ + + ContentInfo( SfxItemPool& rPool ); + ContentInfo( const ContentInfo& rCopyFrom, SfxItemPool& rPoolToUse ); + +public: + ~ContentInfo(); + + const String& GetText() const { return aText; } + const String& GetStyle() const { return aStyle; } + const XEditAttributeList& GetAttribs() const { return aAttribs; } + const SfxItemSet& GetParaAttribs() const { return aParaAttribs; } + SfxStyleFamily GetFamily() const { return eFamily; } + + String& GetText() { return aText; } + String& GetStyle() { return aStyle; } + XEditAttributeList& GetAttribs() { return aAttribs; } + SfxItemSet& GetParaAttribs() { return aParaAttribs; } + SfxStyleFamily& GetFamily() { return eFamily; } + + WrongList* GetWrongList() const { return pWrongs; } + void SetWrongList( WrongList* p ) { pWrongs = p; } + bool operator==( const ContentInfo& rCompare ) const; + + // #i102062# + bool isWrongListEqual(const ContentInfo& rCompare) const; +}; + +typedef ContentInfo* ContentInfoPtr; +SV_DECL_PTRARR( ContentInfoList, ContentInfoPtr, 1, 4 ) + +// MT 05/00: Sollte mal direkt EditTextObjekt werden => keine virtuellen Methoden mehr. + +class BinTextObject : public EditTextObject, public SfxItemPoolUser +{ + using EditTextObject::operator==; + using EditTextObject::isWrongListEqual; + +private: + ContentInfoList aContents; + SfxItemPool* pPool; + BOOL bOwnerOfPool; + XParaPortionList* pPortionInfo; + + sal_uInt32 nObjSettings; + USHORT nMetric; + USHORT nVersion; + USHORT nUserType; + USHORT nScriptType; + + BOOL bVertical; + BOOL bStoreUnicodeStrings; + +protected: + void DeleteContents(); + virtual void StoreData( SvStream& rOStream ) const; + virtual void CreateData( SvStream& rIStream ); + BOOL ImpChangeStyleSheets( const String& rOldName, SfxStyleFamily eOldFamily, + const String& rNewName, SfxStyleFamily eNewFamily ); + +public: + BinTextObject( SfxItemPool* pPool ); + BinTextObject( const BinTextObject& ); + virtual ~BinTextObject(); + + virtual EditTextObject* Clone() const; + + USHORT GetUserType() const; + void SetUserType( USHORT n ); + + ULONG GetObjectSettings() const; + void SetObjectSettings( ULONG n ); + + BOOL IsVertical() const; + void SetVertical( BOOL b ); + + USHORT GetScriptType() const; + void SetScriptType( USHORT nType ); + + USHORT GetVersion() const; // Solange der Outliner keine Recordlaenge speichert + + ContentInfo* CreateAndInsertContent(); + XEditAttribute* CreateAttrib( const SfxPoolItem& rItem, USHORT nStart, USHORT nEnd ); + void DestroyAttrib( XEditAttribute* pAttr ); + + ContentInfoList& GetContents() { return aContents; } + const ContentInfoList& GetContents() const { return aContents; } + SfxItemPool* GetPool() const { return pPool; } + XParaPortionList* GetPortionInfo() const { return pPortionInfo; } + void SetPortionInfo( XParaPortionList* pP ) + { pPortionInfo = pP; } + + virtual USHORT GetParagraphCount() const; + virtual String GetText( USHORT nParagraph ) const; + virtual void Insert( const EditTextObject& rObj, USHORT nPara ); + virtual EditTextObject* CreateTextObject( USHORT nPara, USHORT nParas = 1 ) const; + virtual void RemoveParagraph( USHORT nPara ); + + virtual BOOL HasPortionInfo() const; + virtual void ClearPortionInfo(); + + virtual BOOL HasOnlineSpellErrors() const; + + virtual BOOL HasCharAttribs( USHORT nWhich = 0 ) const; + virtual void GetCharAttribs( USHORT nPara, EECharAttribArray& rLst ) const; + + virtual BOOL RemoveCharAttribs( USHORT nWhich = 0 ); + virtual BOOL RemoveParaAttribs( USHORT nWhich = 0 ); + + virtual void MergeParaAttribs( const SfxItemSet& rAttribs, USHORT nStart, USHORT nEnd ); + + virtual BOOL IsFieldObject() const; + virtual const SvxFieldItem* GetField() const; + virtual BOOL HasField( TypeId Type = NULL ) const; + + SfxItemSet GetParaAttribs( USHORT nPara ) const; + void SetParaAttribs( USHORT nPara, const SfxItemSet& rAttribs ); + + virtual BOOL HasStyleSheet( const XubString& rName, SfxStyleFamily eFamily ) const; + virtual void GetStyleSheet( USHORT nPara, XubString& rName, SfxStyleFamily& eFamily ) const; + virtual void SetStyleSheet( USHORT nPara, const XubString& rName, const SfxStyleFamily& eFamily ); + virtual BOOL ChangeStyleSheets( const XubString& rOldName, SfxStyleFamily eOldFamily, + const String& rNewName, SfxStyleFamily eNewFamily ); + virtual void ChangeStyleSheetName( SfxStyleFamily eFamily, const XubString& rOldName, const XubString& rNewName ); + + void CreateData300( SvStream& rIStream ); + + BOOL HasMetric() const { return nMetric != 0xFFFF; } + USHORT GetMetric() const { return nMetric; } + void SetMetric( USHORT n ) { nMetric = n; } + + BOOL IsOwnerOfPool() const { return bOwnerOfPool; } + void StoreUnicodeStrings( BOOL b ) { bStoreUnicodeStrings = b; } + +/* cl removed because not needed anymore since binfilter + void PrepareStore( SfxStyleSheetPool* pStyleSheetPool ); + void FinishStore(); + void FinishLoad( SfxStyleSheetPool* pStyleSheetPool ); +*/ + + bool operator==( const BinTextObject& rCompare ) const; + + // #i102062# + bool isWrongListEqual(const BinTextObject& rCompare) const; + + // from SfxItemPoolUser + virtual void ObjectInDestruction(const SfxItemPool& rSfxItemPool); +}; + +#endif // _EDITOBJ2_HXX + diff --git a/editeng/source/editeng/editsel.cxx b/editeng/source/editeng/editsel.cxx new file mode 100644 index 000000000000..da7dd8a0311d --- /dev/null +++ b/editeng/source/editeng/editsel.cxx @@ -0,0 +1,124 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editsel.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <eeng_pch.hxx> + +#include <editsel.hxx> +#include <impedit.hxx> +#include <editeng/editview.hxx> + +// ---------------------------------------------------------------------- +// class EditSelFunctionSet +// ---------------------------------------------------------------------- +EditSelFunctionSet::EditSelFunctionSet() +{ + pCurView = NULL; +} + +void __EXPORT EditSelFunctionSet::CreateAnchor() +{ + if ( pCurView ) + pCurView->pImpEditView->CreateAnchor(); +} + +void __EXPORT EditSelFunctionSet::DestroyAnchor() +{ + // Nur bei Mehrfachselektion +} + +BOOL __EXPORT EditSelFunctionSet::SetCursorAtPoint( const Point& rPointPixel, BOOL ) +{ + if ( pCurView ) + return pCurView->pImpEditView->SetCursorAtPoint( rPointPixel ); + + return FALSE; +} + +BOOL __EXPORT EditSelFunctionSet::IsSelectionAtPoint( const Point& rPointPixel ) +{ + if ( pCurView ) + return pCurView->pImpEditView->IsSelectionAtPoint( rPointPixel ); + + return FALSE; +} + +void __EXPORT EditSelFunctionSet::DeselectAtPoint( const Point& ) +{ +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// ! Implementieren, wenn Mehrfachselektion moeglich ! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +} + +void __EXPORT EditSelFunctionSet::BeginDrag() +{ + // Nur bei Mehrfachselektion +} + + +void __EXPORT EditSelFunctionSet::DeselectAll() +{ + if ( pCurView ) + pCurView->pImpEditView->DeselectAll(); +} + +// ---------------------------------------------------------------------- +// class EditSelectionEngine +// ---------------------------------------------------------------------- +EditSelectionEngine::EditSelectionEngine() : SelectionEngine( (Window*)0 ) +{ + // Wegen Bug OV: (1994) + // 1995: RangeSelection lassen, SingleSelection nur fuer ListBoxen geeignet! + SetSelectionMode( RANGE_SELECTION ); + EnableDrag( TRUE ); +} + +void EditSelectionEngine::SetCurView( EditView* pNewView ) +{ + if ( GetFunctionSet() ) + ((EditSelFunctionSet*)GetFunctionSet())->SetCurView( pNewView ); + + if ( pNewView ) + SetWindow( pNewView->GetWindow() ); + else + SetWindow( (Window*)0 ); +} + +EditView* EditSelectionEngine::GetCurView() +{ + EditView* pView = 0; + if ( GetFunctionSet() ) + pView = ((EditSelFunctionSet*)GetFunctionSet())->GetCurView(); + + return pView; +} + diff --git a/editeng/source/editeng/editsel.hxx b/editeng/source/editeng/editsel.hxx new file mode 100644 index 000000000000..8e1e88dd73ed --- /dev/null +++ b/editeng/source/editeng/editsel.hxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editsel.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITSEL_HXX +#define _EDITSEL_HXX + +#include <vcl/seleng.hxx> + +class EditView; + +// ---------------------------------------------------------------------- +// class EditSelFunctionSet +// ---------------------------------------------------------------------- +class EditSelFunctionSet: public FunctionSet +{ +private: + EditView* pCurView; + +public: + EditSelFunctionSet(); + + virtual void BeginDrag(); + + virtual void CreateAnchor(); + virtual void DestroyAnchor(); + + virtual BOOL SetCursorAtPoint( const Point& rPointPixel, BOOL bDontSelectAtCursor = FALSE ); + + virtual BOOL IsSelectionAtPoint( const Point& rPointPixel ); + virtual void DeselectAtPoint( const Point& rPointPixel ); + virtual void DeselectAll(); + + void SetCurView( EditView* pView ) { pCurView = pView; } + EditView* GetCurView() { return pCurView; } +}; + +// ---------------------------------------------------------------------- +// class EditSelectionEngine +// ---------------------------------------------------------------------- +class EditSelectionEngine : public SelectionEngine +{ +private: + +public: + EditSelectionEngine(); + + void SetCurView( EditView* pNewView ); + EditView* GetCurView(); +}; + +#endif // _EDITSEL_HXX diff --git a/editeng/source/editeng/editstt2.hxx b/editeng/source/editeng/editstt2.hxx new file mode 100644 index 000000000000..532df7fc82a0 --- /dev/null +++ b/editeng/source/editeng/editstt2.hxx @@ -0,0 +1,133 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editstt2.hxx,v $ + * $Revision: 1.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITSTT2_HXX +#define _EDITSTT2_HXX + +#include <editeng/editstat.hxx> + +class InternalEditStatus : public EditStatus +{ + +public: + InternalEditStatus() { ; } + + void TurnOnFlags( ULONG nFlags ) + { nControlBits |= nFlags; } + + void TurnOffFlags( ULONG nFlags ) + { nControlBits &= ~nFlags; } + + void TurnOnStatusBits( ULONG nBits ) + { nStatusBits |= nBits; } + + void TurnOffStatusBits( ULONG nBits ) + { nStatusBits &= ~nBits; } + + + BOOL UseCharAttribs() const + { return ( ( nControlBits & EE_CNTRL_USECHARATTRIBS ) != 0 ); } + + BOOL NotifyCursorMovements() const + { return ( ( nControlBits & EE_CNTRL_CRSRLEFTPARA ) != 0 ); } + + BOOL UseIdleFormatter() const + { return ( ( nControlBits & EE_CNTRL_DOIDLEFORMAT) != 0 ); } + + BOOL AllowPasteSpecial() const + { return ( ( nControlBits & EE_CNTRL_PASTESPECIAL ) != 0 ); } + + BOOL DoAutoIndenting() const + { return ( ( nControlBits & EE_CNTRL_AUTOINDENTING ) != 0 ); } + + BOOL DoUndoAttribs() const + { return ( ( nControlBits & EE_CNTRL_UNDOATTRIBS ) != 0 ); } + + BOOL OneCharPerLine() const + { return ( ( nControlBits & EE_CNTRL_ONECHARPERLINE ) != 0 ); } + + BOOL IsOutliner() const + { return ( ( nControlBits & EE_CNTRL_OUTLINER ) != 0 ); } + + BOOL IsOutliner2() const + { return ( ( nControlBits & EE_CNTRL_OUTLINER2 ) != 0 ); } + + BOOL IsAnyOutliner() const + { return IsOutliner() || IsOutliner2(); } + + BOOL DoNotUseColors() const + { return ( ( nControlBits & EE_CNTRL_NOCOLORS ) != 0 ); } + + BOOL AllowBigObjects() const + { return ( ( nControlBits & EE_CNTRL_ALLOWBIGOBJS ) != 0 ); } + + BOOL DoOnlineSpelling() const + { return ( ( nControlBits & EE_CNTRL_ONLINESPELLING ) != 0 ); } + + BOOL DoStretch() const + { return ( ( nControlBits & EE_CNTRL_STRETCHING ) != 0 ); } + + BOOL AutoPageSize() const + { return ( ( nControlBits & EE_CNTRL_AUTOPAGESIZE ) != 0 ); } + BOOL AutoPageWidth() const + { return ( ( nControlBits & EE_CNTRL_AUTOPAGESIZEX ) != 0 ); } + BOOL AutoPageHeight() const + { return ( ( nControlBits & EE_CNTRL_AUTOPAGESIZEY ) != 0 ); } + + BOOL MarkFields() const + { return ( ( nControlBits & EE_CNTRL_MARKFIELDS ) != 0 ); } + + BOOL DoRestoreFont() const + { return ( ( nControlBits & EE_CNTRL_RESTOREFONT ) != 0 ); } + + BOOL DoImportRTFStyleSheets() const + { return ( ( nControlBits & EE_CNTRL_RTFSTYLESHEETS ) != 0 ); } + + BOOL DoAutoCorrect() const + { return ( ( nControlBits & EE_CNTRL_AUTOCORRECT ) != 0 ); } + + BOOL DoAutoComplete() const + { return ( ( nControlBits & EE_CNTRL_AUTOCOMPLETE ) != 0 ); } + + BOOL DoTabIndenting() const + { return ( ( nControlBits & EE_CNTRL_TABINDENTING ) != 0 ); } + + BOOL DoFormat100() const + { return ( ( nControlBits & EE_CNTRL_FORMAT100 ) != 0 ); } + + BOOL ULSpaceSummation() const + { return ( ( nControlBits & EE_CNTRL_ULSPACESUMMATION ) != 0 ); } + + BOOL ULSpaceFirstParagraph() const + { return ( ( nControlBits & EE_CNTRL_ULSPACEFIRSTPARA ) != 0 ); } +}; + +#endif // _EDITSTT2_HXX + diff --git a/editeng/source/editeng/editundo.cxx b/editeng/source/editeng/editundo.cxx new file mode 100644 index 000000000000..6f05b4747b49 --- /dev/null +++ b/editeng/source/editeng/editundo.cxx @@ -0,0 +1,753 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editundo.cxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <eeng_pch.hxx> + +#include <impedit.hxx> +#include <editundo.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> + +DBG_NAME( EditUndo ) + +#define MAX_UNDOS 100 // ab dieser Menge darf geloescht werden.... +#define MIN_UNDOS 50 // soviel muss stehen bleiben... + +#define NO_UNDO 0xFFFF +#define GROUP_NOTFOUND 0xFFFF + +TYPEINIT1( EditUndo, SfxUndoAction ); +TYPEINIT1( EditUndoDelContent, EditUndo ); +TYPEINIT1( EditUndoConnectParas, EditUndo ); +TYPEINIT1( EditUndoSplitPara, EditUndo ); +TYPEINIT1( EditUndoInsertChars, EditUndo ); +TYPEINIT1( EditUndoRemoveChars, EditUndo ); +TYPEINIT1( EditUndoInsertFeature, EditUndo ); +TYPEINIT1( EditUndoMoveParagraphs, EditUndo ); +TYPEINIT1( EditUndoSetStyleSheet, EditUndo ); +TYPEINIT1( EditUndoSetParaAttribs, EditUndo ); +TYPEINIT1( EditUndoSetAttribs, EditUndo ); +TYPEINIT1( EditUndoTransliteration, EditUndo ); +TYPEINIT1( EditUndoMarkSelection, EditUndo ); + +void lcl_DoSetSelection( EditView* pView, USHORT nPara ) +{ + EPaM aEPaM( nPara, 0 ); + EditPaM aPaM( pView->GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + aPaM.SetIndex( aPaM.GetNode()->Len() ); + EditSelection aSel( aPaM, aPaM ); + pView->GetImpEditView()->SetEditSelection( aSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoManager +// ------------------------------------------------------------------------ +EditUndoManager::EditUndoManager( ImpEditEngine* p ) +{ + pImpEE = p; +} + +BOOL __EXPORT EditUndoManager::Undo( USHORT nCount ) +{ + if ( GetUndoActionCount() == 0 ) + return FALSE; + + DBG_ASSERT( pImpEE->GetActiveView(), "Active View?" ); + + if ( !pImpEE->GetActiveView() ) + { + if ( pImpEE->GetEditViews().Count() ) + pImpEE->SetActiveView( pImpEE->GetEditViews().GetObject(0) ); + else + { + DBG_ERROR( "Undo in Engine ohne View nicht moeglich!" ); + return FALSE; + } + } + + pImpEE->GetActiveView()->GetImpEditView()->DrawSelection(); // alte Selektion entfernen + + pImpEE->SetUndoMode( TRUE ); + BOOL bDone = SfxUndoManager::Undo( nCount ); + pImpEE->SetUndoMode( FALSE ); + + EditSelection aNewSel( pImpEE->GetActiveView()->GetImpEditView()->GetEditSelection() ); + DBG_ASSERT( !aNewSel.IsInvalid(), "Ungueltige Selektion nach Undo()" ); + DBG_ASSERT( !aNewSel.DbgIsBuggy( pImpEE->GetEditDoc() ), "Kaputte Selektion nach Undo()" ); + + aNewSel.Min() = aNewSel.Max(); + pImpEE->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); + pImpEE->FormatAndUpdate( pImpEE->GetActiveView() ); + + return bDone; +} + +BOOL __EXPORT EditUndoManager::Redo( USHORT nCount ) +{ + if ( GetRedoActionCount() == 0 ) + return FALSE; + + DBG_ASSERT( pImpEE->GetActiveView(), "Active View?" ); + + if ( !pImpEE->GetActiveView() ) + { + if ( pImpEE->GetEditViews().Count() ) + pImpEE->SetActiveView( pImpEE->GetEditViews().GetObject(0) ); + else + { + DBG_ERROR( "Redo in Engine ohne View nicht moeglich!" ); + return FALSE; + } + } + + pImpEE->GetActiveView()->GetImpEditView()->DrawSelection(); // alte Selektion entfernen + + pImpEE->SetUndoMode( TRUE ); + BOOL bDone = SfxUndoManager::Redo( nCount ); + pImpEE->SetUndoMode( FALSE ); + + EditSelection aNewSel( pImpEE->GetActiveView()->GetImpEditView()->GetEditSelection() ); + DBG_ASSERT( !aNewSel.IsInvalid(), "Ungueltige Selektion nach Undo()" ); + DBG_ASSERT( !aNewSel.DbgIsBuggy( pImpEE->GetEditDoc() ), "Kaputte Selektion nach Redo()" ); + + aNewSel.Min() = aNewSel.Max(); + pImpEE->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); + pImpEE->FormatAndUpdate( pImpEE->GetActiveView() ); + + return bDone; +} + +// ----------------------------------------------------------------------- +// EditUndo +// ------------------------------------------------------------------------ +EditUndo::EditUndo( USHORT nI, ImpEditEngine* p ) +{ + DBG_CTOR( EditUndo, 0 ); + nId = nI; + pImpEE = p; +} + +EditUndo::~EditUndo() +{ + DBG_DTOR( EditUndo, 0 ); +} + +USHORT __EXPORT EditUndo::GetId() const +{ + DBG_CHKTHIS( EditUndo, 0 ); + return nId; +} + +BOOL __EXPORT EditUndo::CanRepeat(SfxRepeatTarget&) const +{ + return FALSE; +} + +XubString __EXPORT EditUndo::GetComment() const +{ + XubString aComment; + if ( pImpEE ) + { + EditEngine* pEditEng = pImpEE->GetEditEnginePtr(); + aComment = pEditEng->GetUndoComment( GetId() ); + } + return aComment; +} + +// ----------------------------------------------------------------------- +// EditUndoDelContent +// ------------------------------------------------------------------------ +EditUndoDelContent::EditUndoDelContent( ImpEditEngine* _pImpEE, ContentNode* pNode, USHORT n ) + : EditUndo( EDITUNDO_DELCONTENT, _pImpEE ) +{ + pContentNode = pNode; + nNode = n; + bDelObject = TRUE; +} + +EditUndoDelContent::~EditUndoDelContent() +{ + if ( bDelObject ) + delete pContentNode; +} + +void __EXPORT EditUndoDelContent::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->InsertContent( pContentNode, nNode ); + bDelObject = FALSE; // gehoert wieder der Engine + EditSelection aSel( EditPaM( pContentNode, 0 ), EditPaM( pContentNode, pContentNode->Len() ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +void __EXPORT EditUndoDelContent::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + + ImpEditEngine* _pImpEE = GetImpEditEngine(); + + // pNode stimmt nicht mehr, falls zwischendurch Undos, in denen + // Absaetze verschmolzen sind. + pContentNode = _pImpEE->GetEditDoc().SaveGetObject( nNode ); + DBG_ASSERT( pContentNode, "EditUndoDelContent::Redo(): Node?!" ); + + delete _pImpEE->GetParaPortions()[nNode]; + _pImpEE->GetParaPortions().Remove( nNode ); + + // Node nicht loeschen, haengt im Undo! + _pImpEE->GetEditDoc().Remove( nNode ); + if( _pImpEE->IsCallParaInsertedOrDeleted() ) + _pImpEE->GetEditEnginePtr()->ParagraphDeleted( nNode ); + + DeletedNodeInfo* pInf = new DeletedNodeInfo( (ULONG)pContentNode, nNode ); + _pImpEE->aDeletedNodes.Insert( pInf, _pImpEE->aDeletedNodes.Count() ); + _pImpEE->UpdateSelections(); + + ContentNode* pN = ( nNode < _pImpEE->GetEditDoc().Count() ) + ? _pImpEE->GetEditDoc().SaveGetObject( nNode ) + : _pImpEE->GetEditDoc().SaveGetObject( nNode-1 ); + DBG_ASSERT( pN && ( pN != pContentNode ), "?! RemoveContent !? " ); + EditPaM aPaM( pN, pN->Len() ); + + bDelObject = TRUE; // gehoert wieder dem Undo + + _pImpEE->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +// ----------------------------------------------------------------------- +// EditUndoConnectParas +// ------------------------------------------------------------------------ +EditUndoConnectParas::EditUndoConnectParas( ImpEditEngine* _pImpEE, USHORT nN, USHORT nSP, + const SfxItemSet& rLeftParaAttribs, const SfxItemSet& rRightParaAttribs, + const SfxStyleSheet* pLeftStyle, const SfxStyleSheet* pRightStyle, BOOL bBkwrd ) + : EditUndo( EDITUNDO_CONNECTPARAS, _pImpEE ), + aLeftParaAttribs( rLeftParaAttribs ), + aRightParaAttribs( rRightParaAttribs ) +{ + nNode = nN; + nSepPos = nSP; + + if ( pLeftStyle ) + { + aLeftStyleName = pLeftStyle->GetName(); + eLeftStyleFamily = pLeftStyle->GetFamily(); + } + if ( pRightStyle ) + { + aRightStyleName = pRightStyle->GetName(); + eRightStyleFamily = pRightStyle->GetFamily(); + } + + bBackward = bBkwrd; +} + +EditUndoConnectParas::~EditUndoConnectParas() +{ +} + +void __EXPORT EditUndoConnectParas::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + + // Bei SplitContent darf noch kein ParagraphInserted gerufen werden, + // weil der Outliner sich auf die Attribute verlaesst um die Tiefe + // des Absatzes zu initialisieren + + BOOL bCall = GetImpEditEngine()->IsCallParaInsertedOrDeleted(); + GetImpEditEngine()->SetCallParaInsertedOrDeleted( FALSE ); + + EditPaM aPaM = GetImpEditEngine()->SplitContent( nNode, nSepPos ); + GetImpEditEngine()->SetParaAttribs( nNode, aLeftParaAttribs ); + GetImpEditEngine()->SetParaAttribs( nNode+1, aRightParaAttribs ); + + GetImpEditEngine()->SetCallParaInsertedOrDeleted( bCall ); + if ( GetImpEditEngine()->IsCallParaInsertedOrDeleted() ) + GetImpEditEngine()->GetEditEnginePtr()->ParagraphInserted( nNode+1 ); + + if ( GetImpEditEngine()->GetStyleSheetPool() ) + { + if ( aLeftStyleName.Len() ) + GetImpEditEngine()->SetStyleSheet( (USHORT)nNode, (SfxStyleSheet*)GetImpEditEngine()->GetStyleSheetPool()->Find( aLeftStyleName, eLeftStyleFamily ) ); + if ( aRightStyleName.Len() ) + GetImpEditEngine()->SetStyleSheet( nNode+1, (SfxStyleSheet*)GetImpEditEngine()->GetStyleSheetPool()->Find( aRightStyleName, eRightStyleFamily ) ); + } + + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +void __EXPORT EditUndoConnectParas::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM = GetImpEditEngine()->ConnectContents( nNode, bBackward ); + + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +// ----------------------------------------------------------------------- +// EditUndoSplitPara +// ------------------------------------------------------------------------ +EditUndoSplitPara::EditUndoSplitPara( ImpEditEngine* _pImpEE, USHORT nN, USHORT nSP ) + : EditUndo( EDITUNDO_SPLITPARA, _pImpEE ) +{ + nNode = nN; + nSepPos = nSP; +} + +EditUndoSplitPara::~EditUndoSplitPara() +{ +} + +void __EXPORT EditUndoSplitPara::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM = GetImpEditEngine()->ConnectContents( nNode, FALSE ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +void __EXPORT EditUndoSplitPara::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM = GetImpEditEngine()->SplitContent( nNode, nSepPos ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aPaM ) ); +} + +// ----------------------------------------------------------------------- +// EditUndoInsertChars +// ------------------------------------------------------------------------ +EditUndoInsertChars::EditUndoInsertChars( ImpEditEngine* _pImpEE, const EPaM& rEPaM, const XubString& rStr ) + : EditUndo( EDITUNDO_INSERTCHARS, _pImpEE ), + aEPaM( rEPaM ), aText( rStr ) +{ +} + +void __EXPORT EditUndoInsertChars::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + aSel.Max().GetIndex() = aSel.Max().GetIndex() + aText.Len(); + EditPaM aNewPaM( GetImpEditEngine()->ImpDeleteSelection( aSel ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aNewPaM, aNewPaM ) ); +} + +void __EXPORT EditUndoInsertChars::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + GetImpEditEngine()->ImpInsertText( EditSelection( aPaM, aPaM ), aText ); + EditPaM aNewPaM( aPaM ); + aNewPaM.GetIndex() = aNewPaM.GetIndex() + aText.Len(); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( EditSelection( aPaM, aNewPaM ) ); +} + +BOOL __EXPORT EditUndoInsertChars::Merge( SfxUndoAction* pNextAction ) +{ + if ( !pNextAction->ISA( EditUndoInsertChars ) ) + return FALSE; + + EditUndoInsertChars* pNext = (EditUndoInsertChars*)pNextAction; + + if ( aEPaM.nPara != pNext->aEPaM.nPara ) + return FALSE; + + if ( ( aEPaM.nIndex + aText.Len() ) == pNext->aEPaM.nIndex ) + { + aText += pNext->aText; + return TRUE; + } + return FALSE; +} + +// ----------------------------------------------------------------------- +// EditUndoRemoveChars +// ------------------------------------------------------------------------ +EditUndoRemoveChars::EditUndoRemoveChars( ImpEditEngine* _pImpEE, const EPaM& rEPaM, const XubString& rStr ) + : EditUndo( EDITUNDO_REMOVECHARS, _pImpEE ), + aEPaM( rEPaM ), aText( rStr ) +{ +} + +void __EXPORT EditUndoRemoveChars::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + GetImpEditEngine()->ImpInsertText( aSel, aText ); + aSel.Max().GetIndex() = aSel.Max().GetIndex() + aText.Len(); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +void __EXPORT EditUndoRemoveChars::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + aSel.Max().GetIndex() = aSel.Max().GetIndex() + aText.Len(); + EditPaM aNewPaM = GetImpEditEngine()->ImpDeleteSelection( aSel ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewPaM ); +} + +// ----------------------------------------------------------------------- +// EditUndoInsertFeature +// ------------------------------------------------------------------------ +EditUndoInsertFeature::EditUndoInsertFeature( ImpEditEngine* _pImpEE, const EPaM& rEPaM, const SfxPoolItem& rFeature) + : EditUndo( EDITUNDO_INSERTFEATURE, _pImpEE ), aEPaM( rEPaM ) +{ + pFeature = rFeature.Clone(); + DBG_ASSERT( pFeature, "Feature konnte nicht dupliziert werden: EditUndoInsertFeature" ); +} + +EditUndoInsertFeature::~EditUndoInsertFeature() +{ + delete pFeature; +} + +void __EXPORT EditUndoInsertFeature::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + // Attribute werden dort implizit vom Dokument korrigiert... + aSel.Max().GetIndex()++; + EditPaM aNewPaM = GetImpEditEngine()->ImpDeleteSelection( aSel ); + aSel.Max().GetIndex()--; // Fuer Selektion + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +void __EXPORT EditUndoInsertFeature::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditPaM aPaM( GetImpEditEngine()->CreateEditPaM( aEPaM ) ); + EditSelection aSel( aPaM, aPaM ); + GetImpEditEngine()->ImpInsertFeature( aSel, *pFeature ); + if ( pFeature->Which() == EE_FEATURE_FIELD ) + GetImpEditEngine()->UpdateFields(); + aSel.Max().GetIndex()++; + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoMoveParagraphs +// ------------------------------------------------------------------------ +EditUndoMoveParagraphs::EditUndoMoveParagraphs + ( ImpEditEngine* _pImpEE, const Range& rParas, USHORT n ) + : EditUndo( EDITUNDO_MOVEPARAGRAPHS, _pImpEE ), + nParagraphs( rParas ) +{ + nDest = n; +} + +EditUndoMoveParagraphs::~EditUndoMoveParagraphs() +{ +} + +void __EXPORT EditUndoMoveParagraphs::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + Range aTmpRange( nParagraphs ); + long nTmpDest = aTmpRange.Min(); + + long nDiff = ( nDest - aTmpRange.Min() ); + aTmpRange.Min() += nDiff; + aTmpRange.Max() += nDiff; + + if ( nParagraphs.Min() < (long)nDest ) + { + long nLen = aTmpRange.Len(); + aTmpRange.Min() -= nLen; + aTmpRange.Max() -= nLen; + } + else + nTmpDest += aTmpRange.Len(); + + EditSelection aNewSel( GetImpEditEngine()->MoveParagraphs( aTmpRange, (USHORT)nTmpDest, 0 ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); +} + +void __EXPORT EditUndoMoveParagraphs::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + EditSelection aNewSel( GetImpEditEngine()->MoveParagraphs( nParagraphs, nDest, 0 ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoSetStyleSheet +// ------------------------------------------------------------------------ +EditUndoSetStyleSheet::EditUndoSetStyleSheet( ImpEditEngine* _pImpEE, USHORT nP, + const XubString& rPrevName, SfxStyleFamily ePrevFam, + const XubString& rNewName, SfxStyleFamily eNewFam, + const SfxItemSet& rPrevParaAttribs ) + : EditUndo( EDITUNDO_STYLESHEET, _pImpEE ), aPrevName( rPrevName ), aNewName( rNewName ), + aPrevParaAttribs( rPrevParaAttribs ) +{ + ePrevFamily = ePrevFam; + eNewFamily = eNewFam; + nPara = nP; +} + +EditUndoSetStyleSheet::~EditUndoSetStyleSheet() +{ +} + +void __EXPORT EditUndoSetStyleSheet::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->SetStyleSheet( nPara, (SfxStyleSheet*)GetImpEditEngine()->GetStyleSheetPool()->Find( aPrevName, ePrevFamily ) ); + GetImpEditEngine()->SetParaAttribs( nPara, aPrevParaAttribs ); + lcl_DoSetSelection( GetImpEditEngine()->GetActiveView(), nPara ); +} + +void __EXPORT EditUndoSetStyleSheet::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->SetStyleSheet( nPara, (SfxStyleSheet*)GetImpEditEngine()->GetStyleSheetPool()->Find( aNewName, eNewFamily ) ); + lcl_DoSetSelection( GetImpEditEngine()->GetActiveView(), nPara ); +} + +// ----------------------------------------------------------------------- +// EditUndoSetParaAttribs +// ------------------------------------------------------------------------ +EditUndoSetParaAttribs::EditUndoSetParaAttribs( ImpEditEngine* _pImpEE, USHORT nP, const SfxItemSet& rPrevItems, const SfxItemSet& rNewItems ) + : EditUndo( EDITUNDO_PARAATTRIBS, _pImpEE ), + aPrevItems( rPrevItems ), + aNewItems(rNewItems ) +{ + nPara = nP; +} + +EditUndoSetParaAttribs::~EditUndoSetParaAttribs() +{ +} + +void __EXPORT EditUndoSetParaAttribs::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->SetParaAttribs( nPara, aPrevItems ); + lcl_DoSetSelection( GetImpEditEngine()->GetActiveView(), nPara ); +} + +void __EXPORT EditUndoSetParaAttribs::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + GetImpEditEngine()->SetParaAttribs( nPara, aNewItems ); + lcl_DoSetSelection( GetImpEditEngine()->GetActiveView(), nPara ); +} + +// ----------------------------------------------------------------------- +// EditUndoSetAttribs +// ------------------------------------------------------------------------ +EditUndoSetAttribs::EditUndoSetAttribs( ImpEditEngine* _pImpEE, const ESelection& rESel, const SfxItemSet& rNewItems ) + : EditUndo( EDITUNDO_ATTRIBS, _pImpEE ), + aESel( rESel ), + aNewAttribs( rNewItems ) +{ + // Wenn das EditUndoSetAttribs eigentlich ein RemoveAttribs ist, koennte + // man das eigentlich an einem leeren ItemSet erkennen, aber dann muesste + // an einigen Stellen abgefangen werden, das ggf. ein SetAttribs mit einem + // leeren ItemSet gemacht wird. + // => Ich habe lieber diesen Member spendiert... + bSetIsRemove = FALSE; + bRemoveParaAttribs = FALSE; + nRemoveWhich = 0; + nSpecial = 0; +} + +EditUndoSetAttribs::~EditUndoSetAttribs() +{ + // Items aus Pool holen... + SfxItemPool* pPool = aNewAttribs.GetPool(); + USHORT nContents = aPrevAttribs.Count(); + for ( USHORT n = 0; n < nContents; n++ ) + { + ContentAttribsInfo* pInf = aPrevAttribs[n]; + DBG_ASSERT( pInf, "Undo_DTOR (SetAttribs): pInf = NULL!" ); + for ( USHORT nAttr = 0; nAttr < pInf->GetPrevCharAttribs().Count(); nAttr++ ) + { + EditCharAttrib* pX = pInf->GetPrevCharAttribs()[nAttr]; + DBG_ASSERT( pX, "Undo_DTOR (SetAttribs): pX = NULL!" ); + pPool->Remove( *pX->GetItem() ); + delete pX; + } + delete pInf; + } +} + +void __EXPORT EditUndoSetAttribs::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + ImpEditEngine* _pImpEE = GetImpEditEngine(); + BOOL bFields = FALSE; + for ( USHORT nPara = aESel.nStartPara; nPara <= aESel.nEndPara; nPara++ ) + { + ContentAttribsInfo* pInf = aPrevAttribs[ (USHORT)(nPara-aESel.nStartPara) ]; + DBG_ASSERT( pInf, "Undo (SetAttribs): pInf = NULL!" ); + + // erstmal die Absatzattribute... + _pImpEE->SetParaAttribs( nPara, pInf->GetPrevParaAttribs() ); + + // Dann die Zeichenattribute... + // Alle Attribute inkl. Features entfernen, werden wieder neu eingestellt. + _pImpEE->RemoveCharAttribs( nPara, 0, TRUE ); + DBG_ASSERT( _pImpEE->GetEditDoc().SaveGetObject( nPara ), "Undo (SetAttribs): pNode = NULL!" ); + ContentNode* pNode = _pImpEE->GetEditDoc().GetObject( nPara ); + for ( USHORT nAttr = 0; nAttr < pInf->GetPrevCharAttribs().Count(); nAttr++ ) + { + EditCharAttrib* pX = pInf->GetPrevCharAttribs()[nAttr]; + DBG_ASSERT( pX, "Redo (SetAttribs): pX = NULL!" ); + // wird autom. 'eingepoolt'. + _pImpEE->GetEditDoc().InsertAttrib( pNode, pX->GetStart(), pX->GetEnd(), *pX->GetItem() ); + if ( pX->Which() == EE_FEATURE_FIELD ) + bFields = TRUE; + } + } + if ( bFields ) + _pImpEE->UpdateFields(); + ImpSetSelection( GetImpEditEngine()->GetActiveView() ); +} + +void __EXPORT EditUndoSetAttribs::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + ImpEditEngine* _pImpEE = GetImpEditEngine(); + + EditSelection aSel( _pImpEE->CreateSel( aESel ) ); + if ( !bSetIsRemove ) + _pImpEE->SetAttribs( aSel, aNewAttribs, nSpecial ); + else + _pImpEE->RemoveCharAttribs( aSel, bRemoveParaAttribs, nRemoveWhich ); + + ImpSetSelection( GetImpEditEngine()->GetActiveView() ); +} + +void EditUndoSetAttribs::ImpSetSelection( EditView* /*pView*/ ) +{ + ImpEditEngine* _pImpEE = GetImpEditEngine(); + EditSelection aSel( _pImpEE->CreateSel( aESel ) ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoTransliteration +// ------------------------------------------------------------------------ +EditUndoTransliteration::EditUndoTransliteration( ImpEditEngine* _pImpEE, const ESelection& rESel, sal_Int32 nM ) + : EditUndo( EDITUNDO_TRANSLITERATE, _pImpEE ), aOldESel( rESel ) +{ + nMode = nM; + pTxtObj = NULL; +} + +EditUndoTransliteration::~EditUndoTransliteration() +{ + delete pTxtObj; +} + +void __EXPORT EditUndoTransliteration::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + + ImpEditEngine* _pImpEE = GetImpEditEngine(); + + EditSelection aSel( _pImpEE->CreateSel( aNewESel ) ); + + // Insert text, but don't expand Atribs at the current position: + aSel = _pImpEE->DeleteSelected( aSel ); + EditSelection aDelSel( aSel ); + aSel = _pImpEE->InsertParaBreak( aSel ); + aDelSel.Max() = aSel.Min(); + aDelSel.Max().GetNode()->GetCharAttribs().DeleteEmptyAttribs( _pImpEE->GetEditDoc().GetItemPool() ); + EditSelection aNewSel; + if ( pTxtObj ) + { + aNewSel = _pImpEE->InsertText( *pTxtObj, aSel ); + } + else + { + aNewSel = _pImpEE->InsertText( aSel, aText ); + } + if ( aNewSel.Min().GetNode() == aDelSel.Max().GetNode() ) + { + aNewSel.Min().SetNode( aDelSel.Min().GetNode() ); + aNewSel.Min().GetIndex() = + aNewSel.Min().GetIndex() + aDelSel.Min().GetIndex(); + } + if ( aNewSel.Max().GetNode() == aDelSel.Max().GetNode() ) + { + aNewSel.Max().SetNode( aDelSel.Min().GetNode() ); + aNewSel.Max().GetIndex() = + aNewSel.Max().GetIndex() + aDelSel.Min().GetIndex(); + } + _pImpEE->DeleteSelected( aDelSel ); + + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); +} + +void __EXPORT EditUndoTransliteration::Redo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + ImpEditEngine* _pImpEE = GetImpEditEngine(); + + EditSelection aSel( _pImpEE->CreateSel( aOldESel ) ); + EditSelection aNewSel = _pImpEE->TransliterateText( aSel, nMode ); + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( aNewSel ); +} + +// ----------------------------------------------------------------------- +// EditUndoMarkSelection +// ------------------------------------------------------------------------ +EditUndoMarkSelection::EditUndoMarkSelection( ImpEditEngine* _pImpEE, const ESelection& rSel ) + : EditUndo( EDITUNDO_MARKSELECTION, _pImpEE ), aSelection( rSel ) +{ +} + +EditUndoMarkSelection::~EditUndoMarkSelection() +{ +} + +void __EXPORT EditUndoMarkSelection::Undo() +{ + DBG_ASSERT( GetImpEditEngine()->GetActiveView(), "Undo/Redo: Keine Active View!" ); + if ( GetImpEditEngine()->GetActiveView() ) + { + if ( GetImpEditEngine()->IsFormatted() ) + GetImpEditEngine()->GetActiveView()->SetSelection( aSelection ); + else + GetImpEditEngine()->GetActiveView()->GetImpEditView()->SetEditSelection( GetImpEditEngine()->CreateSel( aSelection ) ); + } +} + +void __EXPORT EditUndoMarkSelection::Redo() +{ + // Fuer Redo unwichtig, weil am Anfang der Undo-Klammerung +} + diff --git a/editeng/source/editeng/editundo.hxx b/editeng/source/editeng/editundo.hxx new file mode 100644 index 000000000000..3d28fba677d5 --- /dev/null +++ b/editeng/source/editeng/editundo.hxx @@ -0,0 +1,318 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editundo.hxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDITUNDO_HXX +#define _EDITUNDO_HXX + +#include <editdoc.hxx> +#include <editeng/editund2.hxx> +#include <editeng/editdata.hxx> + +#define UNDO_NOACTION 0 +#define UNDO_NEWUNDO 1 +#define UNDO_UNDOSDELETED 2 +#define UNDO_EMPTYGROUPDELETED 3 +#define UNDO_INVALIDEND 4 + +class ImpEditEngine; +class EditView; + +// ----------------------------------------------------------------------- +// EditUndoDelContent +// ------------------------------------------------------------------------ +class EditUndoDelContent : public EditUndo +{ +private: + BOOL bDelObject; + USHORT nNode; + ContentNode* pContentNode; // Zeigt auf das gueltige, + // nicht zerstoerte Objekt! + +public: + TYPEINFO(); + EditUndoDelContent( ImpEditEngine* pImpEE, ContentNode* pNode, USHORT nPortio ); + ~EditUndoDelContent(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoConnectParas +// ------------------------------------------------------------------------ +class EditUndoConnectParas : public EditUndo +{ +private: + USHORT nNode; + USHORT nSepPos; + SfxItemSet aLeftParaAttribs; + SfxItemSet aRightParaAttribs; + + // 2 Pointer waeren schoener, aber dann muesste es ein SfxListener sein. + String aLeftStyleName; + String aRightStyleName; + SfxStyleFamily eLeftStyleFamily; + SfxStyleFamily eRightStyleFamily; + + BOOL bBackward; + +public: + TYPEINFO(); + EditUndoConnectParas( ImpEditEngine* pImpEE, USHORT nNode, USHORT nSepPos, + const SfxItemSet& rLeftParaAttribs, const SfxItemSet& rRightParaAttribs, + const SfxStyleSheet* pLeftStyle, const SfxStyleSheet* pRightStyle, BOOL bBackward ); + ~EditUndoConnectParas(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoSplitPara +// ------------------------------------------------------------------------ +class EditUndoSplitPara : public EditUndo +{ +private: + USHORT nNode; + USHORT nSepPos; + +public: + TYPEINFO(); + EditUndoSplitPara( ImpEditEngine* pImpEE, USHORT nNode, USHORT nSepPos ); + ~EditUndoSplitPara(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoInsertChars +// ------------------------------------------------------------------------ +class EditUndoInsertChars : public EditUndo +{ +private: + EPaM aEPaM; + String aText; + +public: + TYPEINFO(); + EditUndoInsertChars( ImpEditEngine* pImpEE, const EPaM& rEPaM, const String& rStr ); + + const EPaM& GetEPaM() { return aEPaM; } + String& GetStr() { return aText; } + + virtual void Undo(); + virtual void Redo(); + + virtual BOOL Merge( SfxUndoAction *pNextAction ); +}; + +// ----------------------------------------------------------------------- +// EditUndoRemoveChars +// ------------------------------------------------------------------------ +class EditUndoRemoveChars : public EditUndo +{ +private: + EPaM aEPaM; + String aText; + +public: + TYPEINFO(); + EditUndoRemoveChars( ImpEditEngine* pImpEE, const EPaM& rEPaM, const String& rStr ); + + const EPaM& GetEPaM() { return aEPaM; } + String& GetStr() { return aText; } + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoInsertFeature +// ------------------------------------------------------------------------ +class EditUndoInsertFeature : public EditUndo +{ +private: + EPaM aEPaM; + SfxPoolItem* pFeature; + +public: + TYPEINFO(); + EditUndoInsertFeature( ImpEditEngine* pImpEE, const EPaM& rEPaM, + const SfxPoolItem& rFeature); + ~EditUndoInsertFeature(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoMoveParagraphs +// ------------------------------------------------------------------------ +class EditUndoMoveParagraphs: public EditUndo +{ +private: + Range nParagraphs; + USHORT nDest; + +public: + TYPEINFO(); + EditUndoMoveParagraphs( ImpEditEngine* pImpEE, const Range& rParas, USHORT nDest ); + ~EditUndoMoveParagraphs(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoSetStyleSheet +// ------------------------------------------------------------------------ +class EditUndoSetStyleSheet: public EditUndo +{ +private: + USHORT nPara; + XubString aPrevName; + XubString aNewName; + SfxStyleFamily ePrevFamily; + SfxStyleFamily eNewFamily; + SfxItemSet aPrevParaAttribs; + +public: + TYPEINFO(); + + EditUndoSetStyleSheet( ImpEditEngine* pImpEE, USHORT nPara, + const XubString& rPrevName, SfxStyleFamily ePrevFamily, + const XubString& rNewName, SfxStyleFamily eNewFamily, + const SfxItemSet& rPrevParaAttribs ); + ~EditUndoSetStyleSheet(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoSetParaAttribs +// ------------------------------------------------------------------------ +class EditUndoSetParaAttribs: public EditUndo +{ +private: + USHORT nPara; + SfxItemSet aPrevItems; + SfxItemSet aNewItems; + +public: + TYPEINFO(); + EditUndoSetParaAttribs( ImpEditEngine* pImpEE, USHORT nPara, const SfxItemSet& rPrevItems, const SfxItemSet& rNewItems ); + ~EditUndoSetParaAttribs(); + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoSetAttribs +// ------------------------------------------------------------------------ +class EditUndoSetAttribs: public EditUndo +{ +private: + ESelection aESel; + SfxItemSet aNewAttribs; + ContentInfoArray aPrevAttribs; + + BYTE nSpecial; + BOOL bSetIsRemove; + BOOL bRemoveParaAttribs; + USHORT nRemoveWhich; + + void ImpSetSelection( EditView* pView ); + + +public: + TYPEINFO(); + EditUndoSetAttribs( ImpEditEngine* pImpEE, const ESelection& rESel, const SfxItemSet& rNewItems ); + ~EditUndoSetAttribs(); + + ContentInfoArray& GetContentInfos() { return aPrevAttribs; } + SfxItemSet& GetNewAttribs() { return aNewAttribs; } + + void SetSpecial( BYTE n ) { nSpecial = n; } + void SetRemoveAttribs( BOOL b ) { bSetIsRemove = b; } + void SetRemoveParaAttribs( BOOL b ) { bRemoveParaAttribs = b; } + void SetRemoveWhich( USHORT n ) { nRemoveWhich = n; } + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoTransliteration +// ------------------------------------------------------------------------ +class EditUndoTransliteration: public EditUndo +{ +private: + ESelection aOldESel; + ESelection aNewESel; + + sal_Int32 nMode; + EditTextObject* pTxtObj; + String aText; + +public: + TYPEINFO(); + EditUndoTransliteration( ImpEditEngine* pImpEE, const ESelection& rESel, sal_Int32 nMode ); + ~EditUndoTransliteration(); + + void SetText( const String& rText ) { aText = rText; } + void SetText( EditTextObject* pObj ) { pTxtObj = pObj; } + void SetNewSelection( const ESelection& rSel ) { aNewESel = rSel; } + + virtual void Undo(); + virtual void Redo(); +}; + +// ----------------------------------------------------------------------- +// EditUndoMarkSelection +// ------------------------------------------------------------------------ +class EditUndoMarkSelection: public EditUndo +{ +private: + ESelection aSelection; + +public: + TYPEINFO(); + EditUndoMarkSelection( ImpEditEngine* pImpEE, const ESelection& rSel ); + ~EditUndoMarkSelection(); + + virtual void Undo(); + virtual void Redo(); +}; + + +#endif // _EDITUNDO_HXX diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx new file mode 100644 index 000000000000..12c8d9d565bd --- /dev/null +++ b/editeng/source/editeng/editview.cxx @@ -0,0 +1,1598 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editview.cxx,v $ + * $Revision: 1.52.74.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <com/sun/star/i18n/WordType.hpp> +#include <vcl/metric.hxx> + +#include <i18npool/mslangid.hxx> +#include <svl/languageoptions.hxx> +#include <svtools/ctrltool.hxx> +#include <svtools/langtab.hxx> + +#include <svl/srchitem.hxx> + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> + +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/flditem.hxx> +#include <editeng/svxacorr.hxx> +#include <editeng/langitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/eerdll.hxx> +#include <eerdll2.hxx> +#include <editeng.hrc> +#include <helpid.hrc> +#include <i18npool/lang.h> +#include <vcl/menu.hxx> +#include <editeng/acorrcfg.hxx> +#include <editeng/unolingu.hxx> +#include <editeng/fontitem.hxx> + +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/beans/PropertyValues.hdl> +#include <com/sun/star/lang/Locale.hpp> +#include <linguistic/lngprops.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <unotools/lingucfg.hxx> + +using ::rtl::OUString; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::linguistic2; + + +DBG_NAME( EditView ) + + +// From SW => Create common method +LanguageType lcl_CheckLanguage( + const OUString &rText, + Reference< XSpellChecker1 > xSpell, + Reference< linguistic2::XLanguageGuessing > xLangGuess, + sal_Bool bIsParaText ) +{ + LanguageType nLang = LANGUAGE_NONE; + if (bIsParaText) // check longer texts with language-guessing... + { + if (!xLangGuess.is()) + return nLang; + + lang::Locale aLocale( xLangGuess->guessPrimaryLanguage( rText, 0, rText.getLength()) ); + + // get language as from "Tools/Options - Language Settings - Languages: Locale setting" + LanguageType nTmpLang = Application::GetSettings().GetLanguage(); + + // if the result from language guessing does not provide a 'Country' part + // try to get it by looking up the locale setting of the office. + if (aLocale.Country.getLength() == 0) + { + lang::Locale aTmpLocale = SvxCreateLocale( nTmpLang ); + if (aTmpLocale.Language == aLocale.Language) + nLang = nTmpLang; + } + if (nLang == LANGUAGE_NONE) // language not found by looking up the sytem language... + nLang = MsLangId::convertLocaleToLanguageWithFallback( aLocale ); + if (nLang == LANGUAGE_SYSTEM) + nLang = nTmpLang; + if (nLang == LANGUAGE_DONTKNOW) + nLang = LANGUAGE_NONE; + } + else // check single word + { + if (!xSpell.is()) + return nLang; + + // + // build list of languages to check + // + LanguageType aLangList[4]; + const AllSettings& rSettings = Application::GetSettings(); + SvtLinguOptions aLinguOpt; + SvtLinguConfig().GetOptions( aLinguOpt ); + // The default document language from "Tools/Options - Language Settings - Languages: Western" + aLangList[0] = aLinguOpt.nDefaultLanguage; + // The one from "Tools/Options - Language Settings - Languages: User interface" + aLangList[1] = rSettings.GetUILanguage(); + // The one from "Tools/Options - Language Settings - Languages: Locale setting" + aLangList[2] = rSettings.GetLanguage(); + // en-US + aLangList[3] = LANGUAGE_ENGLISH_US; +#ifdef DEBUG + lang::Locale a0( SvxCreateLocale( aLangList[0] ) ); + lang::Locale a1( SvxCreateLocale( aLangList[1] ) ); + lang::Locale a2( SvxCreateLocale( aLangList[2] ) ); + lang::Locale a3( SvxCreateLocale( aLangList[3] ) ); +#endif + + INT32 nCount = sizeof(aLangList) / sizeof(aLangList[0]); + for (INT32 i = 0; i < nCount; i++) + { + INT16 nTmpLang = aLangList[i]; + if (nTmpLang != LANGUAGE_NONE && nTmpLang != LANGUAGE_DONTKNOW) + { + if (xSpell->hasLanguage( nTmpLang ) && + xSpell->isValid( rText, nTmpLang, Sequence< PropertyValue >() )) + { + nLang = nTmpLang; + break; + } + } + } + } + + return nLang; +} + + +// ---------------------------------------------------------------------- +// class EditView +// ---------------------------------------------------------------------- +EditView::EditView( EditEngine* pEng, Window* pWindow ) +{ + DBG_CTOR( EditView, 0 ); + pImpEditView = new ImpEditView( this, pEng, pWindow ); +} + +EditView::~EditView() +{ + DBG_DTOR( EditView, 0 ); + delete pImpEditView; +} + +ImpEditEngine* EditView::GetImpEditEngine() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->pEditEngine->pImpEditEngine; +} + +EditEngine* EditView::GetEditEngine() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->pEditEngine; +} + +void EditView::Invalidate() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + if ( !pImpEditView->DoInvalidateMore() ) + pImpEditView->GetWindow()->Invalidate( pImpEditView->aOutArea ); + else + { + Rectangle aRect( pImpEditView->aOutArea ); + long nMore = pImpEditView->GetWindow()->PixelToLogic( Size( pImpEditView->GetInvalidateMore(), 0 ) ).Width(); + aRect.Left() -= nMore; + aRect.Right() += nMore; + aRect.Top() -= nMore; + aRect.Bottom() += nMore; + pImpEditView->GetWindow()->Invalidate( aRect ); + } +} + +void EditView::SetReadOnly( sal_Bool bReadOnly ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->bReadOnly = bReadOnly; +} + +sal_Bool EditView::IsReadOnly() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->bReadOnly; +} + +void EditView::SetSelection( const ESelection& rESel ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + // Falls jemand gerade ein leeres Attribut hinterlassen hat, + // und dann der Outliner die Selektion manipulitert: + if ( !pImpEditView->GetEditSelection().HasRange() ) + { + ContentNode* pNode = pImpEditView->GetEditSelection().Max().GetNode(); + PIMPEE->CursorMoved( pNode ); + } + EditSelection aNewSelection( PIMPEE->ConvertSelection( rESel.nStartPara, rESel.nStartPos, rESel.nEndPara, rESel.nEndPos ) ); + + // Wenn nach einem KeyInput die Selection manipuliert wird: + PIMPEE->CheckIdleFormatter(); + + // Selektion darf nicht bei einem unsichtbaren Absatz Starten/Enden: + ParaPortion* pPortion = PIMPEE->FindParaPortion( aNewSelection.Min().GetNode() ); + if ( !pPortion->IsVisible() ) + { + pPortion = PIMPEE->GetPrevVisPortion( pPortion ); + ContentNode* pNode = pPortion ? pPortion->GetNode() : PIMPEE->GetEditDoc().GetObject( 0 ); + aNewSelection.Min() = EditPaM( pNode, pNode->Len() ); + } + pPortion = PIMPEE->FindParaPortion( aNewSelection.Max().GetNode() ); + if ( !pPortion->IsVisible() ) + { + pPortion = PIMPEE->GetPrevVisPortion( pPortion ); + ContentNode* pNode = pPortion ? pPortion->GetNode() : PIMPEE->GetEditDoc().GetObject( 0 ); + aNewSelection.Max() = EditPaM( pNode, pNode->Len() ); + } + + pImpEditView->DrawSelection(); // alte Selektion 'weg-zeichnen' + pImpEditView->SetEditSelection( aNewSelection ); + pImpEditView->DrawSelection(); + sal_Bool bGotoCursor = pImpEditView->DoAutoScroll(); + ShowCursor( bGotoCursor ); +} + +ESelection EditView::GetSelection() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + ESelection aSelection; + + aSelection.nStartPara = PIMPEE->GetEditDoc().GetPos( pImpEditView->GetEditSelection().Min().GetNode() ); + aSelection.nEndPara = PIMPEE->GetEditDoc().GetPos( pImpEditView->GetEditSelection().Max().GetNode() ); + + aSelection.nStartPos = pImpEditView->GetEditSelection().Min().GetIndex(); + aSelection.nEndPos = pImpEditView->GetEditSelection().Max().GetIndex(); + + return aSelection; +} + +sal_Bool EditView::HasSelection() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->HasSelection(); +} + +void EditView::DeleteSelected() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->DeleteSelected(); +} + +USHORT EditView::GetSelectedScriptType() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->GetScriptType( pImpEditView->GetEditSelection() ); +} + +void EditView::Paint( const Rectangle& rRect ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Paint( pImpEditView, rRect ); +} + +void EditView::SetEditEngine( EditEngine* pEditEng ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->pEditEngine = pEditEng; + EditSelection aStartSel; + aStartSel = PIMPEE->GetEditDoc().GetStartPaM(); + pImpEditView->SetEditSelection( aStartSel ); +} + +void EditView::SetWindow( Window* pWin ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->pOutWin = pWin; + PIMPEE->GetSelEngine().Reset(); +} + +Window* EditView::GetWindow() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->pOutWin; +} + +void EditView::SetVisArea( const Rectangle& rRec ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetVisDocStartPos( rRec.TopLeft() ); +} + +const Rectangle& EditView::GetVisArea() const +{ + DBG_CHKTHIS( EditView, 0 ); + // Change return value to Rectangle in next incompatible build !!! + static Rectangle aRect; + aRect = pImpEditView->GetVisDocArea(); + return aRect; +} + +void EditView::SetOutputArea( const Rectangle& rRec ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetOutputArea( rRec ); + + // Rest nur hier, wenn API-Aufruf: + pImpEditView->CalcAnchorPoint(); + if ( PIMPEE->GetStatus().AutoPageSize() ) + pImpEditView->RecalcOutputArea(); + pImpEditView->ShowCursor( sal_False, sal_False ); +} + +const Rectangle& EditView::GetOutputArea() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->GetOutputArea(); +} + +void EditView::SetPointer( const Pointer& rPointer ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetPointer( rPointer ); +} + +const Pointer& EditView::GetPointer() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->GetPointer(); +} + +void EditView::SetCursor( const Cursor& rCursor ) +{ + DBG_CHKTHIS( EditView, 0 ); + delete pImpEditView->pCursor; + pImpEditView->pCursor = new Cursor( rCursor ); +} + +Cursor* EditView::GetCursor() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->pCursor; +} + +void EditView::InsertText( const XubString& rStr, sal_Bool bSelect ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + ImpEditEngine* pImpEE = PIMPEE; + pImpEditView->DrawSelection(); + + EditPaM aPaM1; + if ( bSelect ) + { + EditSelection aTmpSel( pImpEditView->GetEditSelection() ); + aTmpSel.Adjust( pImpEE->GetEditDoc() ); + aPaM1 = aTmpSel.Min(); + } + + pImpEE->UndoActionStart( EDITUNDO_INSERT ); + EditPaM aPaM2( pImpEE->InsertText( pImpEditView->GetEditSelection(), rStr ) ); + pImpEE->UndoActionEnd( EDITUNDO_INSERT ); + + if ( bSelect ) + { + DBG_ASSERT( !aPaM1.DbgIsBuggy( pImpEE->GetEditDoc() ), "Insert: PaM kaputt" ); + pImpEditView->SetEditSelection( EditSelection( aPaM1, aPaM2 ) ); + } + else + pImpEditView->SetEditSelection( EditSelection( aPaM2, aPaM2 ) ); + + pImpEE->FormatAndUpdate( this ); +} + +sal_Bool EditView::PostKeyEvent( const KeyEvent& rKeyEvent ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->PostKeyEvent( rKeyEvent ); +} + +sal_Bool EditView::MouseButtonUp( const MouseEvent& rMouseEvent ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->MouseButtonUp( rMouseEvent ); +} + +sal_Bool EditView::MouseButtonDown( const MouseEvent& rMouseEvent ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->MouseButtonDown( rMouseEvent ); +} + +sal_Bool EditView::MouseMove( const MouseEvent& rMouseEvent ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->MouseMove( rMouseEvent ); +} + +void EditView::Command( const CommandEvent& rCEvt ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->Command( rCEvt ); +} + +void EditView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + +// Draw vertraegt die Assertion nicht, spaeter mal aktivieren +// DBG_ASSERT( pImpEditView->pEditEngine->HasView( this ), "ShowCursor - View nicht angemeldet!" ); +// DBG_ASSERT( !GetWindow()->IsInPaint(), "ShowCursor - Why in Paint ?!" ); + + if ( pImpEditView->pEditEngine->HasView( this ) ) + { + // Das ControlWord hat mehr Gewicht: + if ( !pImpEditView->DoAutoScroll() ) + bGotoCursor = sal_False; + pImpEditView->ShowCursor( bGotoCursor, bForceVisCursor ); + } +} + +void EditView::HideCursor() +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->GetCursor()->Hide(); +} + +Pair EditView::Scroll( long ndX, long ndY, BYTE nRangeCheck ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->Scroll( ndX, ndY, nRangeCheck ); +} + +const SfxItemSet& EditView::GetEmptyItemSet() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->GetEmptyItemSet(); +} + +void EditView::SetAttribs( const SfxItemSet& rSet ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + DBG_ASSERT( !pImpEditView->aEditSelection.IsInvalid(), "Blinde Selection in ...." ); + + // Kein Undo-Kappseln noetig... + pImpEditView->DrawSelection(); + PIMPEE->SetAttribs( pImpEditView->GetEditSelection(), rSet, ATTRSPECIAL_WHOLEWORD ); + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::SetParaAttribs( const SfxItemSet& rSet, sal_uInt16 nPara ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + // Kein Undo-Kappseln noetig... + PIMPEE->SetParaAttribs( nPara, rSet ); + // Beim Aendern von Absatzattributen muss immer formatiert werden... + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::RemoveAttribsKeepLanguages( sal_Bool bRemoveParaAttribs ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + pImpEditView->DrawSelection(); + PIMPEE->UndoActionStart( EDITUNDO_RESETATTRIBS ); + EditSelection aSelection( pImpEditView->GetEditSelection() ); + + for (sal_uInt16 nWID = EE_ITEMS_START; nWID <= EE_ITEMS_END; ++nWID) + { + bool bIsLang = EE_CHAR_LANGUAGE == nWID || + EE_CHAR_LANGUAGE_CJK == nWID || + EE_CHAR_LANGUAGE_CTL == nWID; + if (!bIsLang) + PIMPEE->RemoveCharAttribs( aSelection, bRemoveParaAttribs, nWID ); + } + + PIMPEE->UndoActionEnd( EDITUNDO_RESETATTRIBS ); + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::RemoveAttribs( sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + pImpEditView->DrawSelection(); + PIMPEE->UndoActionStart( EDITUNDO_RESETATTRIBS ); + PIMPEE->RemoveCharAttribs( pImpEditView->GetEditSelection(), bRemoveParaAttribs, nWhich ); + PIMPEE->UndoActionEnd( EDITUNDO_RESETATTRIBS ); + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::RemoveCharAttribs( sal_uInt16 nPara, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->UndoActionStart( EDITUNDO_RESETATTRIBS ); + PIMPEE->RemoveCharAttribs( nPara, nWhich ); + PIMPEE->UndoActionEnd( EDITUNDO_RESETATTRIBS ); + PIMPEE->FormatAndUpdate( this ); +} + +SfxItemSet EditView::GetAttribs() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + DBG_ASSERT( !pImpEditView->aEditSelection.IsInvalid(), "Blinde Selection in ...." ); + return PIMPEE->GetAttribs( pImpEditView->GetEditSelection() ); +} + +void EditView::Undo() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Undo( this ); +} + +void EditView::Redo() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Redo( this ); +} + +ULONG EditView::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, sal_Bool bSelect, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + EditSelection aOldSel( pImpEditView->GetEditSelection() ); + pImpEditView->DrawSelection(); + PIMPEE->UndoActionStart( EDITUNDO_READ ); + EditPaM aEndPaM = PIMPEE->Read( rInput, rBaseURL, eFormat, aOldSel, pHTTPHeaderAttrs ); + PIMPEE->UndoActionEnd( EDITUNDO_READ ); + EditSelection aNewSel( aEndPaM, aEndPaM ); + if ( bSelect ) + { + aOldSel.Adjust( PIMPEE->GetEditDoc() ); + aNewSel.Min() = aOldSel.Min(); + } + + pImpEditView->SetEditSelection( aNewSel ); + sal_Bool bGotoCursor = pImpEditView->DoAutoScroll(); + ShowCursor( bGotoCursor ); + + return rInput.GetError(); +} + +#ifndef SVX_LIGHT +ULONG EditView::Write( SvStream& rOutput, EETextFormat eFormat ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Write( rOutput, eFormat, pImpEditView->GetEditSelection() ); + ShowCursor(); + return rOutput.GetError(); +} +#endif + +void EditView::Cut() +{ + DBG_CHKTHIS( EditView, 0 ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + pImpEditView->CutCopy( aClipBoard, sal_True ); +} + +::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > EditView::GetTransferable() +{ + uno::Reference< datatransfer::XTransferable > xData = GetEditEngine()->pImpEditEngine->CreateTransferable( pImpEditView->GetEditSelection() ); + return xData; +} + +void EditView::Copy() +{ + DBG_CHKTHIS( EditView, 0 ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + pImpEditView->CutCopy( aClipBoard, sal_False ); +} + +void EditView::Paste() +{ + DBG_CHKTHIS( EditView, 0 ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + pImpEditView->Paste( aClipBoard, sal_False ); +} + +void EditView::PasteSpecial() +{ + DBG_CHKTHIS( EditView, 0 ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + pImpEditView->Paste(aClipBoard, sal_True ); +} + +void EditView::EnablePaste( sal_Bool bEnable ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->EnablePaste( bEnable ); +} + +sal_Bool EditView::IsPasteEnabled() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->IsPasteEnabled(); +} + +Point EditView::GetWindowPosTopLeft( sal_uInt16 nParagraph ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + Point aDocPos( pImpEditView->pEditEngine->GetDocPosTopLeft( nParagraph ) ); + return pImpEditView->GetWindowPos( aDocPos ); +} + +sal_uInt16 EditView::GetParagraph( const Point& rMousePosPixel ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + Point aMousePos( rMousePosPixel ); + aMousePos = GetWindow()->PixelToLogic( aMousePos ); + Point aDocPos( pImpEditView->GetDocPos( aMousePos ) ); + sal_uInt16 nParagraph = PIMPEE->GetParaPortions().FindParagraph( aDocPos.Y() ); + return nParagraph; +} + +void EditView::IndentBlock() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + PIMPEE->IndentBlock( this, sal_True ); +} + +void EditView::UnindentBlock() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + PIMPEE->IndentBlock( this, sal_False ); +} + +EESelectionMode EditView::GetSelectionMode() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->GetSelectionMode(); +} + +void EditView::SetSelectionMode( EESelectionMode eMode ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetSelectionMode( eMode ); +} + +XubString EditView::GetSelected() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->GetSelected( pImpEditView->GetEditSelection() ); +} + +void EditView::MoveParagraphs( Range aParagraphs, sal_uInt16 nNewPos ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->UndoActionStart( EDITUNDO_MOVEPARAS ); + PIMPEE->MoveParagraphs( aParagraphs, nNewPos, this ); + PIMPEE->UndoActionEnd( EDITUNDO_MOVEPARAS ); +} + +void EditView::MoveParagraphs( long nDiff ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + ESelection aSel = GetSelection(); + Range aRange( aSel.nStartPara, aSel.nEndPara ); + aRange.Justify(); + long nDest = ( nDiff > 0 ? aRange.Max() : aRange.Min() ) + nDiff; + if ( nDiff > 0 ) + nDest++; + DBG_ASSERT( ( nDest >= 0 ) && ( nDest <= pImpEditView->pEditEngine->GetParagraphCount() ), "MoveParagraphs - wrong Parameters!" ); + MoveParagraphs( aRange, + sal::static_int_cast< USHORT >( nDest ) ); +} + +void EditView::SetBackgroundColor( const Color& rColor ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->SetBackgroundColor( rColor ); +} + +Color EditView::GetBackgroundColor() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->GetBackgroundColor(); +} + +void EditView::SetControlWord( sal_uInt32 nWord ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->nControl = nWord; +} + +sal_uInt32 EditView::GetControlWord() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->nControl; +} + +EditTextObject* EditView::CreateTextObject() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->CreateTextObject( pImpEditView->GetEditSelection() ); +} + +void EditView::InsertText( const EditTextObject& rTextObject ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->DrawSelection(); + + PIMPEE->UndoActionStart( EDITUNDO_INSERT ); + EditSelection aTextSel( PIMPEE->InsertText( rTextObject, pImpEditView->GetEditSelection() ) ); + PIMPEE->UndoActionEnd( EDITUNDO_INSERT ); + + aTextSel.Min() = aTextSel.Max(); // Selektion nicht behalten. + pImpEditView->SetEditSelection( aTextSel ); + PIMPEE->FormatAndUpdate( this ); +} + +void EditView::InsertText( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > xDataObj, const String& rBaseURL, BOOL bUseSpecial ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + PIMPEE->UndoActionStart( EDITUNDO_INSERT ); + pImpEditView->DeleteSelected(); + EditSelection aTextSel( PIMPEE->InsertText( xDataObj, rBaseURL, pImpEditView->GetEditSelection().Max(), bUseSpecial ) ); + PIMPEE->UndoActionEnd( EDITUNDO_INSERT ); + + aTextSel.Min() = aTextSel.Max(); // Selektion nicht behalten. + pImpEditView->SetEditSelection( aTextSel ); + PIMPEE->FormatAndUpdate( this ); +} + +sal_Bool EditView::Drop( const DropEvent& ) +{ + return FALSE; +} + +ESelection EditView::GetDropPos() +{ + DBG_ERROR( "GetDropPos - Why?!" ); + return ESelection(); +} + +sal_Bool EditView::QueryDrop( DropEvent& ) +{ + return FALSE; +} + +void EditView::SetEditEngineUpdateMode( sal_Bool bUpdate ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->SetUpdateMode( bUpdate, this ); +} + +void EditView::ForceUpdate() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->SetUpdateMode( sal_True, this, sal_True ); +} + +void EditView::SetStyleSheet( SfxStyleSheet* pStyle ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + EditSelection aSel( pImpEditView->GetEditSelection() ); + PIMPEE->UndoActionStart( EDITUNDO_STYLESHEET ); + PIMPEE->SetStyleSheet( aSel, pStyle ); + PIMPEE->UndoActionEnd( EDITUNDO_STYLESHEET ); +} + +SfxStyleSheet* EditView::GetStyleSheet() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + + EditSelection aSel( pImpEditView->GetEditSelection() ); + aSel.Adjust( PIMPEE->GetEditDoc() ); + sal_uInt16 nStartPara = PIMPEE->GetEditDoc().GetPos( aSel.Min().GetNode() ); + sal_uInt16 nEndPara = PIMPEE->GetEditDoc().GetPos( aSel.Max().GetNode() ); + + SfxStyleSheet* pStyle = NULL; + for ( sal_uInt16 n = nStartPara; n <= nEndPara; n++ ) + { + SfxStyleSheet* pTmpStyle = PIMPEE->GetStyleSheet( n ); + if ( ( n != nStartPara ) && ( pStyle != pTmpStyle ) ) + return NULL; // Nicht eindeutig. + pStyle = pTmpStyle; + } + return pStyle; +} + +sal_Bool EditView::IsInsertMode() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->IsInsertMode(); +} + +void EditView::SetInsertMode( sal_Bool bInsert ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetInsertMode( bInsert ); +} + +void EditView::SetAnchorMode( EVAnchorMode eMode ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetAnchorMode( eMode ); +} + +EVAnchorMode EditView::GetAnchorMode() const +{ + DBG_CHKTHIS( EditView, 0 ); + return pImpEditView->GetAnchorMode(); +} + +void EditView::TransliterateText( sal_Int32 nTransliterationMode ) +{ + DBG_CHKTHIS( EditView, 0 ); + EditSelection aOldSel( pImpEditView->GetEditSelection() ); + EditSelection aNewSel = PIMPEE->TransliterateText( pImpEditView->GetEditSelection(), nTransliterationMode ); + if ( aNewSel != aOldSel ) + { + pImpEditView->DrawSelection(); // alte Selektion 'weg-zeichnen' + pImpEditView->SetEditSelection( aNewSel ); + pImpEditView->DrawSelection(); + } +} + + +sal_Bool EditView::MatchGroup() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + EditSelection aNewSel( PIMPEE->MatchGroup( pImpEditView->GetEditSelection() ) ); + if ( aNewSel.HasRange() ) + { + pImpEditView->DrawSelection(); + pImpEditView->SetEditSelection( aNewSel ); + pImpEditView->DrawSelection(); + ShowCursor(); + return sal_True; + } + return sal_False; +} + +void EditView::CompleteAutoCorrect() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + if ( !pImpEditView->HasSelection() && PIMPEE->GetStatus().DoAutoCorrect() ) + { + pImpEditView->DrawSelection(); + EditSelection aSel = pImpEditView->GetEditSelection(); + aSel = PIMPEE->EndOfWord( aSel.Max() ); + // MT 06/00: Why pass EditSelection to AutoCorrect, not EditPaM?! + aSel = PIMPEE->AutoCorrect( aSel, 0, !IsInsertMode() ); + pImpEditView->SetEditSelection( aSel ); + if ( PIMPEE->IsModified() ) + PIMPEE->FormatAndUpdate( this ); + } +} + +EESpellState EditView::StartSpeller( sal_Bool bMultipleDoc ) +{ +#ifdef SVX_LIGHT + return EE_SPELL_NOSPELLER; +#else + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + if ( !PIMPEE->GetSpeller().is() ) + return EE_SPELL_NOSPELLER; + + return PIMPEE->Spell( this, bMultipleDoc ); +#endif +} + +EESpellState EditView::StartThesaurus() +{ +#ifdef SVX_LIGHT + return EE_SPELL_NOSPELLER; +#else + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + if ( !PIMPEE->GetSpeller().is() ) + return EE_SPELL_NOSPELLER; + + return PIMPEE->StartThesaurus( this ); +#endif +} + + +void EditView::StartTextConversion( + LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, + INT32 nOptions, BOOL bIsInteractive, BOOL bMultipleDoc ) +{ +#ifdef SVX_LIGHT +#else + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + PIMPEE->Convert( this, nSrcLang, nDestLang, pDestFont, nOptions, bIsInteractive, bMultipleDoc ); +#endif +} + + +sal_uInt16 EditView::StartSearchAndReplace( const SvxSearchItem& rSearchItem ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return PIMPEE->StartSearchAndReplace( this, rSearchItem ); +} + +sal_Bool EditView::IsCursorAtWrongSpelledWord( sal_Bool bMarkIfWrong ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + sal_Bool bIsWrong = sal_False; + if ( !HasSelection() ) + { + EditPaM aPaM = pImpEditView->GetEditSelection().Max(); + bIsWrong = pImpEditView->IsWrongSpelledWord( aPaM, bMarkIfWrong ); + } + return bIsWrong; +} + +sal_Bool EditView::IsWrongSpelledWordAtPos( const Point& rPosPixel, sal_Bool bMarkIfWrong ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + Point aPos ( pImpEditView->GetWindow()->PixelToLogic( rPosPixel ) ); + aPos = pImpEditView->GetDocPos( aPos ); + EditPaM aPaM = pImpEditView->pEditEngine->pImpEditEngine->GetPaM( aPos, sal_False ); + return pImpEditView->IsWrongSpelledWord( aPaM , bMarkIfWrong ); +} + +void EditView::ExecuteSpellPopup( const Point& rPosPixel, Link* pCallBack ) +{ +#ifndef SVX_LIGHT + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + Point aPos ( pImpEditView->GetWindow()->PixelToLogic( rPosPixel ) ); + aPos = pImpEditView->GetDocPos( aPos ); + EditPaM aPaM = pImpEditView->pEditEngine->pImpEditEngine->GetPaM( aPos, sal_False ); + Reference< XSpellChecker1 > xSpeller( PIMPEE->GetSpeller() ); + ESelection aOldSel = GetSelection(); + if ( xSpeller.is() && pImpEditView->IsWrongSpelledWord( aPaM, sal_True ) ) + { + PopupMenu aPopupMenu( EditResId( RID_MENU_SPELL ) ); + PopupMenu *pAutoMenu = aPopupMenu.GetPopupMenu( MN_AUTOCORR ); + PopupMenu *pInsertMenu = aPopupMenu.GetPopupMenu( MN_INSERT ); + + EditPaM aPaM2( aPaM ); + aPaM2.GetIndex()++; + + // Gibt es Replace-Vorschlaege? + String aSelected( GetSelected() ); + // + // restrict the maximal number of suggestions displayed + // in the context menu. + // Note: That could of course be done by clipping the + // resulting sequence but the current third party + // implementations result differs greatly if the number of + // suggestions to be retuned gets changed. Statistically + // it gets much better if told to return e.g. only 7 strings + // than returning e.g. 16 suggestions and using only the + // first 7. Thus we hand down the value to use to that + // implementation here by providing an additional parameter. + Sequence< PropertyValue > aPropVals(1); + PropertyValue &rVal = aPropVals.getArray()[0]; + rVal.Name = OUString::createFromAscii( UPN_MAX_NUMBER_OF_SUGGESTIONS ); + rVal.Value <<= (INT16) 7; + // + // Gibt es Replace-Vorschlaege? + Reference< XSpellAlternatives > xSpellAlt = + xSpeller->spell( aSelected, PIMPEE->GetLanguage( aPaM2 ), aPropVals ); + + Reference< XLanguageGuessing > xLangGuesser( EE_DLL()->GetGlobalData()->GetLanguageGuesser() ); + + // check if text might belong to a different language... + LanguageType nGuessLangWord = LANGUAGE_NONE; + LanguageType nGuessLangPara = LANGUAGE_NONE; + if (xSpellAlt.is() && xLangGuesser.is()) + { + String aParaText; + ContentNode *pNode = aPaM.GetNode(); + if (pNode) + { + aParaText = *pNode; + } + else + { + DBG_ERROR( "content node is NULL" ); + } + + nGuessLangWord = lcl_CheckLanguage( xSpellAlt->getWord(), xSpeller, xLangGuesser, sal_False ); + nGuessLangPara = lcl_CheckLanguage( aParaText, xSpeller, xLangGuesser, sal_True ); + } + if (nGuessLangWord != LANGUAGE_NONE || nGuessLangPara != LANGUAGE_NONE) + { + // make sure LANGUAGE_NONE gets not used as menu entry + if (nGuessLangWord == LANGUAGE_NONE) + nGuessLangWord = nGuessLangPara; + if (nGuessLangPara == LANGUAGE_NONE) + nGuessLangPara = nGuessLangWord; + + aPopupMenu.InsertSeparator(); + String aTmpWord( SvtLanguageTable::GetLanguageString( nGuessLangWord ) ); + String aTmpPara( SvtLanguageTable::GetLanguageString( nGuessLangPara ) ); + String aWordStr( EditResId( RID_STR_WORD ) ); + aWordStr.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "%x" ) ), aTmpWord ); + String aParaStr( EditResId( RID_STR_PARAGRAPH ) ); + aParaStr.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "%x" ) ), aTmpPara ); + aPopupMenu.InsertItem( MN_WORDLANGUAGE, aWordStr ); + aPopupMenu.SetHelpId( MN_WORDLANGUAGE, HID_EDITENG_SPELLER_WORDLANGUAGE ); + aPopupMenu.InsertItem( MN_PARALANGUAGE, aParaStr ); + aPopupMenu.SetHelpId( MN_PARALANGUAGE, HID_EDITENG_SPELLER_PARALANGUAGE ); + } + + // ## Create mnemonics here + if ( Application::IsAutoMnemonicEnabled() ) + { + aPopupMenu.CreateAutoMnemonics(); + aPopupMenu.SetMenuFlags( aPopupMenu.GetMenuFlags() | MENU_FLAG_NOAUTOMNEMONICS ); + } + + // Replace suggestions... + Sequence< OUString > aAlt; + if (xSpellAlt.is()) + aAlt = xSpellAlt->getAlternatives(); + const OUString *pAlt = aAlt.getConstArray(); + sal_uInt16 nWords = (USHORT) aAlt.getLength(); + if ( nWords ) + { + for ( sal_uInt16 nW = 0; nW < nWords; nW++ ) + { + String aAlternate( pAlt[nW] ); + aPopupMenu.InsertItem( MN_ALTSTART+nW, aAlternate, 0, nW ); + pAutoMenu->InsertItem( MN_AUTOSTART+nW, aAlternate, 0, nW ); + } + aPopupMenu.InsertSeparator( nWords ); + } + else + aPopupMenu.RemoveItem( MN_AUTOCORR ); // Loeschen? + + Reference< XDictionaryList > xDicList( SvxGetDictionaryList() ); + + Sequence< Reference< XDictionary > > aDics; + if (xDicList.is()) + aDics = xDicList->getDictionaries(); + const Reference< XDictionary > *pDic = aDics.getConstArray(); + sal_uInt16 nLanguage = PIMPEE->GetLanguage( aPaM2 ); + sal_uInt16 nDicCount = (USHORT)aDics.getLength(); + for ( sal_uInt16 i = 0; i < nDicCount; i++ ) + { + Reference< XDictionary > xDic( pDic[i], UNO_QUERY ); + if (xDic.is()) + { + sal_uInt16 nActLanguage = SvxLocaleToLanguage( xDic->getLocale() ); + if( xDic->isActive() && + xDic->getDictionaryType() == DictionaryType_POSITIVE && + (nLanguage == nActLanguage || LANGUAGE_NONE == nActLanguage ) ) + { + pInsertMenu->InsertItem( MN_DICTSTART + i, xDic->getName() ); + } + } + } + + if ( !pInsertMenu->GetItemCount() ) + aPopupMenu.EnableItem( MN_INSERT, sal_False ); + + aPopupMenu.RemoveDisabledEntries( sal_True, sal_True ); + + Rectangle aTempRect = PIMPEE->PaMtoEditCursor( aPaM, GETCRSR_TXTONLY ); + Point aScreenPos = pImpEditView->GetWindowPos( aTempRect.TopLeft() ); + aScreenPos = pImpEditView->GetWindow()->OutputToScreenPixel( aScreenPos ); + aTempRect = pImpEditView->GetWindow()->LogicToPixel( Rectangle(aScreenPos, aTempRect.GetSize() )); + + sal_uInt16 nId = aPopupMenu.Execute( pImpEditView->GetWindow(), aTempRect, POPUPMENU_NOMOUSEUPCLOSE ); + if ( nId == MN_IGNORE ) + { + String aWord = pImpEditView->SpellIgnoreOrAddWord( sal_False ); + if ( pCallBack ) + { + SpellCallbackInfo aInf( SPELLCMD_IGNOREWORD, aWord ); + pCallBack->Call( &aInf ); + } + SetSelection( aOldSel ); + } + else if ( ( nId == MN_WORDLANGUAGE ) || ( nId == MN_PARALANGUAGE ) ) + { + LanguageType nLangToUse = (nId == MN_WORDLANGUAGE) ? nGuessLangWord : nGuessLangPara; + sal_uInt16 nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nLangToUse ); + + SfxItemSet aAttrs = GetEditEngine()->GetEmptyItemSet(); + if (nScriptType == SCRIPTTYPE_LATIN) + aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE ) ); + if (nScriptType == SCRIPTTYPE_COMPLEX) + aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CTL ) ); + if (nScriptType == SCRIPTTYPE_ASIAN) + aAttrs.Put( SvxLanguageItem( nLangToUse, EE_CHAR_LANGUAGE_CJK ) ); + if ( nId == MN_PARALANGUAGE ) + { + ESelection aSel = GetSelection(); + aSel.nStartPos = 0; + aSel.nEndPos = 0xFFFF; + SetSelection( aSel ); + } + SetAttribs( aAttrs ); + PIMPEE->StartOnlineSpellTimer(); + + if ( pCallBack ) + { + SpellCallbackInfo aInf( ( nId == MN_WORDLANGUAGE ) ? SPELLCMD_WORDLANGUAGE : SPELLCMD_PARALANGUAGE, nLangToUse ); + pCallBack->Call( &aInf ); + } + SetSelection( aOldSel ); + } + else if ( nId == MN_SPELLING ) + { + if ( !pCallBack ) + { + // Cursor vor das Wort setzen... + EditPaM aCursor = pImpEditView->GetEditSelection().Min(); + pImpEditView->DrawSelection(); // alte Selektion 'weg-zeichnen' + pImpEditView->SetEditSelection( EditSelection( aCursor, aCursor ) ); + pImpEditView->DrawSelection(); + // Stuerzt ab, wenn keine SfxApp + PIMPEE->Spell( this, sal_False ); + } + else + { + SpellCallbackInfo aInf( SPELLCMD_STARTSPELLDLG, String() ); + pCallBack->Call( &aInf ); + } + } + else if ( nId >= MN_DICTSTART ) + { + Reference< XDictionary > xDic( pDic[nId - MN_DICTSTART], UNO_QUERY ); + if (xDic.is()) + xDic->add( aSelected, sal_False, String() ); + // save modified user-dictionary if it is persistent + Reference< frame::XStorable > xSavDic( xDic, UNO_QUERY ); + if (xSavDic.is()) + xSavDic->store(); + + aPaM.GetNode()->GetWrongList()->GetInvalidStart() = 0; + aPaM.GetNode()->GetWrongList()->GetInvalidEnd() = aPaM.GetNode()->Len(); + PIMPEE->StartOnlineSpellTimer(); + + if ( pCallBack ) + { + SpellCallbackInfo aInf( SPELLCMD_ADDTODICTIONARY, aSelected ); + pCallBack->Call( &aInf ); + } + SetSelection( aOldSel ); + } + else if ( nId >= MN_AUTOSTART ) + { + DBG_ASSERT(nId - MN_AUTOSTART < aAlt.getLength(), "index out of range"); + String aWord = pAlt[nId - MN_AUTOSTART]; + SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get()->GetAutoCorrect(); + if ( pAutoCorrect ) + pAutoCorrect->PutText( aSelected, aWord, PIMPEE->GetLanguage( aPaM2 ) ); + InsertText( aWord ); + } + else if ( nId >= MN_ALTSTART ) // Replace + { + DBG_ASSERT(nId - MN_ALTSTART < aAlt.getLength(), "index out of range"); + String aWord = pAlt[nId - MN_ALTSTART]; + InsertText( aWord ); + } + else + { + SetSelection( aOldSel ); + } + } +#endif +} + +void EditView::SpellIgnoreWord() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + pImpEditView->SpellIgnoreOrAddWord( sal_False ); +} + +sal_Bool EditView::SelectCurrentWord() +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + EditSelection aCurSel( pImpEditView->GetEditSelection() ); + pImpEditView->DrawSelection(); + aCurSel = PIMPEE->SelectWord( aCurSel.Max() ); + pImpEditView->SetEditSelection( aCurSel ); + pImpEditView->DrawSelection(); + ShowCursor( sal_True, sal_False ); + return aCurSel.HasRange() ? sal_True : sal_False; +} + +void EditView::InsertField( const SvxFieldItem& rFld ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + ImpEditEngine* pImpEE = PIMPEE; + pImpEditView->DrawSelection(); + pImpEE->UndoActionStart( EDITUNDO_INSERT ); + EditPaM aPaM( pImpEE->InsertField( pImpEditView->GetEditSelection(), rFld ) ); + pImpEE->UndoActionEnd( EDITUNDO_INSERT ); + pImpEditView->SetEditSelection( EditSelection( aPaM, aPaM ) ); + pImpEE->UpdateFields(); + pImpEE->FormatAndUpdate( this ); +} + +const SvxFieldItem* EditView::GetFieldUnderMousePointer() const +{ + DBG_CHKTHIS( EditView, 0 ); + sal_uInt16 nPara, nPos; + return GetFieldUnderMousePointer( nPara, nPos ); +} + +const SvxFieldItem* EditView::GetField( const Point& rPos, sal_uInt16* pPara, sal_uInt16* pPos ) const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + return pImpEditView->GetField( rPos, pPara, pPos ); +} + +const SvxFieldItem* EditView::GetFieldUnderMousePointer( sal_uInt16& nPara, sal_uInt16& nPos ) const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + Point aPos = pImpEditView->GetWindow()->GetPointerPosPixel(); + aPos = pImpEditView->GetWindow()->PixelToLogic( aPos ); + return GetField( aPos, &nPara, &nPos ); +} + +const SvxFieldItem* EditView::GetFieldAtSelection() const +{ + EditSelection aSel( pImpEditView->GetEditSelection() ); + aSel.Adjust( pImpEditView->pEditEngine->pImpEditEngine->GetEditDoc() ); + // Nur wenn Cursor vor Feld, keine Selektion, oder nur Feld selektiert + if ( ( aSel.Min().GetNode() == aSel.Max().GetNode() ) && + ( ( aSel.Max().GetIndex() == aSel.Min().GetIndex() ) || + ( aSel.Max().GetIndex() == aSel.Min().GetIndex()+1 ) ) ) + { + EditPaM aPaM = aSel.Min(); + const CharAttribArray& rAttrs = aPaM.GetNode()->GetCharAttribs().GetAttribs(); + sal_uInt16 nXPos = aPaM.GetIndex(); + for ( sal_uInt16 nAttr = rAttrs.Count(); nAttr; ) + { + EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->GetStart() == nXPos ) + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + DBG_ASSERT( pAttr->GetItem()->ISA( SvxFieldItem ), "Kein FeldItem..." ); + return (const SvxFieldItem*)pAttr->GetItem(); + } + } + } + return 0; +} + +XubString EditView::GetWordUnderMousePointer() const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + Rectangle aRect; + return GetWordUnderMousePointer( aRect ); +} + +XubString EditView::GetWordUnderMousePointer( Rectangle& rWordRect ) const +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + Point aPos = pImpEditView->GetWindow()->GetPointerPosPixel(); + aPos = pImpEditView->GetWindow()->PixelToLogic( aPos ); + + XubString aWord; + + if( GetOutputArea().IsInside( aPos ) ) + { + ImpEditEngine* pImpEE = pImpEditView->pEditEngine->pImpEditEngine; + Point aDocPos( pImpEditView->GetDocPos( aPos ) ); + EditPaM aPaM = pImpEE->GetPaM( aDocPos, sal_False ); + EditSelection aWordSel = pImpEE->SelectWord( aPaM ); + + Rectangle aTopLeftRec( pImpEE->PaMtoEditCursor( aWordSel.Min() ) ); + Rectangle aBottomRightRec( pImpEE->PaMtoEditCursor( aWordSel.Max() ) ); + +#if OSL_DEBUG_LEVEL > 1 + DBG_ASSERT( aTopLeftRec.Top() == aBottomRightRec.Top(), "Top() in einer Zeile unterschiedlich?" ); +#endif + + Point aPnt1( pImpEditView->GetWindowPos( aTopLeftRec.TopLeft() ) ); + Point aPnt2( pImpEditView->GetWindowPos( aBottomRightRec.BottomRight()) ); + rWordRect = Rectangle( aPnt1, aPnt2 ); + aWord = pImpEE->GetSelected( aWordSel ); + } + + return aWord; +} + +void EditView::SetInvalidateMore( sal_uInt16 nPixel ) +{ + DBG_CHKTHIS( EditView, 0 ); + pImpEditView->SetInvalidateMore( nPixel ); +} + +sal_uInt16 EditView::GetInvalidateMore() const +{ + DBG_CHKTHIS( EditView, 0 ); + return (sal_uInt16)pImpEditView->GetInvalidateMore(); +} + +static void ChangeFontSizeImpl( EditView* pEditView, bool bGrow, const ESelection& rSel, const FontList* pFontList ) +{ + pEditView->SetSelection( rSel ); + + SfxItemSet aSet( pEditView->GetAttribs() ); + if( EditView::ChangeFontSize( bGrow, aSet, pFontList ) ) + { + SfxItemSet aNewSet( pEditView->GetEmptyItemSet() ); + aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT ), EE_CHAR_FONTHEIGHT ); + aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT_CJK ), EE_CHAR_FONTHEIGHT_CJK ); + aNewSet.Put( aSet.Get( EE_CHAR_FONTHEIGHT_CTL ), EE_CHAR_FONTHEIGHT_CTL ); + pEditView->SetAttribs( aNewSet ); + } +} + +void EditView::ChangeFontSize( bool bGrow, const FontList* pFontList ) +{ + DBG_CHKTHIS( EditView, 0 ); + DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 ); + + EditEngine& rEditEngine = *pImpEditView->pEditEngine; + + ESelection aSel( GetSelection() ); + ESelection aOldSelection( aSel ); + aSel.Adjust(); + + if( !aSel.HasRange() ) + { + aSel = rEditEngine.GetWord( aSel, com::sun::star::i18n::WordType::DICTIONARY_WORD ); + } + + if( aSel.HasRange() ) + { + for( USHORT nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + SvUShorts aPortions; + rEditEngine.GetPortions( nPara, aPortions ); + + if( aPortions.Count() == 0 ) + aPortions.Insert( rEditEngine.GetTextLen(nPara), 0 ); + + const USHORT nBeginPos = (nPara == aSel.nStartPara) ? aSel.nStartPos : 0; + const USHORT nEndPos = (nPara == aSel.nEndPara) ? aSel.nEndPos : 0xffff; + + for ( USHORT nPos = 0; nPos < aPortions.Count(); ++nPos ) + { + USHORT nPortionEnd = aPortions.GetObject( nPos ); + USHORT nPortionStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; + + if( (nPortionEnd < nBeginPos) || (nPortionStart > nEndPos) ) + continue; + + if( nPortionStart < nBeginPos ) + nPortionStart = nBeginPos; + if( nPortionEnd > nEndPos ) + nPortionEnd = nEndPos; + + if( nPortionStart == nPortionEnd ) + continue; + + ESelection aPortionSel( nPara, nPortionStart, nPara, nPortionEnd ); + ChangeFontSizeImpl( this, bGrow, aPortionSel, pFontList ); + } + } + } + else + { + ChangeFontSizeImpl( this, bGrow, aSel, pFontList ); + } + + SetSelection( aOldSelection ); +} + +bool EditView::ChangeFontSize( bool bGrow, SfxItemSet& rSet, const FontList* pFontList ) +{ + static const sal_uInt16 gFontSizeWichMap[] = { EE_CHAR_FONTHEIGHT, EE_CHAR_FONTHEIGHT_CJK, EE_CHAR_FONTHEIGHT_CTL, 0 }; + + const SvxFontItem* pFontItem = static_cast<const SvxFontItem*>(&rSet.Get( EE_CHAR_FONTINFO )); + if( !pFontItem || !pFontList ) + return false; + + bool bRet = false; + + const sal_uInt16* pWhich = gFontSizeWichMap; + while( *pWhich ) + { + SvxFontHeightItem aFontHeightItem( static_cast<const SvxFontHeightItem&>(rSet.Get( *pWhich )) ); + long nHeight = aFontHeightItem.GetHeight(); + const SfxMapUnit eUnit = rSet.GetPool()->GetMetric( *pWhich ); + nHeight = OutputDevice::LogicToLogic( nHeight * 10, (MapUnit)eUnit, MAP_POINT ); + + FontInfo aFontInfo = pFontList->Get( pFontItem->GetFamilyName(), pFontItem->GetStyleName() ); + const long* pAry = pFontList->GetSizeAry( aFontInfo ); + + if( bGrow ) + { + while( *pAry ) + { + if( *pAry > nHeight ) + { + nHeight = *pAry; + break; + } + pAry++; + } + + if( *pAry == 0 ) + { + nHeight += (nHeight + 5) / 10; + if( nHeight > 9999 ) + nHeight = 9999; + } + + } + else if( *pAry ) + { + bool bFound = false; + if( *pAry < nHeight ) + { + pAry++; + while( *pAry ) + { + if( *pAry >= nHeight ) + { + nHeight = pAry[-1]; + bFound = true; + break; + } + pAry++; + } + } + + if( !bFound ) + { + nHeight -= (nHeight + 5) / 10; + if( nHeight < 2 ) + nHeight = 2; + } + } + + if( (nHeight >= 2) && (nHeight <= 9999 ) ) + { + nHeight = OutputDevice::LogicToLogic( nHeight, MAP_POINT, (MapUnit)eUnit ) / 10; + + if( nHeight != (long)aFontHeightItem.GetHeight() ) + { + aFontHeightItem.SetHeight( nHeight ); + rSet.Put( aFontHeightItem, *pWhich ); + bRet = true; + } + } + pWhich++; + } + return bRet; +} + +String EditView::GetSurroundingText() const
+{
+ DBG_CHKTHIS( EditView, 0 );
+ DBG_CHKOBJ( pImpEditView->pEditEngine, EditEngine, 0 );
+
+ EditSelection aSel( pImpEditView->GetEditSelection() );
+ aSel.Adjust( PIMPEE->GetEditDoc() );
+
+ if( HasSelection() )
+ {
+ XubString aStr = PIMPEE->GetSelected( aSel );
+
+ // Stop reconversion if the selected text includes a line break.
+ if ( aStr.Search( 0x0A ) == STRING_NOTFOUND )
+ return aStr;
+ else
+ return String();
+ }
+ else
+ {
+ aSel.Min().SetIndex( 0 );
+ aSel.Max().SetIndex( aSel.Max().GetNode()->Len() );
+ return PIMPEE->GetSelected( aSel );
+ }
+}
+
+Selection EditView::GetSurroundingTextSelection() const
+{
+ DBG_CHKTHIS( EditView, 0 );
+
+ ESelection aSelection( GetSelection() );
+ aSelection.Adjust();
+
+ if( HasSelection() )
+ {
+ EditSelection aSel( pImpEditView->GetEditSelection() );
+ aSel.Adjust( PIMPEE->GetEditDoc() );
+ XubString aStr = PIMPEE->GetSelected( aSel );
+
+ // Stop reconversion if the selected text includes a line break.
+ if ( aStr.Search( 0x0A ) == STRING_NOTFOUND )
+ return Selection( 0, aSelection.nEndPos - aSelection.nStartPos );
+ else
+ return Selection( 0, 0 );
+ }
+ else
+ {
+ return Selection( aSelection.nStartPos, aSelection.nEndPos );
+ }
+}
diff --git a/editeng/source/editeng/edtspell.cxx b/editeng/source/editeng/edtspell.cxx new file mode 100644 index 000000000000..95ac3b1ebfbb --- /dev/null +++ b/editeng/source/editeng/edtspell.cxx @@ -0,0 +1,749 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: edtspell.cxx,v $ + * $Revision: 1.16 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <impedit.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> +#include <edtspell.hxx> +#include <editeng/flditem.hxx> +#include <editeng/fontitem.hxx> +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> + +using ::rtl::OUString; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::linguistic2; + + +EditSpellWrapper::EditSpellWrapper( Window* _pWin, + Reference< XSpellChecker1 > &xChecker, + sal_Bool bIsStart, sal_Bool bIsAllRight, EditView* pView ) : + SvxSpellWrapper( _pWin, xChecker, bIsStart, bIsAllRight ) +{ + DBG_ASSERT( pView, "Es muss eine View uebergeben werden!" ); + // IgnoreList behalten, ReplaceList loeschen... + if (SvxGetChangeAllList().is()) + SvxGetChangeAllList()->clear(); + pEditView = pView; +} + +void __EXPORT EditSpellWrapper::SpellStart( SvxSpellArea eArea ) +{ + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + SpellInfo* pSpellInfo = pImpEE->GetSpellInfo(); + + if ( eArea == SVX_SPELL_BODY_START ) + { + // Wird gerufen, wenn + // a) Spell-Forwad ist am Ende angekomment und soll von vorne beginnen + // IsEndDone() liefert auch sal_True, wenn Rueckwaerts-Spelling am Ende gestartet wird! + if ( IsEndDone() ) + { + pSpellInfo->bSpellToEnd = sal_False; + pSpellInfo->aSpellTo = pSpellInfo->aSpellStart; + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetStartPaM() ); + } + else + { + pSpellInfo->bSpellToEnd = sal_True; + pSpellInfo->aSpellTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetStartPaM() ); + } + } + else if ( eArea == SVX_SPELL_BODY_END ) + { + // Wird gerufen, wenn + // a) Spell-Forwad wird gestartet + // IsStartDone() liefert auch sal_True, wenn Vorwaerts-Spelling am Anfang gestartet wird! + if ( !IsStartDone() ) + { + pSpellInfo->bSpellToEnd = sal_True; + pSpellInfo->aSpellTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetEndPaM() ); + } + else + { + pSpellInfo->bSpellToEnd = sal_False; + pSpellInfo->aSpellTo = pSpellInfo->aSpellStart; + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetEndPaM() ); + } + } + else if ( eArea == SVX_SPELL_BODY ) + { + ; // Wird ueber SpellNextDocument von App gehandelt + + // pSpellInfo->bSpellToEnd = sal_True; + // pSpellInfo->aSpellTo = pImpEE->CreateEPaM( pImpEE->GetEditDoc().GetEndPaM() ); + } + else + { + DBG_ERROR( "SpellStart: Unknown Area!" ); + } +} + +sal_Bool EditSpellWrapper::SpellContinue() +{ + SetLast( pEditView->GetImpEditEngine()->ImpSpell( pEditView ) ); + return GetLast().is(); +} + +void __EXPORT EditSpellWrapper::SpellEnd() +{ + // Base class will show language errors... + SvxSpellWrapper::SpellEnd(); +} + +sal_Bool __EXPORT EditSpellWrapper::HasOtherCnt() +{ + return sal_False; +} + +sal_Bool __EXPORT EditSpellWrapper::SpellMore() +{ + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + SpellInfo* pSpellInfo = pImpEE->GetSpellInfo(); + sal_Bool bMore = sal_False; + if ( pSpellInfo->bMultipleDoc ) + { + bMore = pImpEE->GetEditEnginePtr()->SpellNextDocument(); + if ( bMore ) + { + // Der Text wurde in diese Engine getreten, bei Rueckwaerts + // muss die Selektion hinten sein. + Reference< XPropertySet > xProp( SvxGetLinguPropertySet() ); + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetStartPaM() ); + } + } + return bMore; +} + +void __EXPORT EditSpellWrapper::ScrollArea() +{ + // Keine weitere Aktion noetig... + // Es sei denn, der Bereich soll in die Mitte gescrollt werden, + // und nicht irgendwo stehen. +} + +void __EXPORT EditSpellWrapper::ReplaceAll( const String &rNewText, + sal_Int16 ) +{ + // Wird gerufen, wenn Wort in ReplaceList des SpellCheckers + pEditView->InsertText( rNewText ); + CheckSpellTo(); +} + +void __EXPORT EditSpellWrapper::ChangeWord( const String& rNewWord, + const sal_uInt16 ) +{ + // Wird gerufen, wenn Wort Button Change + // bzw. intern von mir bei ChangeAll + + // Wenn Punkt hinterm Wort, wird dieser nicht mitgegeben. + // Falls '"' => PreStripped. + String aNewWord( rNewWord ); + pEditView->InsertText( aNewWord ); + CheckSpellTo(); +} + +void __EXPORT EditSpellWrapper::ChangeThesWord( const String& rNewWord ) +{ + pEditView->InsertText( rNewWord ); + CheckSpellTo(); +} + +void __EXPORT EditSpellWrapper::AutoCorrect( const String&, const String& ) +{ +} + +void EditSpellWrapper::CheckSpellTo() +{ + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + SpellInfo* pSpellInfo = pImpEE->GetSpellInfo(); + EditPaM aPaM( pEditView->GetImpEditView()->GetEditSelection().Max() ); + EPaM aEPaM = pImpEE->CreateEPaM( aPaM ); + if ( aEPaM.nPara == pSpellInfo->aSpellTo.nPara ) + { + // prueffen, ob SpellToEnd noch gueltiger Index, falls in dem Absatz + // ersetzt wurde. + if ( pSpellInfo->aSpellTo.nIndex > aPaM.GetNode()->Len() ) + pSpellInfo->aSpellTo.nIndex = aPaM.GetNode()->Len(); + } +} +SV_IMPL_VARARR( WrongRanges, WrongRange ); + +WrongList::WrongList() +{ + nInvalidStart = 0; + nInvalidEnd = 0xFFFF; +} + +WrongList::~WrongList() +{ +} + +void WrongList::TextInserted( sal_uInt16 nPos, sal_uInt16 nNew, sal_Bool bPosIsSep ) +{ + if ( !IsInvalid() ) + { + nInvalidStart = nPos; + nInvalidEnd = nPos+nNew; + } + else + { + if ( nInvalidStart > nPos ) + nInvalidStart = nPos; + if ( nInvalidEnd >= nPos ) + nInvalidEnd = nInvalidEnd + nNew; + else + nInvalidEnd = nPos+nNew; + } + + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + sal_Bool bRefIsValid = sal_True; + if ( rWrong.nEnd >= nPos ) + { + // Alle Wrongs hinter der Einfuegeposition verschieben... + if ( rWrong.nStart > nPos ) + { + rWrong.nStart = rWrong.nStart + nNew; + rWrong.nEnd = rWrong.nEnd + nNew; + } + // 1: Startet davor, geht bis nPos... + else if ( rWrong.nEnd == nPos ) + { + // Sollte bei einem Blank unterbunden werden! + if ( !bPosIsSep ) + rWrong.nEnd = rWrong.nEnd + nNew; + } + // 2: Startet davor, geht hinter Pos... + else if ( ( rWrong.nStart < nPos ) && ( rWrong.nEnd > nPos ) ) + { + rWrong.nEnd = rWrong.nEnd + nNew; + // Bei einem Trenner das Wrong entfernen und neu pruefen + if ( bPosIsSep ) + { + // Wrong aufteilen... + WrongRange aNewWrong( rWrong.nStart, nPos ); + rWrong.nStart = nPos+1; + Insert( aNewWrong, n ); + bRefIsValid = sal_False; // Referenz nach Insert nicht mehr gueltig, der andere wurde davor an dessen Position eingefuegt + n++; // Diesen nicht nochmal... + } + } + // 3: Attribut startet auf Pos... + else if ( rWrong.nStart == nPos ) + { + rWrong.nEnd = rWrong.nEnd + nNew; + if ( bPosIsSep ) + rWrong.nStart++; + } + } + DBG_ASSERT( !bRefIsValid || ( rWrong.nStart < rWrong.nEnd ), + "TextInserted, WrongRange: Start >= End?!" ); + } + + DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" ); +} + +void WrongList::TextDeleted( sal_uInt16 nPos, sal_uInt16 nDeleted ) +{ + sal_uInt16 nEndChanges = nPos+nDeleted; + if ( !IsInvalid() ) + { + sal_uInt16 nNewInvalidStart = nPos ? nPos - 1 : 0; + nInvalidStart = nNewInvalidStart; + nInvalidEnd = nNewInvalidStart + 1; + } + else + { + if ( nInvalidStart > nPos ) + nInvalidStart = nPos; + if ( nInvalidEnd > nPos ) + { + if ( nInvalidEnd > nEndChanges ) + nInvalidEnd = nInvalidEnd - nDeleted; + else + nInvalidEnd = nPos+1; + } + } + + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + sal_Bool bDelWrong = sal_False; + if ( rWrong.nEnd >= nPos ) + { + // Alles Wrongs hinter der Einfuegeposition verschieben... + if ( rWrong.nStart >= nEndChanges ) + { + rWrong.nStart = rWrong.nStart - nDeleted; + rWrong.nEnd = rWrong.nEnd - nDeleted; + } + // 1. Innenliegende Wrongs loeschen... + else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd <= nEndChanges ) ) + { + bDelWrong = sal_True; + } + // 2. Wrong beginnt davor, endet drinnen oder dahinter... + else if ( ( rWrong.nStart <= nPos ) && ( rWrong.nEnd > nPos ) ) + { + if ( rWrong.nEnd <= nEndChanges ) // endet drinnen + rWrong.nEnd = nPos; + else + rWrong.nEnd = rWrong.nEnd - nDeleted; // endet dahinter + } + // 3. Wrong beginnt drinnen, endet dahinter... + else if ( ( rWrong.nStart >= nPos ) && ( rWrong.nEnd > nEndChanges ) ) + { + rWrong.nStart = nEndChanges; + rWrong.nStart = rWrong.nStart - nDeleted; + rWrong.nEnd = rWrong.nEnd - nDeleted; + } + } + DBG_ASSERT( rWrong.nStart < rWrong.nEnd, + "TextInserted, WrongRange: Start >= End?!" ); + if ( bDelWrong ) + { + Remove( n, 1 ); + n--; + } + } + + DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" ); +} + +sal_Bool WrongList::NextWrong( sal_uInt16& rnStart, sal_uInt16& rnEnd ) const +{ + /* + rnStart enthaelt die Startposition, wird ggf. auf Wrong-Start korrigiert + rnEnd braucht nicht inizialisiert sein. + */ + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( rWrong.nEnd > rnStart ) + { + rnStart = rWrong.nStart; + rnEnd = rWrong.nEnd; + return sal_True; + } + } + return sal_False; +} + +sal_Bool WrongList::HasWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const +{ + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd == nEnd ) ) + return sal_True; + else if ( rWrong.nStart >= nStart ) + break; + } + return sal_False; +} + +sal_Bool WrongList::HasAnyWrong( sal_uInt16 nStart, sal_uInt16 nEnd ) const +{ + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( ( rWrong.nEnd >= nStart ) && ( rWrong.nStart < nEnd ) ) + return sal_True; + else if ( rWrong.nStart >= nEnd ) + break; + } + return sal_False; +} + +void WrongList::ClearWrongs( sal_uInt16 nStart, sal_uInt16 nEnd, + const ContentNode* pNode ) +{ + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( ( rWrong.nEnd > nStart ) && ( rWrong.nStart < nEnd ) ) + { + if ( rWrong.nEnd > nEnd ) // // Laeuft raus + { + rWrong.nStart = nEnd; + // Blanks? + while ( ( rWrong.nStart < pNode->Len() ) && + ( ( pNode->GetChar( rWrong.nStart ) == ' ' ) || + ( pNode->IsFeature( rWrong.nStart ) ) ) ) + { + rWrong.nStart++; + } + } + else + { + Remove( n, 1 ); + n--; + } + } + } + + DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" ); +} + +void WrongList::InsertWrong( sal_uInt16 nStart, sal_uInt16 nEnd, + sal_Bool bClearRange ) +{ + sal_uInt16 nPos = Count(); + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + if ( rWrong.nStart >= nStart ) + { + nPos = n; + if ( bClearRange ) + { + // Es kann eigentlich nur Passieren, dass der Wrong genau + // hier beginnt und weiter rauslauft, aber nicht, dass hier + // mehrere im Bereich liegen... + // Genau im Bereich darf keiner liegen, sonst darf diese Methode + // garnicht erst gerufen werden! + DBG_ASSERT( ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) ) + || ( rWrong.nStart > nEnd ), "InsertWrong: RangeMismatch!" ); + if ( ( rWrong.nStart == nStart ) && ( rWrong.nEnd > nEnd ) ) + rWrong.nStart = nEnd+1; + } + break; + } + } + Insert( WrongRange( nStart, nEnd ), nPos ); + + DBG_ASSERT( !DbgIsBuggy(), "InsertWrong: WrongList kaputt!" ); +} + +void WrongList::MarkWrongsInvalid() +{ + if ( Count() ) + MarkInvalid( GetObject( 0 ).nStart, GetObject( Count()-1 ).nEnd ); +} + +WrongList* WrongList::Clone() const +{ + WrongList* pNew = new WrongList; + for ( sal_uInt16 n = 0; n < Count(); n++ ) + { + WrongRange& rWrong = GetObject( n ); + pNew->Insert( rWrong, pNew->Count() ); + } + + return pNew; +} + +// #i102062# +bool WrongList::operator==(const WrongList& rCompare) const +{ + // cleck direct members + if(GetInvalidStart() != rCompare.GetInvalidStart() + || GetInvalidEnd() != rCompare.GetInvalidEnd() + || Count() != rCompare.Count()) + { + return false; + } + + for(USHORT a(0); a < Count(); a++) + { + const WrongRange& rCandA(GetObject(a)); + const WrongRange& rCandB(rCompare.GetObject(a)); + + if(rCandA.nStart != rCandB.nStart + || rCandA.nEnd != rCandB.nEnd) + { + return false; + } + } + + return true; +} + +#ifdef DBG_UTIL +sal_Bool WrongList::DbgIsBuggy() const +{ + // Pruefen, ob sich Bereiche ueberlappen + sal_Bool bError = sal_False; + for ( sal_uInt16 _nA = 0; !bError && ( _nA < Count() ); _nA++ ) + { + WrongRange& rWrong = GetObject( _nA ); + for ( sal_uInt16 nB = _nA+1; !bError && ( nB < Count() ); nB++ ) + { + WrongRange& rNextWrong = GetObject( nB ); + // 1) Start davor, End hinterm anderen Start + if ( ( rWrong.nStart <= rNextWrong.nStart ) + && ( rWrong.nEnd >= rNextWrong.nStart ) ) + bError = sal_True; + // 2) Start hinter anderen Start, aber noch vorm anderen End + else if ( ( rWrong.nStart >= rNextWrong.nStart) + && ( rWrong.nStart <= rNextWrong.nEnd ) ) + bError = sal_True; + } + } + return bError; +} +#endif + + +EdtAutoCorrDoc::EdtAutoCorrDoc( ImpEditEngine* pE, ContentNode* pN, + sal_uInt16 nCrsr, xub_Unicode cIns ) +{ + pImpEE = pE; + pCurNode = pN; + nCursor = nCrsr; + + bUndoAction = sal_False; + bAllowUndoAction = cIns ? sal_True : sal_False; +} + +EdtAutoCorrDoc::~EdtAutoCorrDoc() +{ + if ( bUndoAction ) + pImpEE->UndoActionEnd( EDITUNDO_INSERT ); +} + +sal_Bool EdtAutoCorrDoc::Delete( sal_uInt16 nStt, sal_uInt16 nEnd ) +{ + EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) ); + pImpEE->ImpDeleteSelection( aSel ); + DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" ); + nCursor -= ( nEnd-nStt ); + bAllowUndoAction = sal_False; + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::Insert( sal_uInt16 nPos, const String& rTxt ) +{ + EditSelection aSel = EditPaM( pCurNode, nPos ); + pImpEE->ImpInsertText( aSel, rTxt ); + DBG_ASSERT( nCursor >= nPos, "Cursor mitten im Geschehen ?!" ); + nCursor = nCursor + rTxt.Len(); + + if ( bAllowUndoAction && ( rTxt.Len() == 1 ) ) + ImplStartUndoAction(); + bAllowUndoAction = sal_False; + + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::Replace( sal_uInt16 nPos, const String& rTxt ) +{ + // Eigentlich ein Replace einfuehren => Entspr. UNDO + sal_uInt16 nEnd = nPos+rTxt.Len(); + if ( nEnd > pCurNode->Len() ) + nEnd = pCurNode->Len(); + + // #i5925# First insert new text behind to be deleted text, for keeping attributes. + pImpEE->ImpInsertText( EditSelection( EditPaM( pCurNode, nEnd ) ), rTxt ); + pImpEE->ImpDeleteSelection( EditSelection( EditPaM( pCurNode, nPos ), EditPaM( pCurNode, nEnd ) ) ); + + if ( nPos == nCursor ) + nCursor = nCursor + rTxt.Len(); + + if ( bAllowUndoAction && ( rTxt.Len() == 1 ) ) + ImplStartUndoAction(); + + bAllowUndoAction = sal_False; + + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::SetAttr( sal_uInt16 nStt, sal_uInt16 nEnd, + sal_uInt16 nSlotId, SfxPoolItem& rItem ) +{ + SfxItemPool* pPool = &pImpEE->GetEditDoc().GetItemPool(); + while ( pPool->GetSecondaryPool() && + !pPool->GetName().EqualsAscii( "EditEngineItemPool" ) ) + { + pPool = pPool->GetSecondaryPool(); + + } + sal_uInt16 nWhich = pPool->GetWhich( nSlotId ); + if ( nWhich ) + { + rItem.SetWhich( nWhich ); + + SfxItemSet aSet( pImpEE->GetEmptyItemSet() ); + aSet.Put( rItem ); + + EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) ); + aSel.Max().SetIndex( nEnd ); // ??? + pImpEE->SetAttribs( aSel, aSet, ATTRSPECIAL_EDGE ); + bAllowUndoAction = sal_False; + } + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::SetINetAttr( sal_uInt16 nStt, sal_uInt16 nEnd, + const String& rURL ) +{ + // Aus dem Text ein Feldbefehl machen... + EditSelection aSel( EditPaM( pCurNode, nStt ), EditPaM( pCurNode, nEnd ) ); + String aText = pImpEE->GetSelected( aSel ); + aSel = pImpEE->ImpDeleteSelection( aSel ); + DBG_ASSERT( nCursor >= nEnd, "Cursor mitten im Geschehen ?!" ); + nCursor -= ( nEnd-nStt ); + SvxFieldItem aField( SvxURLField( rURL, aText, SVXURLFORMAT_REPR ), + EE_FEATURE_FIELD ); + pImpEE->InsertField( aSel, aField ); + nCursor++; + pImpEE->UpdateFields(); + bAllowUndoAction = sal_False; + return sal_True; +} + +sal_Bool EdtAutoCorrDoc::HasSymbolChars( sal_uInt16 nStt, sal_uInt16 nEnd ) +{ + USHORT nScriptType = pImpEE->GetScriptType( EditPaM( pCurNode, nStt ) ); + USHORT nScriptFontInfoItemId = GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ); + + CharAttribArray& rAttribs = pCurNode->GetCharAttribs().GetAttribs(); + sal_uInt16 nAttrs = rAttribs.Count(); + for ( sal_uInt16 n = 0; n < nAttrs; n++ ) + { + EditCharAttrib* pAttr = rAttribs.GetObject( n ); + if ( pAttr->GetStart() >= nEnd ) + return sal_False; + + if ( ( pAttr->Which() == nScriptFontInfoItemId ) && + ( ((SvxFontItem*)pAttr->GetItem())->GetCharSet() == RTL_TEXTENCODING_SYMBOL ) ) + { + // Pruefen, ob das Attribt im Bereich liegt... + if ( pAttr->GetEnd() >= nStt ) + return sal_True; + } + } + return sal_False; +} + +const String* EdtAutoCorrDoc::GetPrevPara( sal_Bool ) +{ + // Vorherigen Absatz zurueck geben, damit ermittel werden kann, + // ob es sich beim aktuellen Wort um einen Satzanfang handelt. + + bAllowUndoAction = sal_False; // Jetzt nicht mehr... + + ContentList& rNodes = pImpEE->GetEditDoc(); + sal_uInt16 nPos = rNodes.GetPos( pCurNode ); + + // Sonderbehandlung: Bullet => Absatzanfang => einfach NULL returnen... + const SfxBoolItem& rBulletState = (const SfxBoolItem&) + pImpEE->GetParaAttrib( nPos, EE_PARA_BULLETSTATE ); + sal_Bool bBullet = rBulletState.GetValue() ? sal_True : sal_False; + if ( !bBullet && ( pImpEE->aStatus.GetControlWord() & EE_CNTRL_OUTLINER ) ) + { + // Der Outliner hat im Gliederungsmodus auf Ebene 0 immer ein Bullet. + const SfxInt16Item& rLevel = (const SfxInt16Item&) + pImpEE->GetParaAttrib( nPos, EE_PARA_OUTLLEVEL ); + if ( rLevel.GetValue() == 0 ) + bBullet = sal_True; + } + if ( bBullet ) + return NULL; + + for ( sal_uInt16 n = nPos; n; ) + { + n--; + ContentNode* pNode = rNodes[n]; + if ( pNode->Len() ) + return pNode; + } + return NULL; + +} + +sal_Bool EdtAutoCorrDoc::ChgAutoCorrWord( sal_uInt16& rSttPos, + sal_uInt16 nEndPos, SvxAutoCorrect& rACorrect, + const String** ppPara ) +{ + // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort + // Kuerzel im Auto + + bAllowUndoAction = sal_False; // Jetzt nicht mehr... + + String aShort( pCurNode->Copy( rSttPos, nEndPos - rSttPos ) ); + sal_Bool bRet = sal_False; + + if( !aShort.Len() ) + return bRet; + + LanguageType eLang = pImpEE->GetLanguage( EditPaM( pCurNode, rSttPos+1 ) ); + const SvxAutocorrWord* pFnd = rACorrect.SearchWordsInList( *pCurNode, rSttPos, nEndPos, *this, eLang ); + if( pFnd && pFnd->IsTextOnly() ) + { + // dann mal ersetzen + EditSelection aSel( EditPaM( pCurNode, rSttPos ), + EditPaM( pCurNode, nEndPos ) ); + aSel = pImpEE->ImpDeleteSelection( aSel ); + DBG_ASSERT( nCursor >= nEndPos, "Cursor mitten im Geschehen ?!" ); + nCursor -= ( nEndPos-rSttPos ); + pImpEE->ImpInsertText( aSel, pFnd->GetLong() ); + nCursor = nCursor + pFnd->GetLong().Len(); + if( ppPara ) + *ppPara = pCurNode; + bRet = sal_True; + } + + return bRet; +} + +LanguageType EdtAutoCorrDoc::GetLanguage( sal_uInt16 nPos, sal_Bool ) const +{ + return pImpEE->GetLanguage( EditPaM( pCurNode, nPos+1 ) ); +} + +void EdtAutoCorrDoc::ImplStartUndoAction() +{ + sal_uInt16 nPara = pImpEE->GetEditDoc().GetPos( pCurNode ); + ESelection aSel( nPara, nCursor, nPara, nCursor ); + pImpEE->UndoActionStart( EDITUNDO_INSERT, aSel ); + bUndoAction = sal_True; + bAllowUndoAction = sal_False; +} + diff --git a/editeng/source/editeng/edtspell.hxx b/editeng/source/editeng/edtspell.hxx new file mode 100644 index 000000000000..aa0f2037121b --- /dev/null +++ b/editeng/source/editeng/edtspell.hxx @@ -0,0 +1,188 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: edtspell.hxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EDTSPELL_HXX +#define _EDTSPELL_HXX + +#include <svtools/svxbox.hxx> +#include <editeng/svxenum.hxx> +#include <editeng/splwrap.hxx> +#include <editeng/svxacorr.hxx> +#include <com/sun/star/uno/Reference.h> +#include <editeng/editengdllapi.h> + +namespace com { namespace sun { namespace star { namespace linguistic2 { + class XSpellChecker1; +}}}} + + +class EditView; +class ImpEditEngine; +class ContentNode; + +class EditSpellWrapper : public SvxSpellWrapper +{ +private: + EditView* pEditView; + void CheckSpellTo(); + +protected: + virtual void SpellStart( SvxSpellArea eArea ); + virtual BOOL SpellContinue(); // Bereich pruefen + virtual void ReplaceAll( const String &rNewText, INT16 nLanguage ); + virtual void SpellEnd(); + virtual BOOL SpellMore(); + virtual BOOL HasOtherCnt(); + virtual void ScrollArea(); + virtual void ChangeWord( const String& rNewWord, const USHORT nLang ); + virtual void ChangeThesWord( const String& rNewWord ); + virtual void AutoCorrect( const String& rOldWord, const String& rNewWord ); + +public: + EditSpellWrapper( Window* pWin, + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellChecker1 > &xChecker, + BOOL bIsStart, + BOOL bIsAllRight, EditView* pView ); + +}; + + +struct WrongRange +{ + USHORT nStart; + USHORT nEnd; + + WrongRange( USHORT nS, USHORT nE ) { nStart = nS; nEnd = nE; } +}; + +SV_DECL_VARARR( WrongRanges, WrongRange, 4, 4 ) +#define NOT_INVALID 0xFFFF + +class WrongList : private WrongRanges +{ +private: + USHORT nInvalidStart; + USHORT nInvalidEnd; + + BOOL DbgIsBuggy() const; + +public: + WrongList(); + ~WrongList(); + + BOOL IsInvalid() const { return nInvalidStart != NOT_INVALID; } + void SetValid() { nInvalidStart = NOT_INVALID; nInvalidEnd = 0; } + void MarkInvalid( USHORT nS, USHORT nE ) + { + if ( ( nInvalidStart == NOT_INVALID ) || ( nInvalidStart > nS ) ) + nInvalidStart = nS; + if ( nInvalidEnd < nE ) + nInvalidEnd = nE; + } + + USHORT Count() const { return WrongRanges::Count(); } + + // Wenn man weiss was man tut: + WrongRange& GetObject( USHORT n ) const { return WrongRanges::GetObject( n ); } + void InsertWrong( const WrongRange& rWrong, USHORT nPos ); + + USHORT GetInvalidStart() const { return nInvalidStart; } + USHORT& GetInvalidStart() { return nInvalidStart; } + + USHORT GetInvalidEnd() const { return nInvalidEnd; } + USHORT& GetInvalidEnd() { return nInvalidEnd; } + + void TextInserted( USHORT nPos, USHORT nChars, BOOL bPosIsSep ); + void TextDeleted( USHORT nPos, USHORT nChars ); + + void ResetRanges() { Remove( 0, Count() ); } + BOOL HasWrongs() const { return Count() != 0; } + void InsertWrong( USHORT nStart, USHORT nEnd, BOOL bClearRange ); + BOOL NextWrong( USHORT& rnStart, USHORT& rnEnd ) const; + BOOL HasWrong( USHORT nStart, USHORT nEnd ) const; + BOOL HasAnyWrong( USHORT nStart, USHORT nEnd ) const; + void ClearWrongs( USHORT nStart, USHORT nEnd, const ContentNode* pNode ); + void MarkWrongsInvalid(); + + WrongList* Clone() const; + + // #i102062# + bool operator==(const WrongList& rCompare) const; +}; + +inline void WrongList::InsertWrong( const WrongRange& rWrong, USHORT nPos ) +{ + WrongRanges::Insert( rWrong, nPos ); +#ifdef DBG_UTIL + DBG_ASSERT( !DbgIsBuggy(), "Insert: WrongList kaputt!" ); +#endif +} + + + +class EdtAutoCorrDoc : public SvxAutoCorrDoc +{ + ImpEditEngine* pImpEE; + ContentNode* pCurNode; + USHORT nCursor; + + BOOL bAllowUndoAction; + BOOL bUndoAction; + +protected: + void ImplStartUndoAction(); + +public: + EdtAutoCorrDoc( ImpEditEngine* pImpEE, ContentNode* pCurNode, USHORT nCrsr, xub_Unicode cIns ); + ~EdtAutoCorrDoc(); + + virtual BOOL Delete( USHORT nStt, USHORT nEnd ); + virtual BOOL Insert( USHORT nPos, const String& rTxt ); + virtual BOOL Replace( USHORT nPos, const String& rTxt ); + + virtual BOOL SetAttr( USHORT nStt, USHORT nEnd, USHORT nSlotId, SfxPoolItem& ); + virtual BOOL SetINetAttr( USHORT nStt, USHORT nEnd, const String& rURL ); + + virtual BOOL HasSymbolChars( USHORT nStt, USHORT nEnd ); + + virtual const String* GetPrevPara( BOOL bAtNormalPos ); + + virtual BOOL ChgAutoCorrWord( USHORT& rSttPos, USHORT nEndPos, + SvxAutoCorrect& rACorrect, const String** ppPara ); + + virtual LanguageType GetLanguage( USHORT nPos, BOOL bPrevPara = FALSE ) const; + + USHORT GetCursor() const { return nCursor; } + +}; + +#endif // EDTSPELL + diff --git a/editeng/source/editeng/eehtml.cxx b/editeng/source/editeng/eehtml.cxx new file mode 100644 index 000000000000..f0dbb6c2281c --- /dev/null +++ b/editeng/source/editeng/eehtml.cxx @@ -0,0 +1,853 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eehtml.cxx,v $ + * $Revision: 1.20 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <eehtml.hxx> +#include <impedit.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/flditem.hxx> +#include <tools/urlobj.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <svtools/htmltokn.h> +#include <svtools/htmlkywd.hxx> + + +#define ACTION_INSERTTEXT 1 +#define ACTION_INSERTPARABRK 2 + +#define STYLE_PRE 101 + +EditHTMLParser::EditHTMLParser( SvStream& rIn, const String& rBaseURL, SvKeyValueIterator* pHTTPHeaderAttrs ) + : HTMLParser( rIn, true ) + , aBaseURL( rBaseURL ) +{ + pImpEditEngine = 0; + pCurAnchor = 0; + bInPara = FALSE; + bWasInPara = FALSE; + nInTable = 0; + nInCell = 0; + nDefListLevel = 0; + nBulletLevel = 0; + nNumberingLevel = 0; + bFieldsInserted = FALSE; + + if ( pHTTPHeaderAttrs ) + SetEncodingByHTTPHeader( pHTTPHeaderAttrs ); +} + +EditHTMLParser::~EditHTMLParser() +{ + delete pCurAnchor; +} + +SvParserState EditHTMLParser::CallParser( ImpEditEngine* pImpEE, const EditPaM& rPaM ) +{ + DBG_ASSERT( pImpEE, "CallParser: ImpEditEngine ?!" ); + pImpEditEngine = pImpEE; + SvParserState _eState = SVPAR_NOTSTARTED; + if ( pImpEditEngine ) + { + // Umbrechmimik vom RTF-Import einbauen? + aCurSel = EditSelection( rPaM, rPaM ); + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_START, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + ImpSetStyleSheet( 0 ); + _eState = HTMLParser::CallParser(); + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_END, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + if ( bFieldsInserted ) + pImpEditEngine->UpdateFields(); + } + return _eState; +} + +void EditHTMLParser::NextToken( int nToken ) +{ + #ifdef DBG_UTIL + HTML_TOKEN_IDS xID = (HTML_TOKEN_IDS)nToken; + (void)xID; + #endif + + switch( nToken ) + { + case HTML_META: + { + const HTMLOptions *_pOptions = GetOptions(); + USHORT nArrLen = _pOptions->Count(); + BOOL bEquiv = FALSE; + for ( USHORT i = 0; i < nArrLen; i++ ) + { + const HTMLOption *pOption = (*_pOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_HTTPEQUIV: + { + bEquiv = TRUE; + } + break; + case HTML_O_CONTENT: + { + if ( bEquiv ) + { + rtl_TextEncoding eEnc = GetEncodingByMIME( pOption->GetString() ); + if ( eEnc != RTL_TEXTENCODING_DONTKNOW ) + SetSrcEncoding( eEnc ); + } + } + break; + } + } + + } + break; + case HTML_PLAINTEXT_ON: + case HTML_PLAINTEXT2_ON: + bInPara = TRUE; + break; + case HTML_PLAINTEXT_OFF: + case HTML_PLAINTEXT2_OFF: + bInPara = FALSE; + break; + + case HTML_LINEBREAK: + case HTML_NEWPARA: + { + if ( ( bInPara || nInTable ) && + ( ( nToken == HTML_LINEBREAK ) || HasTextInCurrentPara() ) ) + { + ImpInsertParaBreak(); + } + } + break; + case HTML_HORZRULE: + { + if ( HasTextInCurrentPara() ) + ImpInsertParaBreak(); + ImpInsertParaBreak(); + } + case HTML_NONBREAKSPACE: + { + if ( bInPara ) + { + ImpInsertText( String( RTL_CONSTASCII_USTRINGPARAM( " " ) ) ); + } + } + break; + case HTML_TEXTTOKEN: + { + if ( !bInPara ) + StartPara( FALSE ); + +// if ( bInPara || pCurAnchor ) + { + String aText = aToken; + if ( aText.Len() && ( aText.GetChar( 0 ) == ' ' ) + && ThrowAwayBlank() && !IsReadPRE() ) + aText.Erase( 0, 1 ); + + if ( pCurAnchor ) + { + pCurAnchor->aText += aText; + } + else + { + // Nur bis HTML mit 319 geschrieben ?! + if ( IsReadPRE() ) + { + USHORT nTabPos = aText.Search( '\t', 0 ); + while ( nTabPos != STRING_NOTFOUND ) + { + aText.Erase( nTabPos, 1 ); + aText.Insert( String( RTL_CONSTASCII_USTRINGPARAM( " " ) ), nTabPos ); + nTabPos = aText.Search( '\t', nTabPos+8 ); + } + } + ImpInsertText( aText ); + } + } + } + break; + + case HTML_CENTER_ON: + case HTML_CENTER_OFF: // if ( bInPara ) + { + USHORT nNode = pImpEditEngine->GetEditDoc().GetPos( aCurSel.Max().GetNode() ); + SfxItemSet aItems( aCurSel.Max().GetNode()->GetContentAttribs().GetItems() ); + aItems.ClearItem( EE_PARA_JUST ); + if ( nToken == HTML_CENTER_ON ) + aItems.Put( SvxAdjustItem( SVX_ADJUST_CENTER, EE_PARA_JUST ) ); + pImpEditEngine->SetParaAttribs( nNode, aItems ); + } + break; + + case HTML_ANCHOR_ON: AnchorStart(); + break; + case HTML_ANCHOR_OFF: AnchorEnd(); + break; + + case HTML_PARABREAK_ON: + if( bInPara && HasTextInCurrentPara() ) + EndPara( TRUE ); + StartPara( TRUE ); + break; + + case HTML_PARABREAK_OFF: + if( bInPara ) + EndPara( TRUE ); + break; + + case HTML_HEAD1_ON: + case HTML_HEAD2_ON: + case HTML_HEAD3_ON: + case HTML_HEAD4_ON: + case HTML_HEAD5_ON: + case HTML_HEAD6_ON: + { + HeadingStart( nToken ); + } + break; + + case HTML_HEAD1_OFF: + case HTML_HEAD2_OFF: + case HTML_HEAD3_OFF: + case HTML_HEAD4_OFF: + case HTML_HEAD5_OFF: + case HTML_HEAD6_OFF: + { + HeadingEnd( nToken ); + } + break; + + case HTML_PREFORMTXT_ON: + case HTML_XMP_ON: + case HTML_LISTING_ON: + { + StartPara( TRUE ); + ImpSetStyleSheet( STYLE_PRE ); + } + break; + + case HTML_DEFLIST_ON: + { + nDefListLevel++; + } + break; + + case HTML_DEFLIST_OFF: + { + if( nDefListLevel ) + nDefListLevel--; + } + break; + + case HTML_TABLE_ON: nInTable++; + break; + case HTML_TABLE_OFF: DBG_ASSERT( nInTable, "Nicht in Table, aber TABLE_OFF?" ); + nInTable--; + break; + + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + nInCell++; + // fallthru + case HTML_BLOCKQUOTE_ON: + case HTML_BLOCKQUOTE_OFF: + case HTML_BLOCKQUOTE30_ON: + case HTML_BLOCKQUOTE30_OFF: + case HTML_LISTHEADER_ON: + case HTML_LI_ON: + case HTML_DD_ON: + case HTML_DT_ON: + case HTML_ORDERLIST_ON: + case HTML_UNORDERLIST_ON: + { + BOOL bHasText = HasTextInCurrentPara(); + if ( bHasText ) + ImpInsertParaBreak(); + StartPara( FALSE ); + } + break; + + case HTML_TABLEHEADER_OFF: + case HTML_TABLEDATA_OFF: + { + if ( nInCell ) + nInCell--; + } + // fallthru + case HTML_LISTHEADER_OFF: + case HTML_LI_OFF: + case HTML_DD_OFF: + case HTML_DT_OFF: + case HTML_ORDERLIST_OFF: + case HTML_UNORDERLIST_OFF: EndPara( FALSE ); + break; + + case HTML_TABLEROW_ON: + case HTML_TABLEROW_OFF: // Nur nach einem CELL ein RETURN, fuer Calc + + case HTML_COL_ON: + case HTML_COLGROUP_ON: + case HTML_COLGROUP_OFF: break; + + case HTML_FONT_ON: // ... + break; + case HTML_FONT_OFF: // ... + break; + + + // #58335# kein SkipGroup on/off auf inline markup etc. + + // globals + case HTML_HTML_ON: + case HTML_HTML_OFF: + case HTML_BODY_ON: + case HTML_BODY_OFF: + case HTML_HEAD_ON: + case HTML_HEAD_OFF: + case HTML_FORM_ON: + case HTML_FORM_OFF: + case HTML_THEAD_ON: + case HTML_THEAD_OFF: + case HTML_TBODY_ON: + case HTML_TBODY_OFF: + case HTML_TITLE_ON: + case HTML_TITLE_OFF: + // inline elements, structural markup + // HTML 3.0 + case HTML_BANNER_ON: + case HTML_BANNER_OFF: + case HTML_DIVISION_ON: + case HTML_DIVISION_OFF: +// case HTML_LISTHEADER_ON: //! special handling +// case HTML_LISTHEADER_OFF: + case HTML_NOTE_ON: + case HTML_NOTE_OFF: + // inline elements, logical markup + // HTML 2.0 + case HTML_ADDRESS_ON: + case HTML_ADDRESS_OFF: +// case HTML_BLOCKQUOTE_ON: //! extra Behandlung +// case HTML_BLOCKQUOTE_OFF: + case HTML_CITIATION_ON: + case HTML_CITIATION_OFF: + case HTML_CODE_ON: + case HTML_CODE_OFF: + case HTML_DEFINSTANCE_ON: + case HTML_DEFINSTANCE_OFF: + case HTML_EMPHASIS_ON: + case HTML_EMPHASIS_OFF: + case HTML_KEYBOARD_ON: + case HTML_KEYBOARD_OFF: + case HTML_SAMPLE_ON: + case HTML_SAMPLE_OFF: + case HTML_STRIKE_ON: + case HTML_STRIKE_OFF: + case HTML_STRONG_ON: + case HTML_STRONG_OFF: + case HTML_VARIABLE_ON: + case HTML_VARIABLE_OFF: + // HTML 3.0 + case HTML_ABBREVIATION_ON: + case HTML_ABBREVIATION_OFF: + case HTML_ACRONYM_ON: + case HTML_ACRONYM_OFF: + case HTML_AUTHOR_ON: + case HTML_AUTHOR_OFF: +// case HTML_BLOCKQUOTE30_ON: //! extra Behandlung +// case HTML_BLOCKQUOTE30_OFF: + case HTML_DELETEDTEXT_ON: + case HTML_DELETEDTEXT_OFF: + case HTML_INSERTEDTEXT_ON: + case HTML_INSERTEDTEXT_OFF: + case HTML_LANGUAGE_ON: + case HTML_LANGUAGE_OFF: + case HTML_PERSON_ON: + case HTML_PERSON_OFF: + case HTML_SHORTQUOTE_ON: + case HTML_SHORTQUOTE_OFF: + case HTML_SUBSCRIPT_ON: + case HTML_SUBSCRIPT_OFF: + case HTML_SUPERSCRIPT_ON: + case HTML_SUPERSCRIPT_OFF: + // inline elements, visual markup + // HTML 2.0 + case HTML_BOLD_ON: + case HTML_BOLD_OFF: + case HTML_ITALIC_ON: + case HTML_ITALIC_OFF: + case HTML_TELETYPE_ON: + case HTML_TELETYPE_OFF: + case HTML_UNDERLINE_ON: + case HTML_UNDERLINE_OFF: + // HTML 3.0 + case HTML_BIGPRINT_ON: + case HTML_BIGPRINT_OFF: + case HTML_STRIKETHROUGH_ON: + case HTML_STRIKETHROUGH_OFF: + case HTML_SMALLPRINT_ON: + case HTML_SMALLPRINT_OFF: + // figures + case HTML_FIGURE_ON: + case HTML_FIGURE_OFF: + case HTML_CAPTION_ON: + case HTML_CAPTION_OFF: + case HTML_CREDIT_ON: + case HTML_CREDIT_OFF: + // misc + case HTML_DIRLIST_ON: + case HTML_DIRLIST_OFF: + case HTML_FOOTNOTE_ON: //! landen so im Text + case HTML_FOOTNOTE_OFF: + case HTML_MENULIST_ON: + case HTML_MENULIST_OFF: +// case HTML_PLAINTEXT_ON: //! extra Behandlung +// case HTML_PLAINTEXT_OFF: +// case HTML_PREFORMTXT_ON: //! extra Behandlung +// case HTML_PREFORMTXT_OFF: + case HTML_SPAN_ON: + case HTML_SPAN_OFF: + // obsolete +// case HTML_XMP_ON: //! extra Behandlung +// case HTML_XMP_OFF: +// case HTML_LISTING_ON: //! extra Behandlung +// case HTML_LISTING_OFF: + // Netscape + case HTML_BLINK_ON: + case HTML_BLINK_OFF: + case HTML_NOBR_ON: + case HTML_NOBR_OFF: + case HTML_NOEMBED_ON: + case HTML_NOEMBED_OFF: + case HTML_NOFRAMES_ON: + case HTML_NOFRAMES_OFF: + // Internet Explorer + case HTML_MARQUEE_ON: + case HTML_MARQUEE_OFF: +// case HTML_PLAINTEXT2_ON: //! extra Behandlung +// case HTML_PLAINTEXT2_OFF: + break; + + default: + { + if ( nToken & HTML_TOKEN_ONOFF ) + { + if ( ( nToken == HTML_UNKNOWNCONTROL_ON ) || ( nToken == HTML_UNKNOWNCONTROL_OFF ) ) + { + ; + } + else if ( !(nToken & 1) ) + { + DBG_ASSERT( !( nToken & 1 ), "Kein Start-Token ?!" ); + SkipGroup( nToken + 1 ); + } + } + } + } // SWITCH + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_NEXTTOKEN, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.nToken = nToken; + aImportInfo.nTokenValue = (short)nTokenValue; + if ( nToken == HTML_TEXTTOKEN ) + aImportInfo.aText = aToken; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + +} + +void EditHTMLParser::ImpInsertParaBreak() +{ + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_INSERTPARA, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + aCurSel = pImpEditEngine->ImpInsertParaBreak( aCurSel ); + nLastAction = ACTION_INSERTPARABRK; +} + +void EditHTMLParser::ImpSetAttribs( const SfxItemSet& rItems, EditSelection* pSel ) +{ + // pSel, wenn Zeichenattribute, sonst Absatzattribute fuer den + // aktuellen Absatz. + DBG_ASSERT( pSel || ( aCurSel.Min().GetNode() == aCurSel.Max().GetNode() ), "ImpInsertAttribs: Selektion?" ); + + EditPaM aStartPaM( pSel ? pSel->Min() : aCurSel.Min() ); + EditPaM aEndPaM( pSel ? pSel->Max() : aCurSel.Max() ); + + if ( !pSel ) + { + aStartPaM.SetIndex( 0 ); + aEndPaM.SetIndex( aEndPaM.GetNode()->Len() ); + } + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + EditSelection aSel( aStartPaM, aEndPaM ); + ImportInfo aImportInfo( HTMLIMP_SETATTR, this, pImpEditEngine->CreateESel( aSel ) ); + aImportInfo.pAttrs = (void*)&rItems; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + ContentNode* pSN = aStartPaM.GetNode(); + USHORT nStartNode = pImpEditEngine->GetEditDoc().GetPos( pSN ); + + // Wenn ein Attribut von 0 bis aktuelle Absatzlaenge geht, + // soll es ein Absatz-Attribut sein! + + // Achtung: Selektion kann ueber mehrere Absaetze gehen. + // Alle vollstaendigen Absaetze sind Absatzattribute... + + // HTML eigentlich nicht: +#ifdef DBG_UTIL + ContentNode* pEN = aEndPaM.GetNode(); + USHORT nEndNode = pImpEditEngine->GetEditDoc().GetPos( pEN ); + DBG_ASSERT( nStartNode == nEndNode, "ImpSetAttribs: Mehrere Absaetze?" ); +#endif + +/* + for ( USHORT z = nStartNode+1; z < nEndNode; z++ ) + { + DBG_ASSERT( pImpEditEngine->GetEditDoc().SaveGetObject( z ), "Node existiert noch nicht(RTF)" ); + pImpEditEngine->SetParaAttribs( z, rSet.GetAttrSet() ); + } + + if ( aStartPaM.GetNode() != aEndPaM.GetNode() ) + { + // Den Rest des StartNodes... + if ( aStartPaM.GetIndex() == 0 ) + pImpEditEngine->SetParaAttribs( nStartNode, rSet.GetAttrSet() ); + else + pImpEditEngine->SetAttribs( EditSelection( aStartPaM, EditPaM( aStartPaM.GetNode(), aStartPaM.GetNode()->Len() ) ), rSet.GetAttrSet() ); + + // Den Anfang des EndNodes.... + if ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) + pImpEditEngine->SetParaAttribs( nEndNode, rSet.GetAttrSet() ); + else + pImpEditEngine->SetAttribs( EditSelection( EditPaM( aEndPaM.GetNode(), 0 ), aEndPaM ), rSet.GetAttrSet() ); + } + else +*/ + { + if ( ( aStartPaM.GetIndex() == 0 ) && ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) ) + { + // Muesse gemergt werden: + SfxItemSet aItems( pImpEditEngine->GetParaAttribs( nStartNode ) ); + aItems.Put( rItems ); + pImpEditEngine->SetParaAttribs( nStartNode, aItems ); + } + else + pImpEditEngine->SetAttribs( EditSelection( aStartPaM, aEndPaM ), rItems ); + } +} + +void EditHTMLParser::ImpSetStyleSheet( USHORT nHLevel ) +{ + /* + nHLevel: 0: Ausschalten + 1-6: Heading + STYLE_PRE: Preformatted + */ + +// if ( pImpEditEngine->GetStatus().DoImportRTFStyleSheets() ) +// { +// SvxRTFStyleType* pS = GetStyleTbl().Get( rSet.StyleNo() ); +// DBG_ASSERT( pS, "Vorlage in RTF nicht definiert!" ); +// if ( pS ) +// pImpEditEngine->SetStyleSheet( EditSelection( aStartPaM, aEndPaM ), pS->sName, SFX_STYLE_FAMILY_ALL ); +// } +// else + { + // Harte Attribute erzeugen... + // Reicht fuer Calc, bei StyleSheets muesste noch geklaert werden, + // dass diese auch in der App liegen sollten, damit sie beim + // fuettern in eine andere Engine auch noch da sind... + + USHORT nNode = pImpEditEngine->GetEditDoc().GetPos( aCurSel.Max().GetNode() ); +// SfxItemSet aItems( pImpEditEngine->GetEmptyItemSet() ); + SfxItemSet aItems( aCurSel.Max().GetNode()->GetContentAttribs().GetItems() ); + + aItems.ClearItem( EE_PARA_ULSPACE ); + aItems.ClearItem( EE_CHAR_FONTHEIGHT ); + aItems.ClearItem( EE_CHAR_FONTINFO ); + aItems.ClearItem( EE_CHAR_WEIGHT ); + + // Fett in den ersten 3 Headings + if ( ( nHLevel >= 1 ) && ( nHLevel <= 3 ) ) + { + SvxWeightItem aWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ); + aItems.Put( aWeightItem ); + } + + // Fonthoehe und Abstaende, wenn LogicToLogic moeglich: + MapUnit eUnit = pImpEditEngine->GetRefMapMode().GetMapUnit(); + if ( ( eUnit != MAP_PIXEL ) && ( eUnit != MAP_SYSFONT ) && + ( eUnit != MAP_APPFONT ) && ( eUnit != MAP_RELATIVE ) ) + { + long nPoints = 10; + if ( nHLevel == 1 ) + nPoints = 22; + else if ( nHLevel == 2 ) + nPoints = 16; + else if ( nHLevel == 3 ) + nPoints = 12; + else if ( nHLevel == 4 ) + nPoints = 11; + + nPoints = OutputDevice::LogicToLogic( nPoints, MAP_POINT, eUnit ); + SvxFontHeightItem aHeightItem( nPoints, 100, EE_CHAR_FONTHEIGHT ); + aItems.Put( aHeightItem ); + + // Absatzabstaende, wenn Heading: + if ( !nHLevel || ((nHLevel >= 1) && (nHLevel <= 6)) ) + { + SvxULSpaceItem aULSpaceItem( EE_PARA_ULSPACE ); + aULSpaceItem.SetUpper( (USHORT)OutputDevice::LogicToLogic( 42, MAP_10TH_MM, eUnit ) ); + aULSpaceItem.SetLower( (USHORT)OutputDevice::LogicToLogic( 35, MAP_10TH_MM, eUnit ) ); + aItems.Put( aULSpaceItem ); + } + } + + // Bei Pre einen proportionalen Font waehlen + if ( nHLevel == STYLE_PRE ) + { + Font aFont = OutputDevice::GetDefaultFont( DEFAULTFONT_FIXED, LANGUAGE_SYSTEM, 0 ); + SvxFontItem aFontItem( aFont.GetFamily(), aFont.GetName(), XubString(), aFont.GetPitch(), aFont.GetCharSet(), EE_CHAR_FONTINFO ); + aItems.Put( aFontItem ); + } + + pImpEditEngine->SetParaAttribs( nNode, aItems ); + } +} + +void EditHTMLParser::ImpInsertText( const String& rText ) +{ + String aText( rText ); + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_INSERTTEXT, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.aText = aText; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + aCurSel = pImpEditEngine->ImpInsertText( aCurSel, aText ); + nLastAction = ACTION_INSERTTEXT; +} + +void EditHTMLParser::SkipGroup( int nEndToken ) +{ + // #69109# groups in cells are closed upon leaving the cell, because those + // ******* web authors don't know their job + // for example: <td><form></td> lacks a closing </form> + BYTE nCellLevel = nInCell; + int nToken; + while( nCellLevel <= nInCell && ( (nToken = GetNextToken() ) != nEndToken ) && nToken ) + { + switch ( nToken ) + { + case HTML_TABLEHEADER_ON: + case HTML_TABLEDATA_ON: + nInCell++; + break; + case HTML_TABLEHEADER_OFF: + case HTML_TABLEDATA_OFF: + if ( nInCell ) + nInCell--; + break; + } + } +} + +void EditHTMLParser::StartPara( BOOL bReal ) +{ + if ( bReal ) + { + const HTMLOptions *_pOptions = GetOptions(); + USHORT nArrLen = _pOptions->Count(); + SvxAdjust eAdjust = SVX_ADJUST_LEFT; + for ( USHORT i = 0; i < nArrLen; i++ ) + { + const HTMLOption *pOption = (*_pOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_ALIGN: + { + if ( pOption->GetString().CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_right ) == COMPARE_EQUAL ) + eAdjust = SVX_ADJUST_RIGHT; + else if ( pOption->GetString().CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_middle ) == COMPARE_EQUAL ) + eAdjust = SVX_ADJUST_CENTER; + else if ( pOption->GetString().CompareIgnoreCaseToAscii( OOO_STRING_SVTOOLS_HTML_AL_center ) == COMPARE_EQUAL ) + eAdjust = SVX_ADJUST_CENTER; + else + eAdjust = SVX_ADJUST_LEFT; + } + break; + } + } + SfxItemSet aItemSet( pImpEditEngine->GetEmptyItemSet() ); + aItemSet.Put( SvxAdjustItem( eAdjust, EE_PARA_JUST ) ); + ImpSetAttribs( aItemSet ); + } + bInPara = TRUE; +} + +void EditHTMLParser::EndPara( BOOL ) +{ + if ( bInPara ) + { + BOOL bHasText = HasTextInCurrentPara(); + if ( bHasText ) + ImpInsertParaBreak(); + // Nur, wenn ohne Absatzabstaende gearbeitet wird... +// if ( !nInTable && bReal && (nNumberingLevel<=1) && (nBulletLevel<=1) ) +// ImpInsertParaBreak(); + } + bInPara = FALSE; +} + +BOOL EditHTMLParser::ThrowAwayBlank() +{ + // Ein Blank muss weggeschmissen werden, wenn der neue Text mit einem + // Blank beginnt und der aktuelle Absatz leer ist oder mit einem + // Blank endet... + ContentNode* pNode = aCurSel.Max().GetNode(); + if ( pNode->Len() && ( pNode->GetChar( pNode->Len()-1 ) != ' ' ) ) + return FALSE; + return TRUE; +} + +BOOL EditHTMLParser::HasTextInCurrentPara() +{ + return aCurSel.Max().GetNode()->Len() ? TRUE : FALSE; +} + +void EditHTMLParser::AnchorStart() +{ + // Anker im Anker ignoriern + if ( !pCurAnchor ) + { + const HTMLOptions* _pOptions = GetOptions(); + USHORT nArrLen = _pOptions->Count(); + + String aRef; + + for ( USHORT i = 0; i < nArrLen; i++ ) + { + const HTMLOption* pOption = (*_pOptions)[i]; + switch( pOption->GetToken() ) + { + case HTML_O_HREF: + aRef = pOption->GetString(); + break; + } + } + + if ( aRef.Len() ) + { + String aURL = aRef; + if ( aURL.Len() && ( aURL.GetChar( 0 ) != '#' ) ) + { + INetURLObject aTargetURL; + INetURLObject aRootURL( aBaseURL ); + aRootURL.GetNewAbsURL( aRef, &aTargetURL ); + aURL = aTargetURL.GetMainURL( INetURLObject::DECODE_TO_IURI ); + } + pCurAnchor = new AnchorInfo; + pCurAnchor->aHRef = aURL; + } + } +} + +void EditHTMLParser::AnchorEnd() +{ + if ( pCurAnchor ) + { + // Als URL-Feld einfuegen... + SvxFieldItem aFld( SvxURLField( pCurAnchor->aHRef, pCurAnchor->aText, SVXURLFORMAT_REPR ), EE_FEATURE_FIELD ); + aCurSel = pImpEditEngine->InsertField( aCurSel, aFld ); + bFieldsInserted = TRUE; + delete pCurAnchor; + pCurAnchor = 0; + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( HTMLIMP_INSERTFIELD, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + } +} + +void EditHTMLParser::HeadingStart( int nToken ) +{ + bWasInPara = bInPara; + StartPara( FALSE ); + + if ( bWasInPara && HasTextInCurrentPara() ) + ImpInsertParaBreak(); + + USHORT nId = sal::static_int_cast< USHORT >( + 1 + ( ( nToken - HTML_HEAD1_ON ) / 2 ) ); + DBG_ASSERT( (nId >= 1) && (nId <= 9), "HeadingStart: ID kann nicht stimmen!" ); + ImpSetStyleSheet( nId ); +} + +void EditHTMLParser::HeadingEnd( int ) +{ + EndPara( FALSE ); + ImpSetStyleSheet( 0 ); + + if ( bWasInPara ) + { + bInPara = TRUE; + bWasInPara = FALSE; + } +} diff --git a/editeng/source/editeng/eehtml.hxx b/editeng/source/editeng/eehtml.hxx new file mode 100644 index 000000000000..d213cb119761 --- /dev/null +++ b/editeng/source/editeng/eehtml.hxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eehtml.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EEHTML_HXX +#define _EEHTML_HXX + +#include <svl/svarray.hxx> + +#include <editdoc.hxx> +#include <svtools/parhtml.hxx> + +class ImpEditEngine; + +#define MAX_NUMBERLEVEL 10 + +struct AnchorInfo +{ + String aHRef; + String aText; +}; + +class EditHTMLParser : public HTMLParser +{ + using HTMLParser::CallParser; +private: + EditSelection aCurSel; + String aBaseURL; + ImpEditEngine* pImpEditEngine; + AnchorInfo* pCurAnchor; + + BOOL bInPara; + BOOL bWasInPara; // bInPara vor HeadingStart merken, weil sonst hinterher weg + BOOL bFieldsInserted; + BYTE nInTable; + BYTE nInCell; + + BYTE nDefListLevel; + BYTE nBulletLevel; + BYTE nNumberingLevel; + + BYTE nLastAction; + + void StartPara( BOOL bReal ); + void EndPara( BOOL bReal ); + void AnchorStart(); + void AnchorEnd(); + void HeadingStart( int nToken ); + void HeadingEnd( int nToken ); + void SkipGroup( int nEndToken ); + BOOL ThrowAwayBlank(); + BOOL HasTextInCurrentPara(); + void ProcessUnknownControl( BOOL bOn ); + + void ImpInsertParaBreak(); + void ImpInsertText( const String& rText ); + void ImpSetAttribs( const SfxItemSet& rItems, EditSelection* pSel = 0 ); + void ImpSetStyleSheet( USHORT nHeadingLevel ); + +protected: + virtual void NextToken( int nToken ); + +public: + EditHTMLParser( SvStream& rIn, const String& rBaseURL, SvKeyValueIterator* pHTTPHeaderAttrs ); + ~EditHTMLParser(); + + virtual SvParserState CallParser( ImpEditEngine* pImpEE, const EditPaM& rPaM ); + + const EditSelection& GetCurSelection() const { return aCurSel; } +}; + +SV_DECL_REF( EditHTMLParser ) +SV_IMPL_REF( EditHTMLParser ); + +#endif // _EEHTML_HXX diff --git a/editeng/source/editeng/eeng_pch.cxx b/editeng/source/editeng/eeng_pch.cxx new file mode 100644 index 000000000000..3f59955cd954 --- /dev/null +++ b/editeng/source/editeng/eeng_pch.cxx @@ -0,0 +1,33 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eeng_pch.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <eeng_pch.hxx> diff --git a/editeng/source/editeng/eeng_pch.hxx b/editeng/source/editeng/eeng_pch.hxx new file mode 100644 index 000000000000..4480ef84480b --- /dev/null +++ b/editeng/source/editeng/eeng_pch.hxx @@ -0,0 +1,37 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eeng_pch.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#define _STD_VAR_ARRAYS + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + + diff --git a/editeng/source/editeng/eeobj.cxx b/editeng/source/editeng/eeobj.cxx new file mode 100644 index 000000000000..67a091e596c8 --- /dev/null +++ b/editeng/source/editeng/eeobj.cxx @@ -0,0 +1,115 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eeobj.cxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + + +#include <eeng_pch.hxx> + +#include <eeobj.hxx> +#include <sot/exchange.hxx> +#include <sot/formats.hxx> +#include <editeng/editeng.hxx> +#include <svl/itempool.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +using namespace ::com::sun::star; + + +EditDataObject::EditDataObject() +{ +} + +EditDataObject::~EditDataObject() +{ +} + +// uno::XInterface +uno::Any EditDataObject::queryInterface( const uno::Type & rType ) throw(uno::RuntimeException) +{ + uno::Any aRet = ::cppu::queryInterface( rType, SAL_STATIC_CAST( datatransfer::XTransferable*, this ) ); + return (aRet.hasValue() ? aRet : OWeakObject::queryInterface( rType )); +} + +// datatransfer::XTransferable +uno::Any EditDataObject::getTransferData( const datatransfer::DataFlavor& rFlavor ) throw(datatransfer::UnsupportedFlavorException, io::IOException, uno::RuntimeException) +{ + uno::Any aAny; + + ULONG nT = SotExchange::GetFormat( rFlavor ); + if ( nT == SOT_FORMAT_STRING ) + { + aAny <<= (::rtl::OUString)GetString(); + } + else if ( ( nT == SOT_FORMATSTR_ID_EDITENGINE ) || ( nT == SOT_FORMAT_RTF ) ) + { + // MT 01/2002: No RTF on demand any more: + // 1) Was not working, because I had to flush() the clipboard immediately anyway + // 2) Don't have the old pool defaults and the StyleSheetPool here. + + SvMemoryStream* pStream = ( nT == SOT_FORMATSTR_ID_EDITENGINE ) ? &GetStream() : &GetRTFStream(); + pStream->Seek( STREAM_SEEK_TO_END ); + ULONG nLen = pStream->Tell(); + pStream->Seek(0); + + uno::Sequence< sal_Int8 > aSeq( nLen ); + memcpy( aSeq.getArray(), pStream->GetData(), nLen ); + aAny <<= aSeq; + } + else + { + datatransfer::UnsupportedFlavorException aException; + throw( aException ); + } + + return aAny; +} + +uno::Sequence< datatransfer::DataFlavor > EditDataObject::getTransferDataFlavors( ) throw(uno::RuntimeException) +{ + uno::Sequence< datatransfer::DataFlavor > aDataFlavors(3); + SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_EDITENGINE, aDataFlavors.getArray()[0] ); + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aDataFlavors.getArray()[1] ); + SotExchange::GetFormatDataFlavor( SOT_FORMAT_RTF, aDataFlavors.getArray()[2] ); + + return aDataFlavors; +} + +sal_Bool EditDataObject::isDataFlavorSupported( const datatransfer::DataFlavor& rFlavor ) throw(uno::RuntimeException) +{ + sal_Bool bSupported = sal_False; + + ULONG nT = SotExchange::GetFormat( rFlavor ); + if ( ( nT == SOT_FORMAT_STRING ) || ( nT == SOT_FORMAT_RTF ) /* || ( nT == SOT_FORMAT_XML ) */ || ( nT == SOT_FORMATSTR_ID_EDITENGINE ) ) + bSupported = sal_True; + + return bSupported; +} diff --git a/editeng/source/editeng/eeobj.hxx b/editeng/source/editeng/eeobj.hxx new file mode 100644 index 000000000000..00f764ddba97 --- /dev/null +++ b/editeng/source/editeng/eeobj.hxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eeobj.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _DATAOBJ_HXX +#define _DATAOBJ_HXX + +#include <cppuhelper/weak.hxx> +#include <com/sun/star/datatransfer/XTransferable.hpp> + +#include <tools/stream.hxx> + +class EditDataObject : public ::com::sun::star::datatransfer::XTransferable, + public ::cppu::OWeakObject + +{ +private: + SvMemoryStream maBinData; + SvMemoryStream maRTFData; + String maText; + + String maOfficeBookmark; + +// String maNetscapeBookmark; +// SvMemoryStream maRTFData; + +public: + EditDataObject(); + ~EditDataObject(); + + SvMemoryStream& GetStream() { return maBinData; } + SvMemoryStream& GetRTFStream() { return maRTFData; } + String& GetString() { return maText; } + String& GetURL() { return maOfficeBookmark; } + + + // ::com::sun::star::uno::XInterface + ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type & rType ) throw(::com::sun::star::uno::RuntimeException); + void SAL_CALL acquire() throw() { OWeakObject::acquire(); } + void SAL_CALL release() throw() { OWeakObject::release(); } + + // ::com::sun::star::datatransfer::XTransferable + ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors( ) throw(::com::sun::star::uno::RuntimeException); + sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw(::com::sun::star::uno::RuntimeException); +}; + +#endif // _DATAOBJ_HXX + diff --git a/editeng/source/editeng/eerdll.cxx b/editeng/source/editeng/eerdll.cxx new file mode 100644 index 000000000000..be0df2cc969d --- /dev/null +++ b/editeng/source/editeng/eerdll.cxx @@ -0,0 +1,240 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eerdll.cxx,v $ + * $Revision: 1.31.148.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/linguistic2/XLanguageGuessing.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <comphelper/processfactory.hxx> + +#include <svl/solar.hrc> +#include <editeng/eerdll.hxx> +#include <eerdll2.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/bulitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/scriptspaceitem.hxx> +#include <svl/itempool.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/xmlcnitm.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <comphelper/processfactory.hxx> + +static EditDLL* pDLL=0; + +using namespace ::com::sun::star; + +EditDLL* EditDLL::Get() +{ + if ( !pDLL ) + pDLL = new EditDLL; + return pDLL; +} + +GlobalEditData::GlobalEditData() +{ + ppDefItems = NULL; + pStdRefDevice = NULL; +} + +GlobalEditData::~GlobalEditData() +{ + // DefItems zerstoeren... + // Oder einfach stehen lassen, da sowieso App-Ende?! + if ( ppDefItems ) + SfxItemPool::ReleaseDefaults( ppDefItems, EDITITEMCOUNT, TRUE ); + delete pStdRefDevice; +} + +SfxPoolItem** GlobalEditData::GetDefItems() +{ + if ( !ppDefItems ) + { + ppDefItems = new SfxPoolItem*[EDITITEMCOUNT]; + + // Absatzattribute: + SvxNumRule aTmpNumRule( 0, 0, FALSE ); + + ppDefItems[0] = new SvxFrameDirectionItem( FRMDIR_HORI_LEFT_TOP, EE_PARA_WRITINGDIR ); + ppDefItems[1] = new SvXMLAttrContainerItem( EE_PARA_XMLATTRIBS ); + ppDefItems[2] = new SfxBoolItem( EE_PARA_HANGINGPUNCTUATION, FALSE ); + ppDefItems[3] = new SfxBoolItem( EE_PARA_FORBIDDENRULES, TRUE ); + ppDefItems[4] = new SvxScriptSpaceItem( TRUE, EE_PARA_ASIANCJKSPACING ); + ppDefItems[5] = new SvxNumBulletItem( aTmpNumRule, EE_PARA_NUMBULLET ); + ppDefItems[6] = new SfxBoolItem( EE_PARA_HYPHENATE, FALSE ); + ppDefItems[7] = new SfxBoolItem( EE_PARA_BULLETSTATE, TRUE ); + ppDefItems[8] = new SvxLRSpaceItem( EE_PARA_OUTLLRSPACE ); + ppDefItems[9] = new SfxInt16Item( EE_PARA_OUTLLEVEL, -1 ); + ppDefItems[10] = new SvxBulletItem( EE_PARA_BULLET ); + ppDefItems[11] = new SvxLRSpaceItem( EE_PARA_LRSPACE ); + ppDefItems[12] = new SvxULSpaceItem( EE_PARA_ULSPACE ); + ppDefItems[13] = new SvxLineSpacingItem( 0, EE_PARA_SBL ); + ppDefItems[14] = new SvxAdjustItem( SVX_ADJUST_LEFT, EE_PARA_JUST ); + ppDefItems[15] = new SvxTabStopItem( 0, 0, SVX_TAB_ADJUST_LEFT, EE_PARA_TABS ); + + // Zeichenattribute: + ppDefItems[16] = new SvxColorItem( Color( COL_AUTO ), EE_CHAR_COLOR ); + ppDefItems[17] = new SvxFontItem( EE_CHAR_FONTINFO ); + ppDefItems[18] = new SvxFontHeightItem( 240, 100, EE_CHAR_FONTHEIGHT ); + ppDefItems[19] = new SvxCharScaleWidthItem( 100, EE_CHAR_FONTWIDTH ); + ppDefItems[20] = new SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ); + ppDefItems[21] = new SvxUnderlineItem( UNDERLINE_NONE, EE_CHAR_UNDERLINE ); + ppDefItems[22] = new SvxCrossedOutItem( STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ); + ppDefItems[23] = new SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC ); + ppDefItems[24] = new SvxContourItem( FALSE, EE_CHAR_OUTLINE ); + ppDefItems[25] = new SvxShadowedItem( FALSE, EE_CHAR_SHADOW ); + ppDefItems[26] = new SvxEscapementItem( 0, 100, EE_CHAR_ESCAPEMENT ); + ppDefItems[27] = new SvxAutoKernItem( FALSE, EE_CHAR_PAIRKERNING ); + ppDefItems[28] = new SvxKerningItem( 0, EE_CHAR_KERNING ); + ppDefItems[29] = new SvxWordLineModeItem( FALSE, EE_CHAR_WLM ); + ppDefItems[30] = new SvxLanguageItem( LANGUAGE_DONTKNOW, EE_CHAR_LANGUAGE ); + ppDefItems[31] = new SvxLanguageItem( LANGUAGE_DONTKNOW, EE_CHAR_LANGUAGE_CJK ); + ppDefItems[32] = new SvxLanguageItem( LANGUAGE_DONTKNOW, EE_CHAR_LANGUAGE_CTL ); + ppDefItems[33] = new SvxFontItem( EE_CHAR_FONTINFO_CJK ); + ppDefItems[34] = new SvxFontItem( EE_CHAR_FONTINFO_CTL ); + ppDefItems[35] = new SvxFontHeightItem( 240, 100, EE_CHAR_FONTHEIGHT_CJK ); + ppDefItems[36] = new SvxFontHeightItem( 240, 100, EE_CHAR_FONTHEIGHT_CTL ); + ppDefItems[37] = new SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CJK ); + ppDefItems[38] = new SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT_CTL ); + ppDefItems[39] = new SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CJK ); + ppDefItems[40] = new SvxPostureItem( ITALIC_NONE, EE_CHAR_ITALIC_CTL ); + ppDefItems[41] = new SvxEmphasisMarkItem( EMPHASISMARK_NONE, EE_CHAR_EMPHASISMARK ); + ppDefItems[42] = new SvxCharReliefItem( RELIEF_NONE, EE_CHAR_RELIEF ); + ppDefItems[43] = new SfxVoidItem( EE_CHAR_RUBI_DUMMY ); +#ifndef SVX_LIGHT + ppDefItems[44] = new SvXMLAttrContainerItem( EE_CHAR_XMLATTRIBS ); +#else + // no need to have alien attributes persistent + ppDefItems[44] = new SfxVoidItem( EE_CHAR_XMLATTRIBS ); +#endif // #ifndef SVX_LIGHT + ppDefItems[45] = new SvxOverlineItem( UNDERLINE_NONE, EE_CHAR_OVERLINE ); + + // Features + ppDefItems[46] = new SfxVoidItem( EE_FEATURE_TAB ); + ppDefItems[47] = new SfxVoidItem( EE_FEATURE_LINEBR ); + ppDefItems[48] = new SvxCharSetColorItem( Color( COL_RED ), RTL_TEXTENCODING_DONTKNOW, EE_FEATURE_NOTCONV ); + ppDefItems[49] = new SvxFieldItem( SvxFieldData(), EE_FEATURE_FIELD ); + + DBG_ASSERT( EDITITEMCOUNT == 50, "ITEMCOUNT geaendert, DefItems nicht angepasst!" ); + + // Init DefFonts: + GetDefaultFonts( *(SvxFontItem*)ppDefItems[EE_CHAR_FONTINFO - EE_ITEMS_START], + *(SvxFontItem*)ppDefItems[EE_CHAR_FONTINFO_CJK - EE_ITEMS_START], + *(SvxFontItem*)ppDefItems[EE_CHAR_FONTINFO_CTL - EE_ITEMS_START] ); + } + + return ppDefItems; +} + +vos::ORef<SvxForbiddenCharactersTable> GlobalEditData::GetForbiddenCharsTable() +{ + if ( !xForbiddenCharsTable.isValid() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + xForbiddenCharsTable = new SvxForbiddenCharactersTable( xMSF ); + } + return xForbiddenCharsTable; +} + +uno::Reference< linguistic2::XLanguageGuessing > GlobalEditData::GetLanguageGuesser() +{ + if (!xLanguageGuesser.is()) + { + uno::Reference< lang::XMultiServiceFactory > xMgr ( comphelper::getProcessServiceFactory() ); + if (xMgr.is()) + { + xLanguageGuesser = uno::Reference< linguistic2::XLanguageGuessing >( + xMgr->createInstance( + rtl::OUString::createFromAscii( "com.sun.star.linguistic2.LanguageGuessing" ) ), + uno::UNO_QUERY ); + } + } + return xLanguageGuesser; +} + +OutputDevice* GlobalEditData::GetStdRefDevice() +{ + if ( !pStdRefDevice ) + { + pStdRefDevice = new VirtualDevice; + pStdRefDevice->SetMapMode( MAP_TWIP ); + } + return pStdRefDevice; +} + +EditResId::EditResId( USHORT nId ): + ResId( nId, *EE_DLL()->GetResMgr() ) +{ +} + +EditDLL::EditDLL() +{ + pGlobalData = new GlobalEditData; + ByteString aResMgrName( "editeng" ); + pResMgr = ResMgr::CreateResMgr( + aResMgrName.GetBuffer(), Application::GetSettings().GetUILocale() ); +} + +EditDLL::~EditDLL() +{ + delete pResMgr; + delete pGlobalData; +} diff --git a/editeng/source/editeng/eerdll2.hxx b/editeng/source/editeng/eerdll2.hxx new file mode 100644 index 000000000000..eb1db3502c8f --- /dev/null +++ b/editeng/source/editeng/eerdll2.hxx @@ -0,0 +1,64 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eerdll2.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _EERDLL2_HXX +#define _EERDLL2_HXX + +#include <com/sun/star/linguistic2/XLanguageGuessing.hpp> +#include <editeng/forbiddencharacterstable.hxx> +#include <vos/ref.hxx> + +class SfxPoolItem; + +class GlobalEditData +{ +private: + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XLanguageGuessing > xLanguageGuesser; + SfxPoolItem** ppDefItems; + OutputDevice* pStdRefDevice; + + vos::ORef<SvxForbiddenCharactersTable> xForbiddenCharsTable; + +public: + GlobalEditData(); + ~GlobalEditData(); + + SfxPoolItem** GetDefItems(); + OutputDevice* GetStdRefDevice(); + + vos::ORef<SvxForbiddenCharactersTable> GetForbiddenCharsTable(); + void SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ) { xForbiddenCharsTable = xForbiddenChars; } + ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XLanguageGuessing > GetLanguageGuesser(); +}; + + +#endif //_EERDLL2_HXX + diff --git a/editeng/source/editeng/eertfpar.cxx b/editeng/source/editeng/eertfpar.cxx new file mode 100644 index 000000000000..d569b933fb49 --- /dev/null +++ b/editeng/source/editeng/eertfpar.cxx @@ -0,0 +1,635 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eertfpar.cxx,v $ + * $Revision: 1.16 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <eertfpar.hxx> +#include <impedit.hxx> +#include <svl/intitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/flditem.hxx> + +#include <svtools/rtftoken.h> + +// alle Werte auf default; wird nach einlesen der Bitmap aufgerufen ! +void SvxRTFPictureType::ResetValues() +{ // setze alle Werte RTF-Defaults + eStyle = RTF_BITMAP; + nMode = HEX_MODE; + nType = nGoalWidth = nGoalHeight = 0; + nWidth = nHeight = nWidthBytes = 0; + uPicLen = 0; + nBitsPerPixel = nPlanes = 1; + nScalX = nScalY = 100; // Skalierung in Prozent + nCropT = nCropB = nCropL = nCropR = 0; +} + +ImportInfo::ImportInfo( ImportState eSt, SvParser* pPrsrs, const ESelection& rSel ) + : aSelection( rSel ) +{ + pParser = pPrsrs, + eState = eSt; + + nToken = 0; + nTokenValue = 0; + pAttrs = NULL; +} + +ImportInfo::~ImportInfo() +{ +} + +EditRTFParser::EditRTFParser( SvStream& rIn, EditSelection aSel, SfxItemPool& rAttrPool, ImpEditEngine* pImpEE ) + : SvxRTFParser( rAttrPool, rIn, 0 ), aRTFMapMode( MAP_TWIP ) +{ + + pImpEditEngine = pImpEE; + aCurSel = aSel; + eDestCharSet = RTL_TEXTENCODING_DONTKNOW; + nDefFont = 0; + nDefTab = 0; + nLastAction = 0; + nDefFontHeight = 0; + + SetInsPos( EditPosition( pImpEditEngine, &aCurSel ) ); + + // Umwandeln der Twips-Werte... + SetCalcValue( TRUE ); + SetChkStyleAttr( pImpEE->GetStatus().DoImportRTFStyleSheets() ); + SetNewDoc( FALSE ); // damit die Pool-Defaults nicht + // ueberschrieben werden... + aEditMapMode = MapMode( pImpEE->GetRefDevice()->GetMapMode().GetMapUnit() ); +} + +EditRTFParser::~EditRTFParser() +{ +} + +SvParserState __EXPORT EditRTFParser::CallParser() +{ + DBG_ASSERT( !aCurSel.HasRange(), "Selection bei CallParser!" ); + // Den Teil, in den importiert wird, vom Rest abtrennen. + // Diese Mimik sollte fuer alle Imports verwendet werden. + // aStart1PaM: Letzte Position vor dem importierten Inhalt + // aEnd1PaM: Erste Position nach dem importierten Inhalt + // aStart2PaM: Erste Position des importierten Inhaltes + // aEnd2PaM: Letzte Position des importierten Inhaltes + EditPaM aStart1PaM( aCurSel.Min().GetNode(), aCurSel.Min().GetIndex() ); + aCurSel = pImpEditEngine->ImpInsertParaBreak( aCurSel ); + EditPaM aStart2PaM = aCurSel.Min(); + // Sinnvoll oder nicht?: + aStart2PaM.GetNode()->GetContentAttribs().GetItems().ClearItem(); + AddRTFDefaultValues( aStart2PaM, aStart2PaM ); + EditPaM aEnd1PaM( pImpEditEngine->ImpInsertParaBreak( aCurSel.Max() ) ); + // aCurCel zeigt jetzt auf den Zwischenraum + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_START, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + SvParserState _eState = SvxRTFParser::CallParser(); + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_END, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + if ( nLastAction == ACTION_INSERTPARABRK ) + { + ContentNode* pCurNode = aCurSel.Max().GetNode(); + USHORT nPara = pImpEditEngine->GetEditDoc().GetPos( pCurNode ); + ContentNode* pPrevNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara-1 ); + DBG_ASSERT( pPrevNode, "Ungueltiges RTF-Dokument ?!" ); + EditSelection aSel; + aSel.Min() = EditPaM( pPrevNode, pPrevNode->Len() ); + aSel.Max() = EditPaM( pCurNode, 0 ); + aCurSel.Max() = pImpEditEngine->ImpDeleteSelection( aSel ); + } + EditPaM aEnd2PaM( aCurSel.Max() ); + //AddRTFDefaultValues( aStart2PaM, aEnd2PaM ); + BOOL bOnlyOnePara = ( aEnd2PaM.GetNode() == aStart2PaM.GetNode() ); + // Den Brocken wieder einfuegen... + // Problem: Absatzattribute duerfen ggf. nicht uebernommen werden + // => Zeichenattribute machen. + + BOOL bSpecialBackward = aStart1PaM.GetNode()->Len() ? FALSE : TRUE; + if ( bOnlyOnePara || aStart1PaM.GetNode()->Len() ) + pImpEditEngine->ParaAttribsToCharAttribs( aStart2PaM.GetNode() ); + aCurSel.Min() = pImpEditEngine->ImpConnectParagraphs( + aStart1PaM.GetNode(), aStart2PaM.GetNode(), bSpecialBackward ); + bSpecialBackward = aEnd1PaM.GetNode()->Len() ? TRUE : FALSE; + // wenn bOnlyOnePara, dann ist der Node beim Connect verschwunden. + if ( !bOnlyOnePara && aEnd1PaM.GetNode()->Len() ) + pImpEditEngine->ParaAttribsToCharAttribs( aEnd2PaM.GetNode() ); + aCurSel.Max() = pImpEditEngine->ImpConnectParagraphs( + ( bOnlyOnePara ? aStart1PaM.GetNode() : aEnd2PaM.GetNode() ), + aEnd1PaM.GetNode(), bSpecialBackward ); + + return _eState; +} + +void EditRTFParser::AddRTFDefaultValues( const EditPaM& rStart, const EditPaM& rEnd ) +{ + // Problem: DefFont und DefFontHeight + Size aSz( 12, 0 ); + MapMode aPntMode( MAP_POINT ); + MapMode _aEditMapMode( pImpEditEngine->GetRefDevice()->GetMapMode().GetMapUnit() ); + aSz = pImpEditEngine->GetRefDevice()->LogicToLogic( aSz, &aPntMode, &_aEditMapMode ); + SvxFontHeightItem aFontHeightItem( aSz.Width(), 100, EE_CHAR_FONTHEIGHT ); + Font aDefFont( GetDefFont() ); + SvxFontItem aFontItem( aDefFont.GetFamily(), aDefFont.GetName(), + aDefFont.GetStyleName(), aDefFont.GetPitch(), aDefFont.GetCharSet(), EE_CHAR_FONTINFO ); + + USHORT nStartPara = pImpEditEngine->GetEditDoc().GetPos( rStart.GetNode() ); + USHORT nEndPara = pImpEditEngine->GetEditDoc().GetPos( rEnd.GetNode() ); + for ( USHORT nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERT( pNode, "AddRTFDefaultValues - Kein Absatz ?!" ); + if ( !pNode->GetContentAttribs().HasItem( EE_CHAR_FONTINFO ) ) + pNode->GetContentAttribs().GetItems().Put( aFontItem ); + if ( !pNode->GetContentAttribs().HasItem( EE_CHAR_FONTHEIGHT ) ) + pNode->GetContentAttribs().GetItems().Put( aFontHeightItem ); + } +} + +void __EXPORT EditRTFParser::NextToken( int nToken ) +{ + switch( nToken ) + { + case RTF_DEFF: + { + nDefFont = USHORT(nTokenValue); + } + break; + case RTF_DEFTAB: + { + nDefTab = USHORT(nTokenValue); + } + break; + case RTF_CELL: + { + aCurSel = pImpEditEngine->ImpInsertParaBreak( aCurSel ); + } + break; + case RTF_LINE: + { + aCurSel = pImpEditEngine->InsertLineBreak( aCurSel ); + } + break; + case RTF_FIELD: + { + ReadField(); + } + break; + case RTF_PGDSCTBL: // #i29453# ignore \*\pgdsctbl destination + case RTF_LISTTEXT: + { + SkipGroup(); + } + break; + default: + { + SvxRTFParser::NextToken( nToken ); + if ( nToken == RTF_STYLESHEET ) + CreateStyleSheets(); + } + break; + } + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_NEXTTOKEN, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.nToken = nToken; + aImportInfo.nTokenValue = short(nTokenValue); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } +} + +void __EXPORT EditRTFParser::UnknownAttrToken( int nToken, SfxItemSet* ) +{ + // fuer Tokens, die im ReadAttr nicht ausgewertet werden + // Eigentlich nur fuer Calc (RTFTokenHdl), damit RTF_INTBL + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_UNKNOWNATTR, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.nToken = nToken; + aImportInfo.nTokenValue = short(nTokenValue); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } +} + +void __EXPORT EditRTFParser::InsertText() +{ + String aText( aToken ); + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_INSERTTEXT, this, pImpEditEngine->CreateESel( aCurSel ) ); + aImportInfo.aText = aText; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + aCurSel = pImpEditEngine->ImpInsertText( aCurSel, aText ); + nLastAction = ACTION_INSERTTEXT; +} + +void __EXPORT EditRTFParser::InsertPara() +{ + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + ImportInfo aImportInfo( RTFIMP_INSERTPARA, this, pImpEditEngine->CreateESel( aCurSel ) ); + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + aCurSel = pImpEditEngine->ImpInsertParaBreak( aCurSel ); + nLastAction = ACTION_INSERTPARABRK; +} + +void __EXPORT EditRTFParser::MovePos( int bForward ) +{ + if( bForward ) + aCurSel = pImpEditEngine->CursorRight( aCurSel.Max(), ::com::sun::star::i18n::CharacterIteratorMode::SKIPCHARACTER ); + else + aCurSel = pImpEditEngine->CursorLeft( aCurSel.Max(), ::com::sun::star::i18n::CharacterIteratorMode::SKIPCHARACTER ); +} + +void __EXPORT EditRTFParser::SetEndPrevPara( SvxNodeIdx*& rpNodePos, + USHORT& rCntPos ) +{ + // Gewollt ist: von der aktuellen Einfuegeposition den vorherigen + // Absatz bestimmen und von dem das Ende setzen. + // Dadurch wird "\pard" immer auf den richtigen Absatz + // angewendet. + + ContentNode* pN = aCurSel.Max().GetNode(); + USHORT nCurPara = pImpEditEngine->GetEditDoc().GetPos( pN ); + DBG_ASSERT( nCurPara != 0, "Absatz gleich 0: SetEnfPrevPara" ); + if ( nCurPara ) + nCurPara--; + ContentNode* pPrevNode = pImpEditEngine->GetEditDoc().SaveGetObject( nCurPara ); + DBG_ASSERT( pPrevNode, "pPrevNode = 0!" ); + rpNodePos = new EditNodeIdx( pImpEditEngine, pPrevNode ); + rCntPos = pPrevNode->Len(); +} + +int __EXPORT EditRTFParser::IsEndPara( SvxNodeIdx* pNd, USHORT nCnt ) const +{ + return ( nCnt == ( ((EditNodeIdx*)pNd)->GetNode()->Len()) ); +} + +void __EXPORT EditRTFParser::SetAttrInDoc( SvxRTFItemStackType &rSet ) +{ + ContentNode* pSttNode = ((EditNodeIdx&)rSet.GetSttNode()).GetNode(); + ContentNode* pEndNode = ((EditNodeIdx&)rSet.GetEndNode()).GetNode(); + + EditPaM aStartPaM( pSttNode, rSet.GetSttCnt() ); + EditPaM aEndPaM( pEndNode, rSet.GetEndCnt() ); + + // ggf. noch das Escapemant-Item umbiegen: + const SfxPoolItem* pItem; + + // #i66167# adapt font heights to destination MapUnit if necessary + const MapUnit eDestUnit = ( MapUnit )( pImpEditEngine->GetEditDoc().GetItemPool().GetMetric(0) ); + const MapUnit eSrcUnit = aRTFMapMode.GetMapUnit(); + if (eDestUnit != eSrcUnit) + { + USHORT aFntHeightIems[3] = { EE_CHAR_FONTHEIGHT, EE_CHAR_FONTHEIGHT_CJK, EE_CHAR_FONTHEIGHT_CTL }; + for (int i = 0; i < 2; ++i) + { + if (SFX_ITEM_SET == rSet.GetAttrSet().GetItemState( aFntHeightIems[i], FALSE, &pItem )) + { + UINT32 nHeight = ((SvxFontHeightItem*)pItem)->GetHeight(); + long nNewHeight; + nNewHeight = pImpEditEngine->GetRefDevice()->LogicToLogic( (long)nHeight, eSrcUnit, eDestUnit ); + + SvxFontHeightItem aFntHeightItem( nNewHeight, ((SvxFontHeightItem*)pItem)->GetProp(), aFntHeightIems[i] ); + rSet.GetAttrSet().Put( aFntHeightItem ); + } + } + } + + if( SFX_ITEM_SET == rSet.GetAttrSet().GetItemState( EE_CHAR_ESCAPEMENT, FALSE, &pItem )) + { + // die richtige + long nEsc = ((SvxEscapementItem*)pItem)->GetEsc(); + + if( ( DFLT_ESC_AUTO_SUPER != nEsc ) && ( DFLT_ESC_AUTO_SUB != nEsc ) ) + { + nEsc *= 10; //HalPoints => Twips wurde in RTFITEM.CXX unterschlagen! + SvxFont aFont; + pImpEditEngine->SeekCursor( aStartPaM.GetNode(), aStartPaM.GetIndex()+1, aFont ); + nEsc = nEsc * 100 / aFont.GetSize().Height(); + + SvxEscapementItem aEscItem( (short) nEsc, ((SvxEscapementItem*)pItem)->GetProp(), EE_CHAR_ESCAPEMENT ); + rSet.GetAttrSet().Put( aEscItem ); + } + } + + if ( pImpEditEngine->aImportHdl.IsSet() ) + { + EditSelection aSel( aStartPaM, aEndPaM ); + ImportInfo aImportInfo( RTFIMP_SETATTR, this, pImpEditEngine->CreateESel( aSel ) ); + aImportInfo.pAttrs = &rSet; + pImpEditEngine->aImportHdl.Call( &aImportInfo ); + } + + ContentNode* pSN = aStartPaM.GetNode(); + ContentNode* pEN = aEndPaM.GetNode(); + USHORT nStartNode = pImpEditEngine->GetEditDoc().GetPos( pSN ); + USHORT nEndNode = pImpEditEngine->GetEditDoc().GetPos( pEN ); + sal_Int16 nOutlLevel = 0xff; + + if ( rSet.StyleNo() && pImpEditEngine->GetStyleSheetPool() && pImpEditEngine->GetStatus().DoImportRTFStyleSheets() ) + { + SvxRTFStyleType* pS = GetStyleTbl().Get( rSet.StyleNo() ); + DBG_ASSERT( pS, "Vorlage in RTF nicht definiert!" ); + if ( pS ) + { + pImpEditEngine->SetStyleSheet( EditSelection( aStartPaM, aEndPaM ), (SfxStyleSheet*)pImpEditEngine->GetStyleSheetPool()->Find( pS->sName, SFX_STYLE_FAMILY_ALL ) ); + nOutlLevel = pS->nOutlineNo; + } + } + + // Wenn ein Attribut von 0 bis aktuelle Absatzlaenge geht, + // soll es ein Absatz-Attribut sein! + + // Achtung: Selektion kann ueber mehrere Absaetze gehen. + // Alle vollstaendigen Absaetze sind Absatzattribute... + for ( USHORT z = nStartNode+1; z < nEndNode; z++ ) + { + DBG_ASSERT( pImpEditEngine->GetEditDoc().SaveGetObject( z ), "Node existiert noch nicht(RTF)" ); + pImpEditEngine->SetParaAttribs( z, rSet.GetAttrSet() ); + } + + if ( aStartPaM.GetNode() != aEndPaM.GetNode() ) + { + // Den Rest des StartNodes... + if ( aStartPaM.GetIndex() == 0 ) + pImpEditEngine->SetParaAttribs( nStartNode, rSet.GetAttrSet() ); + else + pImpEditEngine->SetAttribs( EditSelection( aStartPaM, EditPaM( aStartPaM.GetNode(), aStartPaM.GetNode()->Len() ) ), rSet.GetAttrSet() ); + + // Den Anfang des EndNodes.... + if ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) + pImpEditEngine->SetParaAttribs( nEndNode, rSet.GetAttrSet() ); + else + pImpEditEngine->SetAttribs( EditSelection( EditPaM( aEndPaM.GetNode(), 0 ), aEndPaM ), rSet.GetAttrSet() ); + } + else + { + if ( ( aStartPaM.GetIndex() == 0 ) && ( aEndPaM.GetIndex() == aEndPaM.GetNode()->Len() ) ) + { + // #96298# When settings char attribs as para attribs, we must merge with existing attribs, not overwrite the ItemSet! + SfxItemSet aAttrs = pImpEditEngine->GetParaAttribs( nStartNode ); + aAttrs.Put( rSet.GetAttrSet() ); + pImpEditEngine->SetParaAttribs( nStartNode, aAttrs ); + } + else + { + pImpEditEngine->SetAttribs( EditSelection( aStartPaM, aEndPaM ), rSet.GetAttrSet() ); + } + } + + // OutlLevel... + if ( nOutlLevel != 0xff ) + { + for ( USHORT n = nStartNode; n <= nEndNode; n++ ) + { + ContentNode* pNode = pImpEditEngine->GetEditDoc().SaveGetObject( n ); + pNode->GetContentAttribs().GetItems().Put( SfxInt16Item( EE_PARA_OUTLLEVEL, nOutlLevel ) ); + } + } +} + +SvxRTFStyleType* EditRTFParser::FindStyleSheet( const XubString& rName ) +{ + SvxRTFStyleType* pS = GetStyleTbl().First(); + while ( pS && ( pS->sName != rName ) ) + pS = GetStyleTbl().Next(); + + return pS; +} + +SfxStyleSheet* EditRTFParser::CreateStyleSheet( SvxRTFStyleType* pRTFStyle ) +{ + // Prueffen, ob so eine Vorlage existiert.... + // dann wird sie auch nicht geaendert! + SfxStyleSheet* pStyle = (SfxStyleSheet*)pImpEditEngine->GetStyleSheetPool()->Find( pRTFStyle->sName, SFX_STYLE_FAMILY_ALL ); + if ( pStyle ) + return pStyle; + + String aName( pRTFStyle->sName ); + String aParent; + if ( pRTFStyle->nBasedOn ) + { + SvxRTFStyleType* pS = GetStyleTbl().Get( pRTFStyle->nBasedOn ); + if ( pS && ( pS !=pRTFStyle ) ) + aParent = pS->sName; + } + + pStyle = (SfxStyleSheet*) &pImpEditEngine->GetStyleSheetPool()->Make( aName, SFX_STYLE_FAMILY_PARA ); + + // 1) Items konvertieren und uebernehmen... + ConvertAndPutItems( pStyle->GetItemSet(), pRTFStyle->aAttrSet ); + + // 2) Solange Parent nicht im Pool, auch diesen kreieren... + if ( aParent.Len() && ( aParent != aName ) ) + { + SfxStyleSheet* pS = (SfxStyleSheet*)pImpEditEngine->GetStyleSheetPool()->Find( aParent, SFX_STYLE_FAMILY_ALL ); + if ( !pS ) + { + // Wenn nirgendwo gefunden, aus RTF erzeugen... + SvxRTFStyleType* _pRTFStyle = FindStyleSheet( aParent ); + if ( _pRTFStyle ) + pS = CreateStyleSheet( _pRTFStyle ); + } + // 2b) ItemSet mit Parent verknuepfen... + if ( pS ) + pStyle->GetItemSet().SetParent( &pS->GetItemSet() ); + } + return pStyle; +} + +void EditRTFParser::CreateStyleSheets() +{ + // der SvxRTFParser hat jetzt die Vorlagen erzeugt... + if ( pImpEditEngine->GetStyleSheetPool() && pImpEditEngine->GetStatus().DoImportRTFStyleSheets() ) + { + SvxRTFStyleType* pRTFStyle = GetStyleTbl().First(); + while ( pRTFStyle ) + { + CreateStyleSheet( pRTFStyle ); + + pRTFStyle = GetStyleTbl().Next(); + } + } +} + +void __EXPORT EditRTFParser::CalcValue() +{ + const MapUnit eDestUnit = static_cast< MapUnit >( aEditMapMode.GetMapUnit() ); + const MapUnit eSrcUnit = aRTFMapMode.GetMapUnit(); + if (eDestUnit != eSrcUnit) + nTokenValue = OutputDevice::LogicToLogic( (long)nTokenValue, eSrcUnit, eDestUnit ); +} + +void EditRTFParser::ReadField() +{ + // Aus SwRTFParser::ReadField() + int _nOpenBrakets = 1; // die erste wurde schon vorher erkannt + BOOL bFldInst = FALSE; + BOOL bFldRslt = FALSE; + String aFldInst; + String aFldRslt; + + while( _nOpenBrakets && IsParserWorking() ) + { + switch( GetNextToken() ) + { + case '}': + { + _nOpenBrakets--; + if ( _nOpenBrakets == 1 ) + { + bFldInst = FALSE; + bFldRslt = FALSE; + } + } + break; + + case '{': _nOpenBrakets++; + break; + + case RTF_FIELD: SkipGroup(); + break; + + case RTF_FLDINST: bFldInst = TRUE; + break; + + case RTF_FLDRSLT: bFldRslt = TRUE; + break; + + case RTF_TEXTTOKEN: + { + if ( bFldInst ) + aFldInst += aToken; + else if ( bFldRslt ) + aFldRslt += aToken; + } + break; + } + } + if ( aFldInst.Len() ) + { + String aHyperLinkMarker( RTL_CONSTASCII_USTRINGPARAM( "HYPERLINK " ) ); + if ( aFldInst.CompareIgnoreCaseToAscii( aHyperLinkMarker, aHyperLinkMarker.Len() ) == COMPARE_EQUAL ) + { + aFldInst.Erase( 0, aHyperLinkMarker.Len() ); + aFldInst.EraseLeadingChars(); + aFldInst.EraseTrailingChars(); + aFldInst.Erase( 0, 1 ); // " + aFldInst.Erase( aFldInst.Len()-1, 1 ); // " + + if ( !aFldRslt.Len() ) + aFldRslt = aFldInst; + + SvxFieldItem aField( SvxURLField( aFldInst, aFldRslt, SVXURLFORMAT_REPR ), EE_FEATURE_FIELD ); + aCurSel = pImpEditEngine->InsertField( aCurSel, aField ); + pImpEditEngine->UpdateFields(); + nLastAction = ACTION_INSERTTEXT; + } + } + + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet +} + +void EditRTFParser::SkipGroup() +{ + int _nOpenBrakets = 1; // die erste wurde schon vorher erkannt + + while( _nOpenBrakets && IsParserWorking() ) + { + switch( GetNextToken() ) + { + case '}': + { + _nOpenBrakets--; + } + break; + + case '{': + { + _nOpenBrakets++; + } + break; + } + } + + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet +} + +ULONG __EXPORT EditNodeIdx::GetIdx() const +{ + return pImpEditEngine->GetEditDoc().GetPos( pNode ); +} + +SvxNodeIdx* __EXPORT EditNodeIdx::Clone() const +{ + return new EditNodeIdx( pImpEditEngine, pNode ); +} + +SvxPosition* __EXPORT EditPosition::Clone() const +{ + return new EditPosition( pImpEditEngine, pCurSel ); +} + +SvxNodeIdx* __EXPORT EditPosition::MakeNodeIdx() const +{ + return new EditNodeIdx( pImpEditEngine, pCurSel->Max().GetNode() ); +} + +ULONG __EXPORT EditPosition::GetNodeIdx() const +{ + ContentNode* pN = pCurSel->Max().GetNode(); + return pImpEditEngine->GetEditDoc().GetPos( pN ); +} + +USHORT __EXPORT EditPosition::GetCntIdx() const +{ + return pCurSel->Max().GetIndex(); +} diff --git a/editeng/source/editeng/eertfpar.hxx b/editeng/source/editeng/eertfpar.hxx new file mode 100644 index 000000000000..df8181317fd0 --- /dev/null +++ b/editeng/source/editeng/eertfpar.hxx @@ -0,0 +1,131 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: eertfpar.hxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _EERTFPAR_HXX +#define _EERTFPAR_HXX + +#include <editeng/svxrtf.hxx> + +#include <editdoc.hxx> +#include <impedit.hxx> + +#ifndef SVX_LIGHT + +class EditNodeIdx : public SvxNodeIdx +{ +private: + ContentNode* pNode; + ImpEditEngine* pImpEditEngine; + +public: + EditNodeIdx( ImpEditEngine* pIEE, ContentNode* pNd = 0) + { pImpEditEngine = pIEE; pNode = pNd; } + virtual ULONG GetIdx() const; + virtual SvxNodeIdx* Clone() const; + ContentNode* GetNode() { return pNode; } +}; + +class EditPosition : public SvxPosition +{ +private: + EditSelection* pCurSel; + ImpEditEngine* pImpEditEngine; + +public: + EditPosition( ImpEditEngine* pIEE, EditSelection* pSel ) + { pImpEditEngine = pIEE; pCurSel = pSel; } + + virtual ULONG GetNodeIdx() const; + virtual USHORT GetCntIdx() const; + + // erzeuge von sich selbst eine Kopie + virtual SvxPosition* Clone() const; + + // erzeuge vom NodeIndex eine Kopie + virtual SvxNodeIdx* MakeNodeIdx() const; +}; + +#define ACTION_INSERTTEXT 1 +#define ACTION_INSERTPARABRK 2 + +class EditRTFParser : public SvxRTFParser +{ +private: + EditSelection aCurSel; + ImpEditEngine* pImpEditEngine; + CharSet eDestCharSet; + MapMode aRTFMapMode; + MapMode aEditMapMode; + + USHORT nDefFont; + USHORT nDefTab; + USHORT nDefFontHeight; + BYTE nLastAction; + +protected: + virtual void InsertPara(); + virtual void InsertText(); + virtual void MovePos( int bForward = TRUE ); + virtual void SetEndPrevPara( SvxNodeIdx*& rpNodePos, + USHORT& rCntPos ); + + virtual void UnknownAttrToken( int nToken, SfxItemSet* pSet ); + virtual void NextToken( int nToken ); + virtual void SetAttrInDoc( SvxRTFItemStackType &rSet ); + virtual int IsEndPara( SvxNodeIdx* pNd, USHORT nCnt ) const; + virtual void CalcValue(); + void CreateStyleSheets(); + SfxStyleSheet* CreateStyleSheet( SvxRTFStyleType* pRTFStyle ); + SvxRTFStyleType* FindStyleSheet( const String& rName ); + void AddRTFDefaultValues( const EditPaM& rStart, const EditPaM& rEnd ); + void ReadField(); + void SkipGroup(); + +public: + EditRTFParser( SvStream& rIn, EditSelection aCurSel, SfxItemPool& rAttrPool, ImpEditEngine* pImpEditEngine ); + ~EditRTFParser(); + + virtual SvParserState CallParser(); + + + void SetDestCharSet( CharSet eCharSet ) { eDestCharSet = eCharSet; } + CharSet GetDestCharSet() const { return eDestCharSet; } + + USHORT GetDefTab() const { return nDefTab; } + Font GetDefFont() { return GetFont( nDefFont ); } + + EditPaM GetCurPaM() const { return aCurSel.Max(); } +}; + +SV_DECL_REF( EditRTFParser ) +SV_IMPL_REF( EditRTFParser ); + + +#endif // !SVX_LIGH +#endif //_EERTFPAR_HXX diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx new file mode 100644 index 000000000000..6f81e6fc05b6 --- /dev/null +++ b/editeng/source/editeng/impedit.cxx @@ -0,0 +1,2005 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: impedit.cxx,v $ + * $Revision: 1.64 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <eeng_pch.hxx> + +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <tools/poly.hxx> +#include <editeng/unolingu.hxx> +#include <com/sun/star/linguistic2/XDictionaryEntry.hpp> +#include <com/sun/star/linguistic2/DictionaryType.hpp> +#include <com/sun/star/linguistic2/DictionaryEvent.hpp> +#include <com/sun/star/linguistic2/XDictionaryEventListener.hpp> +#include <com/sun/star/linguistic2/DictionaryEventFlags.hpp> +#include <com/sun/star/linguistic2/XDictionary.hpp> +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp> +#include <vos/mutex.hxx> +#include <editeng/flditem.hxx> +#include <svl/intitem.hxx> +#include <svtools/transfer.hxx> +#include <sot/exchange.hxx> +#include <sot/formats.hxx> + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; + +#define SCRLRANGE 20 // 1/20 der Breite/Hoehe scrollen, wenn im QueryDrop + +inline void lcl_AllignToPixel( Point& rPoint, OutputDevice* pOutDev, short nDiffX, short nDiffY ) +{ + rPoint = pOutDev->LogicToPixel( rPoint ); + + if ( nDiffX ) + rPoint.X() += nDiffX; + if ( nDiffY ) + rPoint.Y() += nDiffY; + + rPoint = pOutDev->PixelToLogic( rPoint ); +} + +// ---------------------------------------------------------------------- +// class ImpEditView +// ---------------------------------------------------------------------- +ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, Window* pWindow ) : + aOutArea( Point(), pEng->GetPaperSize() ) +{ + pEditView = pView; + pEditEngine = pEng; + pOutWin = pWindow; + pPointer = NULL; + pBackgroundColor = NULL; + nScrollDiffX = 0; + nExtraCursorFlags = 0; + nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW; + pCursor = NULL; + pDragAndDropInfo = NULL; + bReadOnly = sal_False; + bClickedInSelection = sal_False; + eSelectionMode = EE_SELMODE_TXTONLY; + eAnchorMode = ANCHOR_TOP_LEFT; + nInvMore = 1; + nTravelXPos = TRAVEL_X_DONTKNOW; + nControl = EV_CNTRL_AUTOSCROLL | EV_CNTRL_ENABLEPASTE; + bActiveDragAndDropListener = FALSE; + + aEditSelection.Min() = pEng->pImpEditEngine->GetEditDoc().GetStartPaM(); + aEditSelection.Max() = pEng->pImpEditEngine->GetEditDoc().GetEndPaM(); +} + +ImpEditView::~ImpEditView() +{ + RemoveDragAndDropListeners(); + + if ( pOutWin && ( pOutWin->GetCursor() == pCursor ) ) + pOutWin->SetCursor( NULL ); + + delete pCursor; + delete pBackgroundColor; + delete pPointer; + delete pDragAndDropInfo; +} + +void ImpEditView::SetBackgroundColor( const Color& rColor ) +{ + delete pBackgroundColor; + pBackgroundColor = new Color( rColor ); +} + +void ImpEditView::SetEditSelection( const EditSelection& rEditSelection ) +{ + // #100856# set state before notification + aEditSelection = rEditSelection; + + if ( pEditEngine->pImpEditEngine->GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_TEXTVIEWSELECTIONCHANGED ); + aNotify.pEditEngine = pEditEngine; + aNotify.pEditView = GetEditViewPtr(); + pEditEngine->pImpEditEngine->CallNotify( aNotify ); + } +} + + +void ImpEditView::DrawSelection( EditSelection aTmpSel, Region* pRegion ) +{ + if ( GetSelectionMode() == EE_SELMODE_HIDDEN ) + return; + + // Vor dem Zeichnen der Selektion muss sichergestellt werden, + // das der Fensterinhalt komplett gueltig ist! + // Muss hier stehen, damit auf jeden Fall weg wenn lerr, nicht spaeter + // zwei Paint-Events! + // 19.10: Muss sogar vor Abfrage von bUpdate, falls nach Invalidate + // noch Paints in der Queue, aber jemand schaltet den UpdateMode um! + + // pRegion: Wenn nicht NULL, dann nur Region berechnen. + PolyPolygon* pPolyPoly = NULL; + if ( pRegion ) + pPolyPoly = new PolyPolygon; + + sal_Bool bClipRegion = pOutWin->IsClipRegion(); + Region aOldRegion = pOutWin->GetClipRegion(); + + if ( !pRegion ) + { + if ( pEditEngine->pImpEditEngine->GetUpdateMode() == sal_False ) + return; + if ( pEditEngine->pImpEditEngine->IsInUndo() ) + return; + + if ( !aTmpSel.HasRange() ) + return; + + // aTmpOutArea: Falls OutputArea > Papierbreite und + // Text > Papierbreite ( uebergrosse Felder ) + Rectangle aTmpOutArea( aOutArea ); + if ( aTmpOutArea.GetWidth() > pEditEngine->pImpEditEngine->GetPaperSize().Width() ) + aTmpOutArea.Right() = aTmpOutArea.Left() + pEditEngine->pImpEditEngine->GetPaperSize().Width(); + pOutWin->IntersectClipRegion( aTmpOutArea ); + + if ( pOutWin->GetCursor() ) + pOutWin->GetCursor()->Hide(); + } + + DBG_ASSERT( !pEditEngine->pImpEditEngine->aIdleFormatter.IsActive(), "DrawSelection: Not formatted!" ); + aTmpSel.Adjust( pEditEngine->pImpEditEngine->GetEditDoc() ); + + ContentNode* pStartNode = aTmpSel.Min().GetNode(); + ContentNode* pEndNode = aTmpSel.Max().GetNode(); + sal_uInt16 nStartPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( pStartNode ); + sal_uInt16 nEndPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( pEndNode ); + // ueber die Absaetze iterieren.... + for ( sal_uInt16 nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + ParaPortion* pTmpPortion = pEditEngine->pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + DBG_ASSERT( pTmpPortion, "Portion in Selektion nicht gefunden!" ); + DBG_ASSERT( !pTmpPortion->IsInvalid(), "Portion in Selektion nicht formatiert!" ); + + if ( !pTmpPortion->IsVisible() || pTmpPortion->IsInvalid() ) + continue; + + long nParaStart = pEditEngine->pImpEditEngine->GetParaPortions().GetYOffset( pTmpPortion ); + if ( ( nParaStart + pTmpPortion->GetHeight() ) < GetVisDocTop() ) + continue; + if ( nParaStart > GetVisDocBottom() ) + break; + + sal_uInt16 nStartLine = 0; + sal_uInt16 nEndLine = pTmpPortion->GetLines().Count() -1; + if ( nPara == nStartPara ) + nStartLine = pTmpPortion->GetLines().FindLine( aTmpSel.Min().GetIndex(), sal_False ); + if ( nPara == nEndPara ) + nEndLine = pTmpPortion->GetLines().FindLine( aTmpSel.Max().GetIndex(), sal_True ); + + // ueber die Zeilen iterieren.... + for ( sal_uInt16 nLine = nStartLine; nLine <= nEndLine; nLine++ ) + { + EditLine* pLine = pTmpPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "Zeile nicht gefunden: DrawSelection()" ); + + BOOL bPartOfLine = FALSE; + sal_uInt16 nStartIndex = pLine->GetStart(); + sal_uInt16 nEndIndex = pLine->GetEnd(); + if ( ( nPara == nStartPara ) && ( nLine == nStartLine ) && ( nStartIndex != aTmpSel.Min().GetIndex() ) ) + { + nStartIndex = aTmpSel.Min().GetIndex(); + bPartOfLine = TRUE; + } + if ( ( nPara == nEndPara ) && ( nLine == nEndLine ) && ( nEndIndex != aTmpSel.Max().GetIndex() ) ) + { + nEndIndex = aTmpSel.Max().GetIndex(); + bPartOfLine = TRUE; + } + + // Kann passieren, wenn am Anfang einer umgebrochenen Zeile. + if ( nEndIndex < nStartIndex ) + nEndIndex = nStartIndex; + + Rectangle aTmpRec( pEditEngine->pImpEditEngine->GetEditCursor( pTmpPortion, nStartIndex ) ); + Point aTopLeft( aTmpRec.TopLeft() ); + Point aBottomRight( aTmpRec.BottomRight() ); + + aTopLeft.Y() += nParaStart; + aBottomRight.Y() += nParaStart; + + // Nur Painten, wenn im sichtbaren Bereich... + if ( aTopLeft.Y() > GetVisDocBottom() ) + break; + + if ( aBottomRight.Y() < GetVisDocTop() ) + continue; + + // Now that we have Bidi, the first/last index doesn't have to be the 'most outside' postion + if ( !bPartOfLine ) + { + Range aLineXPosStartEnd = pEditEngine->pImpEditEngine->GetLineXPosStartEnd( pTmpPortion, pLine ); + aTopLeft.X() = aLineXPosStartEnd.Min(); + aBottomRight.X() = aLineXPosStartEnd.Max(); + ImplDrawHighlightRect( pOutWin, aTopLeft, aBottomRight, pPolyPoly ); + } + else + { + USHORT nTmpStartIndex = nStartIndex; + USHORT nWritingDirStart, nTmpEndIndex; + + while ( nTmpStartIndex < nEndIndex ) + { + pEditEngine->pImpEditEngine->GetRightToLeft( nPara, nTmpStartIndex+1, &nWritingDirStart, &nTmpEndIndex ); + if ( nTmpEndIndex > nEndIndex ) + nTmpEndIndex = nEndIndex; + + DBG_ASSERT( nTmpEndIndex > nTmpStartIndex, "DrawSelection, Start >= End?" ); + + long nX1 = pEditEngine->pImpEditEngine->GetXPos( pTmpPortion, pLine, nTmpStartIndex, TRUE ); + long nX2 = pEditEngine->pImpEditEngine->GetXPos( pTmpPortion, pLine, nTmpEndIndex ); + + Point aPt1( Min( nX1, nX2 ), aTopLeft.Y() ); + Point aPt2( Max( nX1, nX2 ), aBottomRight.Y() ); + + ImplDrawHighlightRect( pOutWin, aPt1, aPt2, pPolyPoly ); + + nTmpStartIndex = nTmpEndIndex; + } + } + + } + } + + if ( pRegion ) + { + *pRegion = Region( *pPolyPoly ); + delete pPolyPoly; + } + else + { + if ( pOutWin->GetCursor() ) + pOutWin->GetCursor()->Show(); + + if ( bClipRegion ) + pOutWin->SetClipRegion( aOldRegion ); + else + pOutWin->SetClipRegion(); + } +} + +void ImpEditView::ImplDrawHighlightRect( Window* _pOutWin, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, PolyPolygon* pPolyPoly ) +{ + if ( rDocPosTopLeft.X() != rDocPosBottomRight.X() ) + { + sal_Bool bPixelMode = _pOutWin->GetMapMode() == MAP_PIXEL; + + Point aPnt1( GetWindowPos( rDocPosTopLeft ) ); + Point aPnt2( GetWindowPos( rDocPosBottomRight ) ); + + if ( !IsVertical() ) + { + lcl_AllignToPixel( aPnt1, _pOutWin, +1, 0 ); + lcl_AllignToPixel( aPnt2, _pOutWin, 0, ( bPixelMode ? 0 : -1 ) ); + } + else + { + lcl_AllignToPixel( aPnt1, _pOutWin, 0, +1 ); + lcl_AllignToPixel( aPnt2, _pOutWin, ( bPixelMode ? 0 : +1 ), 0 ); + } + + Rectangle aRect( aPnt1, aPnt2 ); + if ( pPolyPoly ) + { + Polygon aTmpPoly( 4 ); + aTmpPoly[0] = aRect.TopLeft(); + aTmpPoly[1] = aRect.TopRight(); + aTmpPoly[2] = aRect.BottomRight(); + aTmpPoly[3] = aRect.BottomLeft(); + pPolyPoly->Insert( aTmpPoly ); + } + else + { + _pOutWin->Invert( aRect ); + } + } +} + + +BOOL ImpEditView::IsVertical() const +{ + return pEditEngine->pImpEditEngine->IsVertical(); +} + +Rectangle ImpEditView::GetVisDocArea() const +{ + return Rectangle( GetVisDocLeft(), GetVisDocTop(), GetVisDocRight(), GetVisDocBottom() ); +} + +Point ImpEditView::GetDocPos( const Point& rWindowPos ) const +{ + // Fensterposition => Dokumentposition + Point aPoint; + + if ( !pEditEngine->pImpEditEngine->IsVertical() ) + { + aPoint.X() = rWindowPos.X() - aOutArea.Left() + GetVisDocLeft(); + aPoint.Y() = rWindowPos.Y() - aOutArea.Top() + GetVisDocTop(); + } + else + { + aPoint.X() = rWindowPos.Y() - aOutArea.Top() + GetVisDocLeft(); + aPoint.Y() = aOutArea.Right() - rWindowPos.X() + GetVisDocTop(); + } + + return aPoint; +} + +Point ImpEditView::GetWindowPos( const Point& rDocPos ) const +{ + // Dokumentposition => Fensterposition + Point aPoint; + + if ( !pEditEngine->pImpEditEngine->IsVertical() ) + { + aPoint.X() = rDocPos.X() + aOutArea.Left() - GetVisDocLeft(); + aPoint.Y() = rDocPos.Y() + aOutArea.Top() - GetVisDocTop(); + } + else + { + aPoint.X() = aOutArea.Right() - rDocPos.Y() + GetVisDocTop(); + aPoint.Y() = rDocPos.X() + aOutArea.Top() - GetVisDocLeft(); + } + + return aPoint; +} + +Rectangle ImpEditView::GetWindowPos( const Rectangle& rDocRect ) const +{ + // Dokumentposition => Fensterposition + Point aPos( GetWindowPos( rDocRect.TopLeft() ) ); + Size aSz = rDocRect.GetSize(); + Rectangle aRect; + if ( !pEditEngine->pImpEditEngine->IsVertical() ) + { + aRect = Rectangle( aPos, aSz ); + } + else + { + Point aNewPos( aPos.X()-aSz.Height(), aPos.Y() ); + aRect = Rectangle( aNewPos, Size( aSz.Height(), aSz.Width() ) ); + } + return aRect; +} + + +Region* ImpEditView::CalcSelectedRegion() +{ + Region* pRegion = new Region; + DrawSelection( GetEditSelection(), pRegion ); + return pRegion; +} + +void ImpEditView::SetSelectionMode( EESelectionMode eNewMode ) +{ + if ( eSelectionMode != eNewMode ) + { + DrawSelection(); // 'Wegmalen' ... + eSelectionMode = eNewMode; + DrawSelection(); // und neu zeichnen. + } +} + +void ImpEditView::SetOutputArea( const Rectangle& rRec ) +{ + // sollte besser auf Pixel allignt sein! + Rectangle aNewRec( pOutWin->LogicToPixel( rRec ) ); + aNewRec = pOutWin->PixelToLogic( aNewRec ); + aOutArea = aNewRec; + if ( aOutArea.Right() < aOutArea.Left() ) + aOutArea.Right() = aOutArea.Left(); + if ( aOutArea.Bottom() < aOutArea.Top() ) + aOutArea.Bottom() = aOutArea.Top(); + + if ( DoBigScroll() ) + SetScrollDiffX( (sal_uInt16)aOutArea.GetWidth() * 3 / 10 ); + else + SetScrollDiffX( (sal_uInt16)aOutArea.GetWidth() * 2 / 10 ); +} + +void ImpEditView::ResetOutputArea( const Rectangle& rRec ) +{ + Rectangle aCurArea( aOutArea ); + SetOutputArea( rRec ); + // Umliegende Bereiche invalidieren, wenn UpdateMode der Engine auf sal_True + if ( !aCurArea.IsEmpty() && pEditEngine->pImpEditEngine->GetUpdateMode() ) + { + long nMore = 0; + if ( DoInvalidateMore() ) + nMore = GetWindow()->PixelToLogic( Size( nInvMore, 0 ) ).Width(); + if ( aCurArea.Left() < aOutArea.Left() ) + { + Rectangle aRect( aCurArea.TopLeft(), + Size( aOutArea.Left()-aCurArea.Left(), aCurArea.GetHeight() ) ); + if ( nMore ) + { + aRect.Left() -= nMore; + aRect.Top() -= nMore; + aRect.Bottom() += nMore; + } + GetWindow()->Invalidate( aRect ); + } + if ( aCurArea.Right() > aOutArea.Right() ) + { + long nW = aCurArea.Right() - aOutArea.Right(); + Point aPos( aCurArea.TopRight() ); + aPos.X() -= nW; + Rectangle aRect( aPos, Size( nW, aCurArea.GetHeight() ) ); + if ( nMore ) + { + aRect.Right() += nMore; + aRect.Top() -= nMore; + aRect.Bottom() += nMore; + } + GetWindow()->Invalidate( aRect ); + } + if ( aCurArea.Top() < aOutArea.Top() ) + { + Rectangle aRect( aCurArea.TopLeft(), Size( aCurArea.GetWidth(), aOutArea.Top() - aCurArea.Top() ) ); + if ( nMore ) + { + aRect.Top() -= nMore; + aRect.Left() -= nMore; + aRect.Right() += nMore; + } + GetWindow()->Invalidate( aRect ); + } + if ( aCurArea.Bottom() > aOutArea.Bottom() ) + { + long nH = aCurArea.Bottom() - aOutArea.Bottom(); + Point aPos( aCurArea.BottomLeft() ); + aPos.Y() -= nH; + Rectangle aRect( aPos, Size( aCurArea.GetWidth(), nH ) ); + if ( nMore ) + { + aRect.Bottom() += nMore; + aRect.Left() -= nMore; + aRect.Right() += nMore; + } + + GetWindow()->Invalidate( aRect ); + } + } +} + +void ImpEditView::RecalcOutputArea() +{ + Rectangle aOldArea( aOutArea ); + Point aNewTopLeft( aOutArea.TopLeft() ); + Size aNewSz( aOutArea.GetSize() ); + + // X: + if ( DoAutoWidth() ) + { + if ( pEditEngine->pImpEditEngine->GetStatus().AutoPageWidth() ) + aNewSz.Width() = pEditEngine->pImpEditEngine->GetPaperSize().Width(); + switch ( eAnchorMode ) + { + case ANCHOR_TOP_LEFT: + case ANCHOR_VCENTER_LEFT: + case ANCHOR_BOTTOM_LEFT: + { + aNewTopLeft.X() = aAnchorPoint.X(); + } + break; + case ANCHOR_TOP_HCENTER: + case ANCHOR_VCENTER_HCENTER: + case ANCHOR_BOTTOM_HCENTER: + { + aNewTopLeft.X() = aAnchorPoint.X() - aNewSz.Width() / 2; + } + break; + case ANCHOR_TOP_RIGHT: + case ANCHOR_VCENTER_RIGHT: + case ANCHOR_BOTTOM_RIGHT: + { + aNewTopLeft.X() = aAnchorPoint.X() - aNewSz.Width() - 1; + } + break; + } + } + + // Y: + if ( DoAutoHeight() ) + { + if ( pEditEngine->pImpEditEngine->GetStatus().AutoPageHeight() ) + aNewSz.Height() = pEditEngine->pImpEditEngine->GetPaperSize().Height(); + switch ( eAnchorMode ) + { + case ANCHOR_TOP_LEFT: + case ANCHOR_TOP_HCENTER: + case ANCHOR_TOP_RIGHT: + { + aNewTopLeft.Y() = aAnchorPoint.Y(); + } + break; + case ANCHOR_VCENTER_LEFT: + case ANCHOR_VCENTER_HCENTER: + case ANCHOR_VCENTER_RIGHT: + { + aNewTopLeft.Y() = aAnchorPoint.Y() - aNewSz.Height() / 2; + } + break; + case ANCHOR_BOTTOM_LEFT: + case ANCHOR_BOTTOM_HCENTER: + case ANCHOR_BOTTOM_RIGHT: + { + aNewTopLeft.Y() = aAnchorPoint.Y() - aNewSz.Height() - 1; + } + break; + } + } + ResetOutputArea( Rectangle( aNewTopLeft, aNewSz ) ); +} + +void ImpEditView::SetAnchorMode( EVAnchorMode eMode ) +{ + eAnchorMode = eMode; + CalcAnchorPoint(); +} + +void ImpEditView::CalcAnchorPoint() +{ + // GetHeight() und GetWidth() -1, da Rectangle-Berechnung nicht erwuenscht. + + // X: + switch ( eAnchorMode ) + { + case ANCHOR_TOP_LEFT: + case ANCHOR_VCENTER_LEFT: + case ANCHOR_BOTTOM_LEFT: + { + aAnchorPoint.X() = aOutArea.Left(); + } + break; + case ANCHOR_TOP_HCENTER: + case ANCHOR_VCENTER_HCENTER: + case ANCHOR_BOTTOM_HCENTER: + { + aAnchorPoint.X() = aOutArea.Left() + (aOutArea.GetWidth()-1) / 2; + } + break; + case ANCHOR_TOP_RIGHT: + case ANCHOR_VCENTER_RIGHT: + case ANCHOR_BOTTOM_RIGHT: + { + aAnchorPoint.X() = aOutArea.Right(); + } + break; + } + + // Y: + switch ( eAnchorMode ) + { + case ANCHOR_TOP_LEFT: + case ANCHOR_TOP_HCENTER: + case ANCHOR_TOP_RIGHT: + { + aAnchorPoint.Y() = aOutArea.Top(); + } + break; + case ANCHOR_VCENTER_LEFT: + case ANCHOR_VCENTER_HCENTER: + case ANCHOR_VCENTER_RIGHT: + { + aAnchorPoint.Y() = aOutArea.Top() + (aOutArea.GetHeight()-1) / 2; + } + break; + case ANCHOR_BOTTOM_LEFT: + case ANCHOR_BOTTOM_HCENTER: + case ANCHOR_BOTTOM_RIGHT: + { + aAnchorPoint.Y() = aOutArea.Bottom() - 1; + } + break; + } +} + +void ImpEditView::ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, USHORT nShowCursorFlags ) +{ + // Kein ShowCursor bei einer leeren View... + if ( ( aOutArea.Left() >= aOutArea.Right() ) && ( aOutArea.Top() >= aOutArea.Bottom() ) ) + return; + + pEditEngine->pImpEditEngine->CheckIdleFormatter(); + if ( !pEditEngine->pImpEditEngine->IsFormatted() ) + pEditEngine->pImpEditEngine->FormatDoc(); + + // Aus irgendwelchen Gruenden lande ich waehrend der Formatierung hier, + // wenn sich der Outiner im Paint initialisiert, weil kein SetPool(); + if ( pEditEngine->pImpEditEngine->IsFormatting() ) + return; + if ( pEditEngine->pImpEditEngine->GetUpdateMode() == sal_False ) + return; + if ( pEditEngine->pImpEditEngine->IsInUndo() ) + return; + + if ( pOutWin->GetCursor() != GetCursor() ) + pOutWin->SetCursor( GetCursor() ); + + EditPaM aPaM( aEditSelection.Max() ); + + USHORT nTextPortionStart = 0; + USHORT nPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + if (nPara == USHRT_MAX) // #i94322 + return; + ParaPortion* pParaPortion = pEditEngine->pImpEditEngine->GetParaPortions().GetObject( nPara ); + + nShowCursorFlags |= nExtraCursorFlags; + + nShowCursorFlags |= GETCRSR_TXTONLY; + + // Use CursorBidiLevel 0/1 in meaning of + // 0: prefer portion end, normal mode + // 1: prefer portion start + + if ( ( GetCursorBidiLevel() != CURSOR_BIDILEVEL_DONTKNOW ) && GetCursorBidiLevel() ) + { + nShowCursorFlags |= GETCRSR_PREFERPORTIONSTART; + } + + Rectangle aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, nShowCursorFlags ); + if ( !IsInsertMode() && !aEditSelection.HasRange() ) + { + if ( aPaM.GetNode()->Len() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) ) + { + // If we are behind a portion, and the next portion has other direction, we must change position... + aEditCursor.Left() = aEditCursor.Right() = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, GETCRSR_TXTONLY|GETCRSR_PREFERPORTIONSTART ).Left(); + + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, TRUE ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + if ( pTextPortion->GetKind() == PORTIONKIND_TAB ) + { + aEditCursor.Right() += pTextPortion->GetSize().Width(); + } + else + { + EditPaM aNext = pEditEngine->pImpEditEngine->CursorRight( aPaM, (USHORT)i18n::CharacterIteratorMode::SKIPCELL ); + Rectangle aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GETCRSR_TXTONLY ); + if ( aTmpRect.Top() != aEditCursor.Top() ) + aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GETCRSR_TXTONLY|GETCRSR_ENDOFLINE ); + aEditCursor.Right() = aTmpRect.Left(); + } + } + } + long nMaxHeight = !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth(); + if ( aEditCursor.GetHeight() > nMaxHeight ) + { + aEditCursor.Bottom() = aEditCursor.Top() + nMaxHeight - 1; + } + if ( bGotoCursor ) // && (!pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() ) ) + { + // pruefen, ob scrollen notwendig... + // wenn scrollen, dann Update() und Scroll() ! + long nDocDiffX = 0; + long nDocDiffY = 0; + + Rectangle aTmpVisArea( GetVisDocArea() ); + // aTmpOutArea: Falls OutputArea > Papierbreite und + // Text > Papierbreite ( uebergrosse Felder ) + long nMaxTextWidth = !IsVertical() ? pEditEngine->pImpEditEngine->GetPaperSize().Width() : pEditEngine->pImpEditEngine->GetPaperSize().Height(); + if ( aTmpVisArea.GetWidth() > nMaxTextWidth ) + aTmpVisArea.Right() = aTmpVisArea.Left() + nMaxTextWidth; + + if ( aEditCursor.Bottom() > aTmpVisArea.Bottom() ) + { // hochscrollen, hier positiv + nDocDiffY = aEditCursor.Bottom() - aTmpVisArea.Bottom(); + } + else if ( aEditCursor.Top() < aTmpVisArea.Top() ) + { // runterscrollen, negativ + nDocDiffY = aEditCursor.Top() - aTmpVisArea.Top(); + } + + if ( aEditCursor.Right() > aTmpVisArea.Right() ) + { + // linksscrollen, positiv + nDocDiffX = aEditCursor.Right() - aTmpVisArea.Right(); + // Darfs ein bischen mehr sein? + if ( aEditCursor.Right() < ( nMaxTextWidth - GetScrollDiffX() ) ) + nDocDiffX += GetScrollDiffX(); + else + { + long n = nMaxTextWidth - aEditCursor.Right(); + // Bei einem MapMode != RefMapMode kann der EditCursor auch mal ueber + // die Papierbreite Wandern! + nDocDiffX += ( n > 0 ? n : -n ); + } + } + else if ( aEditCursor.Left() < aTmpVisArea.Left() ) + { // rechtsscrollen + // negativ: + nDocDiffX = aEditCursor.Left() - aTmpVisArea.Left(); + // Darfs ein bischen mehr sein? + if ( aEditCursor.Left() > ( - (long)GetScrollDiffX() ) ) + nDocDiffX -= GetScrollDiffX(); + else + nDocDiffX -= aEditCursor.Left(); + } + if ( aPaM.GetIndex() == 0 ) // braucht Olli fuer den Outliner + { + // Aber sicherstellen, dass dadurch der Cursor nicht den + // sichtbaren bereich verlaesst! + if ( aEditCursor.Left() < aTmpVisArea.GetWidth() ) + { + nDocDiffX = -aTmpVisArea.Left(); + } + } + + if ( nDocDiffX | nDocDiffY ) + { + long nDiffX = !IsVertical() ? nDocDiffX : -nDocDiffY; + long nDiffY = !IsVertical() ? nDocDiffY : nDocDiffX; + + // Negativ: Zum Anfang bzw. linken Rand + if ( ( Abs( nDiffY ) > pEditEngine->pImpEditEngine->nOnePixelInRef ) && DoBigScroll() ) + { + long nH = aOutArea.GetHeight() / 4; + if ( ( nH > aEditCursor.GetHeight() ) && ( Abs( nDiffY ) < nH ) ) + { + if ( nDiffY < 0 ) + nDiffY -= nH; + else + nDiffY += nH; + } + } + + if ( ( Abs( nDiffX ) > pEditEngine->pImpEditEngine->nOnePixelInRef ) && DoBigScroll() ) + { + long nW = aOutArea.GetWidth() / 4; + if ( Abs( nDiffX ) < nW ) + { + if ( nDiffY < 0 ) + nDiffY -= nW; + else + nDiffY += nW; + } + } + + if ( nDiffX ) + pEditEngine->pImpEditEngine->aStatus.GetStatusWord() = pEditEngine->pImpEditEngine->aStatus.GetStatusWord() | EE_STAT_HSCROLL; + if ( nDiffY ) + pEditEngine->pImpEditEngine->aStatus.GetStatusWord() = pEditEngine->pImpEditEngine->aStatus.GetStatusWord() | EE_STAT_VSCROLL; + Scroll( -nDiffX, -nDiffY ); + pEditEngine->pImpEditEngine->DelayedCallStatusHdl(); + } + } + + // Cursor evtl. etwas stutzen... + if ( ( aEditCursor.Bottom() > GetVisDocTop() ) && + ( aEditCursor.Top() < GetVisDocBottom() ) ) + { + if ( aEditCursor.Bottom() > GetVisDocBottom() ) + aEditCursor.Bottom() = GetVisDocBottom(); + if ( aEditCursor.Top() < GetVisDocTop() ) + aEditCursor.Top() = GetVisDocTop(); + } + + long nOnePixel = pOutWin->PixelToLogic( Size( 1, 0 ) ).Width(); + + if ( /* pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() || */ + ( ( aEditCursor.Top() + nOnePixel >= GetVisDocTop() ) && + ( aEditCursor.Bottom() - nOnePixel <= GetVisDocBottom() ) && + ( aEditCursor.Left() + nOnePixel >= GetVisDocLeft() ) && + ( aEditCursor.Right() - nOnePixel <= GetVisDocRight() ) ) ) + { + Rectangle aCursorRect = GetWindowPos( aEditCursor ); + GetCursor()->SetPos( aCursorRect.TopLeft() ); + Size aCursorSz( aCursorRect.GetSize() ); + // Rectangle is inclusive + aCursorSz.Width()--; + aCursorSz.Height()--; + if ( !aCursorSz.Width() || !aCursorSz.Height() ) + { + long nCursorSz = pOutWin->GetSettings().GetStyleSettings().GetCursorSize(); + nCursorSz = pOutWin->PixelToLogic( Size( nCursorSz, 0 ) ).Width(); + if ( !aCursorSz.Width() ) + aCursorSz.Width() = nCursorSz; + if ( !aCursorSz.Height() ) + aCursorSz.Height() = nCursorSz; + } + // #111036# Let VCL do orientation for cursor, otherwise problem when cursor has direction flag + if ( IsVertical() ) + { + Size aOldSz( aCursorSz ); + aCursorSz.Width() = aOldSz.Height(); + aCursorSz.Height() = aOldSz.Width(); + GetCursor()->SetPos( aCursorRect.TopRight() ); + GetCursor()->SetOrientation( 2700 ); + } + else + // --> FME 2004-10-18 #i32593# + // Reset correct orientation in horizontal layout + GetCursor()->SetOrientation( 0 ); + // <-- + + GetCursor()->SetSize( aCursorSz ); + + unsigned char nCursorDir = CURSOR_DIRECTION_NONE; + if ( IsInsertMode() && !aEditSelection.HasRange() && ( pEditEngine->pImpEditEngine->HasDifferentRTLLevels( aPaM.GetNode() ) ) ) + { + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, nShowCursorFlags & GETCRSR_PREFERPORTIONSTART ? TRUE : FALSE ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + USHORT nRTLLevel = pTextPortion->GetRightToLeft(); + if ( nRTLLevel%2 ) + nCursorDir = CURSOR_DIRECTION_RTL; + else + nCursorDir = CURSOR_DIRECTION_LTR; + + } + GetCursor()->SetDirection( nCursorDir ); + + if ( bForceVisCursor ) + GetCursor()->Show(); + + // #102936# Call SetInputContext every time, otherwise we may have the wrong font + // if ( !pEditEngine->pImpEditEngine->mpIMEInfos ) + { + SvxFont aFont; + pEditEngine->pImpEditEngine->SeekCursor( aPaM.GetNode(), aPaM.GetIndex()+1, aFont ); + ULONG nContextFlags = INPUTCONTEXT_TEXT|INPUTCONTEXT_EXTTEXTINPUT; + GetWindow()->SetInputContext( InputContext( aFont, nContextFlags ) ); + } + } + else + { + pEditEngine->pImpEditEngine->GetStatus().GetStatusWord() = pEditEngine->pImpEditEngine->GetStatus().GetStatusWord() | EE_STAT_CURSOROUT; + GetCursor()->Hide(); + GetCursor()->SetPos( Point( -1, -1 ) ); + GetCursor()->SetSize( Size( 0, 0 ) ); + } +} + +Pair ImpEditView::Scroll( long ndX, long ndY, BYTE nRangeCheck ) +{ + DBG_ASSERT( pEditEngine->pImpEditEngine->IsFormatted(), "Scroll: Nicht formatiert!" ); + if ( !ndX && !ndY ) + return Range( 0, 0 ); + +#ifdef DBG_UTIL + Rectangle aR( aOutArea ); + aR = pOutWin->LogicToPixel( aR ); + aR = pOutWin->PixelToLogic( aR ); + DBG_ASSERTWARNING( aR == aOutArea, "OutArea vor Scroll nicht aligned" ); +#endif + + Rectangle aNewVisArea( GetVisDocArea() ); + Size aPaperSz( pEditEngine->pImpEditEngine->GetPaperSize() ); + + // Vertical: + if ( !IsVertical() ) + { + aNewVisArea.Top() -= ndY; + aNewVisArea.Bottom() -= ndY; + } + else + { + aNewVisArea.Top() += ndX; + aNewVisArea.Bottom() += ndX; + } + if ( ( nRangeCheck == RGCHK_PAPERSZ1 ) && ( aNewVisArea.Bottom() > (long)pEditEngine->pImpEditEngine->GetTextHeight() ) ) + { + // GetTextHeight noch optimieren! + long nDiff = pEditEngine->pImpEditEngine->GetTextHeight() - aNewVisArea.Bottom(); // negativ + aNewVisArea.Move( 0, nDiff ); // koennte im neg. Bereich landen... + } + if ( ( aNewVisArea.Top() < 0 ) && ( nRangeCheck != RGCHK_NONE ) ) + aNewVisArea.Move( 0, -aNewVisArea.Top() ); + + // Horizontal: + if ( !IsVertical() ) + { + aNewVisArea.Left() -= ndX; + aNewVisArea.Right() -= ndX; + } + else + { + aNewVisArea.Left() -= ndY; + aNewVisArea.Right() -= ndY; + } + if ( ( nRangeCheck == RGCHK_PAPERSZ1 ) && ( aNewVisArea.Right() > (long)pEditEngine->pImpEditEngine->CalcTextWidth( FALSE ) ) ) + { + long nDiff = pEditEngine->pImpEditEngine->CalcTextWidth( FALSE ) - aNewVisArea.Right(); // negativ + aNewVisArea.Move( nDiff, 0 ); // koennte im neg. Bereich landen... + } + if ( ( aNewVisArea.Left() < 0 ) && ( nRangeCheck != RGCHK_NONE ) ) + aNewVisArea.Move( -aNewVisArea.Left(), 0 ); + + // Die Differenz muss auf Pixel alignt sein (wegen Scroll!) + long nDiffX = !IsVertical() ? ( GetVisDocLeft() - aNewVisArea.Left() ) : -( GetVisDocTop() - aNewVisArea.Top() ); + long nDiffY = !IsVertical() ? ( GetVisDocTop() - aNewVisArea.Top() ) : ( GetVisDocLeft() - aNewVisArea.Left() ); + + Size aDiffs( nDiffX, nDiffY ); + aDiffs = pOutWin->LogicToPixel( aDiffs ); + aDiffs = pOutWin->PixelToLogic( aDiffs ); + + long nRealDiffX = aDiffs.Width(); + long nRealDiffY = aDiffs.Height(); + + + if ( nRealDiffX || nRealDiffY ) + { + Cursor* pCrsr = GetCursor(); + sal_Bool bVisCursor = pCrsr->IsVisible(); + pCrsr->Hide(); + pOutWin->Update(); + if ( !IsVertical() ) + aVisDocStartPos.Move( -nRealDiffX, -nRealDiffY ); + else + aVisDocStartPos.Move( -nRealDiffY, nRealDiffX ); + // Das Move um den allignten Wert ergibt nicht unbedingt ein + // alligntes Rechteck... + // MT 11/00: Align VisArea??? + aVisDocStartPos = pOutWin->LogicToPixel( aVisDocStartPos ); + aVisDocStartPos = pOutWin->PixelToLogic( aVisDocStartPos ); + Rectangle aRec( aOutArea ); + pOutWin->Scroll( nRealDiffX, nRealDiffY, aRec, sal_True ); + pOutWin->Update(); + pCrsr->SetPos( pCrsr->GetPos() + Point( nRealDiffX, nRealDiffY ) ); + if ( bVisCursor ) + { + Rectangle aCursorRec( pCrsr->GetPos(), pCrsr->GetSize() ); + if ( aOutArea.IsInside( aCursorRec ) ) + pCrsr->Show(); + } + + if ( pEditEngine->pImpEditEngine->GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_TEXTVIEWSCROLLED ); + aNotify.pEditEngine = pEditEngine; + aNotify.pEditView = GetEditViewPtr(); + pEditEngine->pImpEditEngine->CallNotify( aNotify ); + } + } + + return Pair( nRealDiffX, nRealDiffY ); +} + +sal_Bool ImpEditView::PostKeyEvent( const KeyEvent& rKeyEvent ) +{ + BOOL bDone = FALSE; + + KeyFuncType eFunc = rKeyEvent.GetKeyCode().GetFunction(); + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_CUT: + { + if ( !bReadOnly ) + { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + CutCopy( aClipBoard, sal_True ); + bDone = sal_True; + } + } + break; + case KEYFUNC_COPY: + { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + CutCopy( aClipBoard, sal_False ); + bDone = TRUE; + } + break; + case KEYFUNC_PASTE: + { + if ( !bReadOnly && IsPasteEnabled() ) + { + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_PASTE ); + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetClipboard()); + Paste( aClipBoard, pEditEngine->pImpEditEngine->GetStatus().AllowPasteSpecial() ); + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_PASTE ); + bDone = sal_True; + } + } + break; + default: + break; + } + } + + if( !bDone ) + bDone = pEditEngine->PostKeyEvent( rKeyEvent, GetEditViewPtr() ); + + return bDone; +} + +sal_Bool ImpEditView::MouseButtonUp( const MouseEvent& rMouseEvent ) +{ + if ( pEditEngine->pImpEditEngine->aStatus.NotifyCursorMovements() ) + { + if ( pEditEngine->pImpEditEngine->aStatus.GetPrevParagraph() != pEditEngine->pImpEditEngine->GetEditDoc().GetPos( GetEditSelection().Max().GetNode() ) ) + { + pEditEngine->pImpEditEngine->aStatus.GetStatusWord() = pEditEngine->pImpEditEngine->aStatus.GetStatusWord() | EE_STAT_CRSRLEFTPARA; + pEditEngine->pImpEditEngine->CallStatusHdl(); + } + } + nTravelXPos = TRAVEL_X_DONTKNOW; + nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW; + nExtraCursorFlags = 0; + bClickedInSelection = sal_False; + + if ( rMouseEvent.IsMiddle() && !bReadOnly && + ( GetWindow()->GetSettings().GetMouseSettings().GetMiddleButtonAction() == MOUSE_MIDDLE_PASTESELECTION ) ) + { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetPrimarySelection()); + Paste( aClipBoard ); + } + else if ( rMouseEvent.IsLeft() && GetEditSelection().HasRange() ) + { + Reference<com::sun::star::datatransfer::clipboard::XClipboard> aClipBoard(GetWindow()->GetPrimarySelection()); + CutCopy( aClipBoard, FALSE ); + } + + return pEditEngine->pImpEditEngine->MouseButtonUp( rMouseEvent, GetEditViewPtr() ); +} + +sal_Bool ImpEditView::MouseButtonDown( const MouseEvent& rMouseEvent ) +{ + pEditEngine->pImpEditEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown + if ( pEditEngine->pImpEditEngine->aStatus.NotifyCursorMovements() ) + pEditEngine->pImpEditEngine->aStatus.GetPrevParagraph() = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( GetEditSelection().Max().GetNode() ); + nTravelXPos = TRAVEL_X_DONTKNOW; + nExtraCursorFlags = 0; + nCursorBidiLevel = CURSOR_BIDILEVEL_DONTKNOW; + bClickedInSelection = IsSelectionAtPoint( rMouseEvent.GetPosPixel() ); + return pEditEngine->pImpEditEngine->MouseButtonDown( rMouseEvent, GetEditViewPtr() ); +} + +sal_Bool ImpEditView::MouseMove( const MouseEvent& rMouseEvent ) +{ + return pEditEngine->pImpEditEngine->MouseMove( rMouseEvent, GetEditViewPtr() ); +} + +void ImpEditView::Command( const CommandEvent& rCEvt ) +{ + pEditEngine->pImpEditEngine->CheckIdleFormatter(); // Falls schnelles Tippen und MouseButtonDown + pEditEngine->pImpEditEngine->Command( rCEvt, GetEditViewPtr() ); +} + + +void ImpEditView::SetInsertMode( sal_Bool bInsert ) +{ + if ( bInsert != IsInsertMode() ) + { + SetFlags( nControl, EV_CNTRL_OVERWRITE, !bInsert ); + ShowCursor( DoAutoScroll(), sal_False ); + } +} + +sal_Bool ImpEditView::IsWrongSpelledWord( const EditPaM& rPaM, sal_Bool bMarkIfWrong ) +{ + sal_Bool bIsWrong = sal_False; +#ifndef SVX_LIGHT + if ( rPaM.GetNode()->GetWrongList() ) + { + EditSelection aSel = pEditEngine->pImpEditEngine->SelectWord( rPaM, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + bIsWrong = rPaM.GetNode()->GetWrongList()->HasWrong( aSel.Min().GetIndex(), aSel.Max().GetIndex() ); + if ( bIsWrong && bMarkIfWrong ) + { + DrawSelection(); // alte Selektion 'weg-zeichnen' + SetEditSelection( aSel ); + DrawSelection(); + } + } +#endif // !SVX_LIGHT + return bIsWrong; +} + +String ImpEditView::SpellIgnoreOrAddWord( sal_Bool bAdd ) +{ + String aWord; +#ifndef SVX_LIGHT + if ( pEditEngine->pImpEditEngine->GetSpeller().is() ) + { + EditPaM aPaM = GetEditSelection().Max(); + if ( !HasSelection() ) + { + EditSelection aSel = pEditEngine->pImpEditEngine->SelectWord( aPaM ); + aWord = pEditEngine->pImpEditEngine->GetSelected( aSel ); + } + else + { + aWord = pEditEngine->pImpEditEngine->GetSelected( GetEditSelection() ); + // Und deselektieren + DrawSelection(); // alte Selektion 'weg-zeichnen' + SetEditSelection( EditSelection( aPaM, aPaM ) ); + DrawSelection(); + } + + if ( aWord.Len() ) + { + if ( bAdd ) + { + DBG_ERROR( "Sorry, AddWord not implemented" ); + } + else // Ignore + { + Reference< XDictionary > xDic( SvxGetIgnoreAllList(), UNO_QUERY ); + if (xDic.is()) + xDic->add( aWord, sal_False, String() ); + } + const EditDoc& rDoc = pEditEngine->pImpEditEngine->GetEditDoc(); + sal_uInt16 nNodes = rDoc.Count(); + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = rDoc.GetObject( n ); + pNode->GetWrongList()->MarkWrongsInvalid(); + } + pEditEngine->pImpEditEngine->DoOnlineSpelling( aPaM.GetNode() ); + pEditEngine->pImpEditEngine->StartOnlineSpellTimer(); + } + } +#endif // !SVX_LIGHT + return aWord; +} + +void ImpEditView::DeleteSelected() +{ + DrawSelection(); + + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DELETE ); + + EditPaM aPaM = pEditEngine->pImpEditEngine->DeleteSelected( GetEditSelection() ); + + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_DELETE ); + + SetEditSelection( EditSelection( aPaM, aPaM ) ); + pEditEngine->pImpEditEngine->FormatAndUpdate( GetEditViewPtr() ); + ShowCursor( DoAutoScroll(), TRUE ); +} + +const SvxFieldItem* ImpEditView::GetField( const Point& rPos, sal_uInt16* pPara, sal_uInt16* pPos ) const +{ + if( !GetOutputArea().IsInside( rPos ) ) + return 0; + + Point aDocPos( GetDocPos( rPos ) ); + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos, sal_False ); + + if ( aPaM.GetIndex() == aPaM.GetNode()->Len() ) + { + // Sonst immer, wenn Feld ganz am Schluss und Mouse unter Text + return 0; + } + + const CharAttribArray& rAttrs = aPaM.GetNode()->GetCharAttribs().GetAttribs(); + sal_uInt16 nXPos = aPaM.GetIndex(); + for ( sal_uInt16 nAttr = rAttrs.Count(); nAttr; ) + { + EditCharAttrib* pAttr = rAttrs[--nAttr]; + if ( pAttr->GetStart() == nXPos ) + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + DBG_ASSERT( pAttr->GetItem()->ISA( SvxFieldItem ), "Kein FeldItem..." ); + if ( pPara ) + *pPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aPaM.GetNode() ); + if ( pPos ) + *pPos = pAttr->GetStart(); + return (const SvxFieldItem*)pAttr->GetItem(); + } + } + return NULL; +} + +BOOL ImpEditView::IsBulletArea( const Point& rPos, sal_uInt16* pPara ) +{ + if ( pPara ) + *pPara = 0xFFFF; + + if( !GetOutputArea().IsInside( rPos ) ) + return FALSE; + + Point aDocPos( GetDocPos( rPos ) ); + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos, sal_False ); + + if ( aPaM.GetIndex() == 0 ) + { + USHORT nPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + Rectangle aBulletArea = pEditEngine->GetBulletArea( nPara ); + long nY = pEditEngine->GetDocPosTopLeft( nPara ).Y(); + ParaPortion* pParaPortion = pEditEngine->pImpEditEngine->GetParaPortions().GetObject( nPara ); + nY += pParaPortion->GetFirstLineOffset(); + if ( ( aDocPos.Y() > ( nY + aBulletArea.Top() ) ) && + ( aDocPos.Y() < ( nY + aBulletArea.Bottom() ) ) && + ( aDocPos.X() > ( aBulletArea.Left() ) ) && + ( aDocPos.X() < ( aBulletArea.Right() ) ) ) + { + if ( pPara ) + *pPara = nPara; + return TRUE; + } + } + + return FALSE; +} + +void ImpEditView::CutCopy( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard, BOOL bCut ) +{ + if ( rxClipboard.is() && GetEditSelection().HasRange() ) + { + uno::Reference< datatransfer::XTransferable > xData = pEditEngine->pImpEditEngine->CreateTransferable( GetEditSelection() ); + + const sal_uInt32 nRef = Application::ReleaseSolarMutex(); + + try + { + rxClipboard->setContents( xData, NULL ); + + // #87756# FlushClipboard, but it would be better to become a TerminateListener to the Desktop and flush on demand... + uno::Reference< datatransfer::clipboard::XFlushableClipboard > xFlushableClipboard( rxClipboard, uno::UNO_QUERY ); + if( xFlushableClipboard.is() ) + xFlushableClipboard->flushClipboard(); + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + + Application::AcquireSolarMutex( nRef ); + + if ( bCut ) + { + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_CUT ); + DeleteSelected(); + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_CUT ); + + } + } +} + +void ImpEditView::Paste( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard, BOOL bUseSpecial ) +{ + if ( rxClipboard.is() ) + { + uno::Reference< datatransfer::XTransferable > xDataObj; + + const sal_uInt32 nRef = Application::ReleaseSolarMutex(); + + try + { + xDataObj = rxClipboard->getContents(); + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + + Application::AcquireSolarMutex( nRef ); + + if ( xDataObj.is() && EditEngine::HasValidData( xDataObj ) ) + { + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_PASTE ); + + EditSelection aSel( GetEditSelection() ); + if ( aSel.HasRange() ) + { + DrawSelection(); + aSel = pEditEngine->pImpEditEngine->ImpDeleteSelection( aSel ); + } + + PasteOrDropInfos aPasteOrDropInfos; + aPasteOrDropInfos.nAction = EE_ACTION_PASTE; + aPasteOrDropInfos.nStartPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() ); + pEditEngine->pImpEditEngine->aBeginPasteOrDropHdl.Call( &aPasteOrDropInfos ); + + if ( DoSingleLinePaste() ) + { + datatransfer::DataFlavor aFlavor; + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); + if ( xDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = xDataObj->getTransferData( aFlavor ); + ::rtl::OUString aTmpText; + aData >>= aTmpText; + String aText( aTmpText ); + aText.ConvertLineEnd( LINEEND_LF ); + aText.SearchAndReplaceAll( LINE_SEP, ' ' ); + aSel = pEditEngine->pImpEditEngine->ImpInsertText( aSel, aText ); + } + catch( ... ) + { + ; // #i9286# can happen, even if isDataFlavorSupported returns true... + } + } + } + else + { + aSel = pEditEngine->pImpEditEngine->InsertText( xDataObj, String(), aSel.Min(), bUseSpecial && pEditEngine->pImpEditEngine->GetStatus().AllowPasteSpecial() ); + } + + aPasteOrDropInfos.nEndPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() ); + pEditEngine->pImpEditEngine->aEndPasteOrDropHdl.Call( &aPasteOrDropInfos ); + + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_PASTE ); + SetEditSelection( aSel ); + pEditEngine->pImpEditEngine->UpdateSelections(); + pEditEngine->pImpEditEngine->FormatAndUpdate( GetEditViewPtr() ); + ShowCursor( DoAutoScroll(), TRUE ); + } + } +} + + +BOOL ImpEditView::IsInSelection( const EditPaM& rPaM ) +{ + EditSelection aSel = GetEditSelection(); + if ( !aSel.HasRange() ) + return FALSE; + + aSel.Adjust( pEditEngine->pImpEditEngine->GetEditDoc() ); + + USHORT nStartNode = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aSel.Max().GetNode() ); + USHORT nCurNode = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( rPaM.GetNode() ); + + if ( ( nCurNode > nStartNode ) && ( nCurNode < nEndNode ) ) + return TRUE; + + if ( nStartNode == nEndNode ) + { + if ( nCurNode == nStartNode ) + if ( ( rPaM.GetIndex() >= aSel.Min().GetIndex() ) && ( rPaM.GetIndex() < aSel.Max().GetIndex() ) ) + return TRUE; + } + else if ( ( nCurNode == nStartNode ) && ( rPaM.GetIndex() >= aSel.Min().GetIndex() ) ) + return TRUE; + else if ( ( nCurNode == nEndNode ) && ( rPaM.GetIndex() < aSel.Max().GetIndex() ) ) + return TRUE; + + return FALSE; +} + +void ImpEditView::CreateAnchor() +{ + pEditEngine->pImpEditEngine->bInSelection = TRUE; + GetEditSelection().Min() = GetEditSelection().Max(); +} + +void ImpEditView::DeselectAll() +{ + pEditEngine->pImpEditEngine->bInSelection = FALSE; + DrawSelection(); + GetEditSelection().Min() = GetEditSelection().Max(); +} + +BOOL ImpEditView::IsSelectionAtPoint( const Point& rPosPixel ) +{ + if ( pDragAndDropInfo && pDragAndDropInfo->pField ) + return TRUE; + + Point aMousePos( rPosPixel ); + + // Logische Einheiten... + aMousePos = GetWindow()->PixelToLogic( aMousePos ); + + if ( ( !GetOutputArea().IsInside( aMousePos ) ) && !pEditEngine->pImpEditEngine->IsInSelectionMode() ) + { + return FALSE; + } + + Point aDocPos( GetDocPos( aMousePos ) ); + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos, FALSE ); + return IsInSelection( aPaM ); +} + +BOOL ImpEditView::SetCursorAtPoint( const Point& rPointPixel ) +{ + pEditEngine->pImpEditEngine->CheckIdleFormatter(); + + Point aMousePos( rPointPixel ); + + // Logische Einheiten... + aMousePos = GetWindow()->PixelToLogic( aMousePos ); + + if ( ( !GetOutputArea().IsInside( aMousePos ) ) && !pEditEngine->pImpEditEngine->IsInSelectionMode() ) + { + return FALSE; + } + + Point aDocPos( GetDocPos( aMousePos ) ); + + // Kann optimiert werden: Erst innerhalb eines Absatzes die Zeilen + // fuer den PaM durchwuehlen, dann nochmal mit dem PaM fuer das Rect, + // obwohl die Zeile schon bekannt ist.... + // Das muss doch nicht sein ! + + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos ); + BOOL bGotoCursor = DoAutoScroll(); + + // aTmpNewSel: Diff zwischen alt und neu, nicht die neue Selektion + EditSelection aTmpNewSel( GetEditSelection().Max(), aPaM ); + + // --> OD 2005-12-16 #i27299# + // work on copy of current selection and set new selection, if it has changed. + EditSelection aNewEditSelection( GetEditSelection() ); + + aNewEditSelection.Max() = aPaM; + if ( !pEditEngine->pImpEditEngine->aSelEngine.HasAnchor() ) + { + if ( aNewEditSelection.Min() != aPaM ) + pEditEngine->pImpEditEngine->CursorMoved( aNewEditSelection.Min().GetNode() ); + aNewEditSelection.Min() = aPaM; + } + else + { + DrawSelection( aTmpNewSel ); + } + + // set changed text selection + if ( GetEditSelection() != aNewEditSelection ) + { + SetEditSelection( aNewEditSelection ); + } + // <-- + + BOOL bForceCursor = ( pDragAndDropInfo ? FALSE : TRUE ) && !pEditEngine->pImpEditEngine->IsInSelectionMode(); + ShowCursor( bGotoCursor, bForceCursor ); + return TRUE; +} + + +void ImpEditView::HideDDCursor() +{ + if ( pDragAndDropInfo && pDragAndDropInfo->bVisCursor ) + { + GetWindow()->DrawOutDev( pDragAndDropInfo->aCurSavedCursor.TopLeft(), pDragAndDropInfo->aCurSavedCursor.GetSize(), + Point(0,0), pDragAndDropInfo->aCurSavedCursor.GetSize(),*pDragAndDropInfo->pBackground ); + pDragAndDropInfo->bVisCursor = sal_False; + } +} + +void ImpEditView::ShowDDCursor( const Rectangle& rRect ) +{ + if ( !pDragAndDropInfo->bVisCursor ) + { + if ( pOutWin->GetCursor() ) + pOutWin->GetCursor()->Hide(); + + Color aOldFillColor = GetWindow()->GetFillColor(); + GetWindow()->SetFillColor( Color(4210752) ); // GRAY BRUSH_50, OLDSV, change to DDCursor! + + // Hintergrund sichern... + Rectangle aSaveRec( GetWindow()->LogicToPixel( rRect ) ); + // lieber etwas mehr sichern... + aSaveRec.Right() += 1; + aSaveRec.Bottom() += 1; + + Size aNewSzPx( aSaveRec.GetSize() ); + if ( !pDragAndDropInfo->pBackground ) + { + pDragAndDropInfo->pBackground = new VirtualDevice( *GetWindow() ); + MapMode aMapMode( GetWindow()->GetMapMode() ); + aMapMode.SetOrigin( Point( 0, 0 ) ); + pDragAndDropInfo->pBackground->SetMapMode( aMapMode ); + + } + +#ifdef DBG_UTIL + Size aCurSzPx( pDragAndDropInfo->pBackground->GetOutputSizePixel() ); + if ( ( aCurSzPx.Width() < aNewSzPx.Width() ) ||( aCurSzPx.Height() < aNewSzPx.Height() ) ) + { + sal_Bool bDone = pDragAndDropInfo->pBackground->SetOutputSizePixel( aNewSzPx ); + DBG_ASSERT( bDone, "Virtuelles Device kaputt?" ); + } +#endif + + aSaveRec = GetWindow()->PixelToLogic( aSaveRec ); + + pDragAndDropInfo->pBackground->DrawOutDev( Point(0,0), aSaveRec.GetSize(), + aSaveRec.TopLeft(), aSaveRec.GetSize(), *GetWindow() ); + pDragAndDropInfo->aCurSavedCursor = aSaveRec; + + // Cursor malen... + GetWindow()->DrawRect( rRect ); + + pDragAndDropInfo->bVisCursor = sal_True; + pDragAndDropInfo->aCurCursor = rRect; + + GetWindow()->SetFillColor( aOldFillColor ); + } +} + +void ImpEditView::dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& rDGE ) throw (::com::sun::star::uno::RuntimeException) +{ + DBG_ASSERT( !pDragAndDropInfo, "dragGestureRecognized - DragAndDropInfo exist!" ); + + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + Point aMousePosPixel( rDGE.DragOriginX, rDGE.DragOriginY ); + + EditSelection aCopySel( GetEditSelection() ); + aCopySel.Adjust( pEditEngine->pImpEditEngine->GetEditDoc() ); + + if ( GetEditSelection().HasRange() && bClickedInSelection ) + { + pDragAndDropInfo = new DragAndDropInfo(); + } + else + { + // Field?! + USHORT nPara, nPos; + Point aMousePos = GetWindow()->PixelToLogic( aMousePosPixel ); + const SvxFieldItem* pField = GetField( aMousePos, &nPara, &nPos ); + if ( pField ) + { + pDragAndDropInfo = new DragAndDropInfo(); + pDragAndDropInfo->pField = pField; + ContentNode* pNode = pEditEngine->pImpEditEngine->GetEditDoc().GetObject( nPara ); + aCopySel = EditSelection( EditPaM( pNode, nPos ), EditPaM( pNode, nPos+1 ) ); + GetEditSelection() = aCopySel; + DrawSelection(); + BOOL bGotoCursor = DoAutoScroll(); + BOOL bForceCursor = ( pDragAndDropInfo ? FALSE : TRUE ) && !pEditEngine->pImpEditEngine->IsInSelectionMode(); + ShowCursor( bGotoCursor, bForceCursor ); + } + else if ( IsBulletArea( aMousePos, &nPara ) ) + { + pDragAndDropInfo = new DragAndDropInfo(); + pDragAndDropInfo->bOutlinerMode = TRUE; + EditPaM aStartPaM( pEditEngine->pImpEditEngine->GetEditDoc().GetObject( nPara ), 0 ); + EditPaM aEndPaM( aStartPaM ); + const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL ); + for ( USHORT n = nPara +1; n < pEditEngine->pImpEditEngine->GetEditDoc().Count(); n++ ) + { + const SfxInt16Item& rL = (const SfxInt16Item&) pEditEngine->GetParaAttrib( n, EE_PARA_OUTLLEVEL ); + if ( rL.GetValue() > rLevel.GetValue() ) + { + aEndPaM.SetNode( pEditEngine->pImpEditEngine->GetEditDoc().GetObject( n ) ); + } + else + { + break; + } + } + aEndPaM.GetIndex() = aEndPaM.GetNode()->Len(); + SetEditSelection( EditSelection( aStartPaM, aEndPaM ) ); + } + } + + if ( pDragAndDropInfo ) + { + + pDragAndDropInfo->bStarterOfDD = sal_True; + + // Sensibler Bereich, wo gescrollt werden soll. + Size aSz( 5, 0 ); + aSz = GetWindow()->PixelToLogic( aSz ); + pDragAndDropInfo->nSensibleRange = (sal_uInt16) aSz.Width(); + pDragAndDropInfo->nCursorWidth = (sal_uInt16) aSz.Width() / 2; + pDragAndDropInfo->aBeginDragSel = pEditEngine->pImpEditEngine->CreateESel( aCopySel ); + + uno::Reference< datatransfer::XTransferable > xData = pEditEngine->pImpEditEngine->CreateTransferable( aCopySel ); + + sal_Int8 nActions = bReadOnly ? datatransfer::dnd::DNDConstants::ACTION_COPY : datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE; + + rDGE.DragSource->startDrag( rDGE, nActions, 0 /*cursor*/, 0 /*image*/, xData, mxDnDListener ); + // Falls Drag&Move in einer Engine, muessen Copy&Del geklammert sein! + GetCursor()->Hide(); + + } +} + +void ImpEditView::dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& rDSDE ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + DBG_ASSERT( pDragAndDropInfo, "ImpEditView::dragDropEnd: pDragAndDropInfo is NULL!" ); + + // #123688# Shouldn't happen, but seems to happen... + if ( pDragAndDropInfo ) + { + if ( !bReadOnly && rDSDE.DropSuccess && !pDragAndDropInfo->bOutlinerMode && ( rDSDE.DropAction & datatransfer::dnd::DNDConstants::ACTION_MOVE ) ) + { + if ( pDragAndDropInfo->bStarterOfDD && pDragAndDropInfo->bDroppedInMe ) + { + // DropPos: Wohin wurde gedroppt, unabhaengig von laenge. + ESelection aDropPos( pDragAndDropInfo->aDropSel.nStartPara, pDragAndDropInfo->aDropSel.nStartPos, pDragAndDropInfo->aDropSel.nStartPara, pDragAndDropInfo->aDropSel.nStartPos ); + ESelection aToBeDelSel = pDragAndDropInfo->aBeginDragSel; + ESelection aNewSel( pDragAndDropInfo->aDropSel.nEndPara, pDragAndDropInfo->aDropSel.nEndPos, + pDragAndDropInfo->aDropSel.nEndPara, pDragAndDropInfo->aDropSel.nEndPos ); + sal_Bool bBeforeSelection = aDropPos.IsLess( pDragAndDropInfo->aBeginDragSel ); + sal_uInt16 nParaDiff = pDragAndDropInfo->aBeginDragSel.nEndPara - pDragAndDropInfo->aBeginDragSel.nStartPara; + if ( bBeforeSelection ) + { + // aToBeDelSel anpassen. + DBG_ASSERT( pDragAndDropInfo->aBeginDragSel.nStartPara >= pDragAndDropInfo->aDropSel.nStartPara, "Doch nicht davor?" ); + aToBeDelSel.nStartPara = aToBeDelSel.nStartPara + nParaDiff; + aToBeDelSel.nEndPara = aToBeDelSel.nEndPara + nParaDiff; + // Zeichen korrigieren? + if ( aToBeDelSel.nStartPara == pDragAndDropInfo->aDropSel.nEndPara ) + { + sal_uInt16 nMoreChars; + if ( pDragAndDropInfo->aDropSel.nStartPara == pDragAndDropInfo->aDropSel.nEndPara ) + nMoreChars = pDragAndDropInfo->aDropSel.nEndPos - pDragAndDropInfo->aDropSel.nStartPos; + else + nMoreChars = pDragAndDropInfo->aDropSel.nEndPos; + aToBeDelSel.nStartPos = + aToBeDelSel.nStartPos + nMoreChars; + if ( aToBeDelSel.nStartPara == aToBeDelSel.nEndPara ) + aToBeDelSel.nEndPos = + aToBeDelSel.nEndPos + nMoreChars; + } + } + else + { + // aToBeDelSel ist ok, aber Selektion der View + // muss angepasst werden, wenn davor geloescht wird! + DBG_ASSERT( pDragAndDropInfo->aBeginDragSel.nStartPara <= pDragAndDropInfo->aDropSel.nStartPara, "Doch nicht davor?" ); + aNewSel.nStartPara = aNewSel.nStartPara - nParaDiff; + aNewSel.nEndPara = aNewSel.nEndPara - nParaDiff; + // Zeichen korrigieren? + if ( pDragAndDropInfo->aBeginDragSel.nEndPara == pDragAndDropInfo->aDropSel.nStartPara ) + { + sal_uInt16 nLessChars; + if ( pDragAndDropInfo->aBeginDragSel.nStartPara == pDragAndDropInfo->aBeginDragSel.nEndPara ) + nLessChars = pDragAndDropInfo->aBeginDragSel.nEndPos - pDragAndDropInfo->aBeginDragSel.nStartPos; + else + nLessChars = pDragAndDropInfo->aBeginDragSel.nEndPos; + aNewSel.nStartPos = aNewSel.nStartPos - nLessChars; + if ( aNewSel.nStartPara == aNewSel.nEndPara ) + aNewSel.nEndPos = aNewSel.nEndPos - nLessChars; + } + } + + DrawSelection(); + EditSelection aDelSel( pEditEngine->pImpEditEngine->CreateSel( aToBeDelSel ) ); + DBG_ASSERT( !aDelSel.DbgIsBuggy( pEditEngine->pImpEditEngine->aEditDoc ), "ToBeDel ist buggy!" ); + pEditEngine->pImpEditEngine->ImpDeleteSelection( aDelSel ); + if ( !bBeforeSelection ) + { + DBG_ASSERT( !pEditEngine->pImpEditEngine->CreateSel( aNewSel ).DbgIsBuggy(pEditEngine->pImpEditEngine->aEditDoc), "Bad" ); + SetEditSelection( pEditEngine->pImpEditEngine->CreateSel( aNewSel ) ); + } + pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() ); + DrawSelection(); + } + else + { + // andere EditEngine... + if ( pEditEngine->pImpEditEngine->ImplHasText() ) // #88630# SC ist removing the content when switching the task + DeleteSelected(); + } + } + + if ( pDragAndDropInfo->bUndoAction ) + pEditEngine->pImpEditEngine->UndoActionEnd( EDITUNDO_DRAGANDDROP ); + + HideDDCursor(); + ShowCursor( DoAutoScroll(), TRUE ); + delete pDragAndDropInfo; + pDragAndDropInfo = NULL; + pEditEngine->GetEndDropHdl().Call(GetEditViewPtr()); + } +} + +void ImpEditView::drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + DBG_ASSERT( pDragAndDropInfo, "Drop - No Drag&Drop info?!" ); + + if ( pDragAndDropInfo->bDragAccepted ) + { + pEditEngine->GetBeginDropHdl().Call(GetEditViewPtr()); + BOOL bChanges = FALSE; + + HideDDCursor(); + + if ( pDragAndDropInfo->bStarterOfDD ) + { + pEditEngine->pImpEditEngine->UndoActionStart( EDITUNDO_DRAGANDDROP ); + pDragAndDropInfo->bUndoAction = TRUE; + } + + if ( pDragAndDropInfo->bOutlinerMode ) + { + bChanges = TRUE; + GetEditViewPtr()->MoveParagraphs( Range( pDragAndDropInfo->aBeginDragSel.nStartPara, pDragAndDropInfo->aBeginDragSel.nEndPara ), pDragAndDropInfo->nOutlinerDropDest ); + } + else + { + uno::Reference< datatransfer::XTransferable > xDataObj = rDTDE.Transferable; + if ( xDataObj.is() ) + { + bChanges = TRUE; + // Selektion wegmalen... + DrawSelection(); + EditPaM aPaM( pDragAndDropInfo->aDropDest ); + + PasteOrDropInfos aPasteOrDropInfos; + aPasteOrDropInfos.nAction = EE_ACTION_DROP; + aPasteOrDropInfos.nStartPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aPaM.GetNode() ); + pEditEngine->pImpEditEngine->aBeginPasteOrDropHdl.Call( &aPasteOrDropInfos ); + + EditSelection aNewSel = pEditEngine->pImpEditEngine->InsertText( xDataObj, String(), aPaM, pEditEngine->pImpEditEngine->GetStatus().AllowPasteSpecial() ); + + aPasteOrDropInfos.nEndPara = pEditEngine->pImpEditEngine->GetEditDoc().GetPos( aNewSel.Max().GetNode() ); + pEditEngine->pImpEditEngine->aEndPasteOrDropHdl.Call( &aPasteOrDropInfos ); + + SetEditSelection( aNewSel ); + pEditEngine->pImpEditEngine->FormatAndUpdate( pEditEngine->pImpEditEngine->GetActiveView() ); + if ( pDragAndDropInfo->bStarterOfDD ) + { + // Nur dann setzen, wenn in gleicher Engine! + pDragAndDropInfo->aDropSel.nStartPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + pDragAndDropInfo->aDropSel.nStartPos = aPaM.GetIndex(); + pDragAndDropInfo->aDropSel.nEndPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aNewSel.Max().GetNode() ); + pDragAndDropInfo->aDropSel.nEndPos = aNewSel.Max().GetIndex(); + pDragAndDropInfo->bDroppedInMe = sal_True; + } + } + } + + if ( bChanges ) + { + rDTDE.Context->acceptDrop( rDTDE.DropAction ); + } + + if ( !pDragAndDropInfo->bStarterOfDD ) + { + delete pDragAndDropInfo; + pDragAndDropInfo = NULL; + } + + rDTDE.Context->dropComplete( bChanges ); + } +} + +void ImpEditView::dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& rDTDEE ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + if ( !pDragAndDropInfo ) + pDragAndDropInfo = new DragAndDropInfo( ); + + pDragAndDropInfo->bHasValidData = sal_False; + + // Check for supported format... + // Only check for text, will also be there if bin or rtf + datatransfer::DataFlavor aTextFlavor; + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aTextFlavor ); + const ::com::sun::star::datatransfer::DataFlavor* pFlavors = rDTDEE.SupportedDataFlavors.getConstArray(); + int nFlavors = rDTDEE.SupportedDataFlavors.getLength(); + for ( int n = 0; n < nFlavors; n++ ) + { + if( TransferableDataHelper::IsEqual( pFlavors[n], aTextFlavor ) ) + { + pDragAndDropInfo->bHasValidData = sal_True; + break; + } + } + + dragOver( rDTDEE ); +} + +void ImpEditView::dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + HideDDCursor(); + + if ( !pDragAndDropInfo->bStarterOfDD ) + { + delete pDragAndDropInfo; + pDragAndDropInfo = NULL; + } +} + +void ImpEditView::dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& rDTDE ) throw (::com::sun::star::uno::RuntimeException) +{ + vos::OGuard aVclGuard( Application::GetSolarMutex() ); + + Point aMousePos( rDTDE.LocationX, rDTDE.LocationY ); + aMousePos = GetWindow()->PixelToLogic( aMousePos ); + + sal_Bool bAccept = sal_False; + + if ( GetOutputArea().IsInside( aMousePos ) && !bReadOnly ) + { +// sal_Int8 nSupportedActions = bReadOnly ? datatransfer::dnd::DNDConstants::ACTION_COPY : datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE; + + if ( pDragAndDropInfo->bHasValidData /* && ( nSupportedActions & rDTDE.DropAction ) MT: Default = 0x80 ?! */ ) + { + bAccept = sal_True; + + sal_Bool bAllowScroll = DoAutoScroll(); + if ( bAllowScroll ) + { + long nScrollX = 0; + long nScrollY = 0; + // pruefen, ob im sensitiven Bereich + if ( ( (aMousePos.X()-pDragAndDropInfo->nSensibleRange) < GetOutputArea().Left() ) && ( ( aMousePos.X() + pDragAndDropInfo->nSensibleRange ) > GetOutputArea().Left() ) ) + nScrollX = GetOutputArea().GetWidth() / SCRLRANGE; + else if ( ( (aMousePos.X()+pDragAndDropInfo->nSensibleRange) > GetOutputArea().Right() ) && ( ( aMousePos.X() - pDragAndDropInfo->nSensibleRange ) < GetOutputArea().Right() ) ) + nScrollX = -( GetOutputArea().GetWidth() / SCRLRANGE ); + + if ( ( (aMousePos.Y()-pDragAndDropInfo->nSensibleRange) < GetOutputArea().Top() ) && ( ( aMousePos.Y() + pDragAndDropInfo->nSensibleRange ) > GetOutputArea().Top() ) ) + nScrollY = GetOutputArea().GetHeight() / SCRLRANGE; + else if ( ( (aMousePos.Y()+pDragAndDropInfo->nSensibleRange) > GetOutputArea().Bottom() ) && ( ( aMousePos.Y() - pDragAndDropInfo->nSensibleRange ) < GetOutputArea().Bottom() ) ) + nScrollY = -( GetOutputArea().GetHeight() / SCRLRANGE ); + + if ( nScrollX || nScrollY ) + { + HideDDCursor(); + Scroll( nScrollX, nScrollY, RGCHK_PAPERSZ1 ); + } + } + + Point aDocPos( GetDocPos( aMousePos ) ); + EditPaM aPaM = pEditEngine->pImpEditEngine->GetPaM( aDocPos ); + pDragAndDropInfo->aDropDest = aPaM; + if ( pDragAndDropInfo->bOutlinerMode ) + { + USHORT nPara = pEditEngine->pImpEditEngine->aEditDoc.GetPos( aPaM.GetNode() ); + ParaPortion* pPPortion = pEditEngine->pImpEditEngine->GetParaPortions().SaveGetObject( nPara ); + long nDestParaStartY = pEditEngine->pImpEditEngine->GetParaPortions().GetYOffset( pPPortion ); + long nRel = aDocPos.Y() - nDestParaStartY; + if ( nRel < ( pPPortion->GetHeight() / 2 ) ) + { + pDragAndDropInfo->nOutlinerDropDest = nPara; + } + else + { + pDragAndDropInfo->nOutlinerDropDest = nPara+1; + } + + if( ( pDragAndDropInfo->nOutlinerDropDest >= pDragAndDropInfo->aBeginDragSel.nStartPara ) && + ( pDragAndDropInfo->nOutlinerDropDest <= (pDragAndDropInfo->aBeginDragSel.nEndPara+1) ) ) + { + bAccept = FALSE; + } + } + else if ( HasSelection() ) + { + // es darf nicht in eine Selektion gedroppt werden + EPaM aP = pEditEngine->pImpEditEngine->CreateEPaM( aPaM ); + ESelection aDestSel( aP.nPara, aP.nIndex, aP.nPara, aP.nIndex); + ESelection aCurSel = pEditEngine->pImpEditEngine->CreateESel( GetEditSelection() ); + aCurSel.Adjust(); + if ( !aDestSel.IsLess( aCurSel ) && !aDestSel.IsGreater( aCurSel ) ) + { + bAccept = FALSE; + } + } + if ( bAccept ) + { + Rectangle aEditCursor; + if ( pDragAndDropInfo->bOutlinerMode ) + { + long nDDYPos; + if ( pDragAndDropInfo->nOutlinerDropDest < pEditEngine->pImpEditEngine->GetEditDoc().Count() ) + { + ParaPortion* pPPortion = pEditEngine->pImpEditEngine->GetParaPortions().SaveGetObject( pDragAndDropInfo->nOutlinerDropDest ); + nDDYPos = pEditEngine->pImpEditEngine->GetParaPortions().GetYOffset( pPPortion ); + } + else + { + nDDYPos = pEditEngine->pImpEditEngine->GetTextHeight(); + } + Point aStartPos( 0, nDDYPos ); + aStartPos = GetWindowPos( aStartPos ); + Point aEndPos( GetOutputArea().GetWidth(), nDDYPos ); + aEndPos = GetWindowPos( aEndPos ); + aEditCursor = GetWindow()->LogicToPixel( Rectangle( aStartPos, aEndPos ) ); + if ( !pEditEngine->IsVertical() ) + { + aEditCursor.Top()--; + aEditCursor.Bottom()++; + } + else + { + aEditCursor.Left()--; + aEditCursor.Right()++; + } + aEditCursor = GetWindow()->PixelToLogic( aEditCursor ); + } + else + { + aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM ); + Point aTopLeft( GetWindowPos( aEditCursor.TopLeft() ) ); + aEditCursor.SetPos( aTopLeft ); + aEditCursor.Right() = aEditCursor.Left() + pDragAndDropInfo->nCursorWidth; + aEditCursor = GetWindow()->LogicToPixel( aEditCursor ); + aEditCursor = GetWindow()->PixelToLogic( aEditCursor ); + } + + sal_Bool bCursorChanged = !pDragAndDropInfo->bVisCursor || ( pDragAndDropInfo->aCurCursor != aEditCursor ); + if ( bCursorChanged ) + { + HideDDCursor(); + ShowDDCursor(aEditCursor ); + } + pDragAndDropInfo->bDragAccepted = TRUE; + rDTDE.Context->acceptDrag( rDTDE.DropAction ); + } + } + } + + if ( !bAccept ) + { + HideDDCursor(); + pDragAndDropInfo->bDragAccepted = FALSE; + rDTDE.Context->rejectDrag(); + } +} + +void ImpEditView::AddDragAndDropListeners() +{ + Window* pWindow = GetWindow(); + if ( !bActiveDragAndDropListener && pWindow && pWindow->GetDragGestureRecognizer().is() ) + { + vcl::unohelper::DragAndDropWrapper* pDnDWrapper = new vcl::unohelper::DragAndDropWrapper( this ); + mxDnDListener = pDnDWrapper; + + uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY ); + pWindow->GetDragGestureRecognizer()->addDragGestureListener( xDGL ); + uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY ); + pWindow->GetDropTarget()->addDropTargetListener( xDTL ); + pWindow->GetDropTarget()->setActive( sal_True ); + pWindow->GetDropTarget()->setDefaultActions( datatransfer::dnd::DNDConstants::ACTION_COPY_OR_MOVE ); + + bActiveDragAndDropListener = TRUE; + } +} + +void ImpEditView::RemoveDragAndDropListeners() +{ + if ( bActiveDragAndDropListener && GetWindow() && GetWindow()->GetDragGestureRecognizer().is() ) + { + uno::Reference< datatransfer::dnd::XDragGestureListener> xDGL( mxDnDListener, uno::UNO_QUERY ); + GetWindow()->GetDragGestureRecognizer()->removeDragGestureListener( xDGL ); + uno::Reference< datatransfer::dnd::XDropTargetListener> xDTL( xDGL, uno::UNO_QUERY ); + GetWindow()->GetDropTarget()->removeDropTargetListener( xDTL ); + + if ( mxDnDListener.is() ) + { + uno::Reference< lang::XEventListener> xEL( mxDnDListener, uno::UNO_QUERY ); + xEL->disposing( lang::EventObject() ); // #95154# Empty Source means it's the Client + mxDnDListener.clear(); + } + + bActiveDragAndDropListener = FALSE; + } +} diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx new file mode 100644 index 000000000000..d77e1c21ad4f --- /dev/null +++ b/editeng/source/editeng/impedit.hxx @@ -0,0 +1,1211 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: impedit.hxx,v $ + * $Revision: 1.89.40.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _IMPEDIT_HXX +#define _IMPEDIT_HXX + +#include <editdoc.hxx> +#include <editsel.hxx> +#include <editundo.hxx> +#include <editobj2.hxx> +#include <editstt2.hxx> +#include <editeng/editdata.hxx> +#include <editeng/svxacorr.hxx> +#include <vcl/virdev.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/cursor.hxx> + +#include <vcl/dndhelp.hxx> +#include <svl/ondemand.hxx> +#include <com/sun/star/linguistic2/XSpellAlternatives.hpp> +#include <com/sun/star/linguistic2/SpellFailure.hpp> +#include <com/sun/star/linguistic2/XSpellChecker.hpp> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> +#include <com/sun/star/linguistic2/XHyphenator.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <com/sun/star/i18n/CharacterIteratorMode.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/XExtendedInputSequenceChecker.hpp> + +#include <i18npool/lang.h> +#include <vos/ref.hxx> + +DBG_NAMEEX( EditView ) +DBG_NAMEEX( EditEngine ) + +#define PIMPEE pImpEditView->pEditEngine->pImpEditEngine + +#define DEL_LEFT 1 +#define DEL_RIGHT 2 +#define TRAVEL_X_DONTKNOW 0xFFFFFFFF +#define CURSOR_BIDILEVEL_DONTKNOW 0xFFFF +#define MAXCHARSINPARA 0x3FFF-CHARPOSGROW // Max 16K, because WYSIWYG array + +#define ATTRSPECIAL_WHOLEWORD 1 +#define ATTRSPECIAL_EDGE 2 + +#define GETCRSR_TXTONLY 0x0001 +#define GETCRSR_STARTOFLINE 0x0002 +#define GETCRSR_ENDOFLINE 0x0004 +#define GETCRSR_PREFERPORTIONSTART 0x0008 + +#define LINE_SEP 0x0A + +typedef EENotify* EENotifyPtr; +SV_DECL_PTRARR_DEL( NotifyList, EENotifyPtr, 1, 1 ) // IMPL is in outliner.cxx, move to EE later and share declaration, or use BlockNotifications from EE directly + + +class EditView; +class EditEngine; +class SvxFontTable; +class SvxColorList; + +class SvxSearchItem; +class SvxLRSpaceItem; +class TextRanger; +class SvKeyValueIterator; +class SvxForbiddenCharactersTable; +class SvtCTLOptions; +#include <editeng/SpellPortions.hxx> + +#include <editeng/eedata.hxx> + +class SvUShorts; +class SvxNumberFormat; + + +namespace com { +namespace sun { +namespace star { +namespace datatransfer { +namespace clipboard { + class XClipboard; +}}}}} + +namespace svtools { + class ColorConfig; +} + +struct DragAndDropInfo +{ + Rectangle aCurCursor; + Rectangle aCurSavedCursor; + sal_uInt16 nSensibleRange; + sal_uInt16 nCursorWidth; + ESelection aBeginDragSel; + EditPaM aDropDest; + USHORT nOutlinerDropDest; + ESelection aDropSel; + VirtualDevice* pBackground; + const SvxFieldItem* pField; + sal_Bool bVisCursor : 1; + sal_Bool bDroppedInMe : 1; + sal_Bool bStarterOfDD : 1; + sal_Bool bHasValidData : 1; + sal_Bool bUndoAction : 1; + sal_Bool bOutlinerMode : 1; + sal_Bool bDragAccepted : 1; + + DragAndDropInfo() + { + pBackground = NULL; bVisCursor = sal_False; bDroppedInMe = sal_False; bStarterOfDD = sal_False; + bHasValidData = sal_False; bUndoAction = sal_False; bOutlinerMode = sal_False; + nSensibleRange = 0; nCursorWidth = 0; pField = 0; nOutlinerDropDest = 0; bDragAccepted = sal_False; + } +}; + +struct ImplIMEInfos +{ + String aOldTextAfterStartPos; + sal_uInt16* pAttribs; + EditPaM aPos; + sal_uInt16 nLen; + sal_Bool bCursor; + sal_Bool bWasCursorOverwrite; + + ImplIMEInfos( const EditPaM& rPos, const String& rOldTextAfterStartPos ); + ~ImplIMEInfos(); + + void CopyAttribs( const sal_uInt16* pA, sal_uInt16 nL ); + void DestroyAttribs(); +}; + +// #i18881# to be able to identify the postions of changed words +// the positions of each portion need to be saved +typedef std::vector<EditSelection> SpellContentSelections; + +struct SpellInfo +{ + EESpellState eState; + EPaM aSpellStart; + EPaM aSpellTo; + sal_Bool bSpellToEnd; + sal_Bool bMultipleDoc; + ::svx::SpellPortions aLastSpellPortions; + SpellContentSelections aLastSpellContentSelections; + SpellInfo() + { bSpellToEnd = sal_True; eState = EE_SPELL_OK; bMultipleDoc = sal_False; } +}; + +// used for text conversion +struct ConvInfo +{ + EPaM aConvStart; + EPaM aConvTo; + EPaM aConvContinue; // position to start search for next text portion (word) with + sal_Bool bConvToEnd; + sal_Bool bMultipleDoc; + + ConvInfo() { bConvToEnd = sal_True; bMultipleDoc = sal_False; } +}; + +struct FormatterFontMetric +{ + sal_uInt16 nMaxAscent; + sal_uInt16 nMaxDescent; + + FormatterFontMetric() { nMaxAscent = 0; nMaxDescent = 0; /* nMinLeading = 0xFFFF; */ } + sal_uInt16 GetHeight() const { return nMaxAscent+nMaxDescent; } +}; + +class IdleFormattter : public Timer +{ +private: + EditView* pView; + int nRestarts; + +public: + IdleFormattter(); + ~IdleFormattter(); + + void DoIdleFormat( EditView* pV ); + void ForceTimeout(); + void ResetRestarts() { nRestarts = 0; } + EditView* GetView() { return pView; } +}; + +// ---------------------------------------------------------------------- +// class ImpEditView +// ---------------------------------------------------------------------- +class ImpEditView : public vcl::unohelper::DragAndDropClient +{ + friend class EditView; + friend class EditEngine; + friend class ImpEditEngine; + using vcl::unohelper::DragAndDropClient::dragEnter; + using vcl::unohelper::DragAndDropClient::dragExit; + using vcl::unohelper::DragAndDropClient::dragOver; + +private: + EditView* pEditView; + Cursor* pCursor; + Color* pBackgroundColor; + EditEngine* pEditEngine; + Window* pOutWin; + Pointer* pPointer; + DragAndDropInfo* pDragAndDropInfo; + + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::dnd::XDragSourceListener > mxDnDListener; + + + long nInvMore; + ULONG nControl; + sal_uInt32 nTravelXPos; + sal_uInt16 nExtraCursorFlags; + sal_uInt16 nCursorBidiLevel; + sal_uInt16 nScrollDiffX; + sal_Bool bReadOnly; + sal_Bool bClickedInSelection; + sal_Bool bActiveDragAndDropListener; + + Point aAnchorPoint; + Rectangle aOutArea; + Point aVisDocStartPos; + EESelectionMode eSelectionMode; + EditSelection aEditSelection; + EVAnchorMode eAnchorMode; + +protected: + + // DragAndDropClient + void dragGestureRecognized( const ::com::sun::star::datatransfer::dnd::DragGestureEvent& dge ) throw (::com::sun::star::uno::RuntimeException); + void dragDropEnd( const ::com::sun::star::datatransfer::dnd::DragSourceDropEvent& dsde ) throw (::com::sun::star::uno::RuntimeException); + void drop( const ::com::sun::star::datatransfer::dnd::DropTargetDropEvent& dtde ) throw (::com::sun::star::uno::RuntimeException); + void dragEnter( const ::com::sun::star::datatransfer::dnd::DropTargetDragEnterEvent& dtdee ) throw (::com::sun::star::uno::RuntimeException); + void dragExit( const ::com::sun::star::datatransfer::dnd::DropTargetEvent& dte ) throw (::com::sun::star::uno::RuntimeException); + void dragOver( const ::com::sun::star::datatransfer::dnd::DropTargetDragEvent& dtde ) throw (::com::sun::star::uno::RuntimeException); + + void ShowDDCursor( const Rectangle& rRect ); + void HideDDCursor(); + + void ImplDrawHighlightRect( Window* pOutWin, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, PolyPolygon* pPolyPoly ); + +public: + ImpEditView( EditView* pView, EditEngine* pEng, Window* pWindow ); + ~ImpEditView(); + + EditView* GetEditViewPtr() { return pEditView; } + + sal_uInt16 GetScrollDiffX() const { return nScrollDiffX; } + void SetScrollDiffX( sal_uInt16 n ) { nScrollDiffX = n; } + + sal_uInt16 GetCursorBidiLevel() const { return nCursorBidiLevel; } + void SetCursorBidiLevel( sal_uInt16 n ) { nCursorBidiLevel = n; } + + Point GetDocPos( const Point& rWindowPos ) const; + Point GetWindowPos( const Point& rDocPos ) const; + Rectangle GetWindowPos( const Rectangle& rDocPos ) const; + + void SetOutputArea( const Rectangle& rRec ); + void ResetOutputArea( const Rectangle& rRec ); + const Rectangle& GetOutputArea() const { return aOutArea; } + + BOOL IsVertical() const; + + BOOL PostKeyEvent( const KeyEvent& rKeyEvent ); + + BOOL MouseButtonUp( const MouseEvent& rMouseEvent ); + BOOL MouseButtonDown( const MouseEvent& rMouseEvent ); + BOOL MouseMove( const MouseEvent& rMouseEvent ); + void Command( const CommandEvent& rCEvt ); + + void CutCopy( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard, sal_Bool bCut ); + void Paste( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::clipboard::XClipboard >& rxClipboard, sal_Bool bUseSpecial = sal_False ); + + void SetVisDocStartPos( const Point& rPos ) { aVisDocStartPos = rPos; } + const Point& GetVisDocStartPos() const { return aVisDocStartPos; } + + long GetVisDocLeft() const { return aVisDocStartPos.X(); } + long GetVisDocTop() const { return aVisDocStartPos.Y(); } + long GetVisDocRight() const { return aVisDocStartPos.X() + ( !IsVertical() ? aOutArea.GetWidth() : aOutArea.GetHeight() ); } + long GetVisDocBottom() const { return aVisDocStartPos.Y() + ( !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth() ); } + Rectangle GetVisDocArea() const; + + EditSelection& GetEditSelection() { return aEditSelection; } + void SetEditSelection( const EditSelection& rEditSelection ); + sal_Bool HasSelection() const { return aEditSelection.HasRange(); } + + void DrawSelection() { DrawSelection( aEditSelection ); } + void DrawSelection( EditSelection, Region* pRegion = NULL ); + Region* CalcSelectedRegion(); + + Window* GetWindow() const { return pOutWin; } + + EESelectionMode GetSelectionMode() const { return eSelectionMode; } + void SetSelectionMode( EESelectionMode eMode ); + + inline void SetPointer( const Pointer& rPointer ); + inline const Pointer& GetPointer(); + + inline void SetCursor( const Cursor& rCursor ); + inline Cursor* GetCursor(); + + void AddDragAndDropListeners(); + void RemoveDragAndDropListeners(); + + BOOL IsBulletArea( const Point& rPos, sal_uInt16* pPara ); + +// Fuer die SelectionEngine... + void CreateAnchor(); + void DeselectAll(); + sal_Bool SetCursorAtPoint( const Point& rPointPixel ); + sal_Bool IsSelectionAtPoint( const Point& rPosPixel ); + sal_Bool IsInSelection( const EditPaM& rPaM ); + + + void SetAnchorMode( EVAnchorMode eMode ); + EVAnchorMode GetAnchorMode() const { return eAnchorMode; } + void CalcAnchorPoint(); + void RecalcOutputArea(); + + void ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, BOOL test ); + void ShowCursor( sal_Bool bGotoCursor, sal_Bool bForceVisCursor, USHORT nShowCursorFlags = 0 ); + Pair Scroll( long ndX, long ndY, BYTE nRangeCheck = RGCHK_NEG ); + + void SetInsertMode( sal_Bool bInsert ); + sal_Bool IsInsertMode() const { return ( ( nControl & EV_CNTRL_OVERWRITE ) == 0 ); } + + void EnablePaste( sal_Bool bEnable ) { SetFlags( nControl, EV_CNTRL_ENABLEPASTE, bEnable ); } + sal_Bool IsPasteEnabled() const { return ( ( nControl & EV_CNTRL_ENABLEPASTE ) != 0 ); } + + sal_Bool DoSingleLinePaste() const { return ( ( nControl & EV_CNTRL_SINGLELINEPASTE ) != 0 ); } + sal_Bool DoAutoScroll() const { return ( ( nControl & EV_CNTRL_AUTOSCROLL ) != 0 ); } + sal_Bool DoBigScroll() const { return ( ( nControl & EV_CNTRL_BIGSCROLL ) != 0 ); } + sal_Bool DoAutoSize() const { return ( ( nControl & EV_CNTRL_AUTOSIZE ) != 0 ); } + sal_Bool DoAutoWidth() const { return ( ( nControl & EV_CNTRL_AUTOSIZEX) != 0 ); } + sal_Bool DoAutoHeight() const { return ( ( nControl & EV_CNTRL_AUTOSIZEY) != 0 ); } + sal_Bool DoInvalidateMore() const { return ( ( nControl & EV_CNTRL_INVONEMORE ) != 0 ); } + + void SetBackgroundColor( const Color& rColor ); + const Color& GetBackgroundColor() const { + return ( pBackgroundColor ? *pBackgroundColor : pOutWin->GetBackground().GetColor() ); } + + sal_Bool IsWrongSpelledWord( const EditPaM& rPaM, sal_Bool bMarkIfWrong ); + String SpellIgnoreOrAddWord( sal_Bool bAdd ); + + const SvxFieldItem* GetField( const Point& rPos, sal_uInt16* pPara, sal_uInt16* pPos ) const; + void DeleteSelected(); + + // Ggf. mehr als OutputArea invalidieren, fuer den DrawingEngine-Textrahmen... + void SetInvalidateMore( sal_uInt16 nPixel ) { nInvMore = nPixel; } + sal_uInt16 GetInvalidateMore() const { return (sal_uInt16)nInvMore; } +}; + +// ---------------------------------------------------------------------- +// ImpEditEngine +// ---------------------------------------------------------------------- + +typedef EditView* EditViewPtr; +SV_DECL_PTRARR( EditViews, EditViewPtr, 0, 1 ) + +class ImpEditEngine : public SfxListener +{ + // Die Undos muessen direkt manipulieren ( private-Methoden ), + // damit keine neues Undos eingefuegt werden! + friend class EditUndoInsertChars; + friend class EditUndoRemoveChars; + friend class EditUndoDelContent; + friend class EditUndoConnectParas; + friend class EditUndoSplitPara; + friend class EditUndoInsertFeature; + friend class EditUndoMoveParagraphs; + + friend class EditView; + friend class ImpEditView; + friend class EditEngine; // Fuer Zugriff auf Imp-Methoden + friend class EditRTFParser; // Fuer Zugriff auf Imp-Methoden + friend class EditHTMLParser; // Fuer Zugriff auf Imp-Methoden + friend class EdtAutoCorrDoc; // Fuer Zugriff auf Imp-Methoden + friend class EditDbg; // DebugRoutinen + +private: + + // ================================================================ + // Daten... + // ================================================================ + + // Dokument-Spezifische Daten... + ParaPortionList aParaPortionList; // Formatierung + Size aPaperSize; // Layout + Size aMinAutoPaperSize; // Layout ? + Size aMaxAutoPaperSize; // Layout ? + EditDoc aEditDoc; // Dokumenteninhalt + + // Engine-Spezifische Daten.... + EditEngine* pEditEngine; + EditViews aEditViews; + EditView* pActiveView; + TextRanger* pTextRanger; + + SfxStyleSheetPool* pStylePool; + SfxItemPool* pTextObjectPool; + + VirtualDevice* pVirtDev; + OutputDevice* pRefDev; + + svtools::ColorConfig* pColorConfig; + mutable SvtCTLOptions* pCTLOptions; + + SfxItemSet* pEmptyItemSet; + EditUndoManager* pUndoManager; + ESelection* pUndoMarkSelection; + + ImplIMEInfos* mpIMEInfos; + + NotifyList aNotifyCache; + + XubString aWordDelimiters; + XubString aGroupChars; + + EditSelFunctionSet aSelFuncSet; + EditSelectionEngine aSelEngine; + + Color maBackgroundColor; + + sal_uInt32 nBlockNotifications; + sal_uInt16 nStretchX; + sal_uInt16 nStretchY; + + USHORT nAsianCompressionMode; + BOOL bKernAsianPunctuation; + BOOL bAddExtLeading; + + EEHorizontalTextDirection eDefaultHorizontalTextDirection; + + sal_uInt16 nBigTextObjectStart; + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellChecker1 > xSpeller; + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenator > xHyphenator; + SpellInfo* pSpellInfo; + mutable ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > xBI; + mutable ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XExtendedInputSequenceChecker > xISC; + + ConvInfo * pConvInfo; + + XubString aAutoCompleteText; + + InternalEditStatus aStatus; + + LanguageType eDefLanguage; + + OnDemandLocaleDataWrapper xLocaleDataWrapper; + OnDemandTransliterationWrapper xTransliterationWrapper; + + sal_Bool bIsFormatting; + sal_Bool bFormatted; + sal_Bool bInSelection; + sal_Bool bIsInUndo; + sal_Bool bUpdate; + sal_Bool bUndoEnabled; + sal_Bool bOwnerOfRefDev; + sal_Bool bDowning; + sal_Bool bUseAutoColor; + sal_Bool bForceAutoColor; + sal_Bool bCallParaInsertedOrDeleted; + sal_Bool bImpConvertFirstCall; // specifies if ImpConvert is called the very first time after Convert was called + sal_Bool bFirstWordCapitalization; // specifies if auto-correction should capitalize the first word or not + + // Fuer Formatierung / Update.... + DeletedNodesList aDeletedNodes; + Rectangle aInvalidRec; + sal_uInt32 nCurTextHeight; + sal_uInt16 nOnePixelInRef; + + IdleFormattter aIdleFormatter; + + Timer aOnlineSpellTimer; + + // Wenn an einer Stelle erkannt wird, dass der StatusHdl gerufen werden + // muss, dies aber nicht sofort geschehen darf (kritischer Abschnitt): + Timer aStatusTimer; + Link aStatusHdlLink; + Link aNotifyHdl; + Link aImportHdl; + Link aBeginMovingParagraphsHdl; + Link aEndMovingParagraphsHdl; + Link aBeginPasteOrDropHdl; + Link aEndPasteOrDropHdl; + Link aModifyHdl; + Link maBeginDropHdl; + Link maEndDropHdl; + + vos::ORef<SvxForbiddenCharactersTable> xForbiddenCharsTable; + + + // ================================================================ + // Methoden... + // ================================================================ + + void CursorMoved( ContentNode* pPrevNode ); + void ParaAttribsChanged( ContentNode* pNode ); + void TextModified(); + void CalcHeight( ParaPortion* pPortion ); + + // ggf. lieber inline, aber so einiges... + void InsertUndo( EditUndo* pUndo, sal_Bool bTryMerge = sal_False ); + void ResetUndoManager(); + sal_Bool HasUndoManager() const { return pUndoManager ? sal_True : sal_False; } + + EditUndoSetAttribs* CreateAttribUndo( EditSelection aSel, const SfxItemSet& rSet ); + + EditPaM GetPaM( Point aDocPos, sal_Bool bSmart = sal_True ); + EditPaM GetPaM( ParaPortion* pPortion, Point aPos, sal_Bool bSmart = sal_True ); + long GetXPos( ParaPortion* pParaPortion, EditLine* pLine, USHORT nIndex, BOOL bPreferPortionStart = FALSE ); + long GetPortionXOffset( ParaPortion* pParaPortion, EditLine* pLine, USHORT nTextPortion ); + USHORT GetChar( ParaPortion* pParaPortion, EditLine* pLine, long nX, BOOL bSmart = TRUE ); + Range GetInvalidYOffsets( ParaPortion* pPortion ); + Range GetLineXPosStartEnd( ParaPortion* pParaPortion, EditLine* pLine ); + + void SetParaAttrib( BYTE nFunc, EditSelection aSel, sal_uInt16 nValue ); + sal_uInt16 GetParaAttrib( BYTE nFunc, EditSelection aSel ); + void SetCharAttrib( EditSelection aSel, const SfxPoolItem& rItem ); + void ParaAttribsToCharAttribs( ContentNode* pNode ); + void GetCharAttribs( sal_uInt16 nPara, EECharAttribArray& rLst ) const; + + EditTextObject* CreateBinTextObject( EditSelection aSelection, SfxItemPool*, sal_Bool bAllowBigObjects = sal_False, sal_uInt16 nBigObjStart = 0 ) const; + void StoreBinTextObject( SvStream& rOStream, BinTextObject& rTextObject ); + EditSelection InsertBinTextObject( BinTextObject&, EditPaM aPaM ); + EditSelection InsertText( ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& rxDataObj, const String& rBaseURL, const EditPaM& rPaM, BOOL bUseSpecial ); + + EditPaM Clear(); + EditPaM RemoveText(); + EditPaM RemoveText( EditSelection aEditSelection ); + sal_Bool CreateLines( USHORT nPara, sal_uInt32 nStartPosY ); + void CreateAndInsertEmptyLine( ParaPortion* pParaPortion, sal_uInt32 nStartPosY ); + sal_Bool FinishCreateLines( ParaPortion* pParaPortion ); + void CalcCharPositions( ParaPortion* pParaPortion ); + void CreateTextPortions( ParaPortion* pParaPortion, sal_uInt16& rStartPos /*, sal_Bool bCreateBlockPortions */ ); + void RecalcTextPortion( ParaPortion* pParaPortion, sal_uInt16 nStartPos, short nNewChars ); + sal_uInt16 SplitTextPortion( ParaPortion* pParaPortion, sal_uInt16 nPos, EditLine* pCurLine = 0 ); + void SeekCursor( ContentNode* pNode, sal_uInt16 nPos, SvxFont& rFont, OutputDevice* pOut = NULL, sal_uInt16 nIgnoreWhich = 0 ); + void RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics, SvxFont& rFont ); + void CheckAutoPageSize(); + + void ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, TextPortion* pPortion, sal_uInt16 nPortionStart, long nRemainingWidth, sal_Bool bCanHyphenate ); + void ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, long nRemainingSpace ); + EditPaM ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pRight, sal_Bool bBackward = sal_False ); + EditPaM ImpDeleteSelection( EditSelection aEditSelection); + EditPaM ImpInsertParaBreak( const EditPaM& rPaM, sal_Bool bKeepEndingAttribs = sal_True ); + EditPaM ImpInsertParaBreak( const EditSelection& rEditSelection, sal_Bool bKeepEndingAttribs = sal_True ); + EditPaM ImpInsertText( EditSelection aCurEditSelection, const String& rStr ); + EditPaM ImpInsertFeature( EditSelection aEditSelection, const SfxPoolItem& rItem ); + void ImpRemoveChars( const EditPaM& rPaM, sal_uInt16 nChars, EditUndoRemoveChars* pCurUndo = 0 ); + void ImpRemoveParagraph( sal_uInt16 nPara ); + EditSelection ImpMoveParagraphs( Range aParagraphs, sal_uInt16 nNewPos ); + + EditPaM ImpFastInsertText( EditPaM aPaM, const String& rStr ); + EditPaM ImpFastInsertParagraph( sal_uInt16 nPara ); + + sal_Bool ImpCheckRefMapMode(); + + BOOL ImplHasText() const; + + void ImpFindKashidas( ContentNode* pNode, USHORT nStart, USHORT nEnd, SvUShorts& rArray ); + + void InsertContent( ContentNode* pNode, sal_uInt16 nPos ); + EditPaM SplitContent( sal_uInt16 nNode, sal_uInt16 nSepPos ); + EditPaM ConnectContents( sal_uInt16 nLeftNode, sal_Bool bBackward ); + + void ShowParagraph( sal_uInt16 nParagraph, sal_Bool bShow ); + sal_Bool IsParagraphVisible( sal_uInt16 nParagraph ); + + EditPaM PageUp( const EditPaM& rPaM, EditView* pView); + EditPaM PageDown( const EditPaM& rPaM, EditView* pView); + EditPaM CursorUp( const EditPaM& rPaM, EditView* pEditView ); + EditPaM CursorDown( const EditPaM& rPaM, EditView* pEditView ); + EditPaM CursorLeft( const EditPaM& rPaM, USHORT nCharacterIteratorMode = ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL ); + EditPaM CursorRight( const EditPaM& rPaM, USHORT nCharacterIteratorMode = ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL ); + EditPaM CursorStartOfLine( const EditPaM& rPaM ); + EditPaM CursorEndOfLine( const EditPaM& rPaM ); + EditPaM CursorStartOfParagraph( const EditPaM& rPaM ); + EditPaM CursorEndOfParagraph( const EditPaM& rPaM ); + EditPaM CursorStartOfDoc(); + EditPaM CursorEndOfDoc(); + EditPaM WordLeft( const EditPaM& rPaM, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + EditPaM WordRight( const EditPaM& rPaM, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + EditPaM StartOfWord( const EditPaM& rPaM, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + EditPaM EndOfWord( const EditPaM& rPaM, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES ); + EditSelection SelectWord( const EditSelection& rCurSelection, sal_Int16 nWordType = ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, BOOL bAcceptStartOfWord = TRUE ); + EditSelection SelectSentence( const EditSelection& rCurSel ); + EditPaM CursorVisualLeftRight( EditView* pEditView, const EditPaM& rPaM, USHORT nCharacterIteratorMode, BOOL bToLeft ); + EditPaM CursorVisualStartEnd( EditView* pEditView, const EditPaM& rPaM, BOOL bStart ); + + + void InitScriptTypes( USHORT nPara ); + USHORT GetScriptType( const EditPaM& rPaM, USHORT* pEndPos = NULL ) const; + USHORT GetScriptType( const EditSelection& rSel ) const; + BOOL IsScriptChange( const EditPaM& rPaM ) const; + BOOL HasScriptType( USHORT nPara, USHORT nType ) const; + + BOOL ImplCalcAsianCompression( ContentNode* pNode, TextPortion* pTextPortion, USHORT nStartPos, sal_Int32* pDXArray, USHORT n100thPercentFromMax, BOOL bManipulateDXArray ); + void ImplExpandCompressedPortions( EditLine* pLine, ParaPortion* pParaPortion, long nRemainingWidth ); + + void ImplInitLayoutMode( OutputDevice* pOutDev, USHORT nPara, USHORT nIndex ); + void ImplInitDigitMode( OutputDevice* pOutDev, String* pString, xub_StrLen nStt, xub_StrLen nLen, LanguageType eLang ); + + EditPaM ReadText( SvStream& rInput, EditSelection aSel ); + EditPaM ReadRTF( SvStream& rInput, EditSelection aSel ); + EditPaM ReadXML( SvStream& rInput, EditSelection aSel ); + EditPaM ReadHTML( SvStream& rInput, const String& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ); + EditPaM ReadBin( SvStream& rInput, EditSelection aSel ); + sal_uInt32 WriteText( SvStream& rOutput, EditSelection aSel ); + sal_uInt32 WriteRTF( SvStream& rOutput, EditSelection aSel ); + sal_uInt32 WriteXML( SvStream& rOutput, EditSelection aSel ); + sal_uInt32 WriteHTML( SvStream& rOutput, EditSelection aSel ); + sal_uInt32 WriteBin( SvStream& rOutput, EditSelection aSel, BOOL bStoreUnicode = FALSE ) const; + + void WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ); + sal_Bool WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ); + long LogicToTwips( long n ); + + inline short GetXValue( short nXValue ) const; + inline sal_uInt16 GetXValue( sal_uInt16 nXValue ) const; + inline long GetXValue( long nXValue ) const; + + inline short GetYValue( short nYValue ) const; + inline sal_uInt16 GetYValue( sal_uInt16 nYValue ) const; + + ContentNode* GetPrevVisNode( ContentNode* pCurNode ); + ContentNode* GetNextVisNode( ContentNode* pCurNode ); + + ParaPortion* GetPrevVisPortion( ParaPortion* pCurPortion ); + ParaPortion* GetNextVisPortion( ParaPortion* pCurPortion ); + + void SetBackgroundColor( const Color& rColor ) { maBackgroundColor = rColor; } + Color GetBackgroundColor() const { return maBackgroundColor; } + + Color GetAutoColor() const; + void EnableAutoColor( BOOL b ) { bUseAutoColor = b; } + BOOL IsAutoColorEnabled() const { return bUseAutoColor; } + void ForceAutoColor( BOOL b ) { bForceAutoColor = b; } + BOOL IsForceAutoColor() const { return bForceAutoColor; } + + inline VirtualDevice* GetVirtualDevice( const MapMode& rMapMode, ULONG nDrawMode ); + inline void EraseVirtualDevice(); + + DECL_LINK( StatusTimerHdl, Timer * ); + DECL_LINK( IdleFormatHdl, Timer * ); + DECL_LINK( OnlineSpellHdl, Timer * ); + DECL_LINK( DocModified, void* ); + + void CheckIdleFormatter(); + + inline ParaPortion* FindParaPortion( ContentNode* pNode ) const; + + ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable > CreateTransferable( const EditSelection& rSelection ) const; + + void SetValidPaperSize( const Size& rSz ); + + ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XBreakIterator > ImplGetBreakIterator() const; + ::com::sun::star::uno::Reference < ::com::sun::star::i18n::XExtendedInputSequenceChecker > ImplGetInputSequenceChecker() const; + + /** Decorate metafile output with verbose text comments + + This method is used to wrap SvxFont::QuickDrawText, to + determine character-by-character wise, which logical text + units like characters, words and sentences are contained in + the output string at hand. This is necessary for slideshow + text effects. + */ + void ImplFillTextMarkingVector(const ::com::sun::star::lang::Locale& rLocale, EEngineData::TextMarkingVector& rTextMarkingVector, const String& rTxt, const USHORT nIdx, const USHORT nLen) const; + +protected: + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + +public: + ImpEditEngine( EditEngine* pEditEngine, SfxItemPool* pPool ); + ~ImpEditEngine(); + + void InitDoc( BOOL bKeepParaAttribs ); + EditDoc& GetEditDoc() { return aEditDoc; } + const EditDoc& GetEditDoc() const { return aEditDoc; } + + inline EditUndoManager& GetUndoManager(); + + void SetUpdateMode( sal_Bool bUp, EditView* pCurView = 0, sal_Bool bForceUpdate = sal_False ); + sal_Bool GetUpdateMode() const { return bUpdate; } + + const ParaPortionList& GetParaPortions() const { return aParaPortionList; } + ParaPortionList& GetParaPortions() { return aParaPortionList; } + EditViews& GetEditViews() { return aEditViews; } + + const Size& GetPaperSize() const { return aPaperSize; } + void SetPaperSize( const Size& rSz ) { aPaperSize = rSz; } + + void SetVertical( BOOL bVertical ); + BOOL IsVertical() const { return GetEditDoc().IsVertical(); } + + void SetFixedCellHeight( BOOL bUseFixedCellHeight ); + BOOL IsFixedCellHeight() const { return GetEditDoc().IsFixedCellHeight(); } + + void SetDefaultHorizontalTextDirection( EEHorizontalTextDirection eHTextDir ) { eDefaultHorizontalTextDirection = eHTextDir; } + EEHorizontalTextDirection GetDefaultHorizontalTextDirection() const { return eDefaultHorizontalTextDirection; } + + + void InitWritingDirections( USHORT nPara ); + BOOL IsRightToLeft( USHORT nPara ) const; + BYTE GetRightToLeft( USHORT nPara, USHORT nChar, USHORT* pStart = NULL, USHORT* pEnd = NULL ); + BOOL HasDifferentRTLLevels( const ContentNode* pNode ); + + void SetTextRanger( TextRanger* pRanger ); + TextRanger* GetTextRanger() const { return pTextRanger; } + + const Size& GetMinAutoPaperSize() const { return aMinAutoPaperSize; } + void SetMinAutoPaperSize( const Size& rSz ) { aMinAutoPaperSize = rSz; } + + const Size& GetMaxAutoPaperSize() const { return aMaxAutoPaperSize; } + void SetMaxAutoPaperSize( const Size& rSz ) { aMaxAutoPaperSize = rSz; } + + void FormatDoc(); + void FormatFullDoc(); + void UpdateViews( EditView* pCurView = 0 ); + void Paint( ImpEditView* pView, const Rectangle& rRect, sal_Bool bUseVirtDev = sal_False ); + void Paint( OutputDevice* pOutDev, Rectangle aClipRec, Point aStartPos, sal_Bool bStripOnly = sal_False, short nOrientation = 0 ); + + sal_Bool MouseButtonUp( const MouseEvent& rMouseEvent, EditView* pView ); + sal_Bool MouseButtonDown( const MouseEvent& rMouseEvent, EditView* pView ); + sal_Bool MouseMove( const MouseEvent& rMouseEvent, EditView* pView ); + void Command( const CommandEvent& rCEvt, EditView* pView ); + + EditSelectionEngine& GetSelEngine() { return aSelEngine; } + XubString GetSelected( const EditSelection& rSel, const LineEnd eParaSep = LINEEND_LF ) const; + + const SfxItemSet& GetEmptyItemSet(); + + void UpdateSelections(); + + void EnableUndo( sal_Bool bEnable ); + sal_Bool IsUndoEnabled() { return bUndoEnabled; } + void SetUndoMode( sal_Bool b ) { bIsInUndo = b; } + sal_Bool IsInUndo() { return bIsInUndo; } + + void SetCallParaInsertedOrDeleted( sal_Bool b ) { bCallParaInsertedOrDeleted = b; } + sal_Bool IsCallParaInsertedOrDeleted() const { return bCallParaInsertedOrDeleted; } + + sal_Bool IsFormatted() const { return bFormatted; } + sal_Bool IsFormatting() const { return bIsFormatting; } + + void SetText( const String& rText ); + EditPaM DeleteSelected( EditSelection aEditSelection); + EditPaM InsertText( const EditSelection& rCurEditSelection, sal_Unicode c, sal_Bool bOverwrite, sal_Bool bIsUserInput = sal_False ); + EditPaM InsertText( EditSelection aCurEditSelection, const String& rStr ); + EditPaM AutoCorrect( const EditSelection& rCurEditSelection, sal_Unicode c, sal_Bool bOverwrite ); + EditPaM DeleteLeftOrRight( const EditSelection& rEditSelection, BYTE nMode, BYTE nDelMode = DELMODE_SIMPLE ); + EditPaM InsertParaBreak( EditSelection aEditSelection ); + EditPaM InsertLineBreak( EditSelection aEditSelection ); + EditPaM InsertTab( EditSelection aEditSelection ); + EditPaM InsertField( EditSelection aEditSelection, const SvxFieldItem& rFld ); + sal_Bool UpdateFields(); + + EditPaM Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs = NULL ); + void Write( SvStream& rOutput, EETextFormat eFormat, EditSelection aSel ); + + EditTextObject* CreateTextObject(); + EditTextObject* CreateTextObject( EditSelection aSel ); + void SetText( const EditTextObject& rTextObject ); + EditSelection InsertText( const EditTextObject& rTextObject, EditSelection aSel ); + + EditSelection MoveCursor( const KeyEvent& rKeyEvent, EditView* pEditView ); + + EditSelection MoveParagraphs( Range aParagraphs, sal_uInt16 nNewPos, EditView* pCurView ); + + sal_uInt32 CalcTextHeight(); + sal_uInt32 GetTextHeight() const; + sal_uInt32 CalcTextWidth( BOOL bIgnoreExtraSpace ); + sal_uInt32 CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, BOOL bIgnoreExtraSpace ); + sal_uInt16 GetLineCount( sal_uInt16 nParagraph ) const; + sal_uInt16 GetLineLen( sal_uInt16 nParagraph, sal_uInt16 nLine ) const; + void GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nParagraph, USHORT nLine ) const; + USHORT GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const; + sal_uInt16 GetLineHeight( sal_uInt16 nParagraph, sal_uInt16 nLine ); + sal_uInt32 GetParaHeight( sal_uInt16 nParagraph ); + + SfxItemSet GetAttribs( USHORT nPara, USHORT nStart, USHORT nEnd, sal_uInt8 nFlags = 0xFF ) const; + SfxItemSet GetAttribs( EditSelection aSel, BOOL bOnlyHardAttrib = FALSE ); + void SetAttribs( EditSelection aSel, const SfxItemSet& rSet, BYTE nSpecial = 0 ); + void RemoveCharAttribs( EditSelection aSel, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich = 0 ); + void RemoveCharAttribs( sal_uInt16 nPara, sal_uInt16 nWhich = 0, sal_Bool bRemoveFeatures = sal_False ); + void SetFlatMode( sal_Bool bFlat ); + + void SetParaAttribs( sal_uInt16 nPara, const SfxItemSet& rSet ); + const SfxItemSet& GetParaAttribs( sal_uInt16 nPara ) const; + + sal_Bool HasParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) const; + const SfxPoolItem& GetParaAttrib( sal_uInt16 nPara, sal_uInt16 nWhich ) const; + + Rectangle PaMtoEditCursor( EditPaM aPaM, sal_uInt16 nFlags = 0 ); + Rectangle GetEditCursor( ParaPortion* pPortion, sal_uInt16 nIndex, sal_uInt16 nFlags = 0 ); + + sal_Bool IsModified() const { return aEditDoc.IsModified(); } + void SetModifyFlag( sal_Bool b ) { aEditDoc.SetModified( b ); } + void SetModifyHdl( const Link& rLink ) { aModifyHdl = rLink; } + Link GetModifyHdl() const { return aModifyHdl; } + + + sal_Bool IsInSelectionMode() { return bInSelection; } + void StopSelectionMode(); + + void IndentBlock( EditView* pView, sal_Bool bRight ); + +// Fuer Undo/Redo + sal_Bool Undo( EditView* pView ); + sal_Bool Redo( EditView* pView ); + sal_Bool Repeat( EditView* pView ); + +// OV-Special + void InvalidateFromParagraph( sal_uInt16 nFirstInvPara ); + EditPaM InsertParagraph( sal_uInt16 nPara ); + EditSelection* SelectParagraph( sal_uInt16 nPara ); + + void SetStatusEventHdl( const Link& rLink ) { aStatusHdlLink = rLink; } + Link GetStatusEventHdl() const { return aStatusHdlLink; } + + void SetNotifyHdl( const Link& rLink ) { aNotifyHdl = rLink; } + Link GetNotifyHdl() const { return aNotifyHdl; } + + void FormatAndUpdate( EditView* pCurView = 0 ); + inline void IdleFormatAndUpdate( EditView* pCurView = 0 ); + + svtools::ColorConfig& GetColorConfig(); + BOOL IsVisualCursorTravelingEnabled(); + BOOL DoVisualCursorTraveling( const ContentNode* pNode ); + + EditSelection ConvertSelection( sal_uInt16 nStartPara, sal_uInt16 nStartPos, sal_uInt16 nEndPara, sal_uInt16 nEndPos ) const; + inline EPaM CreateEPaM( const EditPaM& rPaM ); + inline EditPaM CreateEditPaM( const EPaM& rEPaM ); + inline ESelection CreateESel( const EditSelection& rSel ); + inline EditSelection CreateSel( const ESelection& rSel ); + + + void SetStyleSheetPool( SfxStyleSheetPool* pSPool ); + SfxStyleSheetPool* GetStyleSheetPool() const { return pStylePool; } + + void SetStyleSheet( EditSelection aSel, SfxStyleSheet* pStyle ); + void SetStyleSheet( sal_uInt16 nPara, SfxStyleSheet* pStyle ); + SfxStyleSheet* GetStyleSheet( sal_uInt16 nPara ) const; + + void UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle ); + void RemoveStyleFromParagraphs( SfxStyleSheet* pStyle ); + + OutputDevice* GetRefDevice() const { return pRefDev; } + void SetRefDevice( OutputDevice* pRefDef ); + + const MapMode& GetRefMapMode() { return pRefDev->GetMapMode(); } + void SetRefMapMode( const MapMode& rMapMode ); + + InternalEditStatus& GetStatus() { return aStatus; } + void CallStatusHdl(); + void DelayedCallStatusHdl() { aStatusTimer.Start(); } + + void CallNotify( EENotify& rNotify ); + void EnterBlockNotifications(); + void LeaveBlockNotifications(); + + + EditSelection MatchGroup( const EditSelection& rSel ); + + void UndoActionStart( sal_uInt16 nId ); + void UndoActionStart( sal_uInt16 nId, const ESelection& rSel ); + void UndoActionEnd( sal_uInt16 nId ); + + EditView* GetActiveView() const { return pActiveView; } + void SetActiveView( EditView* pView ); + + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellChecker1 > + GetSpeller(); + void SetSpeller( ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellChecker1 > &xSpl ) + { xSpeller = xSpl; } + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenator > + GetHyphenator() const { return xHyphenator; } + void SetHyphenator( ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenator > &xHyph ) + { xHyphenator = xHyph; } + SpellInfo* GetSpellInfo() const { return pSpellInfo; } + + void SetDefaultLanguage( LanguageType eLang ) { eDefLanguage = eLang; } + LanguageType GetDefaultLanguage() const { return eDefLanguage; } + + + LanguageType GetLanguage( const EditSelection rSelection ) const; + LanguageType GetLanguage( const EditPaM& rPaM, USHORT* pEndPos = NULL ) const; + ::com::sun::star::lang::Locale GetLocale( const EditPaM& rPaM ) const; + + void DoOnlineSpelling( ContentNode* pThisNodeOnly = 0, sal_Bool bSpellAtCursorPos = sal_False, sal_Bool bInteruptable = sal_True ); + EESpellState Spell( EditView* pEditView, sal_Bool bMultipleDoc ); + EESpellState HasSpellErrors(); + EESpellState StartThesaurus( EditView* pEditView ); + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellAlternatives > + ImpSpell( EditView* pEditView ); + + // text conversion functions + void Convert( EditView* pEditView, LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, INT32 nOptions, sal_Bool bIsInteractive, sal_Bool bMultipleDoc ); + void ImpConvert( rtl::OUString &rConvTxt, LanguageType &rConvTxtLang, EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange, + sal_Bool bAllowImplicitChangesForNotConvertibleText, LanguageType nTargetLang, const Font *pTargetFont ); + ConvInfo * GetConvInfo() const { return pConvInfo; } + sal_Bool HasConvertibleTextPortion( LanguageType nLang ); + void SetLanguageAndFont( const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ); + + // returns true if input sequence checking should be applied + sal_Bool IsInputSequenceCheckingRequired( sal_Unicode nChar, const EditSelection& rCurSel ) const; + + //find the next error within the given selection - forward only! + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellAlternatives > + ImpFindNextError(EditSelection& rSelection); + //initialize sentence spelling + void StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc); + //spell and return a sentence + bool SpellSentence(EditView& rView, ::svx::SpellPortions& rToFill, bool bIsGrammarChecking ); + //put spelling back to start of current sentence - needed after switch of grammar support + void PutSpellingToSentenceStart( EditView& rEditView ); + //applies a changed sentence + void ApplyChangedSentence(EditView& rEditView, const ::svx::SpellPortions& rNewPortions, bool bIsGrammarChecking ); + //deinitialize sentence spelling + void EndSpelling(); + //adds one or more portions of text to the SpellPortions depending on language changes + void AddPortionIterated( + EditView& rEditView, + const EditSelection rSel, + ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill); + //adds one portion to the SpellPortions + void AddPortion( + const EditSelection rSel, + ::com::sun::star::uno::Reference< ::com::sun::star::linguistic2::XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill, + bool bIsField ); + + sal_Bool Search( const SvxSearchItem& rSearchItem, EditView* pView ); + sal_Bool ImpSearch( const SvxSearchItem& rSearchItem, const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel ); + sal_uInt16 StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem ); + sal_Bool HasText( const SvxSearchItem& rSearchItem ); + + void SetEditTextObjectPool( SfxItemPool* pP ) { pTextObjectPool = pP; } + SfxItemPool* GetEditTextObjectPool() const { return pTextObjectPool; } + + const SvxNumberFormat * GetNumberFormat( const ContentNode* pNode ) const; + sal_Int32 GetSpaceBeforeAndMinLabelWidth( const ContentNode *pNode, sal_Int32 *pnSpaceBefore = 0, sal_Int32 *pnMinLabelWidth = 0 ) const; + + const SvxLRSpaceItem& GetLRSpaceItem( ContentNode* pNode ); + SvxAdjust GetJustification( USHORT nPara ) const; + + void SetCharStretching( sal_uInt16 nX, sal_uInt16 nY ); + inline void GetCharStretching( sal_uInt16& rX, sal_uInt16& rY ); + void DoStretchChars( sal_uInt16 nX, sal_uInt16 nY ); + + void SetBigTextObjectStart( sal_uInt16 nStartAtPortionCount ) { nBigTextObjectStart = nStartAtPortionCount; } + sal_uInt16 GetBigTextObjectStart() const { return nBigTextObjectStart; } + + inline EditEngine* GetEditEnginePtr() const { return pEditEngine; } + + void StartOnlineSpellTimer() { aOnlineSpellTimer.Start(); } + void StopOnlineSpellTimer() { aOnlineSpellTimer.Stop(); } + + const XubString& GetAutoCompleteText() const { return aAutoCompleteText; } + void SetAutoCompleteText( const String& rStr, sal_Bool bUpdateTipWindow ); + + EditSelection TransliterateText( const EditSelection& rSelection, sal_Int32 nTransliterationMode ); + + void SetAsianCompressionMode( USHORT n ); + USHORT GetAsianCompressionMode() const { return nAsianCompressionMode; } + + void SetKernAsianPunctuation( BOOL b ); + BOOL IsKernAsianPunctuation() const { return bKernAsianPunctuation; } + + void SetAddExtLeading( BOOL b ); + BOOL IsAddExtLeading() const { return bAddExtLeading; } + + vos::ORef<SvxForbiddenCharactersTable> GetForbiddenCharsTable( BOOL bGetInternal = TRUE ) const; + void SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ); + + BOOL mbLastTryMerge; + + /** sets a link that is called at the beginning of a drag operation at an edit view */ + void SetBeginDropHdl( const Link& rLink ) { maBeginDropHdl = rLink; } + Link GetBeginDropHdl() const { return maBeginDropHdl; } + + /** sets a link that is called at the end of a drag operation at an edit view */ + void SetEndDropHdl( const Link& rLink ) { maEndDropHdl = rLink; } + Link GetEndDropHdl() const { return maEndDropHdl; } + + /// specifies if auto-correction should capitalize the first word or not (default is on) + void SetFirstWordCapitalization( BOOL bCapitalize ) { bFirstWordCapitalization = bCapitalize; } + BOOL IsFirstWordCapitalization() const { return bFirstWordCapitalization; } +}; + +inline EPaM ImpEditEngine::CreateEPaM( const EditPaM& rPaM ) +{ + ContentNode* pNode = rPaM.GetNode(); + return EPaM( aEditDoc.GetPos( pNode ), rPaM.GetIndex() ); +} + +inline EditPaM ImpEditEngine::CreateEditPaM( const EPaM& rEPaM ) +{ + DBG_ASSERT( rEPaM.nPara < aEditDoc.Count(), "CreateEditPaM: Ungueltiger Absatz" ); + DBG_ASSERT( aEditDoc[ rEPaM.nPara ]->Len() >= rEPaM.nIndex, "CreateEditPaM: Ungueltiger Index" ); + return EditPaM( aEditDoc[ rEPaM.nPara], rEPaM.nIndex ); +} + +inline ESelection ImpEditEngine::CreateESel( const EditSelection& rSel ) +{ + ContentNode* pStartNode = rSel.Min().GetNode(); + ContentNode* pEndNode = rSel.Max().GetNode(); + ESelection aESel; + aESel.nStartPara = aEditDoc.GetPos( pStartNode ); + aESel.nStartPos = rSel.Min().GetIndex(); + aESel.nEndPara = aEditDoc.GetPos( pEndNode ); + aESel.nEndPos = rSel.Max().GetIndex(); + return aESel; +} + +inline EditSelection ImpEditEngine::CreateSel( const ESelection& rSel ) +{ + DBG_ASSERT( rSel.nStartPara < aEditDoc.Count(), "CreateSel: Ungueltiger Start-Absatz" ); + DBG_ASSERT( rSel.nEndPara < aEditDoc.Count(), "CreateSel: Ungueltiger End-Absatz" ); + EditSelection aSel; + aSel.Min().SetNode( aEditDoc[ rSel.nStartPara ] ); + aSel.Min().SetIndex( rSel.nStartPos ); + aSel.Max().SetNode( aEditDoc[ rSel.nEndPara ] ); + aSel.Max().SetIndex( rSel.nEndPos ); + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "CreateSel: Fehlerhafte Selektion!" ); + return aSel; +} + +inline VirtualDevice* ImpEditEngine::GetVirtualDevice( const MapMode& rMapMode, ULONG nDrawMode ) +{ + if ( !pVirtDev ) + pVirtDev = new VirtualDevice; + + if ( ( pVirtDev->GetMapMode().GetMapUnit() != rMapMode.GetMapUnit() ) || + ( pVirtDev->GetMapMode().GetScaleX() != rMapMode.GetScaleX() ) || + ( pVirtDev->GetMapMode().GetScaleY() != rMapMode.GetScaleY() ) ) + { + MapMode aMapMode( rMapMode ); + aMapMode.SetOrigin( Point( 0, 0 ) ); + pVirtDev->SetMapMode( aMapMode ); + } + + pVirtDev->SetDrawMode( nDrawMode ); + + return pVirtDev; +} + +inline void ImpEditEngine::EraseVirtualDevice() +{ + delete pVirtDev; + pVirtDev = 0; +} + +inline void ImpEditEngine::IdleFormatAndUpdate( EditView* pCurView ) +{ + aIdleFormatter.DoIdleFormat( pCurView ); +} + +#ifndef SVX_LIGHT +inline EditUndoManager& ImpEditEngine::GetUndoManager() +{ + if ( !pUndoManager ) + pUndoManager = new EditUndoManager( this ); + return *pUndoManager; +} +#endif + +inline ParaPortion* ImpEditEngine::FindParaPortion( ContentNode* pNode ) const +{ + sal_uInt16 nPos = aEditDoc.GetPos( pNode ); + DBG_ASSERT( nPos < GetParaPortions().Count(), "Portionloser Node?" ); + return GetParaPortions()[ nPos ]; +} + +inline void ImpEditEngine::GetCharStretching( sal_uInt16& rX, sal_uInt16& rY ) +{ + rX = nStretchX; + rY = nStretchY; +} + +inline short ImpEditEngine::GetXValue( short nXValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchX == 100 ) ) + return nXValue; + + return (short) ((long)nXValue*nStretchX/100); +} + +inline sal_uInt16 ImpEditEngine::GetXValue( sal_uInt16 nXValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchX == 100 ) ) + return nXValue; + + return (sal_uInt16) ((long)nXValue*nStretchX/100); +} + +inline long ImpEditEngine::GetXValue( long nXValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchX == 100 ) ) + return nXValue; + + return nXValue*nStretchX/100; +} + +inline short ImpEditEngine::GetYValue( short nYValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchY == 100 ) ) + return nYValue; + + return (short) ((long)nYValue*nStretchY/100); +} + +inline sal_uInt16 ImpEditEngine::GetYValue( sal_uInt16 nYValue ) const +{ + if ( !aStatus.DoStretch() || ( nStretchY == 100 ) ) + return nYValue; + + return (sal_uInt16) ((long)nYValue*nStretchY/100); +} + +inline void ImpEditView::SetPointer( const Pointer& rPointer ) +{ + delete pPointer; + pPointer = new Pointer( rPointer ); +} + +inline const Pointer& ImpEditView::GetPointer() +{ + if ( !pPointer ) + { + pPointer = new Pointer( IsVertical() ? POINTER_TEXT_VERTICAL : POINTER_TEXT ); + return *pPointer; + } + + if(POINTER_TEXT == pPointer->GetStyle() && IsVertical()) + { + delete pPointer; + pPointer = new Pointer(POINTER_TEXT_VERTICAL); + } + else if(POINTER_TEXT_VERTICAL == pPointer->GetStyle() && !IsVertical()) + { + delete pPointer; + pPointer = new Pointer(POINTER_TEXT); + } + + return *pPointer; +} + +inline void ImpEditView::SetCursor( const Cursor& rCursor ) +{ + delete pCursor; + pCursor = new Cursor( rCursor ); +} + +inline Cursor* ImpEditView::GetCursor() +{ + if ( !pCursor ) + pCursor = new Cursor; + return pCursor; +} + +void ConvertItem( SfxPoolItem& rPoolItem, MapUnit eSourceUnit, MapUnit eDestUnit ); +void ConvertAndPutItems( SfxItemSet& rDest, const SfxItemSet& rSource, const MapUnit* pSourceUnit = NULL, const MapUnit* pDestUnit = NULL ); +BYTE GetCharTypeForCompression( xub_Unicode cChar ); +Point Rotate( const Point& rPoint, short nOrientation, const Point& rOrigin ); + +#endif // _IMPEDIT_HXX + + diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx new file mode 100644 index 000000000000..f867f81bd5fc --- /dev/null +++ b/editeng/source/editeng/impedit2.cxx @@ -0,0 +1,4635 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: impedit2.cxx,v $ + * $Revision: 1.124.40.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/lspcitem.hxx> +#include <editeng/flditem.hxx> +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editdbg.hxx> +#include <eerdll2.hxx> +#include <editeng/eerdll.hxx> +#include <edtspell.hxx> +#include <eeobj.hxx> +#include <editeng/txtrange.hxx> +#include <svl/urlbmk.hxx> +#include <svtools/colorcfg.hxx> +#include <svl/ctloptions.hxx> +#include <editeng/acorrcfg.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/fontitem.hxx> +#include <vcl/cmdevt.h> + +#include <com/sun/star/i18n/CharacterIteratorMode.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/text/CharacterCompressionType.hpp> +#include <com/sun/star/i18n/InputSequenceCheckMode.hpp> + +#include <comphelper/processfactory.hxx> + +#include <sot/formats.hxx> + +#include <unicode/ubidi.h> + +using namespace ::com::sun::star; + +USHORT lcl_CalcExtraSpace( ParaPortion*, const SvxLineSpacingItem& rLSItem ) +{ + USHORT nExtra = 0; + /* if ( ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + && ( rLSItem.GetPropLineSpace() != 100 ) ) + { + // ULONG nH = pPortion->GetNode()->GetCharAttribs().GetDefFont().GetSize().Height(); + ULONG nH = pPortion->GetLines().GetObject( 0 )->GetHeight(); + long n = nH * rLSItem.GetPropLineSpace(); + n /= 100; + n -= nH; // nur den Abstand + if ( n > 0 ) + nExtra = (USHORT)n; + } + else */ + if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + { + nExtra = rLSItem.GetInterLineSpace(); + } + + return nExtra; +} + +// ---------------------------------------------------------------------- +// class ImpEditEngine +// ---------------------------------------------------------------------- + +ImpEditEngine::ImpEditEngine( EditEngine* pEE, SfxItemPool* pItemPool ) : + aPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ), + aMinAutoPaperSize( 0x0, 0x0 ), + aMaxAutoPaperSize( 0x7FFFFFFF, 0x7FFFFFFF ), + aEditDoc( pItemPool ), + aWordDelimiters( RTL_CONSTASCII_USTRINGPARAM( " .,;:-'`'?!_=\"{}()[]\0xFF" ) ), + aGroupChars( RTL_CONSTASCII_USTRINGPARAM( "{}()[]" ) ) +{ + pEditEngine = pEE; + pRefDev = NULL; + pVirtDev = NULL; + pEmptyItemSet = NULL; + pActiveView = NULL; + pSpellInfo = NULL; + pConvInfo = NULL; + pTextObjectPool = NULL; + mpIMEInfos = NULL; + pStylePool = NULL; + pUndoManager = NULL; + pUndoMarkSelection = NULL; + pTextRanger = NULL; + pColorConfig = NULL; + pCTLOptions = NULL; + + nCurTextHeight = 0; + nBlockNotifications = 0; + nBigTextObjectStart = 20; + + nStretchX = 100; + nStretchY = 100; + + bInSelection = FALSE; + bOwnerOfRefDev = FALSE; + bDowning = FALSE; + bIsInUndo = FALSE; + bIsFormatting = FALSE; + bFormatted = FALSE; + bUpdate = TRUE; + bUseAutoColor = TRUE; + bForceAutoColor = FALSE; + bAddExtLeading = FALSE; + bUndoEnabled = TRUE; + bCallParaInsertedOrDeleted = FALSE; + bImpConvertFirstCall= FALSE; + bFirstWordCapitalization = TRUE; + + eDefLanguage = LANGUAGE_DONTKNOW; + maBackgroundColor = COL_AUTO; + + nAsianCompressionMode = text::CharacterCompressionType::NONE; + bKernAsianPunctuation = FALSE; + + eDefaultHorizontalTextDirection = EE_HTEXTDIR_DEFAULT; + + + aStatus.GetControlWord() = EE_CNTRL_USECHARATTRIBS | EE_CNTRL_DOIDLEFORMAT | + EE_CNTRL_PASTESPECIAL | EE_CNTRL_UNDOATTRIBS | + EE_CNTRL_ALLOWBIGOBJS | EE_CNTRL_RTFSTYLESHEETS | + EE_CNTRL_FORMAT100; + + aSelEngine.SetFunctionSet( &aSelFuncSet ); + + aStatusTimer.SetTimeout( 200 ); + aStatusTimer.SetTimeoutHdl( LINK( this, ImpEditEngine, StatusTimerHdl ) ); + + aIdleFormatter.SetTimeout( 5 ); + aIdleFormatter.SetTimeoutHdl( LINK( this, ImpEditEngine, IdleFormatHdl ) ); + + aOnlineSpellTimer.SetTimeout( 100 ); + aOnlineSpellTimer.SetTimeoutHdl( LINK( this, ImpEditEngine, OnlineSpellHdl ) ); + + pRefDev = EE_DLL()->GetGlobalData()->GetStdRefDevice(); + + // Ab hier wird schon auf Daten zugegriffen! + SetRefDevice( pRefDev ); + InitDoc( FALSE ); + + bCallParaInsertedOrDeleted = TRUE; + + aEditDoc.SetModifyHdl( LINK( this, ImpEditEngine, DocModified ) ); + + mbLastTryMerge = FALSE; +} + +ImpEditEngine::~ImpEditEngine() +{ + aStatusTimer.Stop(); + aOnlineSpellTimer.Stop(); + aIdleFormatter.Stop(); + + // das Zerstoeren von Vorlagen kann sonst unnoetiges Formatieren ausloesen, + // wenn eine Parent-Vorlage zerstoert wird. + // Und das nach dem Zerstoeren der Daten! + bDowning = TRUE; + SetUpdateMode( FALSE ); + + delete pVirtDev; + delete pEmptyItemSet; + delete pUndoManager; + delete pTextRanger; + delete mpIMEInfos; + delete pColorConfig; + delete pCTLOptions; + if ( bOwnerOfRefDev ) + delete pRefDev; + delete pSpellInfo; +} + +void ImpEditEngine::SetRefDevice( OutputDevice* pRef ) +{ + if ( bOwnerOfRefDev ) + delete pRefDev; + + pRefDev = pRef; + bOwnerOfRefDev = FALSE; + + if ( !pRef ) + pRefDev = EE_DLL()->GetGlobalData()->GetStdRefDevice(); + + nOnePixelInRef = (USHORT)pRefDev->PixelToLogic( Size( 1, 0 ) ).Width(); + + if ( IsFormatted() ) + { + FormatFullDoc(); + UpdateViews( (EditView*) 0); + } +} + +void ImpEditEngine::SetRefMapMode( const MapMode& rMapMode ) +{ + if ( GetRefDevice()->GetMapMode() == rMapMode ) + return; + + // Wenn RefDev == GlobalRefDev => eigenes anlegen! + if ( !bOwnerOfRefDev && ( pRefDev == EE_DLL()->GetGlobalData()->GetStdRefDevice() ) ) + { + pRefDev = new VirtualDevice; + pRefDev->SetMapMode( MAP_TWIP ); + SetRefDevice( pRefDev ); + bOwnerOfRefDev = TRUE; + } + pRefDev->SetMapMode( rMapMode ); + nOnePixelInRef = (USHORT)pRefDev->PixelToLogic( Size( 1, 0 ) ).Width(); + if ( IsFormatted() ) + { + FormatFullDoc(); + UpdateViews( (EditView*) 0); + } +} + +void ImpEditEngine::InitDoc( BOOL bKeepParaAttribs ) +{ + USHORT nParas = aEditDoc.Count(); + for ( USHORT n = bKeepParaAttribs ? 1 : 0; n < nParas; n++ ) + { + if ( aEditDoc[n]->GetStyleSheet() ) + EndListening( *aEditDoc[n]->GetStyleSheet(), FALSE ); + } + + if ( bKeepParaAttribs ) + aEditDoc.RemoveText(); + else + aEditDoc.Clear(); + + GetParaPortions().Reset(); + + ParaPortion* pIniPortion = new ParaPortion( aEditDoc[0] ); + GetParaPortions().Insert( pIniPortion, 0 ); + + bFormatted = FALSE; + + if ( IsCallParaInsertedOrDeleted() ) + { + GetEditEnginePtr()->ParagraphDeleted( EE_PARA_ALL ); + GetEditEnginePtr()->ParagraphInserted( 0 ); + } + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() ) + aEditDoc.GetObject( 0 )->CreateWrongList(); +#endif // !SVX_LIGHT +} + +EditPaM ImpEditEngine::DeleteSelected( EditSelection aSel ) +{ + EditPaM aPaM ( ImpDeleteSelection( aSel ) ); + return aPaM; +} + +XubString ImpEditEngine::GetSelected( const EditSelection& rSel, const LineEnd eEnd ) const +{ + XubString aText; + if ( !rSel.HasRange() ) + return aText; + + String aSep = EditDoc::GetSepStr( eEnd ); + + EditSelection aSel( rSel ); + aSel.Adjust( aEditDoc ); + + ContentNode* pStartNode = aSel.Min().GetNode(); + ContentNode* pEndNode = aSel.Max().GetNode(); + USHORT nStartNode = aEditDoc.GetPos( pStartNode ); + USHORT nEndNode = aEditDoc.GetPos( pEndNode ); + + DBG_ASSERT( nStartNode <= nEndNode, "Selektion nicht sortiert ?" ); + + // ueber die Absaetze iterieren... + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: GetSelected" ); + ContentNode* pNode = aEditDoc.GetObject( nNode ); + + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + aText += aEditDoc.GetParaAsString( pNode, nStartPos, nEndPos ); + if ( nNode < nEndNode ) + aText += aSep; + } + return aText; +} + +BOOL ImpEditEngine::MouseButtonDown( const MouseEvent& rMEvt, EditView* pView ) +{ + GetSelEngine().SetCurView( pView ); + SetActiveView( pView ); + + if ( GetAutoCompleteText().Len() ) + SetAutoCompleteText( String(), TRUE ); + + GetSelEngine().SelMouseButtonDown( rMEvt ); + // Sonderbehandlungen + EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); + if ( !rMEvt.IsShift() ) + { + if ( rMEvt.GetClicks() == 2 ) + { + // damit die SelectionEngine weiss, dass Anker. + aSelEngine.CursorPosChanging( TRUE, FALSE ); + + EditSelection aNewSelection( SelectWord( aCurSel ) ); + pView->pImpEditView->DrawSelection(); + pView->pImpEditView->SetEditSelection( aNewSelection ); + pView->pImpEditView->DrawSelection(); + pView->ShowCursor( TRUE, TRUE ); + } + else if ( rMEvt.GetClicks() == 3 ) + { + // damit die SelectionEngine weiss, dass Anker. + aSelEngine.CursorPosChanging( TRUE, FALSE ); + + EditSelection aNewSelection( aCurSel ); + aNewSelection.Min().SetIndex( 0 ); + aNewSelection.Max().SetIndex( aCurSel.Min().GetNode()->Len() ); + pView->pImpEditView->DrawSelection(); + pView->pImpEditView->SetEditSelection( aNewSelection ); + pView->pImpEditView->DrawSelection(); + pView->ShowCursor( TRUE, TRUE ); + } + } + return TRUE; +} + +void ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView ) +{ + GetSelEngine().SetCurView( pView ); + SetActiveView( pView ); + if ( rCEvt.GetCommand() == COMMAND_VOICE ) + { + const CommandVoiceData* pData = rCEvt.GetVoiceData(); + if ( pData->GetType() == VOICECOMMANDTYPE_DICTATION ) + { + // Funktionen auf KeyEvents umbiegen, wenn keine entsprechende + // Methode an EditView/EditEngine, damit Undo konsistent bleibt. + + SfxPoolItem* pNewAttr = NULL; + + switch ( pData->GetCommand() ) + { + case DICTATIONCOMMAND_UNKNOWN: + { + pView->InsertText( pData->GetText() ); + } + break; + case DICTATIONCOMMAND_NEWPARAGRAPH: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RETURN, 0 ) ) ); + } + break; + case DICTATIONCOMMAND_NEWLINE: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RETURN, KEY_SHIFT ) ) ); + } + break; + case DICTATIONCOMMAND_TAB: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_TAB, 0 ) ) ); + } + break; + case DICTATIONCOMMAND_LEFT: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1 ) ) ); + } + break; + case DICTATIONCOMMAND_RIGHT: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_RIGHT, KEY_MOD1 ) ) ); + } + break; + case DICTATIONCOMMAND_UP: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_UP, 0 ) ) ); + } + break; + case DICTATIONCOMMAND_DOWN: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_UP, 0 ) ) ); + } + break; + case DICTATIONCOMMAND_UNDO: + { + pView->Undo(); + } + break; + case DICTATIONCOMMAND_DEL: + { + pView->PostKeyEvent( KeyEvent( 0, KeyCode( KEY_LEFT, KEY_MOD1|KEY_SHIFT ) ) ); + pView->DeleteSelected(); + } + break; + case DICTATIONCOMMAND_BOLD_ON: + { + pNewAttr = new SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ); + } + break; + case DICTATIONCOMMAND_BOLD_OFF: + { + pNewAttr = new SvxWeightItem( WEIGHT_NORMAL, EE_CHAR_WEIGHT ); + } + break; + case DICTATIONCOMMAND_ITALIC_ON: + { + pNewAttr = new SvxPostureItem( ITALIC_NORMAL, EE_CHAR_ITALIC ); + } + break; + case DICTATIONCOMMAND_ITALIC_OFF: + { + pNewAttr = new SvxPostureItem( ITALIC_NORMAL, EE_CHAR_ITALIC ); + } + break; + case DICTATIONCOMMAND_UNDERLINE_ON: + { + pNewAttr = new SvxUnderlineItem( UNDERLINE_SINGLE, EE_CHAR_UNDERLINE ); + } + break; + case DICTATIONCOMMAND_UNDERLINE_OFF: + { + pNewAttr = new SvxUnderlineItem( UNDERLINE_NONE, EE_CHAR_UNDERLINE ); + } + break; + } + + if ( pNewAttr ) + { + SfxItemSet aSet( GetEmptyItemSet() ); + aSet.Put( *pNewAttr ); + pView->SetAttribs( aSet ); + delete pNewAttr; + } + } + } + else if ( rCEvt.GetCommand() == COMMAND_STARTEXTTEXTINPUT ) + { + pView->DeleteSelected(); + delete mpIMEInfos; + EditPaM aPaM = pView->GetImpEditView()->GetEditSelection().Max(); + String aOldTextAfterStartPos = aPaM.GetNode()->Copy( aPaM.GetIndex() ); + USHORT nMax = aOldTextAfterStartPos.Search( CH_FEATURE ); + if ( nMax != STRING_NOTFOUND ) // don't overwrite features! + aOldTextAfterStartPos.Erase( nMax ); + mpIMEInfos = new ImplIMEInfos( aPaM, aOldTextAfterStartPos ); + mpIMEInfos->bWasCursorOverwrite = !pView->IsInsertMode(); + UndoActionStart( EDITUNDO_INSERT ); + } + else if ( rCEvt.GetCommand() == COMMAND_ENDEXTTEXTINPUT ) + { + DBG_ASSERT( mpIMEInfos, "COMMAND_ENDEXTTEXTINPUT => Kein Start ?" ); + if( mpIMEInfos ) + { + // #102812# convert quotes in IME text + // works on the last input character, this is escpecially in Korean text often done + // quotes that are inside of the string are not replaced! + // Borrowed from sw: edtwin.cxx + if ( mpIMEInfos->nLen ) + { + EditSelection aSel( mpIMEInfos->aPos ); + aSel.Min().GetIndex() += mpIMEInfos->nLen-1; + aSel.Max().GetIndex() = + aSel.Max().GetIndex() + mpIMEInfos->nLen; + // #102812# convert quotes in IME text + // works on the last input character, this is escpecially in Korean text often done + // quotes that are inside of the string are not replaced! + const sal_Unicode nCharCode = aSel.Min().GetNode()->GetChar( aSel.Min().GetIndex() ); + if ( ( GetStatus().DoAutoCorrect() ) && ( ( nCharCode == '\"' ) || ( nCharCode == '\'' ) ) ) + { + aSel = DeleteSelected( aSel ); + aSel = AutoCorrect( aSel, nCharCode, mpIMEInfos->bWasCursorOverwrite ); + pView->pImpEditView->SetEditSelection( aSel ); + } + } + + ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() ); + pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex(), 0 ); + + BOOL bWasCursorOverwrite = mpIMEInfos->bWasCursorOverwrite; + + delete mpIMEInfos; + mpIMEInfos = NULL; + + FormatAndUpdate( pView ); + + pView->SetInsertMode( !bWasCursorOverwrite ); + } + UndoActionEnd( EDITUNDO_INSERT ); + } + else if ( rCEvt.GetCommand() == COMMAND_EXTTEXTINPUT ) + { + DBG_ASSERT( mpIMEInfos, "COMMAND_EXTTEXTINPUT => Kein Start ?" ); + if( mpIMEInfos ) + { + const CommandExtTextInputData* pData = rCEvt.GetExtTextInputData(); + + if ( !pData->IsOnlyCursorChanged() ) + { + EditSelection aSel( mpIMEInfos->aPos ); + aSel.Max().GetIndex() = + aSel.Max().GetIndex() + mpIMEInfos->nLen; + aSel = DeleteSelected( aSel ); + aSel = ImpInsertText( aSel, pData->GetText() ); + + if ( mpIMEInfos->bWasCursorOverwrite ) + { + USHORT nOldIMETextLen = mpIMEInfos->nLen; + USHORT nNewIMETextLen = pData->GetText().Len(); + + if ( ( nOldIMETextLen > nNewIMETextLen ) && + ( nNewIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) ) + { + // restore old characters + USHORT nRestore = nOldIMETextLen - nNewIMETextLen; + EditPaM aPaM( mpIMEInfos->aPos ); + aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; + ImpInsertText( aPaM, mpIMEInfos->aOldTextAfterStartPos.Copy( nNewIMETextLen, nRestore ) ); + } + else if ( ( nOldIMETextLen < nNewIMETextLen ) && + ( nOldIMETextLen < mpIMEInfos->aOldTextAfterStartPos.Len() ) ) + { + // overwrite + USHORT nOverwrite = nNewIMETextLen - nOldIMETextLen; + if ( ( nOldIMETextLen + nOverwrite ) > mpIMEInfos->aOldTextAfterStartPos.Len() ) + nOverwrite = mpIMEInfos->aOldTextAfterStartPos.Len() - nOldIMETextLen; + DBG_ASSERT( nOverwrite && (nOverwrite < 0xFF00), "IME Overwrite?!" ); + EditPaM aPaM( mpIMEInfos->aPos ); + aPaM.GetIndex() = aPaM.GetIndex() + nNewIMETextLen; + EditSelection _aSel( aPaM ); + _aSel.Max().GetIndex() = + _aSel.Max().GetIndex() + nOverwrite; + DeleteSelected( _aSel ); + } + } + if ( pData->GetTextAttr() ) + { + mpIMEInfos->CopyAttribs( pData->GetTextAttr(), pData->GetText().Len() ); + mpIMEInfos->bCursor = pData->IsCursorVisible(); + } + else + { + mpIMEInfos->DestroyAttribs(); + mpIMEInfos->nLen = pData->GetText().Len(); + } + + ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() ); + pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex(), 0 ); + FormatAndUpdate( pView ); + } + + EditSelection aNewSel = EditPaM( mpIMEInfos->aPos.GetNode(), mpIMEInfos->aPos.GetIndex()+pData->GetCursorPos() ); + pView->SetSelection( CreateESel( aNewSel ) ); + pView->SetInsertMode( !pData->IsCursorOverwrite() ); + + if ( pData->IsCursorVisible() ) + pView->ShowCursor(); + else + pView->HideCursor(); + } + } + else if ( rCEvt.GetCommand() == COMMAND_INPUTCONTEXTCHANGE ) + { + } + else if ( rCEvt.GetCommand() == COMMAND_CURSORPOS ) + { + if ( mpIMEInfos && mpIMEInfos->nLen ) + { + EditPaM aPaM( pView->pImpEditView->GetEditSelection().Max() ); + Rectangle aR1 = PaMtoEditCursor( aPaM, 0 ); + + USHORT nInputEnd = mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen; + + if ( !IsFormatted() ) + FormatDoc(); + + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( GetEditDoc().GetPos( aPaM.GetNode() ) ); + USHORT nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), sal_True ); + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + if ( pLine && ( nInputEnd > pLine->GetEnd() ) ) + nInputEnd = pLine->GetEnd(); + Rectangle aR2 = PaMtoEditCursor( EditPaM( aPaM.GetNode(), nInputEnd ), GETCRSR_ENDOFLINE ); + Rectangle aRect = pView->GetImpEditView()->GetWindowPos( aR1 ); + pView->GetWindow()->SetCursorRect( &aRect, aR2.Left()-aR1.Right() ); + } + else + { + pView->GetWindow()->SetCursorRect(); + } + } + else if ( rCEvt.GetCommand() == COMMAND_SELECTIONCHANGE )
+ {
+ const CommandSelectionChangeData *pData = rCEvt.GetSelectionChangeData();
+
+ ESelection aSelection = pView->GetSelection();
+ aSelection.Adjust();
+
+ if( pView->HasSelection() )
+ {
+ aSelection.nEndPos = aSelection.nStartPos;
+ aSelection.nStartPos += pData->GetStart();
+ aSelection.nEndPos += pData->GetEnd();
+ }
+ else
+ {
+ aSelection.nStartPos = pData->GetStart();
+ aSelection.nEndPos = pData->GetEnd();
+ }
+ pView->SetSelection( aSelection );
+ }
+ else if ( rCEvt.GetCommand() == COMMAND_PREPARERECONVERSION )
+ {
+ if ( pView->HasSelection() )
+ {
+ ESelection aSelection = pView->GetSelection();
+ aSelection.Adjust();
+
+ if ( aSelection.nStartPara != aSelection.nEndPara )
+ {
+ xub_StrLen aParaLen = pEditEngine->GetTextLen( aSelection.nStartPara );
+ aSelection.nEndPara = aSelection.nStartPara;
+ aSelection.nEndPos = aParaLen;
+ pView->SetSelection( aSelection );
+ }
+ }
+ } + + GetSelEngine().Command( rCEvt ); +} + +BOOL ImpEditEngine::MouseButtonUp( const MouseEvent& rMEvt, EditView* pView ) +{ + GetSelEngine().SetCurView( pView ); + GetSelEngine().SelMouseButtonUp( rMEvt ); + bInSelection = FALSE; + // Sonderbehandlungen + EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); + if ( !aCurSel.HasRange() ) + { + if ( ( rMEvt.GetClicks() == 1 ) && rMEvt.IsLeft() && !rMEvt.IsMod2() ) + { + const SvxFieldItem* pFld = pView->GetFieldUnderMousePointer(); + if ( pFld ) + { + EditPaM aPaM( aCurSel.Max() ); + USHORT nPara = GetEditDoc().GetPos( aPaM.GetNode() ); + GetEditEnginePtr()->FieldClicked( *pFld, nPara, aPaM.GetIndex() ); + } + } + } + return TRUE; +} + +BOOL ImpEditEngine::MouseMove( const MouseEvent& rMEvt, EditView* pView ) +{ + // MouseMove wird sofort nach ShowQuickHelp() gerufen! +// if ( GetAutoCompleteText().Len() ) +// SetAutoCompleteText( String(), TRUE ); + GetSelEngine().SetCurView( pView ); + GetSelEngine().SelMouseMove( rMEvt ); + return TRUE; +} + +EditPaM ImpEditEngine::InsertText( EditSelection aSel, const XubString& rStr ) +{ + EditPaM aPaM = ImpInsertText( aSel, rStr ); + return aPaM; +} + +EditPaM ImpEditEngine::Clear() +{ + InitDoc( FALSE ); + + EditPaM aPaM = aEditDoc.GetStartPaM(); + EditSelection aSel( aPaM ); + + nCurTextHeight = 0; + + ResetUndoManager(); + + for ( USHORT nView = aEditViews.Count(); nView; ) + { + EditView* pView = aEditViews[--nView]; + DBG_CHKOBJ( pView, EditView, 0 ); + pView->pImpEditView->SetEditSelection( aSel ); + } + + return aPaM; +} + +EditPaM ImpEditEngine::RemoveText() +{ + InitDoc( TRUE ); + + EditPaM aStartPaM = aEditDoc.GetStartPaM(); + EditSelection aEmptySel( aStartPaM, aStartPaM ); + for ( USHORT nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews.GetObject(nView); + DBG_CHKOBJ( pView, EditView, 0 ); + pView->pImpEditView->SetEditSelection( aEmptySel ); + } + ResetUndoManager(); + return aEditDoc.GetStartPaM(); +} + + +void ImpEditEngine::SetText( const XubString& rText ) +{ + // RemoveText loescht die Undo-Liste! + EditPaM aStartPaM = RemoveText(); + BOOL bUndoCurrentlyEnabled = IsUndoEnabled(); + // Der von Hand reingesteckte Text kann nicht vom Anwender rueckgaengig gemacht werden. + EnableUndo( FALSE ); + + EditSelection aEmptySel( aStartPaM, aStartPaM ); + EditPaM aPaM = aStartPaM; + if ( rText.Len() ) + aPaM = ImpInsertText( aEmptySel, rText ); + + for ( USHORT nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + DBG_CHKOBJ( pView, EditView, 0 ); + pView->pImpEditView->SetEditSelection( EditSelection( aPaM, aPaM ) ); + // Wenn kein Text, dann auch Kein Format&Update + // => Der Text bleibt stehen. + if ( !rText.Len() && GetUpdateMode() ) + { + Rectangle aTmpRec( pView->GetOutputArea().TopLeft(), + Size( aPaperSize.Width(), nCurTextHeight ) ); + aTmpRec.Intersection( pView->GetOutputArea() ); + pView->GetWindow()->Invalidate( aTmpRec ); + } + } + if( !rText.Len() ) // sonst muss spaeter noch invalidiert werden, !bFormatted reicht. + nCurTextHeight = 0; + EnableUndo( bUndoCurrentlyEnabled ); +#ifndef SVX_LIGHT + DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Undo nach SetText?" ); +#endif +} + + +const SfxItemSet& ImpEditEngine::GetEmptyItemSet() +{ + if ( !pEmptyItemSet ) + { + pEmptyItemSet = new SfxItemSet( aEditDoc.GetItemPool(), EE_ITEMS_START, EE_ITEMS_END ); + for ( USHORT nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++) + { + pEmptyItemSet->ClearItem( nWhich ); + } + } + return *pEmptyItemSet; +} + +// ---------------------------------------------------------------------- +// MISC +// ---------------------------------------------------------------------- +void ImpEditEngine::CursorMoved( ContentNode* pPrevNode ) +{ + // Leere Attribute loeschen, aber nur, wenn Absatz nicht leer! + if ( pPrevNode->GetCharAttribs().HasEmptyAttribs() && pPrevNode->Len() ) + pPrevNode->GetCharAttribs().DeleteEmptyAttribs( aEditDoc.GetItemPool() ); +} + +void ImpEditEngine::TextModified() +{ + bFormatted = FALSE; + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_TEXTMODIFIED ); + aNotify.pEditEngine = GetEditEnginePtr(); + CallNotify( aNotify ); + } +} + + +void ImpEditEngine::ParaAttribsChanged( ContentNode* pNode ) +{ + DBG_ASSERT( pNode, "ParaAttribsChanged: Welcher?" ); + + aEditDoc.SetModified( TRUE ); + bFormatted = FALSE; + + ParaPortion* pPortion = FindParaPortion( pNode ); + DBG_ASSERT( pPortion, "ParaAttribsChanged: Portion?" ); + pPortion->MarkSelectionInvalid( 0, pNode->Len() ); + + USHORT nPara = aEditDoc.GetPos( pNode ); + pEditEngine->ParaAttribsChanged( nPara ); + + ParaPortion* pNextPortion = GetParaPortions().SaveGetObject( nPara+1 ); + // => wird sowieso noch formatiert, wenn Invalid. + if ( pNextPortion && !pNextPortion->IsInvalid() ) + CalcHeight( pNextPortion ); +} + +// ---------------------------------------------------------------------- +// Cursorbewegungen +// ---------------------------------------------------------------------- + +EditSelection ImpEditEngine::MoveCursor( const KeyEvent& rKeyEvent, EditView* pEditView ) +{ + // Eigentlich nur bei Up/Down noetig, aber was solls. + CheckIdleFormatter(); + + EditPaM aPaM( pEditView->pImpEditView->GetEditSelection().Max() ); + + EditPaM aOldPaM( aPaM ); + + TextDirectionality eTextDirection = TextDirectionality_LeftToRight_TopToBottom; + if ( IsVertical() ) + eTextDirection = TextDirectionality_TopToBottom_RightToLeft; + else if ( IsRightToLeft( GetEditDoc().GetPos( aPaM.GetNode() ) ) ) + eTextDirection = TextDirectionality_RightToLeft_TopToBottom; + + KeyEvent aTranslatedKeyEvent = rKeyEvent.LogicalTextDirectionality( eTextDirection ); + + BOOL bCtrl = aTranslatedKeyEvent.GetKeyCode().IsMod1() ? TRUE : FALSE; + USHORT nCode = aTranslatedKeyEvent.GetKeyCode().GetCode(); + + if ( DoVisualCursorTraveling( aPaM.GetNode() ) ) + { + // Only for simple cursor movement... + if ( !bCtrl && ( ( nCode == KEY_LEFT ) || ( nCode == KEY_RIGHT ) ) ) + { + aPaM = CursorVisualLeftRight( pEditView, aPaM, rKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL, rKeyEvent.GetKeyCode().GetCode() == KEY_LEFT ); + nCode = 0; // skip switch statement + } + /* + else if ( !bCtrl && ( ( nCode == KEY_HOME ) || ( nCode == KEY_END ) ) ) + { + aPaM = CursorVisualStartEnd( pEditView, aPaM, nCode == KEY_HOME ); + nCode = 0; // skip switch statement + } + */ + } + + bool bKeyModifySelection = aTranslatedKeyEvent.GetKeyCode().IsShift(); + switch ( nCode ) + { + case KEY_UP: aPaM = CursorUp( aPaM, pEditView ); + break; + case KEY_DOWN: aPaM = CursorDown( aPaM, pEditView ); + break; + case KEY_LEFT: aPaM = bCtrl ? WordLeft( aPaM ) : CursorLeft( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL ); + break; + case KEY_RIGHT: aPaM = bCtrl ? WordRight( aPaM ) : CursorRight( aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? i18n::CharacterIteratorMode::SKIPCHARACTER : i18n::CharacterIteratorMode::SKIPCELL ); + break; + case KEY_HOME: aPaM = bCtrl ? CursorStartOfDoc() : CursorStartOfLine( aPaM ); + break; + case KEY_END: aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( aPaM ); + break; + case KEY_PAGEUP: aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM, pEditView ); + break; + case KEY_PAGEDOWN: aPaM = bCtrl ? CursorEndOfDoc() : PageDown( aPaM, pEditView ); + break; + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_LINE: + aPaM = CursorStartOfLine( aPaM ); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_END_OF_LINE: + aPaM = CursorEndOfLine( aPaM ); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_WORD_BACKWARD: + aPaM = WordLeft( aPaM ); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_WORD_FORWARD: + aPaM = WordRight( aPaM ); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_PARAGRAPH: + aPaM = CursorStartOfParagraph( aPaM ); + if( aPaM == aOldPaM ) + { + aPaM = CursorLeft( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + aPaM = CursorStartOfParagraph( aPaM ); + } + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_END_OF_PARAGRAPH: + aPaM = CursorEndOfParagraph( aPaM ); + if( aPaM == aOldPaM ) + { + aPaM = CursorRight( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + aPaM = CursorEndOfParagraph( aPaM ); + } + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_BEGIN_OF_DOCUMENT: + aPaM = CursorStartOfDoc(); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::MOVE_TO_END_OF_DOCUMENT: + aPaM = CursorEndOfDoc(); + bKeyModifySelection = false; + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_LINE: + aPaM = CursorStartOfLine( aPaM ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_LINE: + aPaM = CursorEndOfLine( aPaM ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_BACKWARD: + aPaM = CursorLeft( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_FORWARD: + aPaM = CursorRight( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_WORD_BACKWARD: + aPaM = WordLeft( aPaM ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_WORD_FORWARD: + aPaM = WordRight( aPaM ); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_PARAGRAPH: + aPaM = CursorStartOfParagraph( aPaM ); + if( aPaM == aOldPaM ) + { + aPaM = CursorLeft( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + aPaM = CursorStartOfParagraph( aPaM ); + } + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_PARAGRAPH: + aPaM = CursorEndOfParagraph( aPaM ); + if( aPaM == aOldPaM ) + { + aPaM = CursorRight( aPaM, i18n::CharacterIteratorMode::SKIPCELL ); + aPaM = CursorEndOfParagraph( aPaM ); + } + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_BEGIN_OF_DOCUMENT: + aPaM = CursorStartOfDoc(); + bKeyModifySelection = true; + break; + case com::sun::star::awt::Key::SELECT_TO_END_OF_DOCUMENT: + aPaM = CursorEndOfDoc(); + bKeyModifySelection = true; + break; + } + + if ( aOldPaM != aPaM ) + { + CursorMoved( aOldPaM.GetNode() ); + if ( aStatus.NotifyCursorMovements() && ( aOldPaM.GetNode() != aPaM.GetNode() ) ) + { + aStatus.GetStatusWord() = aStatus.GetStatusWord() | EE_STAT_CRSRLEFTPARA; + aStatus.GetPrevParagraph() = aEditDoc.GetPos( aOldPaM.GetNode() ); + } + } + else + aStatus.GetStatusWord() = aStatus.GetStatusWord() | EE_STAT_CRSRMOVEFAIL; + + // Bewirkt evtl. ein CreateAnchor oder Deselection all + aSelEngine.SetCurView( pEditView ); + aSelEngine.CursorPosChanging( bKeyModifySelection, aTranslatedKeyEvent.GetKeyCode().IsMod1() ); + EditPaM aOldEnd( pEditView->pImpEditView->GetEditSelection().Max() ); + pEditView->pImpEditView->GetEditSelection().Max() = aPaM; + if ( bKeyModifySelection ) + { + // Dann wird die Selektion erweitert... + EditSelection aTmpNewSel( aOldEnd, aPaM ); + pEditView->pImpEditView->DrawSelection( aTmpNewSel ); + } + else + pEditView->pImpEditView->GetEditSelection().Min() = aPaM; + + return pEditView->pImpEditView->GetEditSelection(); +} + +EditPaM ImpEditEngine::CursorVisualStartEnd( EditView* pEditView, const EditPaM& rPaM, BOOL bStart ) +{ + EditPaM aPaM( rPaM ); + + USHORT nPara = GetEditDoc().GetPos( aPaM.GetNode() ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + + USHORT nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), sal_False ); + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + BOOL bEmptyLine = pLine->GetStart() == pLine->GetEnd(); + + pEditView->pImpEditView->nExtraCursorFlags = 0; + + if ( !bEmptyLine ) + { + String aLine( *aPaM.GetNode(), pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() ); +// USHORT nPosInLine = aPaM.GetIndex() - pLine->GetStart(); + + const sal_Unicode* pLineString = aLine.GetBuffer(); + + UErrorCode nError = U_ZERO_ERROR; + UBiDi* pBidi = ubidi_openSized( aLine.Len(), 0, &nError ); + + const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/; + ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), aLine.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW + + USHORT nVisPos = bStart ? 0 : aLine.Len()-1; + USHORT nLogPos = (USHORT)ubidi_getLogicalIndex( pBidi, nVisPos, &nError ); + + ubidi_close( pBidi ); + + aPaM.GetIndex() = nLogPos + pLine->GetStart(); + + USHORT nTmp; + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTmp, TRUE ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + USHORT nRTLLevel = pTextPortion->GetRightToLeft(); +// BOOL bParaRTL = IsRightToLeft( nPara ); + BOOL bPortionRTL = nRTLLevel%2 ? TRUE : FALSE; + + if ( bStart ) + { + pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 0 : 1 ); + // Maybe we must be *behind* the character + if ( bPortionRTL && pEditView->IsInsertMode() ) + aPaM.GetIndex()++; + } + else + { + pEditView->pImpEditView->SetCursorBidiLevel( bPortionRTL ? 1 : 0 ); + if ( !bPortionRTL && pEditView->IsInsertMode() ) + aPaM.GetIndex()++; + } + } + + return aPaM; +} + +EditPaM ImpEditEngine::CursorVisualLeftRight( EditView* pEditView, const EditPaM& rPaM, USHORT nCharacterIteratorMode, BOOL bVisualToLeft ) +{ + EditPaM aPaM( rPaM ); + + USHORT nPara = GetEditDoc().GetPos( aPaM.GetNode() ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + + USHORT nLine = pParaPortion->GetLines().FindLine( aPaM.GetIndex(), sal_False ); + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + BOOL bEmptyLine = pLine->GetStart() == pLine->GetEnd(); + +// USHORT nCurrentCursorFlags = pEditView->pImpEditView->nExtraCursorFlags; + pEditView->pImpEditView->nExtraCursorFlags = 0; + + BOOL bParaRTL = IsRightToLeft( nPara ); + + BOOL bDone = FALSE; + + if ( bEmptyLine ) + { + if ( bVisualToLeft ) + { + aPaM = CursorUp( aPaM, pEditView ); + if ( aPaM != rPaM ) + aPaM = CursorVisualStartEnd( pEditView, aPaM, FALSE ); + } + else + { + aPaM = CursorDown( aPaM, pEditView ); + if ( aPaM != rPaM ) + aPaM = CursorVisualStartEnd( pEditView, aPaM, TRUE ); + } + + bDone = TRUE; + } + + BOOL bLogicalBackward = bParaRTL ? !bVisualToLeft : bVisualToLeft; + + if ( !bDone && pEditView->IsInsertMode() ) + { + // Check if we are within a portion and don't have overwrite mode, then it's easy... + USHORT nPortionStart; + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, FALSE ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + + BOOL bPortionBoundary = ( aPaM.GetIndex() == nPortionStart ) || ( aPaM.GetIndex() == (nPortionStart+pTextPortion->GetLen()) ); + USHORT nRTLLevel = pTextPortion->GetRightToLeft(); + + // Portion boundary doesn't matter if both have same RTL level + USHORT nRTLLevelNextPortion = 0xFFFF; + if ( bPortionBoundary && aPaM.GetIndex() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) ) + { + USHORT nTmp; + USHORT nNextTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex()+1, nTmp, bLogicalBackward ? FALSE : TRUE ); + TextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nNextTextPortion ); + nRTLLevelNextPortion = pNextTextPortion->GetRightToLeft(); + } + + if ( !bPortionBoundary || ( nRTLLevel == nRTLLevelNextPortion ) ) + { + if ( ( bVisualToLeft && !(nRTLLevel%2) ) || ( !bVisualToLeft && (nRTLLevel%2) ) ) + { + aPaM = CursorLeft( aPaM, nCharacterIteratorMode ); + pEditView->pImpEditView->SetCursorBidiLevel( 1 ); + } + else + { + aPaM = CursorRight( aPaM, nCharacterIteratorMode ); + pEditView->pImpEditView->SetCursorBidiLevel( 0 ); + } + bDone = TRUE; + } + } + + if ( !bDone ) + { + BOOL bGotoStartOfNextLine = FALSE; + BOOL bGotoEndOfPrevLine = FALSE; + + String aLine( *aPaM.GetNode(), pLine->GetStart(), pLine->GetEnd() - pLine->GetStart() ); + USHORT nPosInLine = aPaM.GetIndex() - pLine->GetStart(); + + const sal_Unicode* pLineString = aLine.GetBuffer(); + + UErrorCode nError = U_ZERO_ERROR; + UBiDi* pBidi = ubidi_openSized( aLine.Len(), 0, &nError ); + + const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/; + ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(pLineString), aLine.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW + + if ( !pEditView->IsInsertMode() ) + { + BOOL bEndOfLine = nPosInLine == aLine.Len(); + USHORT nVisPos = (USHORT)ubidi_getVisualIndex( pBidi, !bEndOfLine ? nPosInLine : nPosInLine-1, &nError ); + if ( bVisualToLeft ) + { + bGotoEndOfPrevLine = nVisPos == 0; + if ( !bEndOfLine ) + nVisPos--; + } + else + { + bGotoStartOfNextLine = nVisPos == (aLine.Len() - 1); + if ( !bEndOfLine ) + nVisPos++; + } + + if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine ) + { + USHORT nLogPos = (USHORT)ubidi_getLogicalIndex( pBidi, nVisPos, &nError ); + aPaM.GetIndex() = pLine->GetStart() + nLogPos; + pEditView->pImpEditView->SetCursorBidiLevel( 0 ); + } + } + else + { + BOOL bWasBehind = FALSE; + BOOL bBeforePortion = !nPosInLine || pEditView->pImpEditView->GetCursorBidiLevel() == 1; + if ( nPosInLine && ( !bBeforePortion ) ) // before the next portion + bWasBehind = TRUE; // step one back, otherwise visual will be unusable when rtl portion follows. + + USHORT nPortionStart; + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, bBeforePortion ); + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + BOOL bRTLPortion = (pTextPortion->GetRightToLeft() % 2) != 0; + + // -1: We are 'behind' the character + long nVisPos = (long)ubidi_getVisualIndex( pBidi, bWasBehind ? nPosInLine-1 : nPosInLine, &nError ); + if ( bVisualToLeft ) + { + if ( !bWasBehind || bRTLPortion ) + nVisPos--; + } + else + { + if ( bWasBehind || bRTLPortion || bBeforePortion ) + nVisPos++; +// if ( bWasBehind && bRTLPortion ) +// nVisPos++; + } + + bGotoEndOfPrevLine = nVisPos < 0; + bGotoStartOfNextLine = nVisPos >= aLine.Len(); + + if ( !bGotoEndOfPrevLine && !bGotoStartOfNextLine ) + { + USHORT nLogPos = (USHORT)ubidi_getLogicalIndex( pBidi, nVisPos, &nError ); + +/* + if ( nLogPos == aPaM.GetIndex() ) + { + if ( bVisualToLeft ) + bGotoEndOfPrevLine = TRUE; + else + bGotoStartOfNextLine = TRUE; + } + else +*/ + { + aPaM.GetIndex() = pLine->GetStart() + nLogPos; + + // RTL portion, stay visually on the left side. + USHORT _nPortionStart; + // USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nPortionStart, !bRTLPortion ); + USHORT _nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), _nPortionStart, TRUE ); + TextPortion* _pTextPortion = pParaPortion->GetTextPortions().GetObject( _nTextPortion ); + if ( bVisualToLeft && !bRTLPortion && ( _pTextPortion->GetRightToLeft() % 2 ) ) + aPaM.GetIndex()++; + else if ( !bVisualToLeft && bRTLPortion && ( bWasBehind || !(_pTextPortion->GetRightToLeft() % 2 )) ) + aPaM.GetIndex()++; + + pEditView->pImpEditView->SetCursorBidiLevel( _nPortionStart ); + } + } + } + + ubidi_close( pBidi ); + + if ( bGotoEndOfPrevLine ) + { + aPaM = CursorUp( aPaM, pEditView ); + if ( aPaM != rPaM ) + aPaM = CursorVisualStartEnd( pEditView, aPaM, FALSE ); + } + else if ( bGotoStartOfNextLine ) + { + aPaM = CursorDown( aPaM, pEditView ); + if ( aPaM != rPaM ) + aPaM = CursorVisualStartEnd( pEditView, aPaM, TRUE ); + } + } + return aPaM; +} + + +EditPaM ImpEditEngine::CursorLeft( const EditPaM& rPaM, USHORT nCharacterIteratorMode ) +{ + EditPaM aCurPaM( rPaM ); + EditPaM aNewPaM( aCurPaM ); + + if ( aCurPaM.GetIndex() ) + { + sal_Int32 nCount = 1; + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + aNewPaM.SetIndex( (USHORT)_xBI->previousCharacters( *aNewPaM.GetNode(), aNewPaM.GetIndex(), GetLocale( aNewPaM ), nCharacterIteratorMode, nCount, nCount ) ); + } + else + { + ContentNode* pNode = aCurPaM.GetNode(); + pNode = GetPrevVisNode( pNode ); + if ( pNode ) + { + aNewPaM.SetNode( pNode ); + aNewPaM.SetIndex( pNode->Len() ); + } + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorRight( const EditPaM& rPaM, USHORT nCharacterIteratorMode ) +{ + EditPaM aCurPaM( rPaM ); + EditPaM aNewPaM( aCurPaM ); + + if ( aCurPaM.GetIndex() < aCurPaM.GetNode()->Len() ) + { + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + sal_Int32 nCount = 1; + aNewPaM.SetIndex( (USHORT)_xBI->nextCharacters( *aNewPaM.GetNode(), aNewPaM.GetIndex(), GetLocale( aNewPaM ), nCharacterIteratorMode, nCount, nCount ) ); + } + else + { + ContentNode* pNode = aCurPaM.GetNode(); + pNode = GetNextVisNode( pNode ); + if ( pNode ) + { + aNewPaM.SetNode( pNode ); + aNewPaM.SetIndex( 0 ); + } + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView* pView ) +{ + DBG_ASSERT( pView, "Keine View - Keine Cursorbewegung!" ); + + ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pPPortion, "Keine passende Portion gefunden: CursorUp" ); + USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex() ); + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + + long nX; + if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW ) + { + nX = GetXPos( pPPortion, pLine, rPaM.GetIndex() ); + pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef; + } + else + nX = pView->pImpEditView->nTravelXPos; + + EditPaM aNewPaM( rPaM ); + if ( nLine ) // gleicher Absatz + { + EditLine* pPrevLine = pPPortion->GetLines().GetObject(nLine-1); + aNewPaM.SetIndex( GetChar( pPPortion, pPrevLine, nX ) ); + // Wenn davor eine autom.Umgebrochene Zeile, und ich muss genau an das + // Ende dieser Zeile, landet der Cursor in der aktuellen Zeile am Anfang + // Siehe Problem: Letztes Zeichen einer autom.umgebr. Zeile = Cursor + if ( aNewPaM.GetIndex() && ( aNewPaM.GetIndex() == pLine->GetStart() ) ) + aNewPaM = CursorLeft( aNewPaM ); + } + else // vorheriger Absatz + { + ParaPortion* pPrevPortion = GetPrevVisPortion( pPPortion ); + if ( pPrevPortion ) + { + pLine = pPrevPortion->GetLines().GetObject( pPrevPortion->GetLines().Count()-1 ); + DBG_ASSERT( pLine, "Zeile davor nicht gefunden: CursorUp" ); + aNewPaM.SetNode( pPrevPortion->GetNode() ); + aNewPaM.SetIndex( GetChar( pPrevPortion, pLine, nX+nOnePixelInRef ) ); + } + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView* pView ) +{ + DBG_ASSERT( pView, "Keine View - Keine Cursorbewegung!" ); + + ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pPPortion, "Keine passende Portion gefunden: CursorDown" ); + USHORT nLine = pPPortion->GetLineNumber( rPaM.GetIndex() ); + + long nX; + if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW ) + { + EditLine* pLine = pPPortion->GetLines().GetObject(nLine); + nX = GetXPos( pPPortion, pLine, rPaM.GetIndex() ); + pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef; + } + else + nX = pView->pImpEditView->nTravelXPos; + + EditPaM aNewPaM( rPaM ); + if ( nLine < pPPortion->GetLines().Count()-1 ) + { + EditLine* pNextLine = pPPortion->GetLines().GetObject(nLine+1); + aNewPaM.SetIndex( GetChar( pPPortion, pNextLine, nX ) ); + // Sonderbehandlung siehe CursorUp... + if ( ( aNewPaM.GetIndex() == pNextLine->GetEnd() ) && ( aNewPaM.GetIndex() > pNextLine->GetStart() ) && ( aNewPaM.GetIndex() < pPPortion->GetNode()->Len() ) ) + aNewPaM = CursorLeft( aNewPaM ); + } + else // naechster Absatz + { + ParaPortion* pNextPortion = GetNextVisPortion( pPPortion ); + if ( pNextPortion ) + { + EditLine* pLine = pNextPortion->GetLines().GetObject(0); + DBG_ASSERT( pLine, "Zeile davor nicht gefunden: CursorUp" ); + aNewPaM.SetNode( pNextPortion->GetNode() ); + // Nie ganz ans Ende wenn mehrere Zeilen, da dann eine + // Zeile darunter der Cursor angezeigt wird. + aNewPaM.SetIndex( GetChar( pNextPortion, pLine, nX+nOnePixelInRef ) ); + if ( ( aNewPaM.GetIndex() == pLine->GetEnd() ) && ( aNewPaM.GetIndex() > pLine->GetStart() ) && ( pNextPortion->GetLines().Count() > 1 ) ) + aNewPaM = CursorLeft( aNewPaM ); + } + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM ) +{ + ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pCurPortion, "Keine Portion fuer den PaM ?" ); + USHORT nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() ); + EditLine* pLine = pCurPortion->GetLines().GetObject(nLine); + DBG_ASSERT( pLine, "Aktuelle Zeile nicht gefunden ?!" ); + + EditPaM aNewPaM( rPaM ); + aNewPaM.SetIndex( pLine->GetStart() ); + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorEndOfLine( const EditPaM& rPaM ) +{ + ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pCurPortion, "Keine Portion fuer den PaM ?" ); + USHORT nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() ); + EditLine* pLine = pCurPortion->GetLines().GetObject(nLine); + DBG_ASSERT( pLine, "Aktuelle Zeile nicht gefunden ?!" ); + + EditPaM aNewPaM( rPaM ); + aNewPaM.SetIndex( pLine->GetEnd() ); + if ( pLine->GetEnd() > pLine->GetStart() ) + { +// xub_Unicode cLastChar = aNewPaM.GetNode()->GetChar( aNewPaM.GetIndex()-1 ); + if ( aNewPaM.GetNode()->IsFeature( aNewPaM.GetIndex() - 1 ) ) + { + // Bei einem weichen Umbruch muss ich davor stehen! + EditCharAttrib* pNextFeature = aNewPaM.GetNode()->GetCharAttribs().FindFeature( aNewPaM.GetIndex()-1 ); + if ( pNextFeature && ( pNextFeature->GetItem()->Which() == EE_FEATURE_LINEBR ) ) + aNewPaM = CursorLeft( aNewPaM ); + } + else if ( ( aNewPaM.GetNode()->GetChar( aNewPaM.GetIndex() - 1 ) == ' ' ) && ( aNewPaM.GetIndex() != aNewPaM.GetNode()->Len() ) ) + { + // Bei einem Blank in einer autom. umgebrochenen Zeile macht es Sinn, + // davor zu stehen, da der Anwender hinter das Wort will. + // Wenn diese geaendert wird, Sonderbehandlung fuer Pos1 nach End! + aNewPaM = CursorLeft( aNewPaM ); + } + } + return aNewPaM; +} + +EditPaM ImpEditEngine::CursorStartOfParagraph( const EditPaM& rPaM ) +{ + EditPaM aPaM( rPaM.GetNode(), 0 ); + return aPaM; +} + +EditPaM ImpEditEngine::CursorEndOfParagraph( const EditPaM& rPaM ) +{ + EditPaM aPaM( rPaM.GetNode(), rPaM.GetNode()->Len() ); + return aPaM; +} + +EditPaM ImpEditEngine::CursorStartOfDoc() +{ + EditPaM aPaM( aEditDoc.SaveGetObject( 0 ), 0 ); + return aPaM; +} + +EditPaM ImpEditEngine::CursorEndOfDoc() +{ + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); + ParaPortion* pLastPortion = GetParaPortions().SaveGetObject( aEditDoc.Count()-1 ); + DBG_ASSERT( pLastNode && pLastPortion, "CursorEndOfDoc: Node oder Portion nicht gefunden" ); + + if ( !pLastPortion->IsVisible() ) + { + pLastNode = GetPrevVisNode( pLastPortion->GetNode() ); + DBG_ASSERT( pLastNode, "Kein sichtbarer Absatz?" ); + if ( !pLastNode ) + pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); + } + + EditPaM aPaM( pLastNode, pLastNode->Len() ); + return aPaM; +} + +EditPaM ImpEditEngine::PageUp( const EditPaM& rPaM, EditView* pView ) +{ + Rectangle aRec = PaMtoEditCursor( rPaM ); + Point aTopLeft = aRec.TopLeft(); + aTopLeft.Y() -= pView->GetVisArea().GetHeight() *9/10; + aTopLeft.X() += nOnePixelInRef; + if ( aTopLeft.Y() < 0 ) + { + aTopLeft.Y() = 0; + } + return GetPaM( aTopLeft ); +} + +EditPaM ImpEditEngine::PageDown( const EditPaM& rPaM, EditView* pView ) +{ + Rectangle aRec = PaMtoEditCursor( rPaM ); + Point aBottomRight = aRec.BottomRight(); + aBottomRight.Y() += pView->GetVisArea().GetHeight() *9/10; + aBottomRight.X() += nOnePixelInRef; + long nHeight = GetTextHeight(); + if ( aBottomRight.Y() > nHeight ) + { + aBottomRight.Y() = nHeight-2; + } + return GetPaM( aBottomRight ); +} + +EditPaM ImpEditEngine::WordLeft( const EditPaM& rPaM, sal_Int16 nWordType ) +{ + USHORT nCurrentPos = rPaM.GetIndex(); + EditPaM aNewPaM( rPaM ); + if ( nCurrentPos == 0 ) + { + // Vorheriger Absatz... + USHORT nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() ); + ContentNode* pPrevNode = aEditDoc.SaveGetObject( --nCurPara ); + if ( pPrevNode ) + { + aNewPaM.SetNode( pPrevNode ); + aNewPaM.SetIndex( pPrevNode->Len() ); + } + } + else + { + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aNewPaM ); + xub_StrLen nMax = rPaM.GetNode()->Len(); + if ( aTmpPaM.GetIndex() < nMax ) + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + i18n::Boundary aBoundary = _xBI->getWordBoundary( *aNewPaM.GetNode(), nCurrentPos, aLocale, nWordType, sal_True ); + if ( aBoundary.startPos >= nCurrentPos ) + aBoundary = _xBI->previousWord( *aNewPaM.GetNode(), nCurrentPos, aLocale, nWordType ); + aNewPaM.SetIndex( ( aBoundary.startPos != (-1) ) ? (USHORT)aBoundary.startPos : 0 ); + } + + return aNewPaM; +} + +EditPaM ImpEditEngine::WordRight( const EditPaM& rPaM, sal_Int16 nWordType ) +{ + xub_StrLen nMax = rPaM.GetNode()->Len(); + EditPaM aNewPaM( rPaM ); + if ( aNewPaM.GetIndex() < nMax ) + { + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aNewPaM ); + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + i18n::Boundary aBoundary = _xBI->nextWord( *aNewPaM.GetNode(), aNewPaM.GetIndex(), aLocale, nWordType ); + aNewPaM.SetIndex( (USHORT)aBoundary.startPos ); + } + // not 'else', maybe the index reached nMax now... + if ( aNewPaM.GetIndex() >= nMax ) + { + // Naechster Absatz... + USHORT nCurPara = aEditDoc.GetPos( aNewPaM.GetNode() ); + ContentNode* pNextNode = aEditDoc.SaveGetObject( ++nCurPara ); + if ( pNextNode ) + { + aNewPaM.SetNode( pNextNode ); + aNewPaM.SetIndex( 0 ); + } + } + return aNewPaM; +} + +EditPaM ImpEditEngine::StartOfWord( const EditPaM& rPaM, sal_Int16 nWordType ) +{ + EditPaM aNewPaM( rPaM ); + + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aNewPaM ); + xub_StrLen nMax = rPaM.GetNode()->Len(); + if ( aTmpPaM.GetIndex() < nMax ) + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + i18n::Boundary aBoundary = _xBI->getWordBoundary( *rPaM.GetNode(), rPaM.GetIndex(), aLocale, nWordType, sal_True ); + aNewPaM.SetIndex( (USHORT)aBoundary.startPos ); + return aNewPaM; +} + +EditPaM ImpEditEngine::EndOfWord( const EditPaM& rPaM, sal_Int16 nWordType ) +{ + EditPaM aNewPaM( rPaM ); + + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aNewPaM ); + xub_StrLen nMax = rPaM.GetNode()->Len(); + if ( aTmpPaM.GetIndex() < nMax ) + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + i18n::Boundary aBoundary = _xBI->getWordBoundary( *rPaM.GetNode(), rPaM.GetIndex(), aLocale, nWordType, sal_True ); + aNewPaM.SetIndex( (USHORT)aBoundary.endPos ); + return aNewPaM; +} + +EditSelection ImpEditEngine::SelectWord( const EditSelection& rCurSel, sal_Int16 nWordType, BOOL bAcceptStartOfWord ) +{ + EditSelection aNewSel( rCurSel ); + EditPaM aPaM( rCurSel.Max() ); + + // we need to increase the position by 1 when retrieving the locale + // since the attribute for the char left to the cursor position is returned + EditPaM aTmpPaM( aPaM ); + xub_StrLen nMax = aPaM.GetNode()->Len(); + if ( aTmpPaM.GetIndex() < nMax ) + aTmpPaM.SetIndex( aTmpPaM.GetIndex() + 1 ); + lang::Locale aLocale( GetLocale( aTmpPaM ) ); + + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + sal_Int16 nType = _xBI->getWordType( *aPaM.GetNode(), aPaM.GetIndex(), aLocale ); + if ( nType == i18n::WordType::ANY_WORD ) + { + i18n::Boundary aBoundary = _xBI->getWordBoundary( *aPaM.GetNode(), aPaM.GetIndex(), aLocale, nWordType, sal_True ); + // don't select when curser at end of word + if ( ( aBoundary.endPos > aPaM.GetIndex() ) && + ( ( aBoundary.startPos < aPaM.GetIndex() ) || ( bAcceptStartOfWord && ( aBoundary.startPos == aPaM.GetIndex() ) ) ) ) + { + aNewSel.Min().SetIndex( (USHORT)aBoundary.startPos ); + aNewSel.Max().SetIndex( (USHORT)aBoundary.endPos ); + } + } + + return aNewSel; +} + +EditSelection ImpEditEngine::SelectSentence( const EditSelection& rCurSel ) +{ + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + const EditPaM& rPaM = rCurSel.Min(); + const ContentNode* pNode = rPaM.GetNode(); + // #i50710# line breaks are marked with 0x01 - the break iterator prefers 0x0a for that + String sParagraph(*pNode); + sParagraph.SearchAndReplaceAll(0x01,0x0a); + //return Null if search starts at the beginning of the string + long nStart = rPaM.GetIndex() ? _xBI->beginOfSentence( sParagraph, rPaM.GetIndex(), GetLocale( rPaM ) ) : 0; + + long nEnd = _xBI->endOfSentence( *pNode, rPaM.GetIndex(), GetLocale( rPaM ) ); + EditSelection aNewSel( rCurSel ); + DBG_ASSERT(nStart < pNode->Len() && nEnd <= pNode->Len(), "sentence indices out of range"); + aNewSel.Min().SetIndex( (USHORT)nStart ); + aNewSel.Max().SetIndex( (USHORT)nEnd ); + return aNewSel; +} + +sal_Bool ImpEditEngine::IsInputSequenceCheckingRequired( sal_Unicode nChar, const EditSelection& rCurSel ) const +{ + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + if (!pCTLOptions) + pCTLOptions = new SvtCTLOptions; + + // get the index that really is first + USHORT nFirstPos = rCurSel.Min().GetIndex(); + USHORT nMaxPos = rCurSel.Max().GetIndex(); + if (nMaxPos < nFirstPos) + nFirstPos = nMaxPos; + + sal_Bool bIsSequenceChecking = + pCTLOptions->IsCTLFontEnabled() && + pCTLOptions->IsCTLSequenceChecking() && + nFirstPos != 0 && /* first char needs not to be checked */ + _xBI.is() && i18n::ScriptType::COMPLEX == _xBI->getScriptType( rtl::OUString( nChar ), 0 ); + + return bIsSequenceChecking; +} + +/************************************************************************* + * lcl_HasStrongLTR + *************************************************************************/ + bool lcl_HasStrongLTR ( const String& rTxt, xub_StrLen nStart, xub_StrLen nEnd ) + { + for ( xub_StrLen nCharIdx = nStart; nCharIdx < nEnd; ++nCharIdx ) + { + const UCharDirection nCharDir = u_charDirection ( rTxt.GetChar ( nCharIdx )); + if ( nCharDir == U_LEFT_TO_RIGHT || + nCharDir == U_LEFT_TO_RIGHT_EMBEDDING || + nCharDir == U_LEFT_TO_RIGHT_OVERRIDE ) + return true; + } + return false; + } + + + +void ImpEditEngine::InitScriptTypes( USHORT nPara ) +{ + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + rTypes.Remove( 0, rTypes.Count() ); + +// pParaPortion->aExtraCharInfos.Remove( 0, pParaPortion->aExtraCharInfos.Count() ); + + ContentNode* pNode = pParaPortion->GetNode(); + if ( pNode->Len() ) + { + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + + String aText( *pNode ); + + // To handle fields put the character from the field in the string, + // because endOfScript( ... ) will skip the CH_FEATURE, because this is WEAK + EditCharAttrib* pField = pNode->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD, 0 ); + while ( pField ) + { + ::rtl::OUString aFldText( ((EditCharAttribField*)pField)->GetFieldValue() ); + if ( aFldText.getLength() ) + { + aText.SetChar( pField->GetStart(), aFldText.getStr()[0] ); + short nFldScriptType = _xBI->getScriptType( aFldText, 0 ); + + for ( USHORT nCharInField = 1; nCharInField < aFldText.getLength(); nCharInField++ ) + { + short nTmpType = _xBI->getScriptType( aFldText, nCharInField ); + + // First char from field wins... + if ( nFldScriptType == i18n::ScriptType::WEAK ) + { + nFldScriptType = nTmpType; + aText.SetChar( pField->GetStart(), aFldText.getStr()[nCharInField] ); + } + + // ... but if the first one is LATIN, and there are CJK or CTL chars too, + // we prefer that ScripType because we need an other font. + if ( ( nTmpType == i18n::ScriptType::ASIAN ) || ( nTmpType == i18n::ScriptType::COMPLEX ) ) + { + aText.SetChar( pField->GetStart(), aFldText.getStr()[nCharInField] ); + break; + } + } + } + // #112831# Last Field might go from 0xffff to 0x0000 + pField = pField->GetEnd() ? pNode->GetCharAttribs().FindNextAttrib( EE_FEATURE_FIELD, pField->GetEnd() ) : NULL; + } + + ::rtl::OUString aOUText( aText ); + USHORT nTextLen = (USHORT)aOUText.getLength(); + + sal_Int32 nPos = 0; + short nScriptType = _xBI->getScriptType( aOUText, nPos ); + rTypes.Insert( ScriptTypePosInfo( nScriptType, (USHORT)nPos, nTextLen ), rTypes.Count() ); + nPos = _xBI->endOfScript( aOUText, nPos, nScriptType ); + while ( ( nPos != (-1) ) && ( nPos < nTextLen ) ) + { + rTypes[rTypes.Count()-1].nEndPos = (USHORT)nPos; + + nScriptType = _xBI->getScriptType( aOUText, nPos ); + long nEndPos = _xBI->endOfScript( aOUText, nPos, nScriptType ); + + if ( ( nScriptType == i18n::ScriptType::WEAK ) || ( nScriptType == rTypes[rTypes.Count()-1].nScriptType ) ) + { + // Expand last ScriptTypePosInfo, don't create weak or unecessary portions + rTypes[rTypes.Count()-1].nEndPos = (USHORT)nEndPos; + } + else + { + if ( _xBI->getScriptType( aOUText, nPos - 1 ) == i18n::ScriptType::WEAK ) + { + switch ( u_charType(aOUText.iterateCodePoints(&nPos, 0) ) ) { + case U_NON_SPACING_MARK: + case U_ENCLOSING_MARK: + case U_COMBINING_SPACING_MARK: + --nPos; + rTypes[rTypes.Count()-1].nEndPos--; + break; + } + } + rTypes.Insert( ScriptTypePosInfo( nScriptType, (USHORT)nPos, nTextLen ), rTypes.Count() ); + } + + nPos = nEndPos; + } + + if ( rTypes[0].nScriptType == i18n::ScriptType::WEAK ) + rTypes[0].nScriptType = ( rTypes.Count() > 1 ) ? rTypes[1].nScriptType : GetI18NScriptTypeOfLanguage( GetDefaultLanguage() ); + + // create writing direction information: + if ( !pParaPortion->aWritingDirectionInfos.Count() ) + InitWritingDirections( nPara ); + + // i89825: Use CTL font for numbers embedded into an RTL run: + WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos; + for ( USHORT n = 0; n < rDirInfos.Count(); ++n ) + { + const xub_StrLen nStart = rDirInfos[n].nStartPos; + const xub_StrLen nEnd = rDirInfos[n].nEndPos; + const BYTE nCurrDirType = rDirInfos[n].nType; + + if ( nCurrDirType % 2 == UBIDI_RTL || // text in RTL run + ( nCurrDirType > UBIDI_LTR && !lcl_HasStrongLTR( aText, nStart, nEnd ) ) ) // non-strong text in embedded LTR run + { + USHORT nIdx = 0; + + // Skip entries in ScriptArray which are not inside the RTL run: + while ( nIdx < rTypes.Count() && rTypes[nIdx].nStartPos < nStart ) + ++nIdx; + + // Remove any entries *inside* the current run: + while ( nIdx < rTypes.Count() && rTypes[nIdx].nEndPos <= nEnd ) + rTypes.Remove( nIdx ); + + // special case: + if(nIdx < rTypes.Count() && rTypes[nIdx].nStartPos < nStart && rTypes[nIdx].nEndPos > nEnd) + { + rTypes.Insert( ScriptTypePosInfo( rTypes[nIdx].nScriptType, (USHORT)nEnd, rTypes[nIdx].nEndPos ), nIdx ); + rTypes[nIdx].nEndPos = nStart; + } + + if( nIdx ) + rTypes[nIdx - 1].nEndPos = nStart; + + rTypes.Insert( ScriptTypePosInfo( i18n::ScriptType::COMPLEX, (USHORT)nStart, (USHORT)nEnd), nIdx ); + ++nIdx; + + if( nIdx < rTypes.Count() ) + rTypes[nIdx].nStartPos = nEnd; + } + } + +#if OSL_DEBUG_LEVEL > 1 + USHORT nDebugStt = 0; + USHORT nDebugEnd = 0; + short nDebugType = 0; + for ( USHORT n = 0; n < rTypes.Count(); ++n ) + { + nDebugStt = rTypes[n].nStartPos; + nDebugEnd = rTypes[n].nEndPos; + nDebugType = rTypes[n].nScriptType; + } +#endif + } +} + +USHORT ImpEditEngine::GetScriptType( const EditPaM& rPaM, USHORT* pEndPos ) const +{ + USHORT nScriptType = 0; + + if ( pEndPos ) + *pEndPos = rPaM.GetNode()->Len(); + + if ( rPaM.GetNode()->Len() ) + { + USHORT nPara = GetEditDoc().GetPos( rPaM.GetNode() ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( nPara ); + + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + USHORT nPos = rPaM.GetIndex(); + for ( USHORT n = 0; n < rTypes.Count(); n++ ) + { + if ( ( rTypes[n].nStartPos <= nPos ) && ( rTypes[n].nEndPos >= nPos ) ) + { + nScriptType = rTypes[n].nScriptType; + if( pEndPos ) + *pEndPos = rTypes[n].nEndPos; + break; + } + } + } + return nScriptType ? nScriptType : GetI18NScriptTypeOfLanguage( GetDefaultLanguage() ); +} + +USHORT ImpEditEngine::GetScriptType( const EditSelection& rSel ) const +{ + EditSelection aSel( rSel ); + aSel.Adjust( aEditDoc ); + + short nScriptType = 0; + + USHORT nStartPara = GetEditDoc().GetPos( aSel.Min().GetNode() ); + USHORT nEndPara = GetEditDoc().GetPos( aSel.Max().GetNode() ); + + for ( USHORT nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( nPara ); + + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + + // find the first(!) script type position that holds the + // complete selection. Thus it will work for selections as + // well as with just moving the cursor from char to char. + USHORT nS = ( nPara == nStartPara ) ? aSel.Min().GetIndex() : 0; + USHORT nE = ( nPara == nEndPara ) ? aSel.Max().GetIndex() : pParaPortion->GetNode()->Len(); + for ( USHORT n = 0; n < rTypes.Count(); n++ ) + { + if (rTypes[n].nStartPos <= nS && nE <= rTypes[n].nEndPos) + { + if ( rTypes[n].nScriptType != i18n::ScriptType::WEAK ) + { + nScriptType |= GetItemScriptType ( rTypes[n].nScriptType ); + } + else + { + if ( !nScriptType && n ) + { + // #93548# When starting with WEAK, use prev ScriptType... + nScriptType = rTypes[n-1].nScriptType; + } + } + break; + } + } + } + return nScriptType ? nScriptType : GetI18NScriptTypeOfLanguage( GetDefaultLanguage() ); +} + +BOOL ImpEditEngine::IsScriptChange( const EditPaM& rPaM ) const +{ + BOOL bScriptChange = FALSE; + + if ( rPaM.GetNode()->Len() ) + { + USHORT nPara = GetEditDoc().GetPos( rPaM.GetNode() ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( nPara ); + + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + USHORT nPos = rPaM.GetIndex(); + for ( USHORT n = 0; n < rTypes.Count(); n++ ) + { + if ( rTypes[n].nStartPos == nPos ) + { + bScriptChange = TRUE; + break; + } + } + } + return bScriptChange; +} + +BOOL ImpEditEngine::HasScriptType( USHORT nPara, USHORT nType ) const +{ + BOOL bTypeFound = FALSE; + + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( nPara ); + + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + for ( USHORT n = rTypes.Count(); n && !bTypeFound; ) + { + if ( rTypes[--n].nScriptType == nType ) + bTypeFound = TRUE; + } + return bTypeFound; +} + +void ImpEditEngine::InitWritingDirections( USHORT nPara ) +{ + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + WritingDirectionInfos& rInfos = pParaPortion->aWritingDirectionInfos; + rInfos.Remove( 0, rInfos.Count() ); + + BOOL bCTL = FALSE; + ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + for ( USHORT n = 0; n < rTypes.Count(); n++ ) + { + if ( rTypes[n].nScriptType == i18n::ScriptType::COMPLEX ) + { + bCTL = TRUE; + break; + } + } + + const UBiDiLevel nBidiLevel = IsRightToLeft( nPara ) ? 1 /*RTL*/ : 0 /*LTR*/; + if ( ( bCTL || ( nBidiLevel == 1 /*RTL*/ ) ) && pParaPortion->GetNode()->Len() ) + { + + String aText( *pParaPortion->GetNode() ); + + // + // Bidi functions from icu 2.0 + // + UErrorCode nError = U_ZERO_ERROR; + UBiDi* pBidi = ubidi_openSized( aText.Len(), 0, &nError ); + nError = U_ZERO_ERROR; + + ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aText.GetBuffer()), aText.Len(), nBidiLevel, NULL, &nError ); // UChar != sal_Unicode in MinGW + nError = U_ZERO_ERROR; + + long nCount = ubidi_countRuns( pBidi, &nError ); + + int32_t nStart = 0; + int32_t nEnd; + UBiDiLevel nCurrDir; + + for ( USHORT nIdx = 0; nIdx < nCount; ++nIdx ) + { + ubidi_getLogicalRun( pBidi, nStart, &nEnd, &nCurrDir ); + rInfos.Insert( WritingDirectionInfo( nCurrDir, (USHORT)nStart, (USHORT)nEnd ), rInfos.Count() ); + nStart = nEnd; + } + + ubidi_close( pBidi ); + } + + // No infos mean no CTL and default dir is L2R... + if ( !rInfos.Count() ) + rInfos.Insert( WritingDirectionInfo( 0, 0, (USHORT)pParaPortion->GetNode()->Len() ), rInfos.Count() ); + +} + +BOOL ImpEditEngine::IsRightToLeft( USHORT nPara ) const +{ + BOOL bR2L = FALSE; + const SvxFrameDirectionItem* pFrameDirItem = NULL; + + if ( !IsVertical() ) + { + bR2L = GetDefaultHorizontalTextDirection() == EE_HTEXTDIR_R2L; + pFrameDirItem = &(const SvxFrameDirectionItem&)GetParaAttrib( nPara, EE_PARA_WRITINGDIR ); + if ( pFrameDirItem->GetValue() == FRMDIR_ENVIRONMENT ) + { + // #103045# if DefaultHorizontalTextDirection is set, use that value, otherwise pool default. + if ( GetDefaultHorizontalTextDirection() != EE_HTEXTDIR_DEFAULT ) + { + pFrameDirItem = NULL; // bR2L allready set to default horizontal text direction + } + else + { + // Use pool default + pFrameDirItem = &(const SvxFrameDirectionItem&)((ImpEditEngine*)this)->GetEmptyItemSet().Get( EE_PARA_WRITINGDIR ); + } + } + } + + if ( pFrameDirItem ) + bR2L = pFrameDirItem->GetValue() == FRMDIR_HORI_RIGHT_TOP; + + return bR2L; +} + +BOOL ImpEditEngine::HasDifferentRTLLevels( const ContentNode* pNode ) +{ + USHORT nPara = GetEditDoc().GetPos( (ContentNode*)pNode ); + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + + BOOL bHasDifferentRTLLevels = FALSE; + + USHORT nRTLLevel = IsRightToLeft( nPara ) ? 1 : 0; + for ( USHORT n = 0; n < pParaPortion->GetTextPortions().Count(); n++ ) + { + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject( n ); + if ( pTextPortion->GetRightToLeft() != nRTLLevel ) + { + bHasDifferentRTLLevels = TRUE; + break; + } + } + return bHasDifferentRTLLevels; +} + + +BYTE ImpEditEngine::GetRightToLeft( USHORT nPara, USHORT nPos, USHORT* pStart, USHORT* pEnd ) +{ +// BYTE nRightToLeft = IsRightToLeft( nPara ) ? 1 : 0; + BYTE nRightToLeft = 0; + + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + if ( pNode && pNode->Len() ) + { + ParaPortion* pParaPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pParaPortion->aWritingDirectionInfos.Count() ) + InitWritingDirections( nPara ); + +// BYTE nType = 0; + WritingDirectionInfos& rDirInfos = pParaPortion->aWritingDirectionInfos; + for ( USHORT n = 0; n < rDirInfos.Count(); n++ ) + { + if ( ( rDirInfos[n].nStartPos <= nPos ) && ( rDirInfos[n].nEndPos >= nPos ) ) + { + nRightToLeft = rDirInfos[n].nType; + if ( pStart ) + *pStart = rDirInfos[n].nStartPos; + if ( pEnd ) + *pEnd = rDirInfos[n].nEndPos; + break; + } + } + } + return nRightToLeft; +} + +SvxAdjust ImpEditEngine::GetJustification( USHORT nPara ) const +{ + SvxAdjust eJustification = SVX_ADJUST_LEFT; + + if ( !aStatus.IsOutliner() ) + { + eJustification = ((const SvxAdjustItem&) GetParaAttrib( nPara, EE_PARA_JUST )).GetAdjust(); + + if ( IsRightToLeft( nPara ) ) + { + if ( eJustification == SVX_ADJUST_LEFT ) + eJustification = SVX_ADJUST_RIGHT; + else if ( eJustification == SVX_ADJUST_RIGHT ) + eJustification = SVX_ADJUST_LEFT; + } + } + return eJustification; +} + + +// ---------------------------------------------------------------------- +// Textaenderung +// ---------------------------------------------------------------------- + +void ImpEditEngine::ImpRemoveChars( const EditPaM& rPaM, USHORT nChars, EditUndoRemoveChars* pCurUndo ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + XubString aStr( rPaM.GetNode()->Copy( rPaM.GetIndex(), nChars ) ); + + // Pruefen, ob Attribute geloescht oder geaendert werden: + USHORT nStart = rPaM.GetIndex(); + USHORT nEnd = nStart + nChars; + CharAttribArray& rAttribs = rPaM.GetNode()->GetCharAttribs().GetAttribs(); +// USHORT nAttrs = rAttribs.Count(); + for ( USHORT nAttr = 0; nAttr < rAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttribs[nAttr]; + if ( ( pAttr->GetEnd() >= nStart ) && ( pAttr->GetStart() < nEnd ) ) + { +#ifndef SVX_LIGHT + EditSelection aSel( rPaM ); + aSel.Max().GetIndex() = aSel.Max().GetIndex() + nChars; + EditUndoSetAttribs* pAttrUndo = CreateAttribUndo( aSel, GetEmptyItemSet() ); + InsertUndo( pAttrUndo ); +#endif + break; // for + } + } + if ( pCurUndo && ( CreateEditPaM( pCurUndo->GetEPaM() ) == rPaM ) ) + pCurUndo->GetStr() += aStr; +#ifndef SVX_LIGHT + else + InsertUndo( new EditUndoRemoveChars( this, CreateEPaM( rPaM ), aStr ) ); +#endif + } + + aEditDoc.RemoveChars( rPaM, nChars ); + TextModified(); +} + +EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, USHORT nNewPos ) +{ + aOldPositions.Justify(); + BOOL bValidAction = ( (long)nNewPos < aOldPositions.Min() ) || ( (long)nNewPos > aOldPositions.Max() ); + DBG_ASSERT( bValidAction, "Move in sich selbst ?" ); + DBG_ASSERT( aOldPositions.Max() <= (long)GetParaPortions().Count(), "Voll drueber weg: MoveParagraphs" ); + + EditSelection aSelection; + + if ( !bValidAction ) + { + aSelection = aEditDoc.GetStartPaM(); + return aSelection; + } + + ULONG nParaCount = GetParaPortions().Count(); + + if ( nNewPos >= nParaCount ) + nNewPos = GetParaPortions().Count(); + + // Height may change when moving first or last Paragraph + ParaPortion* pRecalc1 = NULL; + ParaPortion* pRecalc2 = NULL; + ParaPortion* pRecalc3 = NULL; + ParaPortion* pRecalc4 = NULL; + + if ( nNewPos == 0 ) // Move to Start + { + pRecalc1 = GetParaPortions().GetObject( 0 ); + pRecalc2 = GetParaPortions().GetObject( (USHORT)aOldPositions.Min() ); + + } + else if ( nNewPos == nParaCount ) + { + pRecalc1 = GetParaPortions().GetObject( (USHORT)(nParaCount-1) ); + pRecalc2 = GetParaPortions().GetObject( (USHORT)aOldPositions.Max() ); + } + + if ( aOldPositions.Min() == 0 ) // Move from Start + { + pRecalc3 = GetParaPortions().GetObject( 0 ); + pRecalc4 = GetParaPortions().GetObject( + sal::static_int_cast< USHORT >( aOldPositions.Max()+1 ) ); + } + else if ( (USHORT)aOldPositions.Max() == (nParaCount-1) ) + { + pRecalc3 = GetParaPortions().GetObject( (USHORT)aOldPositions.Max() ); + pRecalc4 = GetParaPortions().GetObject( (USHORT)(aOldPositions.Min()-1) ); + } + + MoveParagraphsInfo aMoveParagraphsInfo( sal::static_int_cast< USHORT >(aOldPositions.Min()), sal::static_int_cast< USHORT >(aOldPositions.Max()), nNewPos ); + aBeginMovingParagraphsHdl.Call( &aMoveParagraphsInfo ); + + if ( IsUndoEnabled() && !IsInUndo()) + InsertUndo( new EditUndoMoveParagraphs( this, aOldPositions, nNewPos ) ); + + // Position nicht aus dem Auge verlieren! + ParaPortion* pDestPortion = GetParaPortions().SaveGetObject( nNewPos ); + + ParaPortionList aTmpPortionList; + USHORT i; + for ( i = (USHORT)aOldPositions.Min(); i <= (USHORT)aOldPositions.Max(); i++ ) + { + // Immer aOldPositions.Min(), da Remove(). + ParaPortion* pTmpPortion = GetParaPortions().GetObject( (USHORT)aOldPositions.Min() ); + GetParaPortions().Remove( (USHORT)aOldPositions.Min() ); + aEditDoc.Remove( (USHORT)aOldPositions.Min() ); + aTmpPortionList.Insert( pTmpPortion, aTmpPortionList.Count() ); + } + + USHORT nRealNewPos = pDestPortion ? GetParaPortions().GetPos( pDestPortion ) : GetParaPortions().Count(); + DBG_ASSERT( nRealNewPos != USHRT_MAX, "ImpMoveParagraphs: Ungueltige Position!" ); + + for ( i = 0; i < (USHORT)aTmpPortionList.Count(); i++ ) + { + ParaPortion* pTmpPortion = aTmpPortionList.GetObject( i ); + if ( i == 0 ) + aSelection.Min().SetNode( pTmpPortion->GetNode() ); + + aSelection.Max().SetNode( pTmpPortion->GetNode() ); + aSelection.Max().SetIndex( pTmpPortion->GetNode()->Len() ); + + ContentNode* pN = pTmpPortion->GetNode(); + aEditDoc.Insert( pN, nRealNewPos+i ); + + GetParaPortions().Insert( pTmpPortion, nRealNewPos+i ); + } + + aEndMovingParagraphsHdl.Call( &aMoveParagraphsInfo ); + + if ( GetNotifyHdl().IsSet() ) + { + EENotify aNotify( EE_NOTIFY_PARAGRAPHSMOVED ); + aNotify.pEditEngine = GetEditEnginePtr(); + aNotify.nParagraph = nNewPos; + aNotify.nParam1 = sal::static_int_cast< USHORT >(aOldPositions.Min()); + aNotify.nParam2 = sal::static_int_cast< USHORT >(aOldPositions.Max()); + CallNotify( aNotify ); + } + + aEditDoc.SetModified( TRUE ); + + if ( pRecalc1 ) + CalcHeight( pRecalc1 ); + if ( pRecalc2 ) + CalcHeight( pRecalc2 ); + if ( pRecalc3 ) + CalcHeight( pRecalc3 ); + if ( pRecalc4 ) + CalcHeight( pRecalc4 ); + + aTmpPortionList.Remove( 0, aTmpPortionList.Count() ); // wichtig ! + +#ifdef EDITDEBUG + GetParaPortions().DbgCheck(aEditDoc); +#endif + return aSelection; +} + + +EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pRight, BOOL bBackward ) +{ + DBG_ASSERT( pLeft != pRight, "Den gleichen Absatz zusammenfuegen ?" ); + DBG_ASSERT( aEditDoc.GetPos( pLeft ) != USHRT_MAX, "Einzufuegenden Node nicht gefunden(1)" ); + DBG_ASSERT( aEditDoc.GetPos( pRight ) != USHRT_MAX, "Einzufuegenden Node nicht gefunden(2)" ); + + USHORT nParagraphTobeDeleted = aEditDoc.GetPos( pRight ); + DeletedNodeInfo* pInf = new DeletedNodeInfo( (ULONG)pRight, nParagraphTobeDeleted ); + aDeletedNodes.Insert( pInf, aDeletedNodes.Count() ); + + GetEditEnginePtr()->ParagraphConnected( aEditDoc.GetPos( pLeft ), aEditDoc.GetPos( pRight ) ); + +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + { + InsertUndo( new EditUndoConnectParas( this, + aEditDoc.GetPos( pLeft ), pLeft->Len(), + pLeft->GetContentAttribs().GetItems(), pRight->GetContentAttribs().GetItems(), + pLeft->GetStyleSheet(), pRight->GetStyleSheet(), bBackward ) ); + } +#endif + + if ( bBackward ) + { + pLeft->SetStyleSheet( pRight->GetStyleSheet(), TRUE ); + pLeft->GetContentAttribs().GetItems().Set( pRight->GetContentAttribs().GetItems() ); + pLeft->GetCharAttribs().GetDefFont() = pRight->GetCharAttribs().GetDefFont(); + } + + ParaAttribsChanged( pLeft ); + + // Erstmal Portions suchen, da pRight nach ConnectParagraphs weg. + ParaPortion* pLeftPortion = FindParaPortion( pLeft ); + ParaPortion* pRightPortion = FindParaPortion( pRight ); + DBG_ASSERT( pLeftPortion, "Blinde Portion in ImpConnectParagraphs(1)" ); + DBG_ASSERT( pRightPortion, "Blinde Portion in ImpConnectParagraphs(2)" ); + DBG_ASSERT( nParagraphTobeDeleted == GetParaPortions().GetPos( pRightPortion ), "NodePos != PortionPos?" ); + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() ) + { + xub_StrLen nEnd = pLeft->Len(); + xub_StrLen nInv = nEnd ? nEnd-1 : nEnd; + pLeft->GetWrongList()->ClearWrongs( nInv, 0xFFFF, pLeft ); // Evtl. einen wegnehmen + pLeft->GetWrongList()->MarkInvalid( nInv, nEnd+1 ); + // Falschgeschriebene Woerter ruebernehmen: + USHORT nRWrongs = pRight->GetWrongList()->Count(); + for ( USHORT nW = 0; nW < nRWrongs; nW++ ) + { + WrongRange aWrong = pRight->GetWrongList()->GetObject( nW ); + if ( aWrong.nStart != 0 ) // Nicht ein anschliessender + { + aWrong.nStart = aWrong.nStart + nEnd; + aWrong.nEnd = aWrong.nEnd + nEnd; + pLeft->GetWrongList()->InsertWrong( aWrong, pLeft->GetWrongList()->Count() ); + } + } + } +#endif + + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphDeleted( nParagraphTobeDeleted ); + + EditPaM aPaM = aEditDoc.ConnectParagraphs( pLeft, pRight ); + GetParaPortions().Remove( nParagraphTobeDeleted ); + delete pRightPortion; + + pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex(), pLeft->Len() ); + + // der rechte Node wird von EditDoc::ConnectParagraphs() geloescht. + + if ( GetTextRanger() ) + { + // Durch das zusammenfuegen wird der linke zwar neu formatiert, aber + // wenn sich dessen Hoehe nicht aendert bekommt die Formatierung die + // Aenderung der Gesaamthoehe des Textes zu spaet mit... + for ( USHORT n = nParagraphTobeDeleted; n < GetParaPortions().Count(); n++ ) + { + ParaPortion* pPP = GetParaPortions().GetObject( n ); + pPP->MarkSelectionInvalid( 0, pPP->GetNode()->Len() ); + pPP->GetLines().Reset(); + } + } + + TextModified(); + + return aPaM; +} + +EditPaM ImpEditEngine::DeleteLeftOrRight( const EditSelection& rSel, BYTE nMode, BYTE nDelMode ) +{ + DBG_ASSERT( !EditSelection( rSel ).DbgIsBuggy( aEditDoc ), "Index im Wald in DeleteLeftOrRight" ); + + if ( rSel.HasRange() ) // dann nur Sel. loeschen + return ImpDeleteSelection( rSel ); + + const EditPaM aCurPos( rSel.Max() ); + EditPaM aDelStart( aCurPos ); + EditPaM aDelEnd( aCurPos ); + if ( nMode == DEL_LEFT ) + { + if ( nDelMode == DELMODE_SIMPLE ) + { + aDelStart = CursorLeft( aCurPos, i18n::CharacterIteratorMode::SKIPCHARACTER ); + } + else if ( nDelMode == DELMODE_RESTOFWORD ) + { + aDelStart = StartOfWord( aCurPos ); + if ( aDelStart.GetIndex() == aCurPos.GetIndex() ) + aDelStart = WordLeft( aCurPos ); + } + else // DELMODE_RESTOFCONTENT + { + aDelStart.SetIndex( 0 ); + if ( aDelStart == aCurPos ) + { + // kompletter Absatz davor + ContentNode* pPrev = GetPrevVisNode( aCurPos.GetNode() ); + if ( pPrev ) + aDelStart = EditPaM( pPrev, 0 ); + } + } + } + else + { + if ( nDelMode == DELMODE_SIMPLE ) + { + aDelEnd = CursorRight( aCurPos ); + } + else if ( nDelMode == DELMODE_RESTOFWORD ) + { + aDelEnd = EndOfWord( aCurPos ); + if (aDelEnd.GetIndex() == aCurPos.GetIndex()) + { + xub_StrLen nLen = aCurPos.GetNode()->Len(); + // end of para? + if (aDelEnd.GetIndex() == nLen) + aDelEnd = WordLeft( aCurPos ); + else // there's still sth to delete on the right + { + aDelEnd = EndOfWord( WordRight( aCurPos ) ); + // if there'n no next word... + if (aDelEnd.GetIndex() == nLen ) + aDelEnd.SetIndex( nLen ); + } + } + } + else // DELMODE_RESTOFCONTENT + { + aDelEnd.SetIndex( aCurPos.GetNode()->Len() ); + if ( aDelEnd == aCurPos ) + { + // kompletter Absatz dahinter + ContentNode* pNext = GetNextVisNode( aCurPos.GetNode() ); + if ( pNext ) + aDelEnd = EditPaM( pNext, pNext->Len() ); + } + } + } + + // Bei DELMODE_RESTOFCONTENT reicht bei verschiedenen Nodes + // kein ConnectParagraphs. + if ( ( nDelMode == DELMODE_RESTOFCONTENT ) || ( aDelStart.GetNode() == aDelEnd.GetNode() ) ) + return ImpDeleteSelection( EditSelection( aDelStart, aDelEnd ) ); + + // Jetzt entscheiden, ob noch Selektion loeschen (RESTOFCONTENTS) + BOOL bSpecialBackward = ( ( nMode == DEL_LEFT ) && ( nDelMode == DELMODE_SIMPLE ) ) + ? TRUE : FALSE; + if ( aStatus.IsAnyOutliner() ) + bSpecialBackward = FALSE; + + return ImpConnectParagraphs( aDelStart.GetNode(), aDelEnd.GetNode(), bSpecialBackward ); +} + +EditPaM ImpEditEngine::ImpDeleteSelection( EditSelection aSel ) +{ + if ( !aSel.HasRange() ) + return aSel.Min(); + + aSel.Adjust( aEditDoc ); + EditPaM aStartPaM( aSel.Min() ); + EditPaM aEndPaM( aSel.Max() ); + + CursorMoved( aStartPaM.GetNode() ); // nur damit neu eingestellte Attribute verschwinden... + CursorMoved( aEndPaM.GetNode() ); // nur damit neu eingestellte Attribute verschwinden... + + DBG_ASSERT( aStartPaM.GetIndex() <= aStartPaM.GetNode()->Len(), "Index im Wald in ImpDeleteSelection" ); + DBG_ASSERT( aEndPaM.GetIndex() <= aEndPaM.GetNode()->Len(), "Index im Wald in ImpDeleteSelection" ); + + USHORT nStartNode = aEditDoc.GetPos( aStartPaM.GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aEndPaM.GetNode() ); + + DBG_ASSERT( nEndNode != USHRT_MAX, "Start > End ?!" ); + DBG_ASSERT( nStartNode <= nEndNode, "Start > End ?!" ); + + // Alle Nodes dazwischen entfernen.... + for ( ULONG z = nStartNode+1; z < nEndNode; z++ ) + { + // Immer nStartNode+1, wegen Remove()! + ImpRemoveParagraph( nStartNode+1 ); + } + + if ( aStartPaM.GetNode() != aEndPaM.GetNode() ) + { + // Den Rest des StartNodes... + USHORT nChars; + nChars = aStartPaM.GetNode()->Len() - aStartPaM.GetIndex(); + ImpRemoveChars( aStartPaM, nChars ); + ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteSelection(3)" ); + pPortion->MarkSelectionInvalid( aStartPaM.GetIndex(), aStartPaM.GetNode()->Len() ); + + // Den Anfang des EndNodes.... + nChars = aEndPaM.GetIndex(); + aEndPaM.SetIndex( 0 ); + ImpRemoveChars( aEndPaM, nChars ); + pPortion = FindParaPortion( aEndPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteSelection(4)" ); + pPortion->MarkSelectionInvalid( 0, aEndPaM.GetNode()->Len() ); + // Zusammenfuegen.... + aStartPaM = ImpConnectParagraphs( aStartPaM.GetNode(), aEndPaM.GetNode() ); + } + else + { + USHORT nChars; + nChars = aEndPaM.GetIndex() - aStartPaM.GetIndex(); + ImpRemoveChars( aStartPaM, nChars ); + ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpDeleteSelection(5)" ); + pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() ); + } + + UpdateSelections(); + TextModified(); + return aStartPaM; +} + +void ImpEditEngine::ImpRemoveParagraph( USHORT nPara ) +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + ContentNode* pNextNode = aEditDoc.SaveGetObject( nPara+1 ); + ParaPortion* pPortion = GetParaPortions().SaveGetObject( nPara ); + + DBG_ASSERT( pNode, "Blinder Node in ImpRemoveParagraph" ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpRemoveParagraph(2)" ); + + DeletedNodeInfo* pInf = new DeletedNodeInfo( (ULONG)pNode, nPara ); + aDeletedNodes.Insert( pInf, aDeletedNodes.Count() ); + + // Der Node wird vom Undo verwaltet und ggf. zerstoert! + /* delete */ aEditDoc.Remove( nPara ); + GetParaPortions().Remove( nPara ); + delete pPortion; + + if ( IsCallParaInsertedOrDeleted() ) + { + GetEditEnginePtr()->ParagraphDeleted( nPara ); + } + + // Im folgenden muss ggf. Extra-Space neu ermittelt werden. + // Bei ParaAttribsChanged wird leider der Absatz neu formatiert, + // aber diese Methode sollte nicht Zeitkritsch sein! + if ( pNextNode ) + ParaAttribsChanged( pNextNode ); + +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoDelContent( this, pNode, nPara ) ); + else +#endif + { + aEditDoc.RemoveItemsFromPool( pNode ); + if ( pNode->GetStyleSheet() ) + EndListening( *pNode->GetStyleSheet(), FALSE ); + delete pNode; + } +} + +EditPaM ImpEditEngine::AutoCorrect( const EditSelection& rCurSel, xub_Unicode c, BOOL bOverwrite ) +{ + EditSelection aSel( rCurSel ); +#ifndef SVX_LIGHT + SvxAutoCorrect* pAutoCorrect = SvxAutoCorrCfg::Get()->GetAutoCorrect(); + if ( pAutoCorrect ) + { + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( rCurSel ); + + // #i78661 allow application to turn off capitalization of + // start sentence explicitly. + // (This is done by setting IsFirstWordCapitalization to FALSE.) + BOOL bOldCptlSttSntnc = pAutoCorrect->IsAutoCorrFlag( CptlSttSntnc ); + if (!IsFirstWordCapitalization()) + { + ESelection aESel( CreateESel(aSel) ); + EditSelection aFirstWordSel; + EditSelection aSecondWordSel; + if (aESel.nEndPara == 0) // is this the first para? + { + // select first word... + // start by checking if para starts with word. + aFirstWordSel = SelectWord( CreateSel(ESelection()) ); + if (aFirstWordSel.Min().GetIndex() == 0 && aFirstWordSel.Max().GetIndex() == 0) + { + // para does not start with word -> select next/first word + EditPaM aRightWord( WordRight( aFirstWordSel.Max(), 1 ) ); + aFirstWordSel = SelectWord( EditSelection( aRightWord ) ); + } + + // select second word + // (sometimes aSel mightnot point to the end of the first word + // but to some following char like '.'. ':', ... + // In those cases we need aSecondWordSel to see if aSel + // will actually effect the first word.) + EditPaM aRight2Word( WordRight( aFirstWordSel.Max(), 1 ) ); + aSecondWordSel = SelectWord( EditSelection( aRight2Word ) ); + } + BOOL bIsFirstWordInFirstPara = aESel.nEndPara == 0 && + aFirstWordSel.Max().GetIndex() <= aSel.Max().GetIndex() && + aSel.Max().GetIndex() <= aSecondWordSel.Min().GetIndex(); + + if (bIsFirstWordInFirstPara) + pAutoCorrect->SetAutoCorrFlag( CptlSttSntnc, IsFirstWordCapitalization() ); + } + + ContentNode* pNode = aSel.Max().GetNode(); + USHORT nIndex = aSel.Max().GetIndex(); + EdtAutoCorrDoc aAuto( this, pNode, nIndex, c ); + pAutoCorrect->AutoCorrect( aAuto, *pNode, nIndex, c, !bOverwrite ); + aSel.Max().SetIndex( aAuto.GetCursor() ); + + // #i78661 since the SvxAutoCorrect object used here is + // shared we need to reset the value to it's original state. + pAutoCorrect->SetAutoCorrFlag( CptlSttSntnc, bOldCptlSttSntnc ); + } +#endif // !SVX_LIGHT + return aSel.Max(); +} + + +EditPaM ImpEditEngine::InsertText( const EditSelection& rCurSel, + xub_Unicode c, BOOL bOverwrite, sal_Bool bIsUserInput ) +{ + DBG_ASSERT( c != '\t', "Tab bei InsertText ?" ); + DBG_ASSERT( c != '\n', "Zeilenumbruch bei InsertText ?" ); + + EditPaM aPaM( rCurSel.Min() ); + + BOOL bDoOverwrite = ( bOverwrite && + ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) ) ? TRUE : FALSE; + + BOOL bUndoAction = ( rCurSel.HasRange() || bDoOverwrite ); + + if ( bUndoAction ) + UndoActionStart( EDITUNDO_INSERT ); + + if ( rCurSel.HasRange() ) + { + aPaM = ImpDeleteSelection( rCurSel ); + } + else if ( bDoOverwrite ) + { + // Wenn Selektion, dann nicht auch noch ein Zeichen ueberschreiben! + EditSelection aTmpSel( aPaM ); + aTmpSel.Max().GetIndex()++; + DBG_ASSERT( !aTmpSel.DbgIsBuggy( aEditDoc ), "Overwrite: Fehlerhafte Selektion!" ); + ImpDeleteSelection( aTmpSel ); + } + + if ( aPaM.GetNode()->Len() < MAXCHARSINPARA ) + { + if (bIsUserInput && IsInputSequenceCheckingRequired( c, rCurSel )) + { + uno::Reference < i18n::XExtendedInputSequenceChecker > _xISC( ImplGetInputSequenceChecker() ); + if (!pCTLOptions) + pCTLOptions = new SvtCTLOptions; + + if (_xISC.is() || pCTLOptions) + { + xub_StrLen nTmpPos = aPaM.GetIndex(); + sal_Int16 nCheckMode = pCTLOptions->IsCTLSequenceCheckingRestricted() ? + i18n::InputSequenceCheckMode::STRICT : i18n::InputSequenceCheckMode::BASIC; + + // the text that needs to be checked is only the one + // before the current cursor position + rtl::OUString aOldText( aPaM.GetNode()->Copy(0, nTmpPos) ); + rtl::OUString aNewText( aOldText ); + if (pCTLOptions->IsCTLSequenceCheckingTypeAndReplace()) + { + /*const xub_StrLen nPrevPos = static_cast< xub_StrLen >*/( _xISC->correctInputSequence( aNewText, nTmpPos - 1, c, nCheckMode ) ); + + // find position of first character that has changed + sal_Int32 nOldLen = aOldText.getLength(); + sal_Int32 nNewLen = aNewText.getLength(); + const sal_Unicode *pOldTxt = aOldText.getStr(); + const sal_Unicode *pNewTxt = aNewText.getStr(); + sal_Int32 nChgPos = 0; + while ( nChgPos < nOldLen && nChgPos < nNewLen && + pOldTxt[nChgPos] == pNewTxt[nChgPos] ) + ++nChgPos; + + xub_StrLen nChgLen = static_cast< xub_StrLen >( nNewLen - nChgPos ); + String aChgText( aNewText.copy( nChgPos ), nChgLen ); + + // select text from first pos to be changed to current pos + EditSelection aSel( EditPaM( aPaM.GetNode(), (USHORT) nChgPos ), aPaM ); + + if (aChgText.Len()) + return InsertText( aSel, aChgText ); // implicitly handles undo + else + return aPaM; + } + else + { + // should the character be ignored (i.e. not get inserted) ? + if (!_xISC->checkInputSequence( aOldText, nTmpPos - 1, c, nCheckMode )) + return aPaM; // nothing to be done -> no need for undo + } + } + + // at this point now we will insert the character 'normally' some lines below... + } + + if ( IsUndoEnabled() && !IsInUndo() ) + { + EditUndoInsertChars* pNewUndo = new EditUndoInsertChars( this, CreateEPaM( aPaM ), c ); + BOOL bTryMerge = ( !bDoOverwrite && ( c != ' ' ) ) ? TRUE : FALSE; + InsertUndo( pNewUndo, bTryMerge ); + } + + aEditDoc.InsertText( (const EditPaM&)aPaM, c ); + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in InsertText" ); + pPortion->MarkInvalid( aPaM.GetIndex(), 1 ); + aPaM.GetIndex()++; // macht EditDoc-Methode nicht mehr + } + + TextModified(); + + if ( bUndoAction ) + UndoActionEnd( EDITUNDO_INSERT ); + + return aPaM; +} + +EditPaM ImpEditEngine::ImpInsertText( EditSelection aCurSel, const XubString& rStr ) +{ + UndoActionStart( EDITUNDO_INSERT ); + + EditPaM aPaM; + if ( aCurSel.HasRange() ) + aPaM = ImpDeleteSelection( aCurSel ); + else + aPaM = aCurSel.Max(); + + EditPaM aCurPaM( aPaM ); // fuers Invalidieren + + XubString aText( rStr ); + aText.ConvertLineEnd( LINEEND_LF ); + SfxVoidItem aTabItem( EE_FEATURE_TAB ); + + // Konvertiert nach LineSep = \n + // Token mit LINE_SEP abfragen, + // da der MAC-Compiler aus \n etwas anderes macht! + + USHORT nStart = 0; + while ( nStart < aText.Len() ) + { + USHORT nEnd = aText.Search( LINE_SEP, nStart ); + if ( nEnd == STRING_NOTFOUND ) + nEnd = aText.Len(); // nicht dereferenzieren! + + // Start == End => Leerzeile + if ( nEnd > nStart ) + { + XubString aLine( aText, nStart, nEnd-nStart ); + xub_StrLen nChars = aPaM.GetNode()->Len() + aLine.Len(); + if ( nChars > MAXCHARSINPARA ) + { + USHORT nMaxNewChars = MAXCHARSINPARA-aPaM.GetNode()->Len(); + nEnd -= ( aLine.Len() - nMaxNewChars ); // Dann landen die Zeichen im naechsten Absatz. + aLine.Erase( nMaxNewChars ); // Del Rest... + } +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoInsertChars( this, CreateEPaM( aPaM ), aLine ) ); +#endif + // Tabs ? + if ( aLine.Search( '\t' ) == STRING_NOTFOUND ) + aPaM = aEditDoc.InsertText( aPaM, aLine ); + else + { + USHORT nStart2 = 0; + while ( nStart2 < aLine.Len() ) + { + USHORT nEnd2 = aLine.Search( '\t', nStart2 ); + if ( nEnd2 == STRING_NOTFOUND ) + nEnd2 = aLine.Len(); // nicht dereferenzieren! + + if ( nEnd2 > nStart2 ) + aPaM = aEditDoc.InsertText( aPaM, XubString( aLine, nStart2, nEnd2-nStart2 ) ); + if ( nEnd2 < aLine.Len() ) + { + // aPaM = ImpInsertFeature( EditSelection( aPaM, aPaM ), ); + aPaM = aEditDoc.InsertFeature( aPaM, aTabItem ); + } + nStart2 = nEnd2+1; + } + } + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in InsertText" ); + pPortion->MarkInvalid( aCurPaM.GetIndex(), aLine.Len() ); + } + if ( nEnd < aText.Len() ) + aPaM = ImpInsertParaBreak( aPaM ); + + nStart = nEnd+1; + } + + UndoActionEnd( EDITUNDO_INSERT ); + + TextModified(); + return aPaM; +} + +EditPaM ImpEditEngine::ImpFastInsertText( EditPaM aPaM, const XubString& rStr ) +{ + DBG_ASSERT( rStr.Search( 0x0A ) == STRING_NOTFOUND, "FastInsertText: Zeilentrenner nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( 0x0D ) == STRING_NOTFOUND, "FastInsertText: Zeilentrenner nicht erlaubt!" ); + DBG_ASSERT( rStr.Search( '\t' ) == STRING_NOTFOUND, "FastInsertText: Features nicht erlaubt!" ); + + if ( ( aPaM.GetNode()->Len() + rStr.Len() ) < MAXCHARSINPARA ) + { +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoInsertChars( this, CreateEPaM( aPaM ), rStr ) ); +#endif + + aPaM = aEditDoc.InsertText( aPaM, rStr ); + TextModified(); + } + else + { + aPaM = ImpInsertText( aPaM, rStr ); + } + + return aPaM; +} + +EditPaM ImpEditEngine::ImpInsertFeature( EditSelection aCurSel, const SfxPoolItem& rItem ) +{ + EditPaM aPaM; + if ( aCurSel.HasRange() ) + aPaM = ImpDeleteSelection( aCurSel ); + else + aPaM = aCurSel.Max(); + + if ( aPaM.GetIndex() >= 0xfffe ) + return aPaM; + +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoInsertFeature( this, CreateEPaM( aPaM ), rItem ) ); +#endif + aPaM = aEditDoc.InsertFeature( aPaM, rItem ); + + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in InsertFeature" ); + pPortion->MarkInvalid( aPaM.GetIndex()-1, 1 ); + + TextModified(); + + return aPaM; +} + +EditPaM ImpEditEngine::ImpInsertParaBreak( const EditSelection& rCurSel, BOOL bKeepEndingAttribs ) +{ + EditPaM aPaM; + if ( rCurSel.HasRange() ) + aPaM = ImpDeleteSelection( rCurSel ); + else + aPaM = rCurSel.Max(); + + return ImpInsertParaBreak( aPaM, bKeepEndingAttribs ); +} + +EditPaM ImpEditEngine::ImpInsertParaBreak( const EditPaM& rPaM, BOOL bKeepEndingAttribs ) +{ + if ( aEditDoc.Count() >= 0xFFFE ) + { + DBG_ERROR( "Can't process more than 64K paragraphs!" ); + return rPaM; + } + +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new EditUndoSplitPara( this, aEditDoc.GetPos( rPaM.GetNode() ), rPaM.GetIndex() ) ); +#endif + + EditPaM aPaM( aEditDoc.InsertParaBreak( rPaM, bKeepEndingAttribs ) ); + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() ) + { + xub_StrLen nEnd = rPaM.GetNode()->Len(); + aPaM.GetNode()->CreateWrongList(); + WrongList* pLWrongs = rPaM.GetNode()->GetWrongList(); + WrongList* pRWrongs = aPaM.GetNode()->GetWrongList(); + // Falschgeschriebene Woerter ruebernehmen: + USHORT nLWrongs = pLWrongs->Count(); + for ( USHORT nW = 0; nW < nLWrongs; nW++ ) + { + WrongRange& rWrong = pLWrongs->GetObject( nW ); + // Nur wenn wirklich dahinter, ein ueberlappendes wird beim Spell korrigiert + if ( rWrong.nStart > nEnd ) + { + pRWrongs->InsertWrong( rWrong, pRWrongs->Count() ); + WrongRange& rRWrong = pRWrongs->GetObject( pRWrongs->Count() - 1 ); + rRWrong.nStart = rRWrong.nStart - nEnd; + rRWrong.nEnd = rRWrong.nEnd - nEnd; + } + else if ( ( rWrong.nStart < nEnd ) && ( rWrong.nEnd > nEnd ) ) + rWrong.nEnd = nEnd; + } + USHORT nInv = nEnd ? nEnd-1 : nEnd; + if ( nEnd ) + pLWrongs->MarkInvalid( nInv, nEnd ); + else + pLWrongs->SetValid(); + pRWrongs->SetValid(); // sonst 0 - 0xFFFF + pRWrongs->MarkInvalid( 0, 1 ); // Nur das erste Wort testen + } +#endif // !SVX_LIGHT + + + ParaPortion* pPortion = FindParaPortion( rPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in ImpInsertParaBreak" ); + pPortion->MarkInvalid( rPaM.GetIndex(), 0 ); + + // Optimieren: Nicht unnoetig viele GetPos auf die Listen ansetzen! + // Hier z.B. bei Undo, aber auch in allen anderen Methoden. + USHORT nPos = GetParaPortions().GetPos( pPortion ); + ParaPortion* pNewPortion = new ParaPortion( aPaM.GetNode() ); + GetParaPortions().Insert( pNewPortion, nPos + 1 ); + ParaAttribsChanged( pNewPortion->GetNode() ); + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphInserted( nPos+1 ); + + CursorMoved( rPaM.GetNode() ); // falls leeres Attribut entstanden. + TextModified(); + return aPaM; +} + +EditPaM ImpEditEngine::ImpFastInsertParagraph( USHORT nPara ) +{ +#ifndef SVX_LIGHT + if ( IsUndoEnabled() && !IsInUndo() ) + { + if ( nPara ) + { + DBG_ASSERT( aEditDoc.SaveGetObject( nPara-1 ), "FastInsertParagraph: Prev existiert nicht" ); + InsertUndo( new EditUndoSplitPara( this, nPara-1, aEditDoc.GetObject( nPara-1 )->Len() ) ); + } + else + InsertUndo( new EditUndoSplitPara( this, 0, 0 ) ); + } +#endif + + ContentNode* pNode = new ContentNode( aEditDoc.GetItemPool() ); + // Falls FlatMode, wird spaeter kein Font eingestellt: + pNode->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont(); + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() ) + pNode->CreateWrongList(); +#endif // !SVX_LIGHT + + aEditDoc.Insert( pNode, nPara ); + + ParaPortion* pNewPortion = new ParaPortion( pNode ); + GetParaPortions().Insert( pNewPortion, nPara ); + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphInserted( nPara ); + + return EditPaM( pNode, 0 ); +} + +EditPaM ImpEditEngine::InsertParaBreak( EditSelection aCurSel ) +{ + EditPaM aPaM( ImpInsertParaBreak( aCurSel ) ); + if ( aStatus.DoAutoIndenting() ) + { + USHORT nPara = aEditDoc.GetPos( aPaM.GetNode() ); + DBG_ASSERT( nPara > 0, "AutoIndenting: Fehler!" ); + XubString aPrevParaText( GetEditDoc().GetParaAsString( nPara-1 ) ); + USHORT n = 0; + while ( ( n < aPrevParaText.Len() ) && + ( ( aPrevParaText.GetChar(n) == ' ' ) || ( aPrevParaText.GetChar(n) == '\t' ) ) ) + { + if ( aPrevParaText.GetChar(n) == '\t' ) + aPaM = ImpInsertFeature( aPaM, SfxVoidItem( EE_FEATURE_TAB ) ); + else + aPaM = ImpInsertText( aPaM, aPrevParaText.GetChar(n) ); + n++; + } + + } + return aPaM; +} + +EditPaM ImpEditEngine::InsertTab( EditSelection aCurSel ) +{ + EditPaM aPaM( ImpInsertFeature( aCurSel, SfxVoidItem( EE_FEATURE_TAB ) ) ); + return aPaM; +} + +EditPaM ImpEditEngine::InsertField( EditSelection aCurSel, const SvxFieldItem& rFld ) +{ + EditPaM aPaM( ImpInsertFeature( aCurSel, rFld ) ); + return aPaM; +} + +BOOL ImpEditEngine::UpdateFields() +{ + BOOL bChanges = FALSE; + USHORT nParas = GetEditDoc().Count(); + for ( USHORT nPara = 0; nPara < nParas; nPara++ ) + { + BOOL bChangesInPara = FALSE; + ContentNode* pNode = GetEditDoc().GetObject( nPara ); + DBG_ASSERT( pNode, "NULL-Pointer im Doc" ); + CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs(); +// USHORT nAttrs = rAttribs.Count(); + for ( USHORT nAttr = 0; nAttr < rAttribs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttribs[nAttr]; + if ( pAttr->Which() == EE_FEATURE_FIELD ) + { + EditCharAttribField* pField = (EditCharAttribField*)pAttr; + EditCharAttribField* pCurrent = new EditCharAttribField( *pField ); + pField->Reset(); + + if ( aStatus.MarkFields() ) + pField->GetFldColor() = new Color( GetColorConfig().GetColorValue( svtools::WRITERFIELDSHADINGS ).nColor ); + + XubString aFldValue = GetEditEnginePtr()->CalcFieldValue( + (const SvxFieldItem&)*pField->GetItem(), + nPara, pField->GetStart(), + pField->GetTxtColor(), pField->GetFldColor() ); + pField->GetFieldValue() = aFldValue; + if ( *pField != *pCurrent ) + { + bChanges = TRUE; + bChangesInPara = TRUE; + } + delete pCurrent; + } + } + if ( bChangesInPara ) + { + // ggf. etwas genauer invalidieren. + ParaPortion* pPortion = GetParaPortions().GetObject( nPara ); + DBG_ASSERT( pPortion, "NULL-Pointer im Doc" ); + pPortion->MarkSelectionInvalid( 0, pNode->Len() ); + } + } + return bChanges; +} + +EditPaM ImpEditEngine::InsertLineBreak( EditSelection aCurSel ) +{ + EditPaM aPaM( ImpInsertFeature( aCurSel, SfxVoidItem( EE_FEATURE_LINEBR ) ) ); + return aPaM; +} + +// ---------------------------------------------------------------------- +// Hilfsfunktionen +// ---------------------------------------------------------------------- +Rectangle ImpEditEngine::PaMtoEditCursor( EditPaM aPaM, USHORT nFlags ) +{ + DBG_ASSERT( GetUpdateMode(), "Darf bei Update=FALSE nicht erreicht werden: PaMtoEditCursor" ); + + Rectangle aEditCursor; + long nY = 0; + for ( USHORT nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) + { + ParaPortion* pPortion = GetParaPortions().GetObject(nPortion); + ContentNode* pNode = pPortion->GetNode(); + DBG_ASSERT( pNode, "Ungueltiger Node in Portion!" ); + if ( pNode != aPaM.GetNode() ) + { + nY += pPortion->GetHeight(); + } + else + { + aEditCursor = GetEditCursor( pPortion, aPaM.GetIndex(), nFlags ); + aEditCursor.Top() += nY; + aEditCursor.Bottom() += nY; + return aEditCursor; + } + } + DBG_ERROR( "Portion nicht gefunden!" ); + return aEditCursor; +} + +EditPaM ImpEditEngine::GetPaM( Point aDocPos, BOOL bSmart ) +{ + DBG_ASSERT( GetUpdateMode(), "Darf bei Update=FALSE nicht erreicht werden: GetPaM" ); + + long nY = 0; + long nTmpHeight; + EditPaM aPaM; + USHORT nPortion; + for ( nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) + { + ParaPortion* pPortion = GetParaPortions().GetObject(nPortion); + nTmpHeight = pPortion->GetHeight(); // sollte auch bei !bVisible richtig sein! + nY += nTmpHeight; + if ( nY > aDocPos.Y() ) + { + nY -= nTmpHeight; + aDocPos.Y() -= nY; + // unsichtbare Portions ueberspringen: + while ( pPortion && !pPortion->IsVisible() ) + { + nPortion++; + pPortion = GetParaPortions().SaveGetObject( nPortion ); + } + DBG_ASSERT( pPortion, "Keinen sichtbaren Absatz gefunden: GetPaM" ); + aPaM = GetPaM( pPortion, aDocPos, bSmart ); + return aPaM; + + } + } + // Dann den letzten sichtbaren Suchen: + nPortion = GetParaPortions().Count()-1; + while ( nPortion && !GetParaPortions()[nPortion]->IsVisible() ) + nPortion--; + + DBG_ASSERT( GetParaPortions()[nPortion]->IsVisible(), "Keinen sichtbaren Absatz gefunden: GetPaM" ); + aPaM.SetNode( GetParaPortions()[nPortion]->GetNode() ); + aPaM.SetIndex( GetParaPortions()[nPortion]->GetNode()->Len() ); + return aPaM; +} + +sal_uInt32 ImpEditEngine::GetTextHeight() const +{ + DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: GetTextHeight" ); + DBG_ASSERT( IsFormatted() || IsFormatting(), "GetTextHeight: Nicht formatiert" ); + return nCurTextHeight; +} + +sal_uInt32 ImpEditEngine::CalcTextWidth( BOOL bIgnoreExtraSpace ) +{ + // Wenn noch nicht formatiert und nicht gerade dabei. + // Wird in der Formatierung bei AutoPageSize gerufen. + if ( !IsFormatted() && !IsFormatting() ) + FormatDoc(); + + EditLine* pLine; + + long nMaxWidth = 0; + long nCurWidth = 0; + + // -------------------------------------------------- + // Ueber alle Absaetze... + // -------------------------------------------------- + USHORT nParas = GetParaPortions().Count(); +// USHORT nBiggestPara = 0; +// USHORT nBiggestLine = 0; + for ( USHORT nPara = 0; nPara < nParas; nPara++ ) + { + ParaPortion* pPortion = GetParaPortions().GetObject( nPara ); + if ( pPortion->IsVisible() ) + { + const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pPortion->GetNode() ); + sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pPortion->GetNode() ); + + // -------------------------------------------------- + // Ueber die Zeilen des Absatzes... + // -------------------------------------------------- + ULONG nLines = pPortion->GetLines().Count(); + for ( USHORT nLine = 0; nLine < nLines; nLine++ ) + { + pLine = pPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "NULL-Pointer im Zeileniterator in CalcWidth" ); + // nCurWidth = pLine->GetStartPosX(); + // Bei Center oder Right haengt die breite von der + // Papierbreite ab, hier nicht erwuenscht. + // Am besten generell nicht auf StartPosX verlassen, + // es muss auch die rechte Einrueckung beruecksichtigt werden! + nCurWidth = GetXValue( rLRItem.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth ); + if ( nLine == 0 ) + { + long nFI = GetXValue( rLRItem.GetTxtFirstLineOfst() ); + nCurWidth -= nFI; + if ( pPortion->GetBulletX() > nCurWidth ) + { + nCurWidth += nFI; // LI? + if ( pPortion->GetBulletX() > nCurWidth ) + nCurWidth = pPortion->GetBulletX(); + } + } + nCurWidth += GetXValue( rLRItem.GetRight() ); + nCurWidth += CalcLineWidth( pPortion, pLine, bIgnoreExtraSpace ); + if ( nCurWidth > nMaxWidth ) + { + nMaxWidth = nCurWidth; + } + } + } + } + if ( nMaxWidth < 0 ) + nMaxWidth = 0; + + nMaxWidth++; // Ein breiter, da in CreateLines bei >= umgebrochen wird. + return (sal_uInt32)nMaxWidth; +} + +sal_uInt32 ImpEditEngine::CalcLineWidth( ParaPortion* pPortion, EditLine* pLine, BOOL bIgnoreExtraSpace ) +{ + USHORT nPara = GetEditDoc().GetPos( pPortion->GetNode() ); + + // #114278# Saving both layout mode and language (since I'm + // potentially changing both) + GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE ); + + ImplInitLayoutMode( GetRefDevice(), nPara, 0xFFFF ); + + SvxAdjust eJustification = GetJustification( nPara ); + + // Berechnung der Breite ohne die Indents... + sal_uInt32 nWidth = 0; + USHORT nPos = pLine->GetStart(); + for ( USHORT nTP = pLine->GetStartPortion(); nTP <= pLine->GetEndPortion(); nTP++ ) + { + TextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( nTP ); + switch ( pTextPortion->GetKind() ) + { + case PORTIONKIND_FIELD: + case PORTIONKIND_HYPHENATOR: + case PORTIONKIND_TAB: + { + nWidth += pTextPortion->GetSize().Width(); + } + break; + case PORTIONKIND_TEXT: + { + if ( ( eJustification != SVX_ADJUST_BLOCK ) || ( !bIgnoreExtraSpace ) ) + { + nWidth += pTextPortion->GetSize().Width(); + } + else + { + SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() ); + SeekCursor( pPortion->GetNode(), nPos+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + nWidth += aTmpFont.QuickGetTextSize( GetRefDevice(), *pPortion->GetNode(), nPos, pTextPortion->GetLen(), NULL ).Width(); + } + } + break; + } + nPos = nPos + pTextPortion->GetLen(); + } + + GetRefDevice()->Pop(); + + return nWidth; +} + +sal_uInt32 ImpEditEngine::CalcTextHeight() +{ + DBG_ASSERT( GetUpdateMode(), "Sollte bei Update=FALSE nicht verwendet werden: CalcTextHeight" ); + sal_uInt32 nY = 0; + for ( USHORT nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) + nY += GetParaPortions()[nPortion]->GetHeight(); + return nY; +} + +USHORT ImpEditEngine::GetLineCount( USHORT nParagraph ) const +{ + DBG_ASSERT( nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" ); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetLineCount" ); + if ( pPPortion ) + return pPPortion->GetLines().Count(); + + return 0xFFFF; +} + +xub_StrLen ImpEditEngine::GetLineLen( USHORT nParagraph, USHORT nLine ) const +{ + DBG_ASSERT( nParagraph < GetParaPortions().Count(), "GetLineLen: Out of range" ); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetLineLen" ); + if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "Zeile nicht gefunden: GetLineHeight" ); + return pLine->GetLen(); + } + + return 0xFFFF; +} + +void ImpEditEngine::GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nParagraph, USHORT nLine ) const +{ + DBG_ASSERT( nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" ); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetLineBoundaries" ); + rStart = rEnd = 0xFFFF; // default values in case of error + if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "Zeile nicht gefunden: GetLineBoundaries" ); + rStart = pLine->GetStart(); + rEnd = pLine->GetEnd(); + } +} + +USHORT ImpEditEngine::GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const +{ + USHORT nLineNo = 0xFFFF; + ContentNode* pNode = GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERT( pNode, "GetLineNumberAtIndex: invalid paragraph index" ); + if (pNode) + { + // we explicitly allow for the index to point at the character right behind the text + const bool bValidIndex = /*0 <= nIndex &&*/ nIndex <= pNode->Len(); + DBG_ASSERT( bValidIndex, "GetLineNumberAtIndex: invalid index" ); + const USHORT nLineCount = GetLineCount( nPara ); + if (nIndex == pNode->Len()) + nLineNo = nLineCount > 0 ? nLineCount - 1 : 0; + else if (bValidIndex) // nIndex < pNode->Len() + { + USHORT nStart = USHRT_MAX, nEnd = USHRT_MAX; + for (USHORT i = 0; i < nLineCount && nLineNo == 0xFFFF; ++i) + { + GetLineBoundaries( nStart, nEnd, nPara, i ); + if (nStart <= nIndex && nIndex < nEnd) + nLineNo = i; + } + } + } + return nLineNo; +} + +USHORT ImpEditEngine::GetLineHeight( USHORT nParagraph, USHORT nLine ) +{ + DBG_ASSERT( nParagraph < GetParaPortions().Count(), "GetLineCount: Out of range" ); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetLineHeight" ); + if ( pPPortion && ( nLine < pPPortion->GetLines().Count() ) ) + { + EditLine* pLine = pPPortion->GetLines().GetObject( nLine ); + DBG_ASSERT( pLine, "Zeile nicht gefunden: GetLineHeight" ); + return pLine->GetHeight(); + } + + return 0xFFFF; +} + +sal_uInt32 ImpEditEngine::GetParaHeight( USHORT nParagraph ) +{ + sal_uInt32 nHeight = 0; + + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "Absatz nicht gefunden: GetParaHeight" ); + + if ( pPPortion ) + nHeight = pPPortion->GetHeight(); + + return nHeight; +} + +void ImpEditEngine::UpdateSelections() +{ + USHORT nInvNodes = aDeletedNodes.Count(); + + // Pruefen, ob eine der Selektionen auf einem geloeschten Node steht... + // Wenn der Node gueltig ist, muss noch der Index geprueft werden! + for ( USHORT nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews.GetObject(nView); + DBG_CHKOBJ( pView, EditView, 0 ); + EditSelection aCurSel( pView->pImpEditView->GetEditSelection() ); + BOOL bChanged = FALSE; + for ( USHORT n = 0; n < nInvNodes; n++ ) + { + DeletedNodeInfo* pInf = aDeletedNodes.GetObject( n ); + if ( ( ( ULONG )(aCurSel.Min().GetNode()) == pInf->GetInvalidAdress() ) || + ( ( ULONG )(aCurSel.Max().GetNode()) == pInf->GetInvalidAdress() ) ) + { + // ParaPortions verwenden, da jetzt auch versteckte + // Absaetze beruecksichtigt werden muessen! + USHORT nPara = pInf->GetPosition(); + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nPara ); + if ( !pPPortion ) // letzter Absatz + { + nPara = GetParaPortions().Count()-1; + pPPortion = GetParaPortions().GetObject( nPara ); + } + DBG_ASSERT( pPPortion, "Leeres Document in UpdateSelections ?" ); + // Nicht aus einem verstecktem Absatz landen: + USHORT nCurPara = nPara; + USHORT nLastPara = GetParaPortions().Count()-1; + while ( nPara <= nLastPara && !GetParaPortions()[nPara]->IsVisible() ) + nPara++; + if ( nPara > nLastPara ) // dann eben rueckwaerts... + { + nPara = nCurPara; + while ( nPara && !GetParaPortions()[nPara]->IsVisible() ) + nPara--; + } + DBG_ASSERT( GetParaPortions()[nPara]->IsVisible(), "Keinen sichtbaren Absatz gefunden: UpdateSelections" ); + + ParaPortion* pParaPortion = GetParaPortions()[nPara]; + EditSelection aTmpSelection( EditPaM( pParaPortion->GetNode(), 0 ) ); + pView->pImpEditView->SetEditSelection( aTmpSelection ); + bChanged=TRUE; + break; // for-Schleife + } + } + if ( !bChanged ) + { + // Index prueffen, falls Node geschrumpft. + if ( aCurSel.Min().GetIndex() > aCurSel.Min().GetNode()->Len() ) + { + aCurSel.Min().GetIndex() = aCurSel.Min().GetNode()->Len(); + pView->pImpEditView->SetEditSelection( aCurSel ); + } + if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) + { + aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); + pView->pImpEditView->SetEditSelection( aCurSel ); + } + } + } + + // Loeschen... + for ( USHORT n = 0; n < nInvNodes; n++ ) + { + DeletedNodeInfo* pInf = aDeletedNodes.GetObject( n ); + delete pInf; + } + aDeletedNodes.Remove( 0, aDeletedNodes.Count() ); +} + +EditSelection ImpEditEngine::ConvertSelection( USHORT nStartPara, USHORT nStartPos, + USHORT nEndPara, USHORT nEndPos ) const +{ + EditSelection aNewSelection; + + // Start... + ContentNode* pNode = aEditDoc.SaveGetObject( nStartPara ); + USHORT nIndex = nStartPos; + if ( !pNode ) + { + pNode = aEditDoc[ aEditDoc.Count()-1 ]; + nIndex = pNode->Len(); + } + else if ( nIndex > pNode->Len() ) + nIndex = pNode->Len(); + + aNewSelection.Min().SetNode( pNode ); + aNewSelection.Min().SetIndex( nIndex ); + + // End... + pNode = aEditDoc.SaveGetObject( nEndPara ); + nIndex = nEndPos; + if ( !pNode ) + { + pNode = aEditDoc[ aEditDoc.Count()-1 ]; + nIndex = pNode->Len(); + } + else if ( nIndex > pNode->Len() ) + nIndex = pNode->Len(); + + aNewSelection.Max().SetNode( pNode ); + aNewSelection.Max().SetIndex( nIndex ); + + return aNewSelection; +} + +EditSelection ImpEditEngine::MatchGroup( const EditSelection& rSel ) +{ + EditSelection aMatchSel; + EditSelection aTmpSel( rSel ); + aTmpSel.Adjust( GetEditDoc() ); + if ( ( aTmpSel.Min().GetNode() != aTmpSel.Max().GetNode() ) || + ( ( aTmpSel.Max().GetIndex() - aTmpSel.Min().GetIndex() ) > 1 ) ) + { + return aMatchSel; + } + + USHORT nPos = aTmpSel.Min().GetIndex(); + ContentNode* pNode = aTmpSel.Min().GetNode(); + if ( nPos >= pNode->Len() ) + return aMatchSel; + + USHORT nMatchChar = aGroupChars.Search( pNode->GetChar( nPos ) ); + if ( nMatchChar != STRING_NOTFOUND ) + { + USHORT nNode = aEditDoc.GetPos( pNode ); + if ( ( nMatchChar % 2 ) == 0 ) + { + // Vorwaerts suchen... + xub_Unicode nSC = aGroupChars.GetChar( nMatchChar ); + DBG_ASSERT( aGroupChars.Len() > (nMatchChar+1), "Ungueltige Gruppe von MatchChars!" ); + xub_Unicode nEC = aGroupChars.GetChar( nMatchChar+1 ); + + USHORT nCur = aTmpSel.Min().GetIndex()+1; + USHORT nLevel = 1; + while ( pNode && nLevel ) + { + XubString& rStr = *pNode; + while ( nCur < rStr.Len() ) + { + if ( rStr.GetChar( nCur ) == nSC ) + nLevel++; + else if ( rStr.GetChar( nCur ) == nEC ) + { + nLevel--; + if ( !nLevel ) + break; // while nCur... + } + nCur++; + } + + if ( nLevel ) + { + nNode++; + pNode = nNode < aEditDoc.Count() ? aEditDoc.GetObject( nNode ) : 0; + nCur = 0; + } + } + if ( nLevel == 0 ) // gefunden + { + aMatchSel.Min() = aTmpSel.Min(); + aMatchSel.Max() = EditPaM( pNode, nCur+1 ); + } + } + else + { + // Rueckwaerts suchen... + xub_Unicode nEC = aGroupChars.GetChar( nMatchChar ); + xub_Unicode nSC = aGroupChars.GetChar( nMatchChar-1 ); + + USHORT nCur = aTmpSel.Min().GetIndex()-1; + USHORT nLevel = 1; + while ( pNode && nLevel ) + { + if ( pNode->Len() ) + { + XubString& rStr = *pNode; + while ( nCur ) + { + if ( rStr.GetChar( nCur ) == nSC ) + { + nLevel--; + if ( !nLevel ) + break; // while nCur... + } + else if ( rStr.GetChar( nCur ) == nEC ) + nLevel++; + + nCur--; + } + } + + if ( nLevel ) + { + pNode = nNode ? aEditDoc.GetObject( --nNode ) : 0; + if ( pNode ) + nCur = pNode->Len()-1; // egal ob negativ, weil if Len() + } + } + + if ( nLevel == 0 ) // gefunden + { + aMatchSel.Min() = aTmpSel.Min(); + aMatchSel.Min().GetIndex()++; // hinter das Zeichen + aMatchSel.Max() = EditPaM( pNode, nCur ); + } + } + } + return aMatchSel; +} + +void ImpEditEngine::StopSelectionMode() +{ + if ( ( IsInSelectionMode() || aSelEngine.IsInSelection() ) && pActiveView ) + { + pActiveView->pImpEditView->DrawSelection(); // Wegzeichnen... + EditSelection aSel( pActiveView->pImpEditView->GetEditSelection() ); + aSel.Min() = aSel.Max(); + pActiveView->pImpEditView->SetEditSelection( aSel ); + pActiveView->ShowCursor(); + aSelEngine.Reset(); + bInSelection = FALSE; + } +} + +void ImpEditEngine::SetActiveView( EditView* pView ) +{ + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // Eigentlich waere jetzt ein bHasVisSel und HideSelection notwendig !!! + + if ( pView == pActiveView ) + return; + + if ( pActiveView && pActiveView->HasSelection() ) + pActiveView->pImpEditView->DrawSelection(); // Wegzeichnen... + + pActiveView = pView; + + if ( pActiveView && pActiveView->HasSelection() ) + pActiveView->pImpEditView->DrawSelection(); // Wegzeichnen... + + // NN: Quick fix for #78668#: + // When editing of a cell in Calc is ended, the edit engine is not deleted, + // only the edit views are removed. If mpIMEInfos is still set in that case, + // mpIMEInfos->aPos points to an invalid selection. + // -> reset mpIMEInfos now + // (probably something like this is necessary whenever the content is modified + // from the outside) + + if ( !pView && mpIMEInfos ) + { + delete mpIMEInfos; + mpIMEInfos = NULL; + } +} + +uno::Reference< datatransfer::XTransferable > ImpEditEngine::CreateTransferable( const EditSelection& rSelection ) const +{ +#ifndef SVX_LIGHT + EditSelection aSelection( rSelection ); + aSelection.Adjust( GetEditDoc() ); + + EditDataObject* pDataObj = new EditDataObject; + uno::Reference< datatransfer::XTransferable > xDataObj; + xDataObj = pDataObj; + + XubString aText( GetSelected( aSelection ) ); + aText.ConvertLineEnd(); // Systemspezifisch + pDataObj->GetString() = aText; + + SvxFontItem::EnableStoreUnicodeNames( TRUE ); + WriteBin( pDataObj->GetStream(), aSelection, TRUE ); + pDataObj->GetStream().Seek( 0 ); + SvxFontItem::EnableStoreUnicodeNames( FALSE ); + + ((ImpEditEngine*)this)->WriteRTF( pDataObj->GetRTFStream(), aSelection ); + pDataObj->GetRTFStream().Seek( 0 ); + + if ( ( aSelection.Min().GetNode() == aSelection.Max().GetNode() ) + && ( aSelection.Max().GetIndex() == (aSelection.Min().GetIndex()+1) ) ) + { + const EditCharAttrib* pAttr = aSelection.Min().GetNode()->GetCharAttribs(). + FindFeature( aSelection.Min().GetIndex() ); + if ( pAttr && + ( pAttr->GetStart() == aSelection.Min().GetIndex() ) && + ( pAttr->Which() == EE_FEATURE_FIELD ) ) + { + const SvxFieldItem* pField = (const SvxFieldItem*)pAttr->GetItem(); + const SvxFieldData* pFld = pField->GetField(); + if ( pFld && pFld->ISA( SvxURLField ) ) + { + // Office-Bookmark + String aURL( ((const SvxURLField*)pFld)->GetURL() ); + String aTxt( ((const SvxURLField*)pFld)->GetRepresentation() ); + pDataObj->GetURL() = aURL; + } + } + } + + return xDataObj; +#else + return uno::Reference< datatransfer::XTransferable >(); +#endif +} + +EditSelection ImpEditEngine::InsertText( uno::Reference< datatransfer::XTransferable >& rxDataObj, const String& rBaseURL, const EditPaM& rPaM, BOOL bUseSpecial ) +{ + EditSelection aNewSelection( rPaM ); + + if ( rxDataObj.is() ) + { + datatransfer::DataFlavor aFlavor; + BOOL bDone = FALSE; + + if ( bUseSpecial ) + { + // BIN + SotExchange::GetFormatDataFlavor( SOT_FORMATSTR_ID_EDITENGINE, aFlavor ); + if ( rxDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = rxDataObj->getTransferData( aFlavor ); + uno::Sequence< sal_Int8 > aSeq; + aData >>= aSeq; + { + SvMemoryStream aBinStream( aSeq.getArray(), aSeq.getLength(), STREAM_READ ); + aNewSelection = Read( aBinStream, rBaseURL, EE_FORMAT_BIN, rPaM ); + } + bDone = TRUE; + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + } + + if ( !bDone ) + { + // Bookmark + /* + String aURL = ...; + String aTxt = ...; + // Feld nur einfuegen, wenn Factory vorhanden. + if ( ITEMDATA() && ITEMDATA()->GetClassManager().Get( SVX_URLFIELD ) ) + { + SvxFieldItem aField( SvxURLField( aURL, aTxt, SVXURLFORMAT_URL ), EE_FEATURE_FIELD ); + aNewSelection = InsertField( aPaM, aField ); + UpdateFields(); + } + else + aNewSelection = ImpInsertText( aPaM, aURL ); + } + */ + } + if ( !bDone ) + { + // RTF + SotExchange::GetFormatDataFlavor( SOT_FORMAT_RTF, aFlavor ); + if ( rxDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = rxDataObj->getTransferData( aFlavor ); + uno::Sequence< sal_Int8 > aSeq; + aData >>= aSeq; + { + SvMemoryStream aRTFStream( aSeq.getArray(), aSeq.getLength(), STREAM_READ ); + aNewSelection = Read( aRTFStream, rBaseURL, EE_FORMAT_RTF, rPaM ); + } + bDone = TRUE; + } + catch( const ::com::sun::star::uno::Exception& ) + { + } + } + } + if ( !bDone ) + { + // XML ? + // Currently, there is nothing like "The" XML format, StarOffice doesn't offer plain XML in Clipboard... + } + } + if ( !bDone ) + { + SotExchange::GetFormatDataFlavor( SOT_FORMAT_STRING, aFlavor ); + if ( rxDataObj->isDataFlavorSupported( aFlavor ) ) + { + try + { + uno::Any aData = rxDataObj->getTransferData( aFlavor ); + ::rtl::OUString aText; + aData >>= aText; + aNewSelection = ImpInsertText( rPaM, aText ); + bDone = TRUE; + } + catch( ... ) + { + ; // #i9286# can happen, even if isDataFlavorSupported returns true... + } + } + } + } + + return aNewSelection; +} + +Range ImpEditEngine::GetInvalidYOffsets( ParaPortion* pPortion ) +{ + Range aRange( 0, 0 ); + + if ( pPortion->IsVisible() ) + { + const SvxULSpaceItem& rULSpace = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + USHORT nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + + // erst von vorne... + USHORT nFirstInvalid = 0xFFFF; + USHORT nLine; + for ( nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) + { + EditLine* pL = pPortion->GetLines().GetObject( nLine ); + if ( pL->IsInvalid() ) + { + nFirstInvalid = nLine; + break; + } + if ( nLine && !aStatus.IsOutliner() ) // nicht die erste Zeile + aRange.Min() += nSBL; + aRange.Min() += pL->GetHeight(); + } + DBG_ASSERT( nFirstInvalid != 0xFFFF, "Keine ungueltige Zeile gefunden in GetInvalidYOffset(1)" ); + + + // Abgleichen und weiter... + aRange.Max() = aRange.Min(); + aRange.Max() += pPortion->GetFirstLineOffset(); + if ( nFirstInvalid != 0 ) // Nur wenn nicht die erste Zeile ungueltig + aRange.Min() = aRange.Max(); + + USHORT nLastInvalid = pPortion->GetLines().Count()-1; + for ( nLine = nFirstInvalid; nLine < pPortion->GetLines().Count(); nLine++ ) + { + EditLine* pL = pPortion->GetLines().GetObject( nLine ); + if ( pL->IsValid() ) + { + nLastInvalid = nLine; + break; + } + + if ( nLine && !aStatus.IsOutliner() ) + aRange.Max() += nSBL; + aRange.Max() += pL->GetHeight(); + } + + // MT 07/00 SBL kann jetzt kleiner 100% sein => ggf. die Zeile davor neu ausgeben. + if( ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) && rLSItem.GetPropLineSpace() && + ( rLSItem.GetPropLineSpace() < 100 ) ) + { + EditLine* pL = pPortion->GetLines().GetObject( nFirstInvalid ); + long n = pL->GetTxtHeight() * ( 100 - rLSItem.GetPropLineSpace() ); + n /= 100; + aRange.Min() -= n; + aRange.Max() += n; + } + + if ( ( nLastInvalid == pPortion->GetLines().Count()-1 ) && ( !aStatus.IsOutliner() ) ) + aRange.Max() += GetYValue( rULSpace.GetLower() ); + } + return aRange; +} + +EditPaM ImpEditEngine::GetPaM( ParaPortion* pPortion, Point aDocPos, BOOL bSmart ) +{ + DBG_ASSERT( pPortion->IsVisible(), "Wozu GetPaM() bei einem unsichtbaren Absatz?" ); + DBG_ASSERT( IsFormatted(), "GetPaM: Nicht formatiert" ); + + USHORT nCurIndex = 0; + EditPaM aPaM; + aPaM.SetNode( pPortion->GetNode() ); + + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + USHORT nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + + long nY = pPortion->GetFirstLineOffset(); + + DBG_ASSERT( pPortion->GetLines().Count(), "Leere ParaPortion in GetPaM!" ); + + EditLine* pLine = 0; + for ( USHORT nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) + { + EditLine* pTmpLine = pPortion->GetLines().GetObject( nLine ); + nY += pTmpLine->GetHeight(); + if ( !aStatus.IsOutliner() ) + nY += nSBL; + if ( nY > aDocPos.Y() ) // das war 'se + { + pLine = pTmpLine; + break; // richtige Y-Position intressiert nicht + } + + nCurIndex = nCurIndex + pTmpLine->GetLen(); + } + + if ( !pLine ) // darf nur im Bereich von SA passieren! + { + #ifdef DBG_UTIL + const SvxULSpaceItem& rULSpace =(const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + DBG_ASSERT( nY+GetYValue( rULSpace.GetLower() ) >= aDocPos.Y() , "Index in keiner Zeile, GetPaM ?" ); + #endif + aPaM.SetIndex( pPortion->GetNode()->Len() ); + return aPaM; + } + + // Wenn Zeile gefunden, nur noch X-Position => Index + nCurIndex = GetChar( pPortion, pLine, aDocPos.X(), bSmart ); + aPaM.SetIndex( nCurIndex ); + + if ( nCurIndex && ( nCurIndex == pLine->GetEnd() ) && + ( pLine != pPortion->GetLines().GetObject( pPortion->GetLines().Count()-1) ) ) + { + aPaM = CursorLeft( aPaM, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL ); + } + + return aPaM; +} + +USHORT ImpEditEngine::GetChar( ParaPortion* pParaPortion, EditLine* pLine, long nXPos, BOOL bSmart ) +{ + DBG_ASSERT( pLine, "Keine Zeile erhalten: GetChar" ); + + USHORT nChar = 0xFFFF; + USHORT nCurIndex = pLine->GetStart(); + + + // Search best matching portion with GetPortionXOffset() + for ( USHORT i = pLine->GetStartPortion(); i <= pLine->GetEndPortion(); i++ ) + { + TextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( i ); + long nXLeft = GetPortionXOffset( pParaPortion, pLine, i ); + long nXRight = nXLeft + pPortion->GetSize().Width(); + if ( ( nXLeft <= nXPos ) && ( nXRight >= nXPos ) ) + { + nChar = nCurIndex; + + // Search within Portion... + + // Don't search within special portions... + if ( pPortion->GetKind() != PORTIONKIND_TEXT ) + { + // ...but check on which side + if ( bSmart ) + { + long nLeftDiff = nXPos-nXLeft; + long nRightDiff = nXRight-nXPos; + if ( nRightDiff < nLeftDiff ) + nChar++; + } + } + else + { + USHORT nMax = pPortion->GetLen(); + USHORT nOffset = 0xFFFF; + USHORT nTmpCurIndex = nChar - pLine->GetStart(); + + long nXInPortion = nXPos - nXLeft; + if ( pPortion->IsRightToLeft() ) + nXInPortion = nXRight - nXPos; + + // Search in Array... + for ( USHORT x = 0; x < nMax; x++ ) + { + long nTmpPosMax = pLine->GetCharPosArray().GetObject( nTmpCurIndex+x ); + if ( nTmpPosMax > nXInPortion ) + { + // pruefen, ob dieser oder der davor... + long nTmpPosMin = x ? pLine->GetCharPosArray().GetObject( nTmpCurIndex+x-1 ) : 0; + long nDiffLeft = nXInPortion - nTmpPosMin; + long nDiffRight = nTmpPosMax - nXInPortion; + DBG_ASSERT( nDiffLeft >= 0, "DiffLeft negativ" ); + DBG_ASSERT( nDiffRight >= 0, "DiffRight negativ" ); + nOffset = ( bSmart && ( nDiffRight < nDiffLeft ) ) ? x+1 : x; + // I18N: If there are character position with the length of 0, + // they belong to the same character, we can not use this position as an index. + // Skip all 0-positions, cheaper than using XBreakIterator: + if ( nOffset < nMax ) + { + const long nX = pLine->GetCharPosArray().GetObject(nOffset); + while ( ( (nOffset+1) < nMax ) && ( pLine->GetCharPosArray().GetObject(nOffset+1) == nX ) ) + nOffset++; + } + break; + } + } + + // Bei Verwendung des CharPosArray duerfte es keine Ungenauigkeiten geben! + // Vielleicht bei Kerning ? + // 0xFFF passiert z.B. bei Outline-Font, wenn ganz hinten. + if ( nOffset == 0xFFFF ) + nOffset = nMax; + + DBG_ASSERT( nOffset <= nMax, "nOffset > nMax" ); + + nChar = nChar + nOffset; + + // Check if index is within a cell: + if ( nChar && ( nChar < pParaPortion->GetNode()->Len() ) ) + { + EditPaM aPaM( pParaPortion->GetNode(), nChar+1 ); + USHORT nScriptType = GetScriptType( aPaM ); + if ( nScriptType == i18n::ScriptType::COMPLEX ) + { + uno::Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + sal_Int32 nCount = 1; + lang::Locale aLocale = GetLocale( aPaM ); + USHORT nRight = (USHORT)_xBI->nextCharacters( *pParaPortion->GetNode(), nChar, aLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); + USHORT nLeft = (USHORT)_xBI->previousCharacters( *pParaPortion->GetNode(), nRight, aLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, nCount, nCount ); + if ( ( nLeft != nChar ) && ( nRight != nChar ) ) + { + nChar = ( Abs( nRight - nChar ) < Abs( nLeft - nChar ) ) ? nRight : nLeft; + } + } + } + } + } + + nCurIndex = nCurIndex + pPortion->GetLen(); + } + + if ( nChar == 0xFFFF ) + { + nChar = ( nXPos <= pLine->GetStartPosX() ) ? pLine->GetStart() : pLine->GetEnd(); + } + + return nChar; +} + +Range ImpEditEngine::GetLineXPosStartEnd( ParaPortion* pParaPortion, EditLine* pLine ) +{ + Range aLineXPosStartEnd; + + USHORT nPara = GetEditDoc().GetPos( pParaPortion->GetNode() ); + if ( !IsRightToLeft( nPara ) ) + { + aLineXPosStartEnd.Min() = pLine->GetStartPosX(); + aLineXPosStartEnd.Max() = pLine->GetStartPosX() + pLine->GetTextWidth(); + } + else + { + aLineXPosStartEnd.Min() = GetPaperSize().Width() - ( pLine->GetStartPosX() + pLine->GetTextWidth() ); + aLineXPosStartEnd.Max() = GetPaperSize().Width() - pLine->GetStartPosX(); + } + + + return aLineXPosStartEnd; +} + +long ImpEditEngine::GetPortionXOffset( ParaPortion* pParaPortion, EditLine* pLine, USHORT nTextPortion ) +{ + long nX = pLine->GetStartPosX(); + + for ( USHORT i = pLine->GetStartPortion(); i < nTextPortion; i++ ) + { + TextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( i ); + switch ( pPortion->GetKind() ) + { + case PORTIONKIND_FIELD: + case PORTIONKIND_TEXT: + case PORTIONKIND_HYPHENATOR: + case PORTIONKIND_TAB: +// case PORTIONKIND_EXTRASPACE: + { + nX += pPortion->GetSize().Width(); + } + break; + } + } + + USHORT nPara = GetEditDoc().GetPos( pParaPortion->GetNode() ); + BOOL bR2LPara = IsRightToLeft( nPara ); + + TextPortion* pDestPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + if ( pDestPortion->GetKind() != PORTIONKIND_TAB ) + { + if ( !bR2LPara && pDestPortion->GetRightToLeft() ) + { + // Portions behind must be added, visual before this portion + sal_uInt16 nTmpPortion = nTextPortion+1; + while ( nTmpPortion <= pLine->GetEndPortion() ) + { + TextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( pNextTextPortion->GetRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX += pNextTextPortion->GetSize().Width(); + else + break; + nTmpPortion++; + } + // Portions before must be removed, visual behind this portion + nTmpPortion = nTextPortion; + while ( nTmpPortion > pLine->GetStartPortion() ) + { + --nTmpPortion; + TextPortion* pPrevTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( pPrevTextPortion->GetRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX -= pPrevTextPortion->GetSize().Width(); + else + break; + } + } + else if ( bR2LPara && !pDestPortion->IsRightToLeft() ) + { + // Portions behind must be ermoved, visual behind this portion + sal_uInt16 nTmpPortion = nTextPortion+1; + while ( nTmpPortion <= pLine->GetEndPortion() ) + { + TextPortion* pNextTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( !pNextTextPortion->IsRightToLeft() && ( pNextTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX += pNextTextPortion->GetSize().Width(); + else + break; + nTmpPortion++; + } + // Portions before must be added, visual before this portion + nTmpPortion = nTextPortion; + while ( nTmpPortion > pLine->GetStartPortion() ) + { + --nTmpPortion; + TextPortion* pPrevTextPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( !pPrevTextPortion->IsRightToLeft() && ( pPrevTextPortion->GetKind() != PORTIONKIND_TAB ) ) + nX -= pPrevTextPortion->GetSize().Width(); + else + break; + } + } + } + if ( bR2LPara ) + { + // Switch X postions... + DBG_ASSERT( GetTextRanger() || GetPaperSize().Width(), "GetPortionXOffset - paper size?!" ); + DBG_ASSERT( GetTextRanger() || (nX <= GetPaperSize().Width()), "GetPortionXOffset - position out of paper size!" ); + nX = GetPaperSize().Width() - nX; + nX -= pDestPortion->GetSize().Width(); + } + + return nX; +} + +long ImpEditEngine::GetXPos( ParaPortion* pParaPortion, EditLine* pLine, USHORT nIndex, BOOL bPreferPortionStart ) +{ + DBG_ASSERT( pLine, "Keine Zeile erhalten: GetXPos" ); + DBG_ASSERT( ( nIndex >= pLine->GetStart() ) && ( nIndex <= pLine->GetEnd() ) , "GetXPos muss richtig gerufen werden!" ); + + BOOL bDoPreferPortionStart = bPreferPortionStart; + // Assure that the portion belongs to this line: + if ( nIndex == pLine->GetStart() ) + bDoPreferPortionStart = TRUE; + else if ( nIndex == pLine->GetEnd() ) + bDoPreferPortionStart = FALSE; + + USHORT nTextPortionStart = 0; + USHORT nTextPortion = pParaPortion->GetTextPortions().FindPortion( nIndex, nTextPortionStart, bDoPreferPortionStart ); + + DBG_ASSERT( ( nTextPortion >= pLine->GetStartPortion() ) && ( nTextPortion <= pLine->GetEndPortion() ), "GetXPos: Portion not in current line! " ); + + TextPortion* pPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion ); + + long nX = GetPortionXOffset( pParaPortion, pLine, nTextPortion ); + + // calc text width, portion size may include CJK/CTL spacing... + // But the array migh not be init yet, if using text ranger this method is called within CreateLines()... + long nPortionTextWidth = pPortion->GetSize().Width(); + if ( ( pPortion->GetKind() == PORTIONKIND_TEXT ) && pPortion->GetLen() && !GetTextRanger() ) + nPortionTextWidth = pLine->GetCharPosArray().GetObject( nTextPortionStart + pPortion->GetLen() - 1 - pLine->GetStart() ); + + if ( nTextPortionStart != nIndex ) + { + // Search within portion... + if ( nIndex == ( nTextPortionStart + pPortion->GetLen() ) ) + { + // End of Portion + if ( pPortion->GetKind() == PORTIONKIND_TAB ) + { + if ( (nTextPortion+1) < pParaPortion->GetTextPortions().Count() ) + { + TextPortion* pNextPortion = pParaPortion->GetTextPortions().GetObject( nTextPortion+1 ); + if ( pNextPortion->GetKind() != PORTIONKIND_TAB ) + { + // DBG_ASSERT( !bPreferPortionStart, "GetXPos - How can we this tab portion here???" ); + // #109879# We loop if nIndex == pLine->GetEnd, because bPreferPortionStart will be reset + if ( !bPreferPortionStart ) + nX = GetXPos( pParaPortion, pLine, nIndex, TRUE ); + else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) ) + nX += nPortionTextWidth; + } + } + else if ( !IsRightToLeft( GetEditDoc().GetPos( pParaPortion->GetNode() ) ) ) + { + nX += nPortionTextWidth; + } + } + else if ( !pPortion->IsRightToLeft() ) + { + nX += nPortionTextWidth; + } + } + else if ( pPortion->GetKind() == PORTIONKIND_TEXT ) + { + DBG_ASSERT( nIndex != pLine->GetStart(), "Strange behavior in new GetXPos()" ); + DBG_ASSERT( pLine && pLine->GetCharPosArray().Count(), "svx::ImpEditEngine::GetXPos(), portion in an empty line?" ); + + if( pLine->GetCharPosArray().Count() ) + { + USHORT nPos = nIndex - 1 - pLine->GetStart(); + if( nPos >= pLine->GetCharPosArray().Count() ) + { + nPos = pLine->GetCharPosArray().Count()-1; + DBG_ERROR("svx::ImpEditEngine::GetXPos(), index out of range!"); + } + + long nPosInPortion = pLine->GetCharPosArray().GetObject( nPos ); + + if ( !pPortion->IsRightToLeft() ) + { + nX += nPosInPortion; + } + else + { + nX += nPortionTextWidth - nPosInPortion; + } + + if ( pPortion->GetExtraInfos() && pPortion->GetExtraInfos()->bCompressed ) + { + nX += pPortion->GetExtraInfos()->nPortionOffsetX; + if ( pPortion->GetExtraInfos()->nAsianCompressionTypes & CHAR_PUNCTUATIONRIGHT ) + { + BYTE nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex ) ); + if ( nType == CHAR_PUNCTUATIONRIGHT ) + { + USHORT n = nIndex - nTextPortionStart; + const sal_Int32* pDXArray = pLine->GetCharPosArray().GetData()+( nTextPortionStart-pLine->GetStart() ); + sal_Int32 nCharWidth = ( ( (n+1) < pPortion->GetLen() ) ? pDXArray[n] : pPortion->GetSize().Width() ) + - ( n ? pDXArray[n-1] : 0 ); + if ( (n+1) < pPortion->GetLen() ) + { + // smaller, when char behind is CHAR_PUNCTUATIONRIGHT also + nType = GetCharTypeForCompression( pParaPortion->GetNode()->GetChar( nIndex+1 ) ); + if ( nType == CHAR_PUNCTUATIONRIGHT ) + { + sal_Int32 nNextCharWidth = ( ( (n+2) < pPortion->GetLen() ) ? pDXArray[n+1] : pPortion->GetSize().Width() ) + - pDXArray[n]; + sal_Int32 nCompressed = nNextCharWidth/2; + nCompressed *= pPortion->GetExtraInfos()->nMaxCompression100thPercent; + nCompressed /= 10000; + nCharWidth += nCompressed; + } + } + else + { + nCharWidth *= 2; // last char pos to portion end is only compressed size + } + nX += nCharWidth/2; // 50% compression + } + } + } + } + } + } + else // if ( nIndex == pLine->GetStart() ) + { + if ( pPortion->IsRightToLeft() ) + { + nX += nPortionTextWidth; + } + } + + return nX; +} + +void ImpEditEngine::CalcHeight( ParaPortion* pPortion ) +{ + pPortion->nHeight = 0; + pPortion->nFirstLineOffset = 0; + + if ( pPortion->IsVisible() ) + { + DBG_ASSERT( pPortion->GetLines().Count(), "Absatz ohne Zeilen in ParaPortion::CalcHeight" ); + for ( USHORT nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) + pPortion->nHeight += pPortion->GetLines().GetObject( nLine )->GetHeight(); + + if ( !aStatus.IsOutliner() ) + { + const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + USHORT nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + + if ( nSBL ) + { + if ( pPortion->GetLines().Count() > 1 ) + pPortion->nHeight += ( pPortion->GetLines().Count() - 1 ) * nSBL; + if ( aStatus.ULSpaceSummation() ) + pPortion->nHeight += nSBL; + } + + USHORT nPortion = GetParaPortions().GetPos( pPortion ); + if ( nPortion || aStatus.ULSpaceFirstParagraph() ) + { + USHORT nUpper = GetYValue( rULItem.GetUpper() ); + pPortion->nHeight += nUpper; + pPortion->nFirstLineOffset = nUpper; + } + + if ( ( nPortion != (GetParaPortions().Count()-1) ) ) + { + pPortion->nHeight += GetYValue( rULItem.GetLower() ); // nicht in letzter + } + + + if ( nPortion && !aStatus.ULSpaceSummation() ) + { + ParaPortion* pPrev = GetParaPortions().SaveGetObject( nPortion-1 ); + const SvxULSpaceItem& rPrevULItem = (const SvxULSpaceItem&)pPrev->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + const SvxLineSpacingItem& rPrevLSItem = (const SvxLineSpacingItem&)pPrev->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + + // Verhalten WinWord6/Writer3: + // Bei einem proportionalen Zeilenabstand wird auch der Absatzabstand + // manipuliert. + // Nur Writer3: Nicht aufaddieren, sondern Mindestabstand. + + // Pruefen, ob Abstand durch LineSpacing > Upper: + USHORT nExtraSpace = GetYValue( lcl_CalcExtraSpace( pPortion, rLSItem ) ); + if ( nExtraSpace > pPortion->nFirstLineOffset ) + { + // Absatz wird 'groesser': + pPortion->nHeight += ( nExtraSpace - pPortion->nFirstLineOffset ); + pPortion->nFirstLineOffset = nExtraSpace; + } + + // nFirstLineOffset jetzt f(pNode) => jetzt f(pNode, pPrev) ermitteln: + USHORT nPrevLower = GetYValue( rPrevULItem.GetLower() ); + + // Dieser PrevLower steckt noch in der Hoehe der PrevPortion... + if ( nPrevLower > pPortion->nFirstLineOffset ) + { + // Absatz wird 'kleiner': + pPortion->nHeight -= pPortion->nFirstLineOffset; + pPortion->nFirstLineOffset = 0; + } + else if ( nPrevLower ) + { + // Absatz wird 'etwas kleiner': + pPortion->nHeight -= nPrevLower; + pPortion->nFirstLineOffset = + pPortion->nFirstLineOffset - nPrevLower; + } + + // Finde ich zwar nicht so gut, aber Writer3-Feature: + // Pruefen, ob Abstand durch LineSpacing > Lower: + // Dieser Wert steckt nicht in der Hoehe der PrevPortion. + if ( !pPrev->IsInvalid() ) + { + nExtraSpace = GetYValue( lcl_CalcExtraSpace( pPrev, rPrevLSItem ) ); + if ( nExtraSpace > nPrevLower ) + { + USHORT nMoreLower = nExtraSpace - nPrevLower; + // Absatz wird 'groesser', 'waechst' nach unten: + if ( nMoreLower > pPortion->nFirstLineOffset ) + { + pPortion->nHeight += ( nMoreLower - pPortion->nFirstLineOffset ); + pPortion->nFirstLineOffset = nMoreLower; + } + } + } + } + } + } +} + +Rectangle ImpEditEngine::GetEditCursor( ParaPortion* pPortion, USHORT nIndex, USHORT nFlags ) +{ + DBG_ASSERT( pPortion->IsVisible(), "Wozu GetEditCursor() bei einem unsichtbaren Absatz?" ); + DBG_ASSERT( IsFormatted() || GetTextRanger(), "GetEditCursor: Nicht formatiert" ); + + /* + GETCRSR_ENDOFLINE: Wenn hinter dem letzten Zeichen einer umgebrochenen Zeile, + am Ende der Zeile bleiben, nicht am Anfang der naechsten. + Zweck: - END => wirklich hinter das letzte Zeichen + - Selektion.... + */ + + long nY = pPortion->GetFirstLineOffset(); + + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + USHORT nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + + USHORT nCurIndex = 0; + DBG_ASSERT( pPortion->GetLines().Count(), "Leere ParaPortion in GetEditCursor!" ); + EditLine* pLine = 0; + BOOL bEOL = ( nFlags & GETCRSR_ENDOFLINE ) ? TRUE : FALSE; + for ( USHORT nLine = 0; nLine < pPortion->GetLines().Count(); nLine++ ) + { + EditLine* pTmpLine = pPortion->GetLines().GetObject( nLine ); + if ( ( pTmpLine->GetStart() == nIndex ) || ( pTmpLine->IsIn( nIndex, bEOL ) ) ) + { + pLine = pTmpLine; + break; + } + + nCurIndex = nCurIndex + pTmpLine->GetLen(); + nY += pTmpLine->GetHeight(); + if ( !aStatus.IsOutliner() ) + nY += nSBL; + } + if ( !pLine ) + { + // Cursor am Ende des Absatzes. + DBG_ASSERT( nIndex == nCurIndex, "Index voll daneben in GetEditCursor!" ); + + pLine = pPortion->GetLines().GetObject( pPortion->GetLines().Count()-1 ); + nY -= pLine->GetHeight(); + if ( !aStatus.IsOutliner() ) + nY -= nSBL; + nCurIndex = nCurIndex - pLine->GetLen(); + } + + Rectangle aEditCursor; + + aEditCursor.Top() = nY; + nY += pLine->GetHeight(); + aEditCursor.Bottom() = nY-1; + + // innerhalb der Zeile suchen... + long nX; + + if ( ( nIndex == pLine->GetStart() ) && ( nFlags & GETCRSR_STARTOFLINE ) ) + { + Range aXRange = GetLineXPosStartEnd( pPortion, pLine ); + nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Min() : aXRange.Max(); + } + else if ( ( nIndex == pLine->GetEnd() ) && ( nFlags & GETCRSR_ENDOFLINE ) ) + { + Range aXRange = GetLineXPosStartEnd( pPortion, pLine ); + nX = !IsRightToLeft( GetEditDoc().GetPos( pPortion->GetNode() ) ) ? aXRange.Max() : aXRange.Min(); + } + else + { + nX = GetXPos( pPortion, pLine, nIndex, ( nFlags & GETCRSR_PREFERPORTIONSTART ) ? TRUE : FALSE ); + } + + aEditCursor.Left() = aEditCursor.Right() = nX; + + if ( nFlags & GETCRSR_TXTONLY ) + aEditCursor.Top() = aEditCursor.Bottom() - pLine->GetTxtHeight() + 1; + else + aEditCursor.Top() = aEditCursor.Bottom() - Min( pLine->GetTxtHeight(), pLine->GetHeight() ) + 1; + + return aEditCursor; +} + +void ImpEditEngine::SetValidPaperSize( const Size& rNewSz ) +{ + aPaperSize = rNewSz; + + long nMinWidth = aStatus.AutoPageWidth() ? aMinAutoPaperSize.Width() : 0; + long nMaxWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : 0x7FFFFFFF; + long nMinHeight = aStatus.AutoPageHeight() ? aMinAutoPaperSize.Height() : 0; + long nMaxHeight = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : 0x7FFFFFFF; + + // Minimale/Maximale Breite: + if ( aPaperSize.Width() < nMinWidth ) + aPaperSize.Width() = nMinWidth; + else if ( aPaperSize.Width() > nMaxWidth ) + aPaperSize.Width() = nMaxWidth; + + // Minimale/Maximale Hoehe: + if ( aPaperSize.Height() < nMinHeight ) + aPaperSize.Height() = nMinHeight; + else if ( aPaperSize.Height() > nMaxHeight ) + aPaperSize.Height() = nMaxHeight; +} + +void ImpEditEngine::IndentBlock( EditView* pEditView, BOOL bRight ) +{ + ESelection aESel( CreateESel( pEditView->pImpEditView->GetEditSelection() ) ); + aESel.Adjust(); + + // Nur wenn mehrere selektierte Absaetze... + if ( aESel.nEndPara > aESel.nStartPara ) + { + ESelection aNewSel = aESel; + aNewSel.nStartPos = 0; + aNewSel.nEndPos = 0xFFFF; + + if ( aESel.nEndPos == 0 ) + { + aESel.nEndPara--; // dann diesen Absatz nicht... + aNewSel.nEndPos = 0; + } + + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( + pEditView->pImpEditView->GetEditSelection().Max() ); + UndoActionStart( bRight ? EDITUNDO_INDENTBLOCK : EDITUNDO_UNINDENTBLOCK ); + + for ( USHORT nPara = aESel.nStartPara; nPara <= aESel.nEndPara; nPara++ ) + { + ContentNode* pNode = GetEditDoc().GetObject( nPara ); + if ( bRight ) + { + // Tabs hinzufuegen + EditPaM aPaM( pNode, 0 ); + InsertTab( aPaM ); + } + else + { + // Tabs entfernen + EditCharAttrib* pFeature = pNode->GetCharAttribs().FindFeature( 0 ); + if ( pFeature && ( pFeature->GetStart() == 0 ) && + ( pFeature->GetItem()->Which() == EE_FEATURE_TAB ) ) + { + EditPaM aStartPaM( pNode, 0 ); + EditPaM aEndPaM( pNode, 1 ); + ImpDeleteSelection( EditSelection( aStartPaM, aEndPaM ) ); + } + } + } + + UndoActionEnd( bRight ? EDITUNDO_INDENTBLOCK : EDITUNDO_UNINDENTBLOCK ); + UpdateSelections(); + FormatAndUpdate( pEditView ); + + ContentNode* pLastNode = GetEditDoc().GetObject( aNewSel.nEndPara ); + if ( pLastNode->Len() < aNewSel.nEndPos ) + aNewSel.nEndPos = pLastNode->Len(); + pEditView->pImpEditView->SetEditSelection( CreateSel( aNewSel ) ); + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->ShowCursor( FALSE, TRUE ); + } +} + +vos::ORef<SvxForbiddenCharactersTable> ImpEditEngine::GetForbiddenCharsTable( BOOL bGetInternal ) const +{ + vos::ORef<SvxForbiddenCharactersTable> xF = xForbiddenCharsTable; + if ( !xF.isValid() && bGetInternal ) + xF = EE_DLL()->GetGlobalData()->GetForbiddenCharsTable(); + return xF; +} + +void ImpEditEngine::SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ) +{ + EE_DLL()->GetGlobalData()->SetForbiddenCharsTable( xForbiddenChars ); +} + +svtools::ColorConfig& ImpEditEngine::GetColorConfig() +{ + if ( !pColorConfig ) + pColorConfig = new svtools::ColorConfig; + + return *pColorConfig; +} + +BOOL ImpEditEngine::IsVisualCursorTravelingEnabled() +{ + BOOL bVisualCursorTravaling = FALSE; + + if( !pCTLOptions ) + pCTLOptions = new SvtCTLOptions; + + if ( pCTLOptions->IsCTLFontEnabled() && ( pCTLOptions->GetCTLCursorMovement() == SvtCTLOptions::MOVEMENT_VISUAL ) ) + { + bVisualCursorTravaling = TRUE; + } + + return bVisualCursorTravaling; + +} + +BOOL ImpEditEngine::DoVisualCursorTraveling( const ContentNode* ) +{ + // Don't check if it's necessary, because we also need it when leaving the paragraph + return IsVisualCursorTravelingEnabled(); +/* + BOOL bDoVisualCursorTraveling = FALSE; + + if ( IsVisualCursorTravelingEnabled() && pNode->Len() ) + { + // Only necessary when RTL text in LTR para or LTR text in RTL para + bDoVisualCursorTraveling = HasDifferentRTLLevels( pNode ); + } + + return bDoVisualCursorTraveling; +*/ +} + + +void ImpEditEngine::CallNotify( EENotify& rNotify ) +{ + if ( !nBlockNotifications ) + { + GetNotifyHdl().Call( &rNotify ); + } + else + { + EENotify* pNewNotify = new EENotify( rNotify ); + aNotifyCache.Insert( pNewNotify, aNotifyCache.Count() ); + } +} + +void ImpEditEngine::EnterBlockNotifications() +{ + if( !nBlockNotifications ) + { + // #109864# Send out START notification immediately, to allow + // external, non-queued events to be captured as well from + // client side + EENotify aNotify( EE_NOTIFY_BLOCKNOTIFICATION_START ); + aNotify.pEditEngine = GetEditEnginePtr(); + GetNotifyHdl().Call( &aNotify ); + } + + nBlockNotifications++; +} + +void ImpEditEngine::LeaveBlockNotifications() +{ + DBG_ASSERT( nBlockNotifications, "LeaveBlockNotifications - Why?" ); + + nBlockNotifications--; + if ( !nBlockNotifications ) + { + // Call blocked notify events... + while ( aNotifyCache.Count() ) + { + EENotify* pNotify = aNotifyCache[0]; + // Remove from list before calling, maybe we enter LeaveBlockNotifications while calling the handler... + aNotifyCache.Remove( 0 ); + GetNotifyHdl().Call( pNotify ); + delete pNotify; + } + + EENotify aNotify( EE_NOTIFY_BLOCKNOTIFICATION_END ); + aNotify.pEditEngine = GetEditEnginePtr(); + GetNotifyHdl().Call( &aNotify ); + } +} + +IMPL_LINK( ImpEditEngine, DocModified, void*, EMPTYARG ) +{ + aModifyHdl.Call( NULL /*GetEditEnginePtr()*/ ); // NULL, because also used for Outliner + return 0; +} diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx new file mode 100644 index 000000000000..6eabdc50497c --- /dev/null +++ b/editeng/source/editeng/impedit3.cxx @@ -0,0 +1,4680 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: impedit3.cxx,v $ + * $Revision: 1.124.82.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> +#include <vcl/metaact.hxx> +#include <vcl/gdimtf.hxx> + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> + +#include <vcl/wrkwin.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/flditem.hxx> +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/txtrange.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/scriptspaceitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/numitem.hxx> + +#include <svtools/colorcfg.hxx> +#include <svl/ctloptions.hxx> + +#include <editeng/forbiddencharacterstable.hxx> + +#include <unotools/localedatawrapper.hxx> + +#include <editeng/unolingu.hxx> + +#include <math.h> +#include <vcl/svapp.hxx> +#include <vcl/metric.hxx> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/text/CharacterCompressionType.hpp> +#include <vcl/pdfextoutdevdata.hxx> +#include <i18npool/mslangid.hxx> + +#include <comphelper/processfactory.hxx> + +using ::rtl::OUString; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::linguistic2; + +SV_DECL_VARARR_SORT( SortedPositions, sal_uInt32, 16, 8 ) +SV_IMPL_VARARR_SORT( SortedPositions, sal_uInt32 ); + +#define CH_HYPH '-' + +#define RESDIFF 10 + +#define WRONG_SHOW_MIN 5 +#define WRONG_SHOW_SMALL 11 +#define WRONG_SHOW_MEDIUM 15 + +struct TabInfo +{ + BOOL bValid; + + SvxTabStop aTabStop; + xub_StrLen nCharPos; + USHORT nTabPortion; + long nStartPosX; + long nTabPos; + + TabInfo() { bValid = FALSE; } +}; + +Point Rotate( const Point& rPoint, short nOrientation, const Point& rOrigin ) +{ + double nRealOrientation = nOrientation*F_PI1800; + double nCos = cos( nRealOrientation ); + double nSin = sin( nRealOrientation ); + + Point aRotatedPos; + Point aTranslatedPos( rPoint ); + + // Translation + aTranslatedPos -= rOrigin; + + // Rotation... + aRotatedPos.X() = (long) ( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() ); + aRotatedPos.Y() = (long) - ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() ); + aTranslatedPos = aRotatedPos; + + // Translation... + aTranslatedPos += rOrigin; + return aTranslatedPos; +} + +BYTE GetCharTypeForCompression( xub_Unicode cChar ) +{ + switch ( cChar ) + { + case 0x3008: case 0x300A: case 0x300C: case 0x300E: + case 0x3010: case 0x3014: case 0x3016: case 0x3018: + case 0x301A: case 0x301D: + { + return CHAR_PUNCTUATIONRIGHT; + } + case 0x3001: case 0x3002: case 0x3009: case 0x300B: + case 0x300D: case 0x300F: case 0x3011: case 0x3015: + case 0x3017: case 0x3019: case 0x301B: case 0x301E: + case 0x301F: + { + return CHAR_PUNCTUATIONLEFT; + } + default: + { + return ( ( 0x3040 <= cChar ) && ( 0x3100 > cChar ) ) ? CHAR_KANA : CHAR_NORMAL; + } + } +} + +void lcl_DrawRedLines( + OutputDevice* pOutDev, + long nFontHeight, + const Point& rPnt, + sal_uInt16 nIndex, + sal_uInt16 nMaxEnd, + const sal_Int32* pDXArray, + WrongList* pWrongs, + short nOrientation, + const Point& rOrigin, + BOOL bVertical, + BOOL bIsRightToLeft ) +{ +#ifndef SVX_LIGHT + // Aber nur, wenn Font nicht zu klein... + long nHght = pOutDev->LogicToPixel( Size( 0, nFontHeight ) ).Height(); + if( WRONG_SHOW_MIN < nHght ) + { + sal_uInt16 nStyle; + if( WRONG_SHOW_MEDIUM < nHght ) + nStyle = WAVE_NORMAL; + else if( WRONG_SHOW_SMALL < nHght ) + nStyle = WAVE_SMALL; + else + nStyle = WAVE_FLAT; + + sal_uInt16 nEnd, nStart = nIndex; + sal_Bool bWrong = pWrongs->NextWrong( nStart, nEnd ); + while ( bWrong ) + { + if ( nStart >= nMaxEnd ) + break; + + if ( nStart < nIndex ) // Wurde korrigiert + nStart = nIndex; + if ( nEnd > nMaxEnd ) + nEnd = nMaxEnd; + Point aPnt1( rPnt ); + if ( bVertical && ( nStyle != WAVE_FLAT ) ) + { + // VCL doesn't know that the text is vertical, and is manipulating + // the positions a little bit in y direction... + long nOnePixel = pOutDev->PixelToLogic( Size( 0, 1 ) ).Height(); + long nCorrect = ( nStyle == WAVE_NORMAL ) ? 2*nOnePixel : nOnePixel; + aPnt1.Y() -= nCorrect; + aPnt1.X() -= nCorrect; + } + if ( nStart > nIndex ) + { + if ( !bVertical ) + { + // since for RTL portions rPnt is on the visual right end of the portion + // (i.e. at the start of the first RTL char) we need to subtract the offset + // for RTL portions... + aPnt1.X() += (bIsRightToLeft ? -1 : 1) * pDXArray[ nStart - nIndex - 1 ]; + } + else + aPnt1.Y() += pDXArray[ nStart - nIndex - 1 ]; + } + Point aPnt2( rPnt ); + DBG_ASSERT( nEnd > nIndex, "RedLine: aPnt2?" ); + if ( !bVertical ) + { + // since for RTL portions rPnt is on the visual right end of the portion + // (i.e. at the start of the first RTL char) we need to subtract the offset + // for RTL portions... + aPnt2.X() += (bIsRightToLeft ? -1 : 1) * pDXArray[ nEnd - nIndex - 1 ]; + } + else + aPnt2.Y() += pDXArray[ nEnd - nIndex - 1 ]; + if ( nOrientation ) + { + aPnt1 = Rotate( aPnt1, nOrientation, rOrigin ); + aPnt2 = Rotate( aPnt2, nOrientation, rOrigin ); + } + + pOutDev->DrawWaveLine( aPnt1, aPnt2, nStyle ); + + nStart = nEnd+1; + if ( nEnd < nMaxEnd ) + bWrong = pWrongs->NextWrong( nStart, nEnd ); + else + bWrong = sal_False; + } + } +#endif // !SVX_LIGHT +} + +Point lcl_ImplCalcRotatedPos( Point rPos, Point rOrigin, double nSin, double nCos ) +{ + Point aRotatedPos; + // Translation... + Point aTranslatedPos( rPos); + aTranslatedPos -= rOrigin; + + aRotatedPos.X() = (long) ( nCos*aTranslatedPos.X() + nSin*aTranslatedPos.Y() ); + aRotatedPos.Y() = (long) - ( nSin*aTranslatedPos.X() - nCos*aTranslatedPos.Y() ); + aTranslatedPos = aRotatedPos; + // Translation... + aTranslatedPos += rOrigin; + + return aTranslatedPos; +} + +sal_Bool lcl_IsLigature( xub_Unicode cCh, xub_Unicode cNextCh ) // For Kashidas from sw/source/core/text/porlay.txt +{ + // Lam + Alef + return ( 0x644 == cCh && 0x627 == cNextCh ) || + // Beh + Reh + ( 0x628 == cCh && 0x631 == cNextCh ); +} + +sal_Bool lcl_ConnectToPrev( xub_Unicode cCh, xub_Unicode cPrevCh ) // For Kashidas from sw/source/core/text/porlay.txt +{ + // Alef, Dal, Thal, Reh, Zain, and Waw do not connect to the left + sal_Bool bRet = 0x627 != cPrevCh && 0x62F != cPrevCh && 0x630 != cPrevCh && + 0x631 != cPrevCh && 0x632 != cPrevCh && 0x648 != cPrevCh; + + // check for ligatures cPrevChar + cChar + if ( bRet ) + bRet = ! lcl_IsLigature( cPrevCh, cCh ); + + return bRet; +} + + +// ---------------------------------------------------------------------- +// class ImpEditEngine +// ---------------------------------------------------------------------- +void ImpEditEngine::UpdateViews( EditView* pCurView ) +{ + if ( !GetUpdateMode() || IsFormatting() || aInvalidRec.IsEmpty() ) + return; + + DBG_ASSERT( IsFormatted(), "UpdateViews: Doc nicht formatiert!" ); + + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + DBG_CHKOBJ( pView, EditView, 0 ); + pView->HideCursor(); + + Rectangle aClipRec( aInvalidRec ); + Rectangle aVisArea( pView->GetVisArea() ); + aClipRec.Intersection( aVisArea ); + + if ( !aClipRec.IsEmpty() ) + { + // in Fensterkoordinaten umwandeln.... + aClipRec = pView->pImpEditView->GetWindowPos( aClipRec ); + + if ( ( pView == pCurView ) ) + Paint( pView->pImpEditView, aClipRec, sal_True ); + else + pView->GetWindow()->Invalidate( aClipRec ); + } + } + + if ( pCurView ) + { + sal_Bool bGotoCursor = pCurView->pImpEditView->DoAutoScroll(); + pCurView->ShowCursor( bGotoCursor ); + } + + aInvalidRec = Rectangle(); + CallStatusHdl(); +} + +IMPL_LINK( ImpEditEngine, OnlineSpellHdl, Timer *, EMPTYARG ) +{ + if ( !Application::AnyInput( INPUT_KEYBOARD ) && GetUpdateMode() && IsFormatted() ) + DoOnlineSpelling(); + else + aOnlineSpellTimer.Start(); + + return 0; +} + +IMPL_LINK_INLINE_START( ImpEditEngine, IdleFormatHdl, Timer *, EMPTYARG ) +{ + aIdleFormatter.ResetRestarts(); + + // #i97146# check if that view is still available + // else probably the idle format timer fired while we're already + // downing + EditView* pView = aIdleFormatter.GetView(); + for( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + if( aEditViews[nView] == pView ) + { + FormatAndUpdate( pView ); + break; + } + } + return 0; +} +IMPL_LINK_INLINE_END( ImpEditEngine, IdleFormatHdl, Timer *, EMPTYARG ) + +void ImpEditEngine::CheckIdleFormatter() +{ + aIdleFormatter.ForceTimeout(); + // Falls kein Idle, aber trotzdem nicht formatiert: + if ( !IsFormatted() ) + FormatDoc(); +} + +void ImpEditEngine::FormatFullDoc() +{ + for ( sal_uInt16 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) + GetParaPortions()[nPortion]->MarkSelectionInvalid( 0, GetParaPortions()[nPortion]->GetNode()->Len() ); + FormatDoc(); +} + +void ImpEditEngine::FormatDoc() +{ + if ( !GetUpdateMode() || IsFormatting() ) + return; + + EnterBlockNotifications(); + + bIsFormatting = sal_True; + + // Dann kann ich auch den Spell-Timer starten... + if ( GetStatus().DoOnlineSpelling() ) + StartOnlineSpellTimer(); + + long nY = 0; + sal_Bool bGrow = sal_False; + + Font aOldFont( GetRefDevice()->GetFont() ); + + // Hier schon, damit nicht jedesmal in CreateLines... + sal_Bool bMapChanged = ImpCheckRefMapMode(); + + aInvalidRec = Rectangle(); // leermachen + for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) + { + ParaPortion* pParaPortion = GetParaPortions().GetObject( nPara ); + if ( pParaPortion->MustRepaint() || ( pParaPortion->IsInvalid() && pParaPortion->IsVisible() ) ) + { + if ( pParaPortion->IsInvalid() ) + { + sal_Bool bChangedByDerivedClass = GetEditEnginePtr()->FormattingParagraph( nPara ); + if ( bChangedByDerivedClass ) + { + pParaPortion->GetTextPortions().Reset(); + pParaPortion->MarkSelectionInvalid( 0, pParaPortion->GetNode()->Len() ); + } + } + // bei MustRepaint() sollte keine Formatierung noetig sein! + // 23.1.95: Evtl. ist sie durch eine andere Aktion aber doch + // ungueltig geworden! +// if ( pParaPortion->MustRepaint() || CreateLines( nPara ) ) + if ( ( pParaPortion->MustRepaint() && !pParaPortion->IsInvalid() ) + || CreateLines( nPara, nY ) ) + { + if ( !bGrow && GetTextRanger() ) + { + // Bei einer Aenderung der Hoehe muss alles weiter unten + // neu formatiert werden... + for ( sal_uInt16 n = nPara+1; n < GetParaPortions().Count(); n++ ) + { + ParaPortion* pPP = GetParaPortions().GetObject( n ); + pPP->MarkSelectionInvalid( 0, pPP->GetNode()->Len() ); + pPP->GetLines().Reset(); + } + } + bGrow = sal_True; + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphHeightChanged( nPara ); + pParaPortion->SetMustRepaint( sal_False ); + } + + // InvalidRec nur einmal setzen... + if ( aInvalidRec.IsEmpty() ) + { + // Bei Paperwidth 0 (AutoPageSize) bleibt es sonst Empty()... + long nWidth = Max( (long)1, ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) ); + Range aInvRange( GetInvalidYOffsets( pParaPortion ) ); + aInvalidRec = Rectangle( Point( 0, nY+aInvRange.Min() ), + Size( nWidth, aInvRange.Len() ) ); + } + else + { + aInvalidRec.Bottom() = nY + pParaPortion->GetHeight(); + } + } + else if ( bGrow ) + { + aInvalidRec.Bottom() = nY + pParaPortion->GetHeight(); + } + nY += pParaPortion->GetHeight(); + } + + // Man kann auch durch UpdateMode An=>AUS=>AN in die Formatierung gelangen... + // Optimierung erst nach Vobis-Auslieferung aktivieren... +// if ( !aInvalidRec.IsEmpty() ) + { + sal_uInt32 nNewHeight = CalcTextHeight(); + long nDiff = nNewHeight - nCurTextHeight; + if ( nDiff ) + aStatus.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTHEIGHTCHANGED : EE_STAT_TEXTWIDTHCHANGED; + if ( nNewHeight < nCurTextHeight ) + { + aInvalidRec.Bottom() = (long)Max( nNewHeight, nCurTextHeight ); + if ( aInvalidRec.IsEmpty() ) + { + aInvalidRec.Top() = 0; + // Left und Right werden nicht ausgewertet, aber wegen IsEmpty gesetzt. + aInvalidRec.Left() = 0; + aInvalidRec.Right() = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height(); + } + } + + nCurTextHeight = nNewHeight; + + if ( aStatus.AutoPageSize() ) + CheckAutoPageSize(); + else if ( nDiff ) + { + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + ImpEditView* pImpView = pView->pImpEditView; + if ( pImpView->DoAutoHeight() ) + { + Size aSz( pImpView->GetOutputArea().GetWidth(), nCurTextHeight ); + if ( aSz.Height() > aMaxAutoPaperSize.Height() ) + aSz.Height() = aMaxAutoPaperSize.Height(); + else if ( aSz.Height() < aMinAutoPaperSize.Height() ) + aSz.Height() = aMinAutoPaperSize.Height(); + pImpView->ResetOutputArea( Rectangle( + pImpView->GetOutputArea().TopLeft(), aSz ) ); + } + } + } + } + + if ( aStatus.DoRestoreFont() ) + GetRefDevice()->SetFont( aOldFont ); + bIsFormatting = sal_False; + bFormatted = sal_True; + + if ( bMapChanged ) + GetRefDevice()->Pop(); + + CallStatusHdl(); // Falls Modified... + + LeaveBlockNotifications(); +} + +sal_Bool ImpEditEngine::ImpCheckRefMapMode() +{ + sal_Bool bChange = sal_False; + + if ( aStatus.DoFormat100() ) + { + MapMode aMapMode( GetRefDevice()->GetMapMode() ); + if ( aMapMode.GetScaleX().GetNumerator() != aMapMode.GetScaleX().GetDenominator() ) + bChange = sal_True; + else if ( aMapMode.GetScaleY().GetNumerator() != aMapMode.GetScaleY().GetDenominator() ) + bChange = sal_True; + + if ( bChange ) + { + Fraction Scale1( 1, 1 ); + aMapMode.SetScaleX( Scale1 ); + aMapMode.SetScaleY( Scale1 ); + GetRefDevice()->Push(); + GetRefDevice()->SetMapMode( aMapMode ); + } + } + + return bChange; +} + +void ImpEditEngine::CheckAutoPageSize() +{ + Size aPrevPaperSize( GetPaperSize() ); + if ( GetStatus().AutoPageWidth() ) + aPaperSize.Width() = (long) !IsVertical() ? CalcTextWidth( TRUE ) : GetTextHeight(); + if ( GetStatus().AutoPageHeight() ) + aPaperSize.Height() = (long) !IsVertical() ? GetTextHeight() : CalcTextWidth( TRUE ); + + SetValidPaperSize( aPaperSize ); //Min, Max beruecksichtigen + + if ( aPaperSize != aPrevPaperSize ) + { + if ( ( !IsVertical() && ( aPaperSize.Width() != aPrevPaperSize.Width() ) ) + || ( IsVertical() && ( aPaperSize.Height() != aPrevPaperSize.Height() ) ) ) + { + // Falls davor zentriert/rechts oder Tabs... + aStatus.GetStatusWord() |= !IsVertical() ? EE_STAT_TEXTWIDTHCHANGED : EE_STAT_TEXTHEIGHTCHANGED; + for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) + { + // Es brauchen nur Absaetze neu formatiert werden, + // die nicht linksbuendig sind. + // Die Hoehe kann sich hier nicht mehr aendern. + ParaPortion* pParaPortion = GetParaPortions().GetObject( nPara ); + ContentNode* pNode = pParaPortion->GetNode(); + SvxAdjust eJustification = GetJustification( nPara ); + if ( eJustification != SVX_ADJUST_LEFT ) + { + pParaPortion->MarkSelectionInvalid( 0, pNode->Len() ); + CreateLines( nPara, 0 ); // 0: Bei AutoPageSize kein TextRange! + } + } + } + + Size aInvSize = aPaperSize; + if ( aPaperSize.Width() < aPrevPaperSize.Width() ) + aInvSize.Width() = aPrevPaperSize.Width(); + if ( aPaperSize.Height() < aPrevPaperSize.Height() ) + aInvSize.Height() = aPrevPaperSize.Height(); + + Size aSz( aInvSize ); + if ( IsVertical() ) + { + aSz.Width() = aInvSize.Height(); + aSz.Height() = aInvSize.Width(); + } + aInvalidRec = Rectangle( Point(), aSz ); + + + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + pView->pImpEditView->RecalcOutputArea(); + } + } +} + +static sal_Int32 ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontHeight ) +{ + return ( nFontHeight * 12 ) / 10; // + 20% +} + +sal_Bool ImpEditEngine::CreateLines( USHORT nPara, sal_uInt32 nStartPosY ) +{ + ParaPortion* pParaPortion = GetParaPortions().GetObject( nPara ); + + // sal_Bool: Aenderung der Hoehe des Absatzes Ja/Nein - sal_True/sal_False + DBG_ASSERT( pParaPortion->GetNode(), "Portion ohne Node in CreateLines" ); + DBG_ASSERT( pParaPortion->IsVisible(), "Unsichtbare Absaetze nicht formatieren!" ); + DBG_ASSERT( pParaPortion->IsInvalid(), "CreateLines: Portion nicht invalid!" ); + + BOOL bProcessingEmptyLine = ( pParaPortion->GetNode()->Len() == 0 ); + BOOL bEmptyNodeWithPolygon = ( pParaPortion->GetNode()->Len() == 0 ) && GetTextRanger(); + + // --------------------------------------------------------------- + // Schnelle Sonderbehandlung fuer leere Absaetze... + // --------------------------------------------------------------- + if ( ( pParaPortion->GetNode()->Len() == 0 ) && !GetTextRanger() ) + { + // schnelle Sonderbehandlung... + if ( pParaPortion->GetTextPortions().Count() ) + pParaPortion->GetTextPortions().Reset(); + if ( pParaPortion->GetLines().Count() ) + pParaPortion->GetLines().Reset(); + CreateAndInsertEmptyLine( pParaPortion, nStartPosY ); + return FinishCreateLines( pParaPortion ); + } + + // --------------------------------------------------------------- + // Initialisierung...... + // --------------------------------------------------------------- + + // Immer fuer 100% formatieren: + sal_Bool bMapChanged = ImpCheckRefMapMode(); + + if ( pParaPortion->GetLines().Count() == 0 ) + { + EditLine* pL = new EditLine; + pParaPortion->GetLines().Insert( pL, 0 ); + } + + // --------------------------------------------------------------- + // Absatzattribute holen...... + // --------------------------------------------------------------- + ContentNode* const pNode = pParaPortion->GetNode(); + + BOOL bRightToLeftPara = IsRightToLeft( nPara ); + + SvxAdjust eJustification = GetJustification( nPara ); + sal_Bool bHyphenatePara = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_HYPHENATE )).GetValue(); + sal_Int32 nSpaceBefore = 0; + sal_Int32 nMinLabelWidth = 0; + sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pNode, &nSpaceBefore, &nMinLabelWidth ); + const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pNode ); + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&) pNode->GetContentAttribs().GetItem( EE_PARA_SBL ); + const BOOL bScriptSpace = ((const SvxScriptSpaceItem&) pNode->GetContentAttribs().GetItem( EE_PARA_ASIANCJKSPACING )).GetValue(); + +// const sal_uInt16 nInvalidEnd = ( pParaPortion->GetInvalidDiff() > 0 ) +// ? pParaPortion->GetInvalidPosStart() + pParaPortion->GetInvalidDiff() +// : pNode->Len(); + const short nInvalidDiff = pParaPortion->GetInvalidDiff(); + const sal_uInt16 nInvalidStart = pParaPortion->GetInvalidPosStart(); + const sal_uInt16 nInvalidEnd = nInvalidStart + Abs( nInvalidDiff ); + + sal_Bool bQuickFormat = sal_False; + if ( !bEmptyNodeWithPolygon && !HasScriptType( nPara, i18n::ScriptType::COMPLEX ) ) + { + if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff > 0 ) && + ( pNode->Search( CH_FEATURE, nInvalidStart ) > nInvalidEnd ) ) + { + bQuickFormat = sal_True; + } + else if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) ) + { + // pruefen, ob loeschen ueber Portiongrenzen erfolgte... + sal_uInt16 nStart = nInvalidStart; // DOPPELT !!!!!!!!!!!!!!! + sal_uInt16 nEnd = nStart - nInvalidDiff; // neg. + bQuickFormat = sal_True; + sal_uInt16 nPos = 0; + sal_uInt16 nPortions = pParaPortion->GetTextPortions().Count(); + for ( sal_uInt16 nTP = 0; nTP < nPortions; nTP++ ) + { + // Es darf kein Start/Ende im geloeschten Bereich liegen. + TextPortion* const pTP = pParaPortion->GetTextPortions()[ nTP ]; + nPos = nPos + pTP->GetLen(); + if ( ( nPos > nStart ) && ( nPos < nEnd ) ) + { + bQuickFormat = sal_False; + break; + } + } + } + } + + // SW disables TEXT_LAYOUT_COMPLEX_DISABLED, so maybe I have to enable it... + + // #114278# Saving both layout mode and language (since I'm + // potentially changing both) + + GetRefDevice()->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE ); + + ImplInitLayoutMode( GetRefDevice(), nPara, 0xFFFF ); + + sal_uInt16 nRealInvalidStart = nInvalidStart; + + if ( bEmptyNodeWithPolygon ) + { + TextPortion* pDummyPortion = new TextPortion( 0 ); + pParaPortion->GetTextPortions().Reset(); + pParaPortion->GetTextPortions().Insert( pDummyPortion, 0 ); + } + else if ( bQuickFormat ) + { + // schnellere Methode: + RecalcTextPortion( pParaPortion, nInvalidStart, nInvalidDiff ); + } + else // nRealInvalidStart kann vor InvalidStart liegen, weil Portions geloescht.... + { + CreateTextPortions( pParaPortion, nRealInvalidStart ); + } + + + // --------------------------------------------------------------- + // Zeile mit InvalidPos suchen, eine Zeile davor beginnen... + // Zeilen flaggen => nicht removen ! + // --------------------------------------------------------------- + + sal_uInt16 nLine = pParaPortion->GetLines().Count()-1; + for ( sal_uInt16 nL = 0; nL <= nLine; nL++ ) + { + EditLine* pLine = pParaPortion->GetLines().GetObject( nL ); + if ( pLine->GetEnd() > nRealInvalidStart ) // nicht nInvalidStart! + { + nLine = nL; + break; + } + pLine->SetValid(); + } + // Eine Zeile davor beginnen... + // Wenn ganz hinten getippt wird, kann sich die Zeile davor nicht aendern. + if ( nLine && ( !pParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) ) + nLine--; + + EditLine* pLine = pParaPortion->GetLines().GetObject( nLine ); + + static Rectangle aZeroArea = Rectangle( Point(), Point() ); + Rectangle aBulletArea( aZeroArea ); + if ( !nLine ) + { + aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) ); + if ( aBulletArea.Right() > 0 ) + pParaPortion->SetBulletX( (sal_uInt16) GetXValue( aBulletArea.Right() ) ); + else + pParaPortion->SetBulletX( 0 ); // Falls Bullet falsch eingestellt. + } + + // --------------------------------------------------------------- + // Ab hier alle Zeilen durchformatieren... + // --------------------------------------------------------------- + sal_uInt16 nDelFromLine = 0xFFFF; + sal_Bool bLineBreak = sal_False; + + sal_uInt16 nIndex = pLine->GetStart(); + EditLine aSaveLine( *pLine ); + SvxFont aTmpFont( pNode->GetCharAttribs().GetDefFont() ); + + sal_Bool bCalcCharPositions = sal_True; + sal_Int32* pBuf = new sal_Int32[ pNode->Len() ]; + + sal_Bool bSameLineAgain = sal_False; // Fuer TextRanger, wenn sich die Hoehe aendert. + TabInfo aCurrentTab; + + BOOL bForceOneRun = bEmptyNodeWithPolygon; + BOOL bCompressedChars = FALSE; + + while ( ( nIndex < pNode->Len() ) || bForceOneRun ) + { + bForceOneRun = FALSE; + + sal_Bool bEOL = sal_False; + sal_Bool bEOC = sal_False; + sal_uInt16 nPortionStart = 0; + sal_uInt16 nPortionEnd = 0; + + long nStartX = GetXValue( rLRItem.GetTxtLeft() + nSpaceBeforeAndMinLabelWidth ); + if ( nIndex == 0 ) + { + long nFI = GetXValue( rLRItem.GetTxtFirstLineOfst() ); + nStartX += nFI; + + if ( !nLine && ( pParaPortion->GetBulletX() > nStartX ) ) + { +// TL_NFLR nStartX += nFI; // Vielleicht reicht der LI? +// TL_NFLR if ( pParaPortion->GetBulletX() > nStartX ) + nStartX = pParaPortion->GetBulletX(); + } + } + + long nMaxLineWidth; + if ( !IsVertical() ) + nMaxLineWidth = aStatus.AutoPageWidth() ? aMaxAutoPaperSize.Width() : aPaperSize.Width(); + else + nMaxLineWidth = aStatus.AutoPageHeight() ? aMaxAutoPaperSize.Height() : aPaperSize.Height(); + + nMaxLineWidth -= GetXValue( rLRItem.GetRight() ); + nMaxLineWidth -= nStartX; + + // Wenn PaperSize == long_max, kann ich keinen neg. Erstzeileneinzug + // abziehen (Overflow) + if ( ( nMaxLineWidth < 0 ) && ( nStartX < 0 ) ) + nMaxLineWidth = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) - GetXValue( rLRItem.GetRight() ); + + // Wenn jetzt noch kleiner 0, kann es nur der rechte Rand sein. + if ( nMaxLineWidth <= 0 ) + nMaxLineWidth = 1; + + // Problem: Da eine Zeile _vor_ der ungueltigen Position mit der + // Formatierung begonnen wird, werden hier leider auch die Positionen + // neu bestimmt... + // Loesungsansatz: + // Die Zeile davor kann nur groesser werden, nicht kleiner + // => ... + if ( bCalcCharPositions ) + pLine->GetCharPosArray().Remove( 0, pLine->GetCharPosArray().Count() ); + + sal_uInt16 nTmpPos = nIndex; + sal_uInt16 nTmpPortion = pLine->GetStartPortion(); + long nTmpWidth = 0; + long nXWidth = nMaxLineWidth; + if ( nXWidth <= nTmpWidth ) // while muss 1x durchlaufen werden + nXWidth = nTmpWidth+1; + + SvLongsPtr pTextRanges = 0; + long nTextExtraYOffset = 0; + long nTextXOffset = 0; + long nTextLineHeight = 0; + if ( GetTextRanger() ) + { + GetTextRanger()->SetVertical( IsVertical() ); + + long nTextY = nStartPosY + GetEditCursor( pParaPortion, pLine->GetStart() ).Top(); + if ( !bSameLineAgain ) + { + SeekCursor( pNode, nTmpPos+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + + if ( IsFixedCellHeight() ) + nTextLineHeight = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() ); + else + nTextLineHeight = aTmpFont.GetPhysTxtSize( GetRefDevice(), String() ).Height(); + // Metriken koennen groesser sein + FormatterFontMetric aTempFormatterMetrics; + RecalcFormatterFontMetrics( aTempFormatterMetrics, aTmpFont ); + sal_uInt16 nLineHeight = aTempFormatterMetrics.GetHeight(); + if ( nLineHeight > nTextLineHeight ) + nTextLineHeight = nLineHeight; + } + else + nTextLineHeight = pLine->GetHeight(); + + nXWidth = 0; + while ( !nXWidth ) + { + long nYOff = nTextY + nTextExtraYOffset; + long nYDiff = nTextLineHeight; + if ( IsVertical() ) + { + long nMaxPolygonX = GetTextRanger()->GetBoundRect().Right(); + nYOff = nMaxPolygonX-nYOff; + nYDiff = -nTextLineHeight; + } + pTextRanges = GetTextRanger()->GetTextRanges( Range( nYOff, nYOff + nYDiff ) ); + DBG_ASSERT( pTextRanges, "GetTextRanges?!" ); + long nMaxRangeWidth = 0; + // Den breitesten Bereich verwenden... + // Der breiteste Bereich koennte etwas verwirren, also + // generell den ersten. Am besten mal richtig mit Luecken. +// for ( sal_uInt16 n = 0; n < pTextRanges->Count(); ) + if ( pTextRanges->Count() ) + { + sal_uInt16 n = 0; + long nA = pTextRanges->GetObject( n++ ); + long nB = pTextRanges->GetObject( n++ ); + DBG_ASSERT( nA <= nB, "TextRange verdreht?" ); + long nW = nB - nA; + if ( nW > nMaxRangeWidth ) + { + nMaxRangeWidth = nW; + nTextXOffset = nA; + } + } + nXWidth = nMaxRangeWidth; + if ( nXWidth ) + nMaxLineWidth = nXWidth - nStartX - GetXValue( rLRItem.GetRight() ); + else + { + // Weiter unten im Polygon versuchen. + // Unterhalb des Polygons die Paperbreite verwenden. + nTextExtraYOffset += Max( (long)(nTextLineHeight / 10), (long)1 ); + if ( ( nTextY + nTextExtraYOffset ) > GetTextRanger()->GetBoundRect().Bottom() ) + { + nXWidth = !IsVertical() ? GetPaperSize().Width() : GetPaperSize().Height(); + if ( !nXWidth ) // AutoPaperSize + nXWidth = 0x7FFFFFFF; + } + } + } + } + + // Portion suchen, die nicht mehr in Zeile passt.... + TextPortion* pPortion = 0; + sal_Bool bBrokenLine = sal_False; + bLineBreak = sal_False; + EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( pLine->GetStart() ); + while ( ( nTmpWidth < nXWidth ) && !bEOL && ( nTmpPortion < pParaPortion->GetTextPortions().Count() ) ) + { + nPortionStart = nTmpPos; + pPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + if ( pPortion->GetKind() == PORTIONKIND_HYPHENATOR ) + { + // Portion wegschmeissen, ggf. die davor korrigieren, wenn + // die Hyph-Portion ein Zeichen geschluckt hat... + pParaPortion->GetTextPortions().Remove( nTmpPortion ); + if ( nTmpPortion && pPortion->GetLen() ) + { + nTmpPortion--; + TextPortion* pPrev = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + DBG_ASSERT( pPrev->GetKind() == PORTIONKIND_TEXT, "Portion?!" ); + nTmpWidth -= pPrev->GetSize().Width(); + nTmpPos = nTmpPos - pPrev->GetLen(); + pPrev->SetLen( pPrev->GetLen() + pPortion->GetLen() ); + pPrev->GetSize().Width() = (-1); + } + delete pPortion; + DBG_ASSERT( nTmpPortion < pParaPortion->GetTextPortions().Count(), "Keine Portion mehr da!" ); + pPortion = pParaPortion->GetTextPortions().GetObject( nTmpPortion ); + } + DBG_ASSERT( pPortion->GetKind() != PORTIONKIND_HYPHENATOR, "CreateLines: Hyphenator-Portion!" ); + DBG_ASSERT( pPortion->GetLen() || bProcessingEmptyLine, "Leere Portion in CreateLines ?!" ); + if ( pNextFeature && ( pNextFeature->GetStart() == nTmpPos ) ) + { + sal_uInt16 nWhich = pNextFeature->GetItem()->Which(); + switch ( nWhich ) + { + case EE_FEATURE_TAB: + { + long nOldTmpWidth = nTmpWidth; + + // Tab-Pos suchen... + long nCurPos = nTmpWidth+nStartX; +// nCurPos -= rLRItem.GetTxtLeft(); // Tabs relativ zu LI + // Skalierung rausrechnen + if ( aStatus.DoStretch() && ( nStretchX != 100 ) ) + nCurPos = nCurPos*100/nStretchX; + + short nAllSpaceBeforeText = static_cast< short >(rLRItem.GetTxtLeft()/* + rLRItem.GetTxtLeft()*/ + nSpaceBeforeAndMinLabelWidth); + aCurrentTab.aTabStop = pNode->GetContentAttribs().FindTabStop( nCurPos - nAllSpaceBeforeText /*rLRItem.GetTxtLeft()*/, aEditDoc.GetDefTab() ); + aCurrentTab.nTabPos = GetXValue( (long) ( aCurrentTab.aTabStop.GetTabPos() + nAllSpaceBeforeText /*rLRItem.GetTxtLeft()*/ ) ); + aCurrentTab.bValid = FALSE; + + // Switch direction in R2L para... + if ( bRightToLeftPara ) + { + if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT ) + aCurrentTab.aTabStop.GetAdjustment() = SVX_TAB_ADJUST_LEFT; + else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_LEFT ) + aCurrentTab.aTabStop.GetAdjustment() = SVX_TAB_ADJUST_RIGHT; + } + + if ( ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT ) || + ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_CENTER ) || + ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL ) ) + { + // Bei LEFT/DEFAULT wird dieses Tab nicht mehr betrachtet. + aCurrentTab.bValid = TRUE; + aCurrentTab.nStartPosX = nTmpWidth; + aCurrentTab.nCharPos = nTmpPos; + aCurrentTab.nTabPortion = nTmpPortion; + } + + pPortion->GetKind() = PORTIONKIND_TAB; + pPortion->SetExtraValue( aCurrentTab.aTabStop.GetFill() ); + pPortion->GetSize().Width() = aCurrentTab.nTabPos - (nTmpWidth+nStartX); + + // #90520# Height needed... + SeekCursor( pNode, nTmpPos+1, aTmpFont ); + pPortion->GetSize().Height() = aTmpFont.QuickGetTextSize( GetRefDevice(), String(), 0, 0, NULL ).Height(); + + DBG_ASSERT( pPortion->GetSize().Width() >= 0, "Tab falsch berechnet!" ); + + nTmpWidth = aCurrentTab.nTabPos-nStartX; + + // Wenn dies das erste Token in der Zeile ist, + // und nTmpWidth > aPaperSize.Width, habe ich eine + // Endlos-Schleife! + if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) ) + { + // Aber was jetzt ? + // Tab passend machen + pPortion->GetSize().Width() = nXWidth-nOldTmpWidth; + nTmpWidth = nXWidth-1; + bEOL = sal_True; + bBrokenLine = sal_True; + } + pLine->GetCharPosArray().Insert( pPortion->GetSize().Width(), nTmpPos-pLine->GetStart() ); + bCompressedChars = FALSE; + } + break; + case EE_FEATURE_LINEBR: + { + DBG_ASSERT( pPortion, "?!" ); + pPortion->GetSize().Width() = 0; + bEOL = sal_True; + bLineBreak = sal_True; + pPortion->GetKind() = PORTIONKIND_LINEBREAK; + bCompressedChars = FALSE; + pLine->GetCharPosArray().Insert( pPortion->GetSize().Width(), nTmpPos-pLine->GetStart() ); + } + break; + case EE_FEATURE_FIELD: + { +// long nCurWidth = nTmpWidth; + SeekCursor( pNode, nTmpPos+1, aTmpFont ); + sal_Unicode cChar = 0; // later: NBS? + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + + String aFieldValue = cChar ? String(cChar) : ((EditCharAttribField*)pNextFeature)->GetFieldValue(); + if ( bCalcCharPositions || !pPortion->HasValidSize() ) + { + pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), aFieldValue, 0, aFieldValue.Len(), 0 ); + // Damit kein Scrollen bei ueberlangen Feldern + if ( pPortion->GetSize().Width() > nXWidth ) + pPortion->GetSize().Width() = nXWidth; + } + nTmpWidth += pPortion->GetSize().Width(); + pLine->GetCharPosArray().Insert( pPortion->GetSize().Width(), nTmpPos-pLine->GetStart() ); + pPortion->GetKind() = cChar ? PORTIONKIND_TEXT : PORTIONKIND_FIELD; + // Wenn dies das erste Token in der Zeile ist, + // und nTmpWidth > aPaperSize.Width, habe ich eine + // Endlos-Schleife! + if ( ( nTmpWidth >= nXWidth ) && ( nTmpPortion == pLine->GetStartPortion() ) ) + { + nTmpWidth = nXWidth-1; + bEOL = sal_True; + bBrokenLine = sal_True; + } + // Compression in Fields???? + // I think this could be a little bit difficult and is not very usefull + bCompressedChars = FALSE; + } + break; + default: DBG_ERROR( "Was fuer ein Feature ?" ); + } + pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1 ); + } + else + { + DBG_ASSERT( pPortion->GetLen() || bProcessingEmptyLine, "Empty Portion - Extra Space?!" ); + SeekCursor( pNode, nTmpPos+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + + if ( bCalcCharPositions || !pPortion->HasValidSize() ) + { + pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(), *pParaPortion->GetNode(), nTmpPos, pPortion->GetLen(), pBuf ); + + // #i9050# Do Kerning also behind portions... + if ( ( aTmpFont.GetFixKerning() > 0 ) && ( ( nTmpPos + pPortion->GetLen() ) < pNode->Len() ) ) + pPortion->GetSize().Width() += aTmpFont.GetFixKerning(); + if ( IsFixedCellHeight() ) + pPortion->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() ); + } + if ( bCalcCharPositions ) + { + sal_uInt16 nLen = pPortion->GetLen(); + // Es wird am Anfang generell das Array geplaettet + // => Immer einfach schnelles insert. + sal_uInt16 nPos = nTmpPos - pLine->GetStart(); + pLine->GetCharPosArray().Insert( pBuf, nLen, nPos ); + } + + // And now check for Compression: + if ( pPortion->GetLen() && GetAsianCompressionMode() ) + bCompressedChars |= ImplCalcAsianCompression( pNode, pPortion, nTmpPos, (sal_Int32*)pLine->GetCharPosArray().GetData() + (nTmpPos-pLine->GetStart()), 10000, FALSE ); + + nTmpWidth += pPortion->GetSize().Width(); + + pPortion->SetRightToLeft( GetRightToLeft( nPara, nTmpPos+1 ) ); + + USHORT _nPortionEnd = nTmpPos + pPortion->GetLen(); + if( bScriptSpace && ( _nPortionEnd < pNode->Len() ) && ( nTmpWidth < nXWidth ) && IsScriptChange( EditPaM( pNode, _nPortionEnd ) ) ) + { + BOOL bAllow = FALSE; + USHORT nScriptTypeLeft = GetScriptType( EditPaM( pNode, _nPortionEnd ) ); + USHORT nScriptTypeRight = GetScriptType( EditPaM( pNode, _nPortionEnd+1 ) ); + if ( ( nScriptTypeLeft == i18n::ScriptType::ASIAN ) || ( nScriptTypeRight == i18n::ScriptType::ASIAN ) ) + bAllow = TRUE; + + // No spacing within L2R/R2L nesting + if ( bAllow ) + { + long nExtraSpace = pPortion->GetSize().Height()/5; + nExtraSpace = GetXValue( nExtraSpace ); + pPortion->GetSize().Width() += nExtraSpace; + nTmpWidth += nExtraSpace; + } + } + } + + if ( aCurrentTab.bValid && ( nTmpPortion != aCurrentTab.nTabPortion ) ) + { + long nWidthAfterTab = 0; + for ( USHORT n = aCurrentTab.nTabPortion+1; n <= nTmpPortion; n++ ) + { + TextPortion* pTP = pParaPortion->GetTextPortions().GetObject( n ); + nWidthAfterTab += pTP->GetSize().Width(); + } + long nW = nWidthAfterTab; // Length before tab position + if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_RIGHT ) + { +// nW = nWidthAfterTab; + } + else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_CENTER ) + { + nW = nWidthAfterTab/2; + } + else if ( aCurrentTab.aTabStop.GetAdjustment() == SVX_TAB_ADJUST_DECIMAL ) + { +// nW = nWidthAfterTab; + String aText = GetSelected( EditSelection( EditPaM( pParaPortion->GetNode(), nTmpPos ), + EditPaM( pParaPortion->GetNode(), nTmpPos + pPortion->GetLen() ) ) ); + USHORT nDecPos = aText.Search( aCurrentTab.aTabStop.GetDecimal() ); + if ( nDecPos != STRING_NOTFOUND ) + { + nW -= pParaPortion->GetTextPortions().GetObject( nTmpPortion )->GetSize().Width(); + nW += aTmpFont.QuickGetTextSize( GetRefDevice(), *pParaPortion->GetNode(), nTmpPos, nDecPos, NULL ).Width(); + aCurrentTab.bValid = FALSE; + } + } + else + { + DBG_ERROR( "CreateLines: Tab not handled!" ); + } + long nMaxW = aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nStartX; + if ( nW >= nMaxW ) + { + nW = nMaxW; + aCurrentTab.bValid = FALSE; + } + TextPortion* pTabPortion = pParaPortion->GetTextPortions().GetObject( aCurrentTab.nTabPortion ); + pTabPortion->GetSize().Width() = aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nW - nStartX; + nTmpWidth = aCurrentTab.nStartPosX + pTabPortion->GetSize().Width() + nWidthAfterTab; + } + + nTmpPos = nTmpPos + pPortion->GetLen(); + nPortionEnd = nTmpPos; + nTmpPortion++; + if ( aStatus.OneCharPerLine() ) + bEOL = sal_True; + } + + DBG_ASSERT( pPortion, "no portion!?" ); + + aCurrentTab.bValid = FALSE; + + // das war evtl. eine Portion zu weit: + sal_Bool bFixedEnd = sal_False; + if ( aStatus.OneCharPerLine() ) + { + // Zustand vor Portion: ( bis auf nTmpWidth ) + nPortionEnd = nTmpPos; + nTmpPos -= pPortion ? pPortion->GetLen() : 0; + nPortionStart = nTmpPos; + nTmpPortion--; + + bEOL = sal_True; + bEOC = sal_False; + + // Und jetzt genau ein Zeichen: + nTmpPos++; + nTmpPortion++; + nPortionEnd = nTmpPortion; + // Eine Nicht-Feature-Portion muss gebrochen werden + if ( pPortion->GetLen() > 1 ) + { + DBG_ASSERT( pPortion && (pPortion->GetKind() == PORTIONKIND_TEXT), "Len>1, aber keine TextPortion?" ); + nTmpWidth -= pPortion ? pPortion->GetSize().Width() : 0; + sal_uInt16 nP = SplitTextPortion( pParaPortion, nTmpPos, pLine ); + TextPortion* p = pParaPortion->GetTextPortions().GetObject( nP ); + DBG_ASSERT( p, "Portion ?!" ); + nTmpWidth += p->GetSize().Width(); + } + } + else if ( nTmpWidth >= nXWidth ) + { + nPortionEnd = nTmpPos; + nTmpPos -= pPortion ? pPortion->GetLen() : 0; + nPortionStart = nTmpPos; + nTmpPortion--; + bEOL = sal_False; + bEOC = sal_False; + if( pPortion ) switch ( pPortion->GetKind() ) + { + case PORTIONKIND_TEXT: + { + nTmpWidth -= pPortion->GetSize().Width(); + } + break; + case PORTIONKIND_FIELD: + case PORTIONKIND_TAB: + { + nTmpWidth -= pPortion->GetSize().Width(); + bEOL = sal_True; + bFixedEnd = sal_True; + } + break; + default: + { + // Ein Feature wird nicht umgebrochen: + DBG_ASSERT( ( pPortion->GetKind() == PORTIONKIND_LINEBREAK ), "Was fuer ein Feature ?" ); + bEOL = sal_True; + bFixedEnd = sal_True; + } + } + } + else + { + bEOL = sal_True; + bEOC = sal_True; + pLine->SetEnd( nPortionEnd ); + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "Keine TextPortions?" ); + pLine->SetEndPortion( (sal_uInt16)pParaPortion->GetTextPortions().Count() - 1 ); + } + + if ( aStatus.OneCharPerLine() ) + { + pLine->SetEnd( nPortionEnd ); + pLine->SetEndPortion( nTmpPortion-1 ); + } + else if ( bFixedEnd ) + { + pLine->SetEnd( nPortionStart ); + pLine->SetEndPortion( nTmpPortion-1 ); + } + else if ( bLineBreak || bBrokenLine ) + { + pLine->SetEnd( nPortionStart+1 ); + pLine->SetEndPortion( nTmpPortion-1 ); + bEOC = sal_False; // wurde oben gesetzt, vielleich mal die if's umstellen? + } + else if ( !bEOL ) + { + DBG_ASSERT( pPortion && ((nPortionEnd-nPortionStart) == pPortion->GetLen()), "Doch eine andere Portion?!" ); + long nRemainingWidth = nMaxLineWidth - nTmpWidth; + sal_Bool bCanHyphenate = ( aTmpFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ); + if ( bCompressedChars && pPortion && ( pPortion->GetLen() > 1 ) && pPortion->GetExtraInfos() && pPortion->GetExtraInfos()->bCompressed ) + { + // I need the manipulated DXArray for determining the break postion... + ImplCalcAsianCompression( pNode, pPortion, nPortionStart, const_cast<sal_Int32*>(( pLine->GetCharPosArray().GetData() + (nPortionStart-pLine->GetStart()) )), 10000, TRUE ); + } + if( pPortion ) + ImpBreakLine( pParaPortion, pLine, pPortion, nPortionStart, + nRemainingWidth, bCanHyphenate && bHyphenatePara ); + } + + // ------------------------------------------------------------------ + // Zeile fertig => justieren + // ------------------------------------------------------------------ + + // CalcTextSize sollte besser durch ein kontinuierliches + // Registrieren ersetzt werden ! + Size aTextSize = pLine->CalcTextSize( *pParaPortion ); + + if ( aTextSize.Height() == 0 ) + { + SeekCursor( pNode, pLine->GetStart()+1, aTmpFont ); + aTmpFont.SetPhysFont( pRefDev ); + ImplInitDigitMode( pRefDev, 0, 0, 0, aTmpFont.GetLanguage() ); + + if ( IsFixedCellHeight() ) + aTextSize.Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() ); + else + aTextSize.Height() = aTmpFont.GetPhysTxtSize( pRefDev, String() ).Height(); + pLine->SetHeight( (sal_uInt16)aTextSize.Height() ); + } + + // Die Fontmetriken koennen nicht kontinuierlich berechnet werden, + // wenn der Font sowieso eingestellt ist, weil ggf. ein grosser Font + // erst nach dem Umbrechen ploetzlich in der naechsten Zeile landet + // => Font-Metriken zu gross. + FormatterFontMetric aFormatterMetrics; + sal_uInt16 nTPos = pLine->GetStart(); + for ( sal_uInt16 nP = pLine->GetStartPortion(); nP <= pLine->GetEndPortion(); nP++ ) + { + TextPortion* pTP = pParaPortion->GetTextPortions().GetObject( nP ); + // #95819# problem with hard font height attribute, when everthing but the line break has this attribute + if ( pTP->GetKind() != PORTIONKIND_LINEBREAK ) + { + SeekCursor( pNode, nTPos+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont ); + } + nTPos = nTPos + pTP->GetLen(); + } + sal_uInt16 nLineHeight = aFormatterMetrics.GetHeight(); + if ( nLineHeight > pLine->GetHeight() ) + pLine->SetHeight( nLineHeight ); + pLine->SetMaxAscent( aFormatterMetrics.nMaxAscent ); + + bSameLineAgain = sal_False; + if ( GetTextRanger() && ( pLine->GetHeight() > nTextLineHeight ) ) + { + // Nochmal mit der anderen Groesse aufsetzen! + bSameLineAgain = sal_True; + } + + + if ( !bSameLineAgain && !aStatus.IsOutliner() ) + { + if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN ) + { + sal_uInt16 nMinHeight = GetYValue( rLSItem.GetLineHeight() ); + sal_uInt16 nTxtHeight = pLine->GetHeight(); + if ( nTxtHeight < nMinHeight ) + { + // Der Ascent muss um die Differenz angepasst werden: + long nDiff = nMinHeight - nTxtHeight; + pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + nDiff) ); + pLine->SetHeight( nMinHeight, nTxtHeight ); + } + } + else if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + if ( nPara || IsFixedCellHeight() || pLine->GetStartPortion() ) // Nicht die aller erste Zeile + { + // #100508# There are documents with PropLineSpace 0, why? + // (cmc: re above question :-) such documents can be seen by importing a .ppt + if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) ) + { + sal_uInt16 nTxtHeight = pLine->GetHeight(); + sal_Int32 nH = nTxtHeight; + nH *= rLSItem.GetPropLineSpace(); + nH /= 100; + // Der Ascent muss um die Differenz angepasst werden: + long nDiff = pLine->GetHeight() - nH; + if ( nDiff > pLine->GetMaxAscent() ) + nDiff = pLine->GetMaxAscent(); + pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() - nDiff) ); + pLine->SetHeight( (sal_uInt16)nH, nTxtHeight ); + } + } + } + } + + + // #80582# - Bullet should not influence line height +// if ( !nLine ) +// { +// long nBulletHeight = aBulletArea.GetHeight(); +// if ( nBulletHeight > (long)pLine->GetHeight() ) +// { +// long nDiff = nBulletHeight - (long)pLine->GetHeight(); +// // nDiff auf oben und unten verteilen. +// pLine->SetMaxAscent( (sal_uInt16)(pLine->GetMaxAscent() + nDiff/2) ); +// pLine->SetHeight( (sal_uInt16)nBulletHeight ); +// } +// } + + if ( ( !IsVertical() && aStatus.AutoPageWidth() ) || + ( IsVertical() && aStatus.AutoPageHeight() ) ) + { + // Wenn die Zeile in die aktuelle Papierbreite passt, muss + // diese Breite fuer die Ausrichting verwendet werden. + // Wenn sie nicht passt oder sie die Papierbreite aendert, + // wird bei Justification != LEFT sowieso noch mal formatiert. + long nMaxLineWidthFix = ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) + - GetXValue( rLRItem.GetRight() ) - nStartX; + if ( aTextSize.Width() < nMaxLineWidthFix ) + nMaxLineWidth = nMaxLineWidthFix; + } + + if ( bCompressedChars ) + { + long nRemainingWidth = nMaxLineWidth - aTextSize.Width(); + if ( nRemainingWidth > 0 ) + { + ImplExpandCompressedPortions( pLine, pParaPortion, nRemainingWidth ); + aTextSize = pLine->CalcTextSize( *pParaPortion ); + } + } + + if ( pLine->IsHangingPunctuation() ) + { + // Width from HangingPunctuation was set to 0 in ImpBreakLine, + // check for rel width now, maybe create compression... + long n = nMaxLineWidth - aTextSize.Width(); + TextPortion* pTP = pParaPortion->GetTextPortions().GetObject( pLine->GetEndPortion() ); + sal_uInt16 nPosInArray = pLine->GetEnd()-1-pLine->GetStart(); + long nNewValue = ( nPosInArray ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0 ) + n; + pLine->GetCharPosArray()[ nPosInArray ] = nNewValue; + pTP->GetSize().Width() += n; + } + + pLine->SetTextWidth( aTextSize.Width() ); + switch ( eJustification ) + { + case SVX_ADJUST_CENTER: + { + long n = ( nMaxLineWidth - aTextSize.Width() ) / 2; + n += nStartX; // Einrueckung bleibt erhalten. + if ( n > 0 ) + pLine->SetStartPosX( (sal_uInt16)n ); + else + pLine->SetStartPosX( 0 ); + + } + break; + case SVX_ADJUST_RIGHT: + { + // Bei automatisch umgebrochenen Zeilen, die ein Blank + // am Ende enthalten, darf das Blank nicht ausgegeben werden! + + long n = nMaxLineWidth - aTextSize.Width(); + n += nStartX; // Einrueckung bleibt erhalten. + if ( n > 0 ) + pLine->SetStartPosX( (sal_uInt16)n ); + else + pLine->SetStartPosX( 0 ); + } + break; + case SVX_ADJUST_BLOCK: + { + long nRemainingSpace = nMaxLineWidth - aTextSize.Width(); + pLine->SetStartPosX( (sal_uInt16)nStartX ); + if ( !bEOC && ( nRemainingSpace > 0 ) ) // nicht die letzte Zeile... + ImpAdjustBlocks( pParaPortion, pLine, nRemainingSpace ); + } + break; + default: + { + pLine->SetStartPosX( (sal_uInt16)nStartX ); // FI, LI + } + break; + } + + // ----------------------------------------------------------------- + // pruefen, ob die Zeile neu ausgegeben werden muss... + // ----------------------------------------------------------------- + pLine->SetInvalid(); + + // Wenn eine Portion umgebrochen wurde sind ggf. viel zu viele Positionen + // im CharPosArray: + if ( bCalcCharPositions ) + { + sal_uInt16 nLen = pLine->GetLen(); + sal_uInt16 nCount = pLine->GetCharPosArray().Count(); + if ( nCount > nLen ) + pLine->GetCharPosArray().Remove( nLen, nCount-nLen ); + } + + if ( GetTextRanger() ) + { + if ( nTextXOffset ) + pLine->SetStartPosX( (sal_uInt16) ( pLine->GetStartPosX() + nTextXOffset ) ); + if ( nTextExtraYOffset ) + { + pLine->SetHeight( (sal_uInt16) ( pLine->GetHeight() + nTextExtraYOffset ), 0, pLine->GetHeight() ); + pLine->SetMaxAscent( (sal_uInt16) ( pLine->GetMaxAscent() + nTextExtraYOffset ) ); + } + } + + // Fuer kleiner 0 noch ueberlegen! + if ( pParaPortion->IsSimpleInvalid() /* && ( nInvalidDiff > 0 ) */ ) + { + // Aenderung durch einfache Textaenderung... + // Formatierung nicht abbrechen, da Portions evtl. wieder + // gesplittet werden muessen! + // Wenn irgendwann mal abbrechbar, dann fogende Zeilen Validieren! + // Aber ggf. als Valid markieren, damit weniger Ausgabe... + if ( pLine->GetEnd() < nInvalidStart ) + { + if ( *pLine == aSaveLine ) + { + pLine->SetValid(); + } + } + else + { + sal_uInt16 nStart = pLine->GetStart(); + sal_uInt16 nEnd = pLine->GetEnd(); + + if ( nStart > nInvalidEnd ) + { + if ( ( ( nStart-nInvalidDiff ) == aSaveLine.GetStart() ) && + ( ( nEnd-nInvalidDiff ) == aSaveLine.GetEnd() ) ) + { + pLine->SetValid(); + if ( bCalcCharPositions && bQuickFormat ) + { + bCalcCharPositions = sal_False; + bLineBreak = sal_False; + pParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); + break; + } + } + } + else if ( bCalcCharPositions && bQuickFormat && ( nEnd > nInvalidEnd) ) + { + // Wenn die ungueltige Zeile so endet, dass die naechste an + // der 'gleichen' Textstelle wie vorher beginnt, also nicht + // anders umgebrochen wird, brauche ich dort auch nicht die + // textbreiten neu bestimmen: + if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) ) + { + bCalcCharPositions = sal_False; + bLineBreak = sal_False; + pParaPortion->CorrectValuesBehindLastFormattedLine( nLine ); + break; + } + } + } + } + + if ( !bSameLineAgain ) + { + nIndex = pLine->GetEnd(); // naechste Zeile Start = letzte Zeile Ende + // weil nEnd hinter das letzte Zeichen zeigt! + + sal_uInt16 nEndPortion = pLine->GetEndPortion(); + + // Naechste Zeile oder ggf. neue Zeile.... + pLine = 0; + if ( nLine < pParaPortion->GetLines().Count()-1 ) + pLine = pParaPortion->GetLines().GetObject( ++nLine ); + if ( pLine && ( nIndex >= pNode->Len() ) ) + { + nDelFromLine = nLine; + break; + } + if ( !pLine ) + { + if ( nIndex < pNode->Len() ) + { + pLine = new EditLine; + pParaPortion->GetLines().Insert( pLine, ++nLine ); + } + else if ( nIndex && bLineBreak && GetTextRanger() ) + { + // normaly CreateAndInsertEmptyLine would be called, but I want to use + // CreateLines, so I need Polygon code only here... + TextPortion* pDummyPortion = new TextPortion( 0 ); + pParaPortion->GetTextPortions().Insert( pDummyPortion, pParaPortion->GetTextPortions().Count() ); + pLine = new EditLine; + pParaPortion->GetLines().Insert( pLine, ++nLine ); + bForceOneRun = TRUE; + bProcessingEmptyLine = TRUE; + } + } + if ( pLine ) + { + aSaveLine = *pLine; + pLine->SetStart( nIndex ); + pLine->SetEnd( nIndex ); + pLine->SetStartPortion( nEndPortion+1 ); + pLine->SetEndPortion( nEndPortion+1 ); + } + } + } // while ( Index < Len ) + + if ( nDelFromLine != 0xFFFF ) + pParaPortion->GetLines().DeleteFromLine( nDelFromLine ); + + DBG_ASSERT( pParaPortion->GetLines().Count(), "Keine Zeile nach CreateLines!" ); + + if ( bLineBreak == sal_True ) + CreateAndInsertEmptyLine( pParaPortion, nStartPosY ); + + delete[] pBuf; + + sal_Bool bHeightChanged = FinishCreateLines( pParaPortion ); + + if ( bMapChanged ) + GetRefDevice()->Pop(); + + GetRefDevice()->Pop(); + + return bHeightChanged; +} + +void ImpEditEngine::CreateAndInsertEmptyLine( ParaPortion* pParaPortion, sal_uInt32 ) +{ + DBG_ASSERT( !GetTextRanger(), "Don't use CreateAndInsertEmptyLine with a polygon!" ); + + EditLine* pTmpLine = new EditLine; + pTmpLine->SetStart( pParaPortion->GetNode()->Len() ); + pTmpLine->SetEnd( pParaPortion->GetNode()->Len() ); + pParaPortion->GetLines().Insert( pTmpLine, pParaPortion->GetLines().Count() ); + + sal_Bool bLineBreak = pParaPortion->GetNode()->Len() ? sal_True : sal_False; + sal_Int32 nSpaceBefore = 0; + sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pParaPortion->GetNode(), &nSpaceBefore ); + const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pParaPortion->GetNode() ); + const SvxLineSpacingItem& rLSItem = (const SvxLineSpacingItem&)pParaPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL ); + short nStartX = GetXValue( (short)(rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBefore)); + + Rectangle aBulletArea = Rectangle( Point(), Point() ); + if ( bLineBreak == sal_True ) + { + nStartX = (short)GetXValue( rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth ); + } + else + { + aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) ); + if ( aBulletArea.Right() > 0 ) + pParaPortion->SetBulletX( (sal_uInt16) GetXValue( aBulletArea.Right() ) ); + else + pParaPortion->SetBulletX( 0 ); // Falls Bullet falsch eingestellt. + if ( pParaPortion->GetBulletX() > nStartX ) + { + nStartX = (short)GetXValue( rLRItem.GetTxtLeft() + rLRItem.GetTxtFirstLineOfst() + nSpaceBeforeAndMinLabelWidth ); + if ( pParaPortion->GetBulletX() > nStartX ) + nStartX = pParaPortion->GetBulletX(); + } + } + + SvxFont aTmpFont; + SeekCursor( pParaPortion->GetNode(), bLineBreak ? pParaPortion->GetNode()->Len() : 0, aTmpFont ); + aTmpFont.SetPhysFont( pRefDev ); + + TextPortion* pDummyPortion = new TextPortion( 0 ); + pDummyPortion->GetSize() = aTmpFont.GetPhysTxtSize( pRefDev, String() ); + if ( IsFixedCellHeight() ) + pDummyPortion->GetSize().Height() = ImplCalculateFontIndependentLineSpacing( aTmpFont.GetHeight() ); + pParaPortion->GetTextPortions().Insert( pDummyPortion, pParaPortion->GetTextPortions().Count() ); + FormatterFontMetric aFormatterMetrics; + RecalcFormatterFontMetrics( aFormatterMetrics, aTmpFont ); + pTmpLine->SetMaxAscent( aFormatterMetrics.nMaxAscent ); + pTmpLine->SetHeight( (sal_uInt16) pDummyPortion->GetSize().Height() ); + sal_uInt16 nLineHeight = aFormatterMetrics.GetHeight(); + if ( nLineHeight > pTmpLine->GetHeight() ) + pTmpLine->SetHeight( nLineHeight ); + + if ( !aStatus.IsOutliner() ) + { + USHORT nPara = GetParaPortions().GetPos( pParaPortion ); + SvxAdjust eJustification = GetJustification( nPara ); + long nMaxLineWidth = !IsVertical() ? aPaperSize.Width() : aPaperSize.Height(); + nMaxLineWidth -= GetXValue( rLRItem.GetRight() ); + long nTextXOffset = 0; + if ( nMaxLineWidth < 0 ) + nMaxLineWidth = 1; + if ( eJustification == SVX_ADJUST_CENTER ) + nStartX = sal::static_int_cast< short >(nMaxLineWidth / 2); + else if ( eJustification == SVX_ADJUST_RIGHT ) + nStartX = sal::static_int_cast< short >(nMaxLineWidth); + + nStartX = sal::static_int_cast< short >(nStartX + nTextXOffset); + } + + pTmpLine->SetStartPosX( nStartX ); + + if ( !aStatus.IsOutliner() ) + { + if ( rLSItem.GetLineSpaceRule() == SVX_LINE_SPACE_MIN ) + { + sal_uInt16 nMinHeight = rLSItem.GetLineHeight(); + sal_uInt16 nTxtHeight = pTmpLine->GetHeight(); + if ( nTxtHeight < nMinHeight ) + { + // Der Ascent muss um die Differenz angepasst werden: + long nDiff = nMinHeight - nTxtHeight; + pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + nDiff) ); + pTmpLine->SetHeight( nMinHeight, nTxtHeight ); + } + } + else if ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + USHORT nPara = GetParaPortions().GetPos( pParaPortion ); + if ( nPara || IsFixedCellHeight() || pTmpLine->GetStartPortion() ) // Nicht die aller erste Zeile + { + // #100508# There are documents with PropLineSpace 0, why? + // (cmc: re above question :-) such documents can be seen by importing a .ppt + if ( rLSItem.GetPropLineSpace() && ( rLSItem.GetPropLineSpace() != 100 ) ) + { + sal_uInt16 nTxtHeight = pTmpLine->GetHeight(); + sal_Int32 nH = nTxtHeight; + nH *= rLSItem.GetPropLineSpace(); + nH /= 100; + // Der Ascent muss um die Differenz angepasst werden: + long nDiff = pTmpLine->GetHeight() - nH; + if ( nDiff > pTmpLine->GetMaxAscent() ) + nDiff = pTmpLine->GetMaxAscent(); + pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() - nDiff) ); + pTmpLine->SetHeight( (sal_uInt16)nH, nTxtHeight ); + } + } + } + } + + if ( !bLineBreak ) + { + long nMinHeight = aBulletArea.GetHeight(); + if ( nMinHeight > (long)pTmpLine->GetHeight() ) + { + long nDiff = nMinHeight - (long)pTmpLine->GetHeight(); + // nDiff auf oben und unten verteilen. + pTmpLine->SetMaxAscent( (sal_uInt16)(pTmpLine->GetMaxAscent() + nDiff/2) ); + pTmpLine->SetHeight( (sal_uInt16)nMinHeight ); + } + } + else + { + // -2: Die neue ist bereits eingefuegt. +#ifdef DBG_UTIL + EditLine* pLastLine = pParaPortion->GetLines().GetObject( pParaPortion->GetLines().Count()-2 ); + DBG_ASSERT( pLastLine, "Weicher Umbruch, keine Zeile ?!" ); + DBG_ASSERT( pLastLine->GetEnd() == pParaPortion->GetNode()->Len(), "Doch anders?" ); +#endif +// pTmpLine->SetStart( pLastLine->GetEnd() ); +// pTmpLine->SetEnd( pLastLine->GetEnd() ); + sal_uInt16 nPos = (sal_uInt16) pParaPortion->GetTextPortions().Count() - 1 ; + pTmpLine->SetStartPortion( nPos ); + pTmpLine->SetEndPortion( nPos ); + } +} + +sal_Bool ImpEditEngine::FinishCreateLines( ParaPortion* pParaPortion ) +{ +// CalcCharPositions( pParaPortion ); + pParaPortion->SetValid(); + long nOldHeight = pParaPortion->GetHeight(); +// sal_uInt16 nPos = GetParaPortions().GetPos( pParaPortion ); +// DBG_ASSERT( nPos != USHRT_MAX, "FinishCreateLines: Portion nicht in Liste!" ); +// ParaPortion* pPrev = nPos ? GetParaPortions().GetObject( nPos-1 ) : 0; + CalcHeight( pParaPortion ); + + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "FinishCreateLines: Keine Text-Portion?" ); + sal_Bool bRet = ( pParaPortion->GetHeight() != nOldHeight ); + return bRet; +} + +void ImpEditEngine::ImpBreakLine( ParaPortion* pParaPortion, EditLine* pLine, TextPortion* pPortion, sal_uInt16 nPortionStart, long nRemainingWidth, sal_Bool bCanHyphenate ) +{ + ContentNode* const pNode = pParaPortion->GetNode(); + + sal_uInt16 nBreakInLine = nPortionStart - pLine->GetStart(); + sal_uInt16 nMax = nBreakInLine + pPortion->GetLen(); + while ( ( nBreakInLine < nMax ) && ( pLine->GetCharPosArray()[nBreakInLine] < nRemainingWidth ) ) + nBreakInLine++; + + sal_uInt16 nMaxBreakPos = nBreakInLine + pLine->GetStart(); + sal_uInt16 nBreakPos = 0xFFFF; + + sal_Bool bCompressBlank = sal_False; + sal_Bool bHyphenated = sal_False; + sal_Bool bHangingPunctuation = sal_False; + sal_Unicode cAlternateReplChar = 0; + sal_Unicode cAlternateExtraChar = 0; + + if ( ( nMaxBreakPos < ( nMax + pLine->GetStart() ) ) && ( pNode->GetChar( nMaxBreakPos ) == ' ' ) ) + { + // Break behind the blank, blank will be compressed... + nBreakPos = nMaxBreakPos + 1; + bCompressBlank = sal_True; + } + else + { + sal_uInt16 nMinBreakPos = pLine->GetStart(); + USHORT nAttrs = pNode->GetCharAttribs().GetAttribs().Count(); + for ( USHORT nAttr = nAttrs; nAttr; ) + { + EditCharAttrib* pAttr = pNode->GetCharAttribs().GetAttribs()[--nAttr]; + if ( pAttr->IsFeature() && ( pAttr->GetEnd() > nMinBreakPos ) && ( pAttr->GetEnd() <= nMaxBreakPos ) ) + { + nMinBreakPos = pAttr->GetEnd(); + break; + } + } + + lang::Locale aLocale = GetLocale( EditPaM( pNode, nMaxBreakPos ) ); + + Reference < i18n::XBreakIterator > _xBI( ImplGetBreakIterator() ); + OUString aText( *pNode ); + Reference< XHyphenator > xHyph; + if ( bCanHyphenate ) + xHyph = GetHyphenator(); + i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, Sequence< PropertyValue >(), 1 ); + i18n::LineBreakUserOptions aUserOptions; + + const i18n::ForbiddenCharacters* pForbidden = GetForbiddenCharsTable()->GetForbiddenCharacters( SvxLocaleToLanguage( aLocale ), TRUE ); + aUserOptions.forbiddenBeginCharacters = pForbidden->beginLine; + aUserOptions.forbiddenEndCharacters = pForbidden->endLine; + aUserOptions.applyForbiddenRules = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_FORBIDDENRULES )).GetValue(); + aUserOptions.allowPunctuationOutsideMargin = ((const SfxBoolItem&)pNode->GetContentAttribs().GetItem( EE_PARA_HANGINGPUNCTUATION )).GetValue(); + aUserOptions.allowHyphenateEnglish = FALSE; + + i18n::LineBreakResults aLBR = _xBI->getLineBreak( *pNode, nMaxBreakPos, aLocale, nMinBreakPos, aHyphOptions, aUserOptions ); + nBreakPos = (USHORT)aLBR.breakIndex; + + // BUG in I18N - under special condition (break behind field, #87327#) breakIndex is < nMinBreakPos + if ( nBreakPos < nMinBreakPos ) + { + nBreakPos = nMinBreakPos; + } + else if ( ( nBreakPos > nMaxBreakPos ) && !aUserOptions.allowPunctuationOutsideMargin ) + { + DBG_ERROR( "I18N: XBreakIterator::getLineBreak returns position > Max" ); + nBreakPos = nMaxBreakPos; + } + + // #101795# nBreakPos can never be outside the portion, even not with hangig punctuation + if ( nBreakPos > nMaxBreakPos ) + nBreakPos = nMaxBreakPos; + + // BUG in I18N - the japanese dot is in the next line! + // !!! Testen!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if ( (nBreakPos + ( aUserOptions.allowPunctuationOutsideMargin ? 0 : 1 ) ) <= nMaxBreakPos ) + { + sal_Unicode cFirstInNextLine = ( (nBreakPos+1) < pNode->Len() ) ? pNode->GetChar( nBreakPos ) : 0; + if ( cFirstInNextLine == 12290 ) + nBreakPos++; + } + + bHangingPunctuation = ( nBreakPos > nMaxBreakPos ) ? sal_True : sal_False; + pLine->SetHangingPunctuation( bHangingPunctuation ); + + #ifndef SVX_LIGHT + // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch + // die Silbentrennung jagen... + // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt, + // nBreakPos ist der Wort-Anfang + // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort + // auf mehr als Zwei Zeilen gebrochen wird... + if ( !bHangingPunctuation && bCanHyphenate && GetHyphenator().is() ) + { + i18n::Boundary aBoundary = _xBI->getWordBoundary( *pNode, nBreakPos, GetLocale( EditPaM( pNode, nBreakPos ) ), ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True ); +// sal_uInt16 nWordStart = nBreakPos; +// sal_uInt16 nBreakPos_OLD = nBreakPos; + sal_uInt16 nWordStart = nBreakPos; + sal_uInt16 nWordEnd = (USHORT) aBoundary.endPos; + DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" ); + + USHORT nWordLen = nWordEnd - nWordStart; + if ( ( nWordEnd >= nMaxBreakPos ) && ( nWordLen > 3 ) ) + { + // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD + // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" ); + String aWord( *pNode, nWordStart, nWordLen ); + sal_uInt16 nMinTrail = nWordEnd-nMaxBreakPos+1; //+1: Vor dem angeknacksten Buchstaben + Reference< XHyphenatedWord > xHyphWord; + if (xHyphenator.is()) + xHyphWord = xHyphenator->hyphenate( aWord, aLocale, aWord.Len() - nMinTrail, Sequence< PropertyValue >() ); + if (xHyphWord.is()) + { + sal_Bool bAlternate = xHyphWord->isAlternativeSpelling(); + sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos(); + + if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= (pLine->GetStart() + 2 ) ) ) + { + if ( !bAlternate ) + { + bHyphenated = sal_True; + nBreakPos = nWordStart + _nWordLen; + } + else + { + String aAlt( xHyphWord->getHyphenatedWord() ); + + // Wir gehen von zwei Faellen aus, die nun + // vorliegen koennen: + // 1) packen wird zu pak-ken + // 2) Schiffahrt wird zu Schiff-fahrt + // In Fall 1 muss ein Zeichen ersetzt werden, + // in Fall 2 wird ein Zeichen hinzugefuegt. + // Die Identifikation wird erschwert durch Worte wie + // "Schiffahrtsbrennesseln", da der Hyphenator alle + // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln" + // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom + // Index des AlternativWord auf aWord schliessen. + + // Das ganze geraffel wird durch eine Funktion am + // Hyphenator vereinfacht werden, sobald AMA sie einbaut... + sal_uInt16 nAltStart = _nWordLen - 1; + sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len()); + sal_uInt16 nTxtEnd = nTxtStart; + sal_uInt16 nAltEnd = nAltStart; + + // Die Bereiche zwischen den nStart und nEnd ist + // die Differenz zwischen Alternativ- und OriginalString. + while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() && + aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) ) + { + ++nTxtEnd; + ++nAltEnd; + } + + // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt: + if( nAltEnd > nTxtEnd && nAltStart == nAltEnd && + aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) ) + { + ++nAltEnd; + ++nTxtStart; + ++nTxtEnd; + } + + DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Falsche Annahme!" ); + + if ( nTxtEnd > nTxtStart ) + cAlternateReplChar = aAlt.GetChar( nAltStart ); + else + cAlternateExtraChar = aAlt.GetChar( nAltStart ); + + bHyphenated = sal_True; + nBreakPos = nWordStart + nTxtStart; + if ( cAlternateReplChar ) + nBreakPos++; + } + } + } + } + } + + #endif // !SVX_LIGHT + + if ( nBreakPos <= pLine->GetStart() ) + { + // keine Trenner in Zeile => abhacken ! + nBreakPos = nMaxBreakPos; + // MT: I18N nextCharacters !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + if ( nBreakPos <= pLine->GetStart() ) + nBreakPos = pLine->GetStart() + 1; // Sonst Endlosschleife! + } + } + + // die angeknackste Portion ist die End-Portion + pLine->SetEnd( nBreakPos ); + + sal_uInt16 nEndPortion = SplitTextPortion( pParaPortion, nBreakPos, pLine ); + + if ( !bCompressBlank && !bHangingPunctuation ) + { + // #96187# When justification is not SVX_ADJUST_LEFT, it's important to compress + // the trailing space even if there is enough room for the space... + // Don't check for SVX_ADJUST_LEFT, doesn't matter to compress in this case too... + DBG_ASSERT( nBreakPos > pLine->GetStart(), "ImpBreakLines - BreakPos not expected!" ); + if ( pNode->GetChar( nBreakPos-1 ) == ' ' ) + bCompressBlank = sal_True; + } + + if ( bCompressBlank || bHangingPunctuation ) + { + TextPortion* pTP = pParaPortion->GetTextPortions().GetObject( nEndPortion ); + DBG_ASSERT( pTP->GetKind() == PORTIONKIND_TEXT, "BlankRubber: Keine TextPortion!" ); + DBG_ASSERT( nBreakPos > pLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" ); + sal_uInt16 nPosInArray = nBreakPos - 1 - pLine->GetStart(); + pTP->GetSize().Width() = ( nPosInArray && ( pTP->GetLen() > 1 ) ) ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0; + pLine->GetCharPosArray()[ nPosInArray ] = pTP->GetSize().Width(); + } + else if ( bHyphenated ) + { + // Eine Portion fuer den Trenner einbauen... + TextPortion* pHyphPortion = new TextPortion( 0 ); + pHyphPortion->GetKind() = PORTIONKIND_HYPHENATOR; + String aHyphText( CH_HYPH ); + if ( cAlternateReplChar ) + { + TextPortion* pPrev = pParaPortion->GetTextPortions().GetObject( nEndPortion ); + DBG_ASSERT( pPrev && pPrev->GetLen(), "Hyphenate: Prev portion?!" ); + pPrev->SetLen( pPrev->GetLen() - 1 ); + pHyphPortion->SetLen( 1 ); + pHyphPortion->SetExtraValue( cAlternateReplChar ); + // Breite der Portion davor korrigieren: + pPrev->GetSize().Width() = + pLine->GetCharPosArray()[ nBreakPos-1 - pLine->GetStart() - 1 ]; + } + else if ( cAlternateExtraChar ) + { + pHyphPortion->SetExtraValue( cAlternateExtraChar ); + aHyphText.Insert( cAlternateExtraChar, 0 ); + } + + // Breite der Hyph-Portion ermitteln: + SvxFont aFont; + SeekCursor( pParaPortion->GetNode(), nBreakPos, aFont ); + aFont.SetPhysFont( GetRefDevice() ); + pHyphPortion->GetSize().Height() = GetRefDevice()->GetTextHeight(); + pHyphPortion->GetSize().Width() = GetRefDevice()->GetTextWidth( aHyphText ); + + pParaPortion->GetTextPortions().Insert( pHyphPortion, ++nEndPortion ); + } + pLine->SetEndPortion( nEndPortion ); +} + +void ImpEditEngine::ImpAdjustBlocks( ParaPortion* pParaPortion, EditLine* pLine, long nRemainingSpace ) +{ + DBG_ASSERT( nRemainingSpace > 0, "AdjustBlocks: Etwas zuwenig..." ); + DBG_ASSERT( pLine, "AdjustBlocks: Zeile ?!" ); + if ( ( nRemainingSpace < 0 ) || pLine->IsEmpty() ) + return ; + + const USHORT nFirstChar = pLine->GetStart(); + const USHORT nLastChar = pLine->GetEnd() -1; // Last zeigt dahinter + ContentNode* pNode = pParaPortion->GetNode(); + + DBG_ASSERT( nLastChar < pNode->Len(), "AdjustBlocks: Out of range!" ); + + // Search blanks or Kashidas... + SvUShorts aPositions; + USHORT nChar; + for ( nChar = nFirstChar; nChar <= nLastChar; nChar++ ) + { + if ( pNode->GetChar(nChar) == ' ' ) + { + // Don't use blank if language is arabic + LanguageType eLang = GetLanguage( EditPaM( pNode, nChar ) ); + if ( MsLangId::getPrimaryLanguage( eLang) != LANGUAGE_ARABIC_PRIMARY_ONLY ) + aPositions.Insert( nChar, aPositions.Count() ); + } + } + + // Kashidas ? + ImpFindKashidas( pNode, nFirstChar, nLastChar, aPositions ); + + + if ( !aPositions.Count() ) + return; + + // Wenn das letzte Zeichen ein Blank ist, will ich es nicht haben! + // Die Breite muss auf die Blocker davor verteilt werden... + // Aber nicht, wenn es das einzige ist + if ( ( pNode->GetChar( nLastChar ) == ' ' ) && ( aPositions.Count() > 1 ) && ( MsLangId::getPrimaryLanguage( GetLanguage( EditPaM( pNode, nLastChar ) ) ) != LANGUAGE_ARABIC_PRIMARY_ONLY ) ) + { + aPositions.Remove( aPositions.Count()-1, 1 ); + USHORT nPortionStart, nPortion; + nPortion = pParaPortion->GetTextPortions().FindPortion( nLastChar+1, nPortionStart ); + TextPortion* pLastPortion = pParaPortion->GetTextPortions()[ nPortion ]; + long nRealWidth = pLine->GetCharPosArray()[nLastChar-nFirstChar]; + long nBlankWidth = nRealWidth; + if ( nLastChar > nPortionStart ) + nBlankWidth -= pLine->GetCharPosArray()[nLastChar-nFirstChar-1]; + // Evtl. ist das Blank schon in ImpBreakLine abgezogen worden: + if ( nRealWidth == pLastPortion->GetSize().Width() ) + { + // Beim letzten Zeichen muss die Portion hinter dem Blank aufhoeren + // => Korrektur vereinfachen: + DBG_ASSERT( ( nPortionStart + pLastPortion->GetLen() ) == ( nLastChar+1 ), "Blank doch nicht am Portion-Ende?!" ); + pLastPortion->GetSize().Width() -= nBlankWidth; + nRemainingSpace += nBlankWidth; + } + pLine->GetCharPosArray()[nLastChar-nFirstChar] -= nBlankWidth; + } + + USHORT nGaps = aPositions.Count(); + const long nMore4Everyone = nRemainingSpace / nGaps; + long nSomeExtraSpace = nRemainingSpace - nMore4Everyone*nGaps; + + DBG_ASSERT( nSomeExtraSpace < (long)nGaps, "AdjustBlocks: ExtraSpace zu gross" ); + DBG_ASSERT( nSomeExtraSpace >= 0, "AdjustBlocks: ExtraSpace < 0 " ); + + // Die Positionen im Array und die Portion-Breiten korrigieren: + // Letztes Zeichen wird schon nicht mehr beachtet... + for ( USHORT n = 0; n < aPositions.Count(); n++ ) + { + nChar = aPositions[n]; + if ( nChar < nLastChar ) + { + USHORT nPortionStart, nPortion; + nPortion = pParaPortion->GetTextPortions().FindPortion( nChar, nPortionStart ); + TextPortion* pLastPortion = pParaPortion->GetTextPortions()[ nPortion ]; + + // Die Breite der Portion: + pLastPortion->GetSize().Width() += nMore4Everyone; + if ( nSomeExtraSpace ) + pLastPortion->GetSize().Width()++; + + // Correct positions in array + // Even for kashidas just change positions, VCL will then draw the kashida automaticly + USHORT nPortionEnd = nPortionStart + pLastPortion->GetLen(); + for ( USHORT _n = nChar; _n < nPortionEnd; _n++ ) + { + pLine->GetCharPosArray()[_n-nFirstChar] += nMore4Everyone; + if ( nSomeExtraSpace ) + pLine->GetCharPosArray()[_n-nFirstChar]++; + } + + if ( nSomeExtraSpace ) + nSomeExtraSpace--; + } + } + + // Now the text width contains the extra width... + pLine->SetTextWidth( pLine->GetTextWidth() + nRemainingSpace ); +} + +void ImpEditEngine::ImpFindKashidas( ContentNode* pNode, USHORT nStart, USHORT nEnd, SvUShorts& rArray ) +{ + // the search has to be performed on a per word base + + EditSelection aWordSel( EditPaM( pNode, nStart ) ); + aWordSel = SelectWord( aWordSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + if ( aWordSel.Min().GetIndex() < nStart ) + aWordSel.Min().GetIndex() = nStart; + + while ( ( aWordSel.Min().GetNode() == pNode ) && ( aWordSel.Min().GetIndex() < nEnd ) ) + { + USHORT nSavPos = aWordSel.Max().GetIndex(); + if ( aWordSel.Max().GetIndex() > nEnd ) + aWordSel.Max().GetIndex() = nEnd; + + String aWord = GetSelected( aWordSel ); + + // restore selection for proper iteration at the end of the function + aWordSel.Max().GetIndex() = nSavPos; + + xub_StrLen nIdx = 0; + xub_StrLen nKashidaPos = STRING_LEN; + xub_Unicode cCh; + xub_Unicode cPrevCh = 0; + + while ( nIdx < aWord.Len() ) + { + cCh = aWord.GetChar( nIdx ); + + // 1. Priority: + // after user inserted kashida + if ( 0x640 == cCh ) + { + nKashidaPos = aWordSel.Min().GetIndex() + nIdx; + break; + } + + // 2. Priority: + // after a Seen or Sad + if ( nIdx + 1 < aWord.Len() && + ( 0x633 == cCh || 0x635 == cCh ) ) + { + nKashidaPos = aWordSel.Min().GetIndex() + nIdx; + break; + } + + // 3. Priority: + // before final form of Teh Marbuta, Hah, Dal + // 4. Priority: + // before final form of Alef, Lam or Kaf + if ( nIdx && nIdx + 1 == aWord.Len() && + ( 0x629 == cCh || 0x62D == cCh || 0x62F == cCh || + 0x627 == cCh || 0x644 == cCh || 0x643 == cCh ) ) + { + DBG_ASSERT( 0 != cPrevCh, "No previous character" ); + + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1; + break; + } + } + + // 5. Priority: + // before media Bah + if ( nIdx && nIdx + 1 < aWord.Len() && 0x628 == cCh ) + { + DBG_ASSERT( 0 != cPrevCh, "No previous character" ); + + // check if next character is Reh, Yeh or Alef Maksura + xub_Unicode cNextCh = aWord.GetChar( nIdx + 1 ); + + if ( 0x631 == cNextCh || 0x64A == cNextCh || + 0x649 == cNextCh ) + { + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1; + } + } + + // 6. Priority: + // other connecting possibilities + if ( nIdx && nIdx + 1 == aWord.Len() && + 0x60C <= cCh && 0x6FE >= cCh ) + { + DBG_ASSERT( 0 != cPrevCh, "No previous character" ); + + // check if character is connectable to previous character, + if ( lcl_ConnectToPrev( cCh, cPrevCh ) ) + { + // only choose this position if we did not find + // a better one: + if ( STRING_LEN == nKashidaPos ) + nKashidaPos = aWordSel.Min().GetIndex() + nIdx - 1; + break; + } + } + + // Do not consider Fathatan, Dammatan, Kasratan, Fatha, + // Damma, Kasra, Shadda and Sukun when checking if + // a character can be connected to previous character. + if ( cCh < 0x64B || cCh > 0x652 ) + cPrevCh = cCh; + + ++nIdx; + } // end of current word + + if ( STRING_LEN != nKashidaPos ) + rArray.Insert( nKashidaPos, rArray.Count() ); + + aWordSel = WordRight( aWordSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWordSel = SelectWord( aWordSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + } +} + +sal_uInt16 ImpEditEngine::SplitTextPortion( ParaPortion* pPortion, sal_uInt16 nPos, EditLine* pCurLine ) +{ + DBG_ASSERT( pPortion, "SplitTextPortion: Welche ?" ); + + // Die Portion bei nPos wird geplittet, wenn bei nPos nicht + // sowieso ein Wechsel ist + if ( nPos == 0 ) + return 0; + + sal_uInt16 nSplitPortion; + sal_uInt16 nTmpPos = 0; + TextPortion* pTextPortion = 0; + sal_uInt16 nPortions = pPortion->GetTextPortions().Count(); + for ( nSplitPortion = 0; nSplitPortion < nPortions; nSplitPortion++ ) + { + TextPortion* pTP = pPortion->GetTextPortions().GetObject(nSplitPortion); + nTmpPos = nTmpPos + pTP->GetLen(); + if ( nTmpPos >= nPos ) + { + if ( nTmpPos == nPos ) // dann braucht nichts geteilt werden + { + // Skip Portions with ExtraSpace +// while ( ( (nSplitPortion+1) < nPortions ) && (pPortion->GetTextPortions().GetObject(nSplitPortion+1)->GetKind() == PORTIONKIND_EXTRASPACE ) ) +// nSplitPortion++; + + return nSplitPortion; + } + pTextPortion = pTP; + break; + } + } + + DBG_ASSERT( pTextPortion, "Position ausserhalb des Bereichs!" ); + DBG_ASSERT( pTextPortion->GetKind() == PORTIONKIND_TEXT, "SplitTextPortion: Keine TextPortion!" ); + + sal_uInt16 nOverlapp = nTmpPos - nPos; + pTextPortion->GetLen() = pTextPortion->GetLen() - nOverlapp; + TextPortion* pNewPortion = new TextPortion( nOverlapp ); + pPortion->GetTextPortions().Insert( pNewPortion, nSplitPortion+1 ); + // Groessen setzen: + if ( pCurLine ) + { + // Kein neues GetTextSize, sondern Werte aus Array verwenden: + DBG_ASSERT( nPos > pCurLine->GetStart(), "SplitTextPortion am Anfang der Zeile?" ); + pTextPortion->GetSize().Width() = pCurLine->GetCharPosArray()[ nPos-pCurLine->GetStart()-1 ]; + + if ( pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed ) + { + // We need the original size from the portion + USHORT nTxtPortionStart = pPortion->GetTextPortions().GetStartPos( nSplitPortion ); + SvxFont aTmpFont( pPortion->GetNode()->GetCharAttribs().GetDefFont() ); + SeekCursor( pPortion->GetNode(), nTxtPortionStart+1, aTmpFont ); + aTmpFont.SetPhysFont( GetRefDevice() ); + GetRefDevice()->Push( PUSH_TEXTLANGUAGE ); + ImplInitDigitMode( GetRefDevice(), 0, 0, 0, aTmpFont.GetLanguage() ); + Size aSz = aTmpFont.QuickGetTextSize( GetRefDevice(), *pPortion->GetNode(), nTxtPortionStart, pTextPortion->GetLen(), NULL ); + GetRefDevice()->Pop(); + pTextPortion->GetExtraInfos()->nOrgWidth = aSz.Width(); + } + } + else + pTextPortion->GetSize().Width() = (-1); + + return nSplitPortion; +} + +void ImpEditEngine::CreateTextPortions( ParaPortion* pParaPortion, sal_uInt16& rStart /* , sal_Bool bCreateBlockPortions */ ) +{ + sal_uInt16 nStartPos = rStart; + ContentNode* pNode = pParaPortion->GetNode(); + DBG_ASSERT( pNode->Len(), "CreateTextPortions sollte nicht fuer leere Absaetze verwendet werden!" ); + + SortedPositions aPositions; + aPositions.Insert( (sal_uInt32) 0 ); + + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttrib ) + { + // Start und Ende in das Array eintragen... + // Die InsertMethode laesst keine doppelten Werte zu.... + aPositions.Insert( pAttrib->GetStart() ); + aPositions.Insert( pAttrib->GetEnd() ); + nAttr++; + pAttrib = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + aPositions.Insert( pNode->Len() ); + + if ( !pParaPortion->aScriptInfos.Count() ) + ((ImpEditEngine*)this)->InitScriptTypes( GetParaPortions().GetPos( pParaPortion ) ); + + const ScriptTypePosInfos& rTypes = pParaPortion->aScriptInfos; + for ( USHORT nT = 0; nT < rTypes.Count(); nT++ ) + aPositions.Insert( rTypes[nT].nStartPos ); + + const WritingDirectionInfos& rWritingDirections = pParaPortion->aWritingDirectionInfos; + for ( USHORT nD = 0; nD < rWritingDirections.Count(); nD++ ) + aPositions.Insert( rWritingDirections[nD].nStartPos ); + + if ( mpIMEInfos && mpIMEInfos->nLen && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) ) + { + sal_uInt16 nLastAttr = 0xFFFF; + for( sal_uInt16 n = 0; n < mpIMEInfos->nLen; n++ ) + { + if ( mpIMEInfos->pAttribs[n] != nLastAttr ) + { + aPositions.Insert( mpIMEInfos->aPos.GetIndex() + n ); + nLastAttr = mpIMEInfos->pAttribs[n]; + } + } + aPositions.Insert( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ); + } + + // Ab ... loeschen: + // Leider muss die Anzahl der TextPortions mit aPositions.Count() + // nicht uebereinstimmen, da evtl. Zeilenumbrueche... + sal_uInt16 nPortionStart = 0; + sal_uInt16 nInvPortion = 0; + sal_uInt16 nP; + for ( nP = 0; nP < pParaPortion->GetTextPortions().Count(); nP++ ) + { + TextPortion* pTmpPortion = pParaPortion->GetTextPortions().GetObject(nP); + nPortionStart = nPortionStart + pTmpPortion->GetLen(); + if ( nPortionStart >= nStartPos ) + { + nPortionStart = nPortionStart - pTmpPortion->GetLen(); + rStart = nPortionStart; + nInvPortion = nP; + break; + } + } + DBG_ASSERT( nP < pParaPortion->GetTextPortions().Count() || !pParaPortion->GetTextPortions().Count(), "Nichts zum loeschen: CreateTextPortions" ); + if ( nInvPortion && ( nPortionStart+pParaPortion->GetTextPortions().GetObject(nInvPortion)->GetLen() > nStartPos ) ) + { + // lieber eine davor... + // Aber nur wenn es mitten in der Portion war, sonst ist es evtl. + // die einzige in der Zeile davor ! + nInvPortion--; + nPortionStart = nPortionStart - pParaPortion->GetTextPortions().GetObject(nInvPortion)->GetLen(); + } + pParaPortion->GetTextPortions().DeleteFromPortion( nInvPortion ); + + // Eine Portion kann auch durch einen Zeilenumbruch entstanden sein: + aPositions.Insert( nPortionStart ); + + sal_uInt16 nInvPos; +#ifdef DBG_UTIL + sal_Bool bFound = +#endif + aPositions.Seek_Entry( nPortionStart, &nInvPos ); + + DBG_ASSERT( bFound && ( nInvPos < (aPositions.Count()-1) ), "InvPos ?!" ); + for ( sal_uInt16 i = nInvPos+1; i < aPositions.Count(); i++ ) + { + TextPortion* pNew = new TextPortion( (sal_uInt16)aPositions[i] - (sal_uInt16)aPositions[i-1] ); + pParaPortion->GetTextPortions().Insert( pNew, pParaPortion->GetTextPortions().Count()); + } + + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "Keine Portions?!" ); +#ifdef EDITDEBUG + DBG_ASSERT( pParaPortion->DbgCheckTextPortions(), "Portions kaputt?" ); +#endif +} + +void ImpEditEngine::RecalcTextPortion( ParaPortion* pParaPortion, sal_uInt16 nStartPos, short nNewChars ) +{ + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "Keine Portions!" ); + DBG_ASSERT( nNewChars, "RecalcTextPortion mit Diff == 0" ); + + ContentNode* const pNode = pParaPortion->GetNode(); + if ( nNewChars > 0 ) + { + // Wenn an nStartPos ein Attribut beginnt/endet, faengt eine neue Portion + // an, ansonsten wird die Portion an nStartPos erweitert. + + if ( pNode->GetCharAttribs().HasBoundingAttrib( nStartPos ) || IsScriptChange( EditPaM( pNode, nStartPos ) ) ) + { + sal_uInt16 nNewPortionPos = 0; + if ( nStartPos ) + nNewPortionPos = SplitTextPortion( pParaPortion, nStartPos ) + 1; + + // Eine leere Portion kann hier stehen, wenn der Absatz leer war, + // oder eine Zeile durch einen harten Zeilenumbruch entstanden ist. + if ( ( nNewPortionPos < pParaPortion->GetTextPortions().Count() ) && + !pParaPortion->GetTextPortions()[nNewPortionPos]->GetLen() ) + { + DBG_ASSERT( pParaPortion->GetTextPortions()[nNewPortionPos]->GetKind() == PORTIONKIND_TEXT, "Leere Portion war keine TextPortion!" ); + USHORT & r = + pParaPortion->GetTextPortions()[nNewPortionPos]->GetLen(); + r = r + nNewChars; + } + else + { + TextPortion* pNewPortion = new TextPortion( nNewChars ); + pParaPortion->GetTextPortions().Insert( pNewPortion, nNewPortionPos ); + } + } + else + { + sal_uInt16 nPortionStart; + const sal_uInt16 nTP = pParaPortion->GetTextPortions(). + FindPortion( nStartPos, nPortionStart ); + TextPortion* const pTP = pParaPortion->GetTextPortions()[ nTP ]; + DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); + pTP->GetLen() = pTP->GetLen() + nNewChars; + pTP->GetSize().Width() = (-1); + } + } + else + { + // Portion schrumpfen oder ggf. entfernen. + // Vor Aufruf dieser Methode muss sichergestellt sein, dass + // keine Portions in dem geloeschten Bereich lagen! + + // Es darf keine reinragende oder im Bereich startende Portion geben, + // also muss nStartPos <= nPos <= nStartPos - nNewChars(neg.) sein + sal_uInt16 nPortion = 0; + sal_uInt16 nPos = 0; + sal_uInt16 nEnd = nStartPos-nNewChars; + sal_uInt16 nPortions = pParaPortion->GetTextPortions().Count(); + TextPortion* pTP = 0; + for ( nPortion = 0; nPortion < nPortions; nPortion++ ) + { + pTP = pParaPortion->GetTextPortions()[ nPortion ]; + if ( ( nPos+pTP->GetLen() ) > nStartPos ) + { + DBG_ASSERT( nPos <= nStartPos, "Start falsch!" ); + DBG_ASSERT( nPos+pTP->GetLen() >= nEnd, "End falsch!" ); + break; + } + nPos = nPos + pTP->GetLen(); + } + DBG_ASSERT( pTP, "RecalcTextPortion: Portion nicht gefunden" ); + if ( ( nPos == nStartPos ) && ( (nPos+pTP->GetLen()) == nEnd ) ) + { + // Portion entfernen; + BYTE nType = pTP->GetKind(); + pParaPortion->GetTextPortions().Remove( nPortion ); + delete pTP; + if ( nType == PORTIONKIND_LINEBREAK ) + { + TextPortion* pNext = pParaPortion->GetTextPortions()[ nPortion ]; + if ( pNext && !pNext->GetLen() ) + { + // Dummy-Portion entfernen + pParaPortion->GetTextPortions().Remove( nPortion ); + delete pNext; + } + } + } + else + { + DBG_ASSERT( pTP->GetLen() > (-nNewChars), "Portion zu klein zum schrumpfen!" ); + pTP->GetLen() = pTP->GetLen() + nNewChars; + } + + // ganz am Schluss darf keine HYPHENATOR-Portion stehen bleiben... + DBG_ASSERT( pParaPortion->GetTextPortions().Count(), "RecalcTextPortions: Keine mehr da!" ); + sal_uInt16 nLastPortion = pParaPortion->GetTextPortions().Count() - 1; + pTP = pParaPortion->GetTextPortions().GetObject( nLastPortion ); + if ( pTP->GetKind() == PORTIONKIND_HYPHENATOR ) + { + // Portion wegschmeissen, ggf. die davor korrigieren, wenn + // die Hyph-Portion ein Zeichen geschluckt hat... + pParaPortion->GetTextPortions().Remove( nLastPortion ); + if ( nLastPortion && pTP->GetLen() ) + { + TextPortion* pPrev = pParaPortion->GetTextPortions().GetObject( nLastPortion - 1 ); + DBG_ASSERT( pPrev->GetKind() == PORTIONKIND_TEXT, "Portion?!" ); + pPrev->SetLen( pPrev->GetLen() + pTP->GetLen() ); + pPrev->GetSize().Width() = (-1); + } + delete pTP; + } + } +#ifdef EDITDEBUG + DBG_ASSERT( pParaPortion->DbgCheckTextPortions(), "Portions kaputt?" ); +#endif +} + +void ImpEditEngine::SetTextRanger( TextRanger* pRanger ) +{ + if ( pTextRanger != pRanger ) + { + delete pTextRanger; + pTextRanger = pRanger; + + for ( sal_uInt16 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) + { + ParaPortion* pParaPortion = GetParaPortions().GetObject( nPara ); + pParaPortion->MarkSelectionInvalid( 0, pParaPortion->GetNode()->Len() ); + pParaPortion->GetLines().Reset(); + } + + FormatFullDoc(); + UpdateViews( GetActiveView() ); + if ( GetUpdateMode() && GetActiveView() ) + pActiveView->ShowCursor( sal_False, sal_False ); + } +} + +void ImpEditEngine::SetVertical( BOOL bVertical ) +{ + if ( IsVertical() != bVertical ) + { + GetEditDoc().SetVertical( bVertical ); + sal_Bool bUseCharAttribs = ( aStatus.GetControlWord() & EE_CNTRL_USECHARATTRIBS ) ? sal_True : sal_False; + GetEditDoc().CreateDefFont( bUseCharAttribs ); + if ( IsFormatted() ) + { + FormatFullDoc(); + UpdateViews( GetActiveView() ); + } + } +} + +void ImpEditEngine::SetFixedCellHeight( BOOL bUseFixedCellHeight ) +{ + if ( IsFixedCellHeight() != bUseFixedCellHeight ) + { + GetEditDoc().SetFixedCellHeight( bUseFixedCellHeight ); + if ( IsFormatted() ) + { + FormatFullDoc(); + UpdateViews( GetActiveView() ); + } + } +} + +void ImpEditEngine::SeekCursor( ContentNode* pNode, sal_uInt16 nPos, SvxFont& rFont, OutputDevice* pOut, sal_uInt16 nIgnoreWhich ) +{ + // Es war mal geplant, SeekCursor( nStartPos, nEndPos, ... ), damit nur + // ab der StartPosition neu gesucht wird. + // Problem: Es mussten zwei Listen beruecksichtigt/gefuehrt werden: + // OrderedByStart,OrderedByEnd. + + if ( nPos > pNode->Len() ) + nPos = pNode->Len(); + + rFont = pNode->GetCharAttribs().GetDefFont(); + + short nScriptType = GetScriptType( EditPaM( pNode, nPos ) ); + if ( ( nScriptType == i18n::ScriptType::ASIAN ) || ( nScriptType == i18n::ScriptType::COMPLEX ) ) + { + const SvxFontItem& rFontItem = (const SvxFontItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) ); + rFont.SetName( rFontItem.GetFamilyName() ); + rFont.SetFamily( rFontItem.GetFamily() ); + rFont.SetPitch( rFontItem.GetPitch() ); + rFont.SetCharSet( rFontItem.GetCharSet() ); + Size aSz( rFont.GetSize() ); + aSz.Height() = ((const SvxFontHeightItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ) ).GetHeight(); + rFont.SetSize( aSz ); + rFont.SetWeight( ((const SvxWeightItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ))).GetWeight() ); + rFont.SetItalic( ((const SvxPostureItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ))).GetPosture() ); + rFont.SetLanguage( ((const SvxLanguageItem&)pNode->GetContentAttribs().GetItem( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ))).GetLanguage() ); + } + + sal_uInt16 nRelWidth = ((const SvxCharScaleWidthItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH)).GetValue(); + + if ( pOut ) + { + const SvxUnderlineItem& rTextLineColor = (const SvxUnderlineItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_UNDERLINE ); + if ( rTextLineColor.GetColor() != COL_TRANSPARENT ) + pOut->SetTextLineColor( rTextLineColor.GetColor() ); + else + pOut->SetTextLineColor(); + } + + if ( pOut ) + { + const SvxOverlineItem& rOverlineColor = (const SvxOverlineItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_OVERLINE ); + if ( rOverlineColor.GetColor() != COL_TRANSPARENT ) + pOut->SetOverlineColor( rOverlineColor.GetColor() ); + else + pOut->SetOverlineColor(); + } + + const SvxLanguageItem* pCJKLanguageItem = NULL; + + if ( aStatus.UseCharAttribs() ) + { + const CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs(); + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttrib = GetAttrib( rAttribs, nAttr ); + while ( pAttrib && ( pAttrib->GetStart() <= nPos ) ) + { + // Beim Seeken nicht die Attr beruecksichtigen, die dort beginnen! + // Leere Attribute werden beruecksichtigt( verwendet), da diese + // gerade eingestellt wurden. + // 12.4.95: Doch keine Leeren Attribute verwenden: + // - Wenn gerade eingestellt und leer => keine Auswirkung auf Font + // In einem leeren Absatz eingestellte Zeichen werden sofort wirksam. + if ( ( pAttrib->Which() != nIgnoreWhich ) && + ( ( ( pAttrib->GetStart() < nPos ) && ( pAttrib->GetEnd() >= nPos ) ) + || ( !pNode->Len() ) ) ) + { + DBG_ASSERT( ( pAttrib->Which() >= EE_CHAR_START ) && ( pAttrib->Which() <= EE_FEATURE_END ), "Unglueltiges Attribut in Seek() " ); + if ( IsScriptItemValid( pAttrib->Which(), nScriptType ) ) + { + pAttrib->SetFont( rFont, pOut ); + // #i1550# hard color attrib should win over text color from field + if ( pAttrib->Which() == EE_FEATURE_FIELD ) + { + EditCharAttrib* pColorAttr = pNode->GetCharAttribs().FindAttrib( EE_CHAR_COLOR, nPos ); + if ( pColorAttr ) + pColorAttr->SetFont( rFont, pOut ); + } + } + if ( pAttrib->Which() == EE_CHAR_FONTWIDTH ) + nRelWidth = ((const SvxCharScaleWidthItem*)pAttrib->GetItem())->GetValue(); + if ( pAttrib->Which() == EE_CHAR_LANGUAGE_CJK ) + pCJKLanguageItem = (const SvxLanguageItem*) pAttrib->GetItem(); + } + pAttrib = GetAttrib( rAttribs, ++nAttr ); + } + } + + if ( !pCJKLanguageItem ) + pCJKLanguageItem = (const SvxLanguageItem*) &pNode->GetContentAttribs().GetItem( EE_CHAR_LANGUAGE_CJK ); + + rFont.SetCJKContextLanguage( pCJKLanguageItem->GetLanguage() ); + + if ( rFont.GetKerning() && IsKernAsianPunctuation() && ( nScriptType == i18n::ScriptType::ASIAN ) ) + rFont.SetKerning( rFont.GetKerning() | KERNING_ASIAN ); + + if ( aStatus.DoNotUseColors() ) + { + // Hack fuer DL,weil JOE staendig die Pooldefaults verbiegt! + // const SvxColorItem& rColorItem = (const SvxColorItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_COLOR ); + rFont.SetColor( /* rColorItem.GetValue() */ COL_BLACK ); + } + + if ( aStatus.DoStretch() || ( nRelWidth != 100 ) ) + { + // Fuer das aktuelle Ausgabegeraet, weil es sonst bei einem + // Drucker als RefDev auf dem Bildschirm #?!@' aussieht! + OutputDevice* pDev = pOut ? pOut : GetRefDevice(); + rFont.SetPhysFont( pDev ); + FontMetric aMetric( pDev->GetFontMetric() ); + // Fuer die Hoehe nicht die Metriken nehmen, da das bei + // Hoch-/Tiefgestellt schief geht. + Size aRealSz( aMetric.GetSize().Width(), rFont.GetSize().Height() ); + if ( aStatus.DoStretch() ) + { + if ( nStretchY != 100 ) + { + aRealSz.Height() *= nStretchY; + aRealSz.Height() /= 100; + } + if ( nStretchX != 100 ) + { + aRealSz.Width() *= nStretchX; + aRealSz.Width() /= 100; + + // Auch das Kerning: (long wegen Zwischenergebnis) + long nKerning = rFont.GetFixKerning(); +/* + Die Ueberlegung war: Wenn neg. Kerning, aber StretchX = 200 + => Nicht das Kerning verdoppelt, also die Buchstaben weiter + zusammenziehen + --------------------------- + Kern StretchX =>Kern + --------------------------- + >0 <100 < (Proportional) + <0 <100 < (Proportional) + >0 >100 > (Proportional) + <0 >100 < (Der Betrag, also Antiprop) +*/ + if ( ( nKerning < 0 ) && ( nStretchX > 100 ) ) + { + // Antiproportional + nKerning *= 100; + nKerning /= nStretchX; + } + else if ( nKerning ) + { + // Proportional + nKerning *= nStretchX; + nKerning /= 100; + } + rFont.SetFixKerning( (short)nKerning ); + } + } + if ( nRelWidth != 100 ) + { + aRealSz.Width() *= nRelWidth; + aRealSz.Width() /= 100; + } + rFont.SetSize( aRealSz ); + // Font wird nicht restauriert... + } + + if ( ( ( rFont.GetColor() == COL_AUTO ) || ( IsForceAutoColor() ) ) && pOut ) + { + // #i75566# Do not use AutoColor when printing OR Pdf export + const bool bPrinting(OUTDEV_PRINTER == pOut->GetOutDevType()); + const bool bPDFExporting(0 != pOut->GetPDFWriter()); + + if ( IsAutoColorEnabled() && !bPrinting && !bPDFExporting) + { + // Never use WindowTextColor on the printer + rFont.SetColor( GetAutoColor() ); + } + else + { + if ( ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() ) + rFont.SetColor( COL_WHITE ); + else + rFont.SetColor( COL_BLACK ); + } + } + + if ( mpIMEInfos && mpIMEInfos->pAttribs && ( mpIMEInfos->aPos.GetNode() == pNode ) && + ( nPos > mpIMEInfos->aPos.GetIndex() ) && ( nPos <= ( mpIMEInfos->aPos.GetIndex() + mpIMEInfos->nLen ) ) ) + { + sal_uInt16 nAttr = mpIMEInfos->pAttribs[ nPos - mpIMEInfos->aPos.GetIndex() - 1 ]; + if ( nAttr & EXTTEXTINPUT_ATTR_UNDERLINE ) + rFont.SetUnderline( UNDERLINE_SINGLE ); + else if ( nAttr & EXTTEXTINPUT_ATTR_BOLDUNDERLINE ) + rFont.SetUnderline( UNDERLINE_BOLD ); + else if ( nAttr & EXTTEXTINPUT_ATTR_DOTTEDUNDERLINE ) + rFont.SetUnderline( UNDERLINE_DOTTED ); + else if ( nAttr & EXTTEXTINPUT_ATTR_DASHDOTUNDERLINE ) + rFont.SetUnderline( UNDERLINE_DOTTED ); + else if ( nAttr & EXTTEXTINPUT_ATTR_REDTEXT ) + rFont.SetColor( Color( COL_RED ) ); + else if ( nAttr & EXTTEXTINPUT_ATTR_HALFTONETEXT ) + rFont.SetColor( Color( COL_LIGHTGRAY ) ); + if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT ) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + rFont.SetColor( rStyleSettings.GetHighlightTextColor() ); + rFont.SetFillColor( rStyleSettings.GetHighlightColor() ); + rFont.SetTransparent( FALSE ); + } + else if ( nAttr & EXTTEXTINPUT_ATTR_GRAYWAVELINE ) + { + rFont.SetUnderline( UNDERLINE_WAVE ); + if( pOut ) + pOut->SetTextLineColor( Color( COL_LIGHTGRAY ) ); + } + } +} + +void ImpEditEngine::RecalcFormatterFontMetrics( FormatterFontMetric& rCurMetrics, SvxFont& rFont ) +{ + // Fuer Zeilenhoehe bei Hoch/Tief erstmal ohne Propr! + sal_uInt16 nPropr = rFont.GetPropr(); + DBG_ASSERT( ( nPropr == 100 ) || rFont.GetEscapement(), "Propr ohne Escape?!" ); + if ( nPropr != 100 ) + { + rFont.SetPropr( 100 ); + rFont.SetPhysFont( pRefDev ); + } + sal_uInt16 nAscent, nDescent; + + FontMetric aMetric( pRefDev->GetFontMetric() ); + nAscent = (sal_uInt16)aMetric.GetAscent(); + if ( IsAddExtLeading() ) + nAscent = sal::static_int_cast< sal_uInt16 >( + nAscent + aMetric.GetExtLeading() ); + nDescent = (sal_uInt16)aMetric.GetDescent(); + + if ( IsFixedCellHeight() ) + { +/* creating correct proportional ascent and descent values lead to problems if different fonts are used + in the same portion, it results in a bigger linespacing. + sal_Int32 f = nAscent + nDescent; + if ( f ) + { + sal_Int32 nHeight = ImplCalculateFontIndependentLineSpacing( rFont.GetHeight() ); + nAscent = (sal_Int16)(( nHeight * nAscent ) / f ); + nDescent = (sal_Int16)(nHeight - nAscent); + } +*/ + nAscent = sal::static_int_cast< sal_uInt16 >( rFont.GetHeight() ); + nDescent= sal::static_int_cast< sal_uInt16 >( ImplCalculateFontIndependentLineSpacing( rFont.GetHeight() ) - nAscent ); + } + else + { + sal_uInt16 nIntLeading = ( aMetric.GetIntLeading() > 0 ) ? (sal_uInt16)aMetric.GetIntLeading() : 0; + // Fonts ohne Leading bereiten Probleme + if ( ( nIntLeading == 0 ) && ( pRefDev->GetOutDevType() == OUTDEV_PRINTER ) ) + { + // Da schaun wir mal, was fuer eine Leading ich auf dem + // Bildschirm erhalte + VirtualDevice* pVDev = GetVirtualDevice( pRefDev->GetMapMode(), pRefDev->GetDrawMode() ); + rFont.SetPhysFont( pVDev ); + aMetric = pVDev->GetFontMetric(); + + // Damit sich die Leading nicht wieder rausrechnet, + // wenn die ganze Zeile den Font hat, nTmpLeading. + + // 4/96: Kommt bei HP Laserjet 4V auch nicht hin + // => Werte komplett vom Bildschirm holen. + // sal_uInt16 nTmpLeading = (sal_uInt16)aMetric.GetLeading(); + // nAscent += nTmpLeading; + nAscent = (sal_uInt16)aMetric.GetAscent(); + nDescent = (sal_uInt16)aMetric.GetDescent(); + // nLeading = (sal_uInt16)aMetric.GetLeading(); + } + } + if ( nAscent > rCurMetrics.nMaxAscent ) + rCurMetrics.nMaxAscent = nAscent; + if ( nDescent > rCurMetrics.nMaxDescent ) + rCurMetrics.nMaxDescent= nDescent; + // Sonderbehandlung Hoch/Tief: + if ( rFont.GetEscapement() ) + { + // Jetzt unter Beruecksichtigung von Escape/Propr + // Ascent oder Descent ggf vergroessern + short nDiff = (short)(rFont.GetSize().Height()*rFont.GetEscapement()/100L); + if ( rFont.GetEscapement() > 0 ) + { + nAscent = (sal_uInt16) (((long)nAscent)*nPropr/100 + nDiff); + if ( nAscent > rCurMetrics.nMaxAscent ) + rCurMetrics.nMaxAscent = nAscent; + } + else // muss < 0 sein + { + nDescent = (sal_uInt16) (((long)nDescent)*nPropr/100 - nDiff); + if ( nDescent > rCurMetrics.nMaxDescent ) + rCurMetrics.nMaxDescent= nDescent; + } + } +} + +void ImpEditEngine::Paint( OutputDevice* pOutDev, Rectangle aClipRec, Point aStartPos, sal_Bool bStripOnly, short nOrientation ) +{ + if ( !GetUpdateMode() && !bStripOnly ) + return; + + if ( !IsFormatted() ) + FormatDoc(); + + long nFirstVisXPos = - pOutDev->GetMapMode().GetOrigin().X(); + long nFirstVisYPos = - pOutDev->GetMapMode().GetOrigin().Y(); + + EditLine* pLine; + Point aTmpPos; + Point aRedLineTmpPos; + DBG_ASSERT( GetParaPortions().Count(), "Keine ParaPortion?!" ); + SvxFont aTmpFont( GetParaPortions()[0]->GetNode()->GetCharAttribs().GetDefFont() ); + Font aOldFont( pOutDev->GetFont() ); + vcl::PDFExtOutDevData* pPDFExtOutDevData = PTR_CAST( vcl::PDFExtOutDevData, pOutDev->GetExtOutDevData() ); + + // Bei gedrehtem Text wird aStartPos als TopLeft angesehen, da andere + // Informationen fehlen, und sowieso das ganze Object ungescrollt + // dargestellt wird. + // Das Rechteck ist unendlich gross. + Point aOrigin( aStartPos ); + double nCos = 0.0, nSin = 0.0; + if ( nOrientation ) + { + double nRealOrientation = nOrientation*F_PI1800; + nCos = cos( nRealOrientation ); + nSin = sin( nRealOrientation ); + } + + // #110496# Added some more optional metafile comments. This + // change: factored out some duplicated code. + GDIMetaFile* pMtf = pOutDev->GetConnectMetaFile(); + const bool bMetafileValid( pMtf != NULL ); + + // Fuer OnlineSpelling: +// EditPaM aCursorPos; +// if( GetStatus().DoOnlineSpelling() && pActiveView ) +// aCurPos = pActiveView->pImpEditView->GetEditSelections().Max(); + + // -------------------------------------------------- + // Ueber alle Absaetze... + // -------------------------------------------------- + for ( sal_uInt16 n = 0; n < GetParaPortions().Count(); n++ ) + { + ParaPortion* pPortion = GetParaPortions().GetObject( n ); + DBG_ASSERT( pPortion, "NULL-Pointer in TokenList in Paint" ); + // falls beim Tippen Idle-Formatierung, asynchrones Paint. + // Unsichtbare Portions koennen ungueltig sein. + if ( pPortion->IsVisible() && pPortion->IsInvalid() ) + return; + + if ( pPDFExtOutDevData ) + pPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph ); + + long nParaHeight = pPortion->GetHeight(); + sal_uInt16 nIndex = 0; + if ( pPortion->IsVisible() && ( + ( !IsVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRec.Top() ) ) || + ( IsVertical() && ( ( aStartPos.X() - nParaHeight ) < aClipRec.Right() ) ) ) ) + + { + // -------------------------------------------------- + // Ueber die Zeilen des Absatzes... + // -------------------------------------------------- + sal_uInt16 nLines = pPortion->GetLines().Count(); + sal_uInt16 nLastLine = nLines-1; + + if ( !IsVertical() ) + aStartPos.Y() += pPortion->GetFirstLineOffset(); + else + aStartPos.X() -= pPortion->GetFirstLineOffset(); + + Point aParaStart( aStartPos ); + + const SvxLineSpacingItem& rLSItem = ((const SvxLineSpacingItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL )); + sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_FIX ) + ? GetYValue( rLSItem.GetInterLineSpace() ) : 0; + for ( sal_uInt16 nLine = 0; nLine < nLines; nLine++ ) + { + pLine = pPortion->GetLines().GetObject(nLine); + DBG_ASSERT( pLine, "NULL-Pointer im Zeileniterator in UpdateViews" ); + aTmpPos = aStartPos; + if ( !IsVertical() ) + { + aTmpPos.X() += pLine->GetStartPosX(); + aTmpPos.Y() += pLine->GetMaxAscent(); + aStartPos.Y() += pLine->GetHeight(); + } + else + { + aTmpPos.Y() += pLine->GetStartPosX(); + aTmpPos.X() -= pLine->GetMaxAscent(); + aStartPos.X() -= pLine->GetHeight(); + } + + if ( ( !IsVertical() && ( aStartPos.Y() > aClipRec.Top() ) ) + || ( IsVertical() && aStartPos.X() < aClipRec.Right() ) ) + { + // Why not just also call when stripping portions? This will give the correct values + // and needs no position corrections in OutlinerEditEng::DrawingText which tries to call + // PaintBullet correctly; exactly what GetEditEnginePtr()->PaintingFirstLine + // does, too. No change for not-layouting (painting). + if(0 == nLine) // && !bStripOnly) + { + // VERT??? + GetEditEnginePtr()->PaintingFirstLine( n, aParaStart, aTmpPos.Y(), aOrigin, nOrientation, pOutDev ); + } + + // -------------------------------------------------- + // Ueber die Portions der Zeile... + // -------------------------------------------------- + nIndex = pLine->GetStart(); + for ( sal_uInt16 y = pLine->GetStartPortion(); y <= pLine->GetEndPortion(); y++ ) + { + DBG_ASSERT( pPortion->GetTextPortions().Count(), "Zeile ohne Textportion im Paint!" ); + TextPortion* pTextPortion = pPortion->GetTextPortions().GetObject( y ); + DBG_ASSERT( pTextPortion, "NULL-Pointer im Portioniterator in UpdateViews" ); + + long nPortionXOffset = GetPortionXOffset( pPortion, pLine, y ); + if ( !IsVertical() ) + { + aTmpPos.X() = aStartPos.X() + nPortionXOffset; + if ( aTmpPos.X() > aClipRec.Right() ) + break; // Keine weitere Ausgabe in Zeile noetig + } + else + { + aTmpPos.Y() = aStartPos.Y() + nPortionXOffset; + if ( aTmpPos.Y() > aClipRec.Bottom() ) + break; // Keine weitere Ausgabe in Zeile noetig + } + + // R2L replaces with obove... + // New position after processing R2L text... +// R2L if ( nR2LWidth && !pTextPortion->GetRightToLeft() ) +// R2L { +// R2L if ( !IsVertical() ) +// R2L aTmpPos.X() += nR2LWidth; +// R2L else +// R2L aTmpPos.Y() += nR2LWidth; +// R2L +// R2L nR2LWidth = 0; +// R2L } + + switch ( pTextPortion->GetKind() ) + { + case PORTIONKIND_TEXT: + case PORTIONKIND_FIELD: + case PORTIONKIND_HYPHENATOR: + { + SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev ); + + BOOL bDrawFrame = FALSE; + + if ( ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) && !aTmpFont.IsTransparent() && + ( GetBackgroundColor() != COL_AUTO ) && GetBackgroundColor().IsDark() && + ( IsAutoColorEnabled() && ( pOutDev->GetOutDevType() != OUTDEV_PRINTER ) ) ) + { + aTmpFont.SetTransparent( TRUE ); + pOutDev->SetFillColor(); + pOutDev->SetLineColor( GetAutoColor() ); + bDrawFrame = TRUE; + } + +#ifdef EDITDEBUG + if ( pTextPortion->GetKind() == PORTIONKIND_HYPHENATOR ) + { + aTmpFont.SetFillColor( COL_LIGHTGRAY ); + aTmpFont.SetTransparent( sal_False ); + } + if ( pTextPortion->GetRightToLeft() ) + { + aTmpFont.SetFillColor( COL_LIGHTGRAY ); + aTmpFont.SetTransparent( sal_False ); + } + else if ( GetScriptType( EditPaM( pPortion->GetNode(), nIndex+1 ) ) == i18n::ScriptType::COMPLEX ) + { + aTmpFont.SetFillColor( COL_LIGHTCYAN ); + aTmpFont.SetTransparent( sal_False ); + } +#endif + aTmpFont.SetPhysFont( pOutDev ); + + // #114278# Saving both layout mode and language (since I'm + // potentially changing both) + pOutDev->Push( PUSH_TEXTLAYOUTMODE|PUSH_TEXTLANGUAGE ); + ImplInitLayoutMode( pOutDev, n, nIndex ); + ImplInitDigitMode( pOutDev, 0, 0, 0, aTmpFont.GetLanguage() ); + + XubString aText; + USHORT nTextStart = 0; + USHORT nTextLen = 0; + const sal_Int32* pDXArray = 0; + sal_Int32* pTmpDXArray = 0; + + if ( pTextPortion->GetKind() == PORTIONKIND_TEXT ) + { + aText = *pPortion->GetNode(); + nTextStart = nIndex; + nTextLen = pTextPortion->GetLen(); + pDXArray = pLine->GetCharPosArray().GetData()+( nIndex-pLine->GetStart() ); + + // --> FME 2005-10-18 #i55716# Paint control characters + if ( aStatus.MarkFields() ) + { + xub_StrLen nTmpIdx; + const xub_StrLen nTmpEnd = nTextStart + pTextPortion->GetLen(); + + for ( nTmpIdx = nTextStart; nTmpIdx <= nTmpEnd ; ++nTmpIdx ) + { + const sal_Unicode cChar = ( nTmpIdx != aText.Len() && ( nTmpIdx != nTextStart || 0 == nTextStart ) ) ? + aText.GetChar( nTmpIdx ) : + 0; + + if ( 0x200B == cChar || 0x2060 == cChar ) + { + const String aBlank( ' ' ); + long nHalfBlankWidth = aTmpFont.QuickGetTextSize( pOutDev, aBlank, 0, 1, 0 ).Width() / 2; + + const long nAdvanceX = ( nTmpIdx == nTmpEnd ? + pTextPortion->GetSize().Width() : + pDXArray[ nTmpIdx - nTextStart ] ) - nHalfBlankWidth; + const long nAdvanceY = -pLine->GetMaxAscent(); + + Point aTopLeftRectPos( aTmpPos ); + if ( !IsVertical() ) + { + aTopLeftRectPos.X() += nAdvanceX; + aTopLeftRectPos.Y() += nAdvanceY; + } + else + { + aTopLeftRectPos.Y() += nAdvanceX; + aTopLeftRectPos.X() -= nAdvanceY; + } + + Point aBottomRightRectPos( aTopLeftRectPos ); + if ( !IsVertical() ) + { + aBottomRightRectPos.X() += 2 * nHalfBlankWidth; + aBottomRightRectPos.Y() += pLine->GetHeight(); + } + else + { + aBottomRightRectPos.X() -= pLine->GetHeight(); + aBottomRightRectPos.Y() += 2 * nHalfBlankWidth; + } + + pOutDev->Push( PUSH_FILLCOLOR ); + pOutDev->Push( PUSH_LINECOLOR ); + pOutDev->SetFillColor( COL_LIGHTGRAY ); + pOutDev->SetLineColor( COL_LIGHTGRAY ); + + const Rectangle aBackRect( aTopLeftRectPos, aBottomRightRectPos ); + pOutDev->DrawRect( aBackRect ); + + pOutDev->Pop(); + pOutDev->Pop(); + + if ( 0x200B == cChar ) + { + const String aSlash( '/' ); + const short nOldEscapement = aTmpFont.GetEscapement(); + const BYTE nOldPropr = aTmpFont.GetPropr(); + + aTmpFont.SetEscapement( -20 ); + aTmpFont.SetPropr( 25 ); + aTmpFont.SetPhysFont( pOutDev ); + + const Size aSlashSize = aTmpFont.QuickGetTextSize( pOutDev, aSlash, 0, 1, 0 ); + Point aSlashPos( aTmpPos ); + const long nAddX = nHalfBlankWidth - aSlashSize.Width() / 2; + if ( !IsVertical() ) + { + aSlashPos.X() = aTopLeftRectPos.X() + nAddX; + } + else + { + aSlashPos.Y() = aTopLeftRectPos.Y() + nAddX; + } + + aTmpFont.QuickDrawText( pOutDev, aSlashPos, aSlash, 0, 1, 0 ); + + aTmpFont.SetEscapement( nOldEscapement ); + aTmpFont.SetPropr( nOldPropr ); + aTmpFont.SetPhysFont( pOutDev ); + } + } + } + } + // <-- + } + else if ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) + { + EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature( nIndex ); + DBG_ASSERT( pAttr, "Feld nicht gefunden" ); + DBG_ASSERT( pAttr && pAttr->GetItem()->ISA( SvxFieldItem ), "Feld vom falschen Typ!" ); + aText = ((EditCharAttribField*)pAttr)->GetFieldValue(); + nTextStart = 0; + nTextLen = aText.Len(); + + pTmpDXArray = new sal_Int32[ aText.Len() ]; + pDXArray = pTmpDXArray; + Font _aOldFont( GetRefDevice()->GetFont() ); + aTmpFont.SetPhysFont( GetRefDevice() ); + aTmpFont.QuickGetTextSize( GetRefDevice(), aText, 0, aText.Len(), pTmpDXArray ); + if ( aStatus.DoRestoreFont() ) + GetRefDevice()->SetFont( _aOldFont ); + + // add a meta file comment if we record to a metafile + if( bMetafileValid ) + { + SvxFieldItem* pFieldItem = PTR_CAST( SvxFieldItem, pAttr->GetItem() ); + if( pFieldItem ) + { + const SvxFieldData* pFieldData = pFieldItem->GetField(); + if( pFieldData ) + pMtf->AddAction( pFieldData->createBeginComment() ); + } + } + + } + else if ( pTextPortion->GetKind() == PORTIONKIND_HYPHENATOR ) + { + if ( pTextPortion->GetExtraValue() ) + aText = pTextPortion->GetExtraValue(); + aText += CH_HYPH; + nTextStart = 0; + nTextLen = aText.Len(); + + // #b6668980# crash when accessing 0 pointer in pDXArray + pTmpDXArray = new sal_Int32[ aText.Len() ]; + pDXArray = pTmpDXArray; + Font _aOldFont( GetRefDevice()->GetFont() ); + aTmpFont.SetPhysFont( GetRefDevice() ); + aTmpFont.QuickGetTextSize( GetRefDevice(), aText, 0, aText.Len(), pTmpDXArray ); + if ( aStatus.DoRestoreFont() ) + GetRefDevice()->SetFont( _aOldFont ); + } + + long nTxtWidth = pTextPortion->GetSize().Width(); + + Point aOutPos( aTmpPos ); + aRedLineTmpPos = aTmpPos; + // In RTL portions spell markup pos should be at the start of the + // first chara as well. That is on the right end of the portion + if (pTextPortion->IsRightToLeft()) + aRedLineTmpPos.X() += pTextPortion->GetSize().Width(); + +//L2R if ( pTextPortion->GetRightToLeft() ) +//L2R { +//L2R sal_uInt16 nNextPortion = y+1; +//L2R while ( nNextPortion <= pLine->GetEndPortion() ) +//L2R { +//L2R TextPortion* pNextTextPortion = pPortion->GetTextPortions().GetObject( nNextPortion ); +//L2R if ( pNextTextPortion->GetRightToLeft() ) +//L2R { +//L2R if ( !IsVertical() ) +//L2R aOutPos.X() += pNextTextPortion->GetSize().Width(); +//L2R else +//L2R aOutPos.Y() += pNextTextPortion->GetSize().Width(); +//L2R } +//L2R else +//L2R break; +//L2R nNextPortion++; +//L2R } +//L2R } + if ( bStripOnly ) + { + EEngineData::WrongSpellVector aWrongSpellVector; + + if(GetStatus().DoOnlineSpelling() && pTextPortion->GetLen()) + { + WrongList* pWrongs = pPortion->GetNode()->GetWrongList(); + + if(pWrongs && pWrongs->HasWrongs()) + { + sal_uInt16 nStart(nIndex); + sal_uInt16 nEnd(0); + sal_Bool bWrong(pWrongs->NextWrong(nStart, nEnd)); + const sal_uInt16 nMaxEnd(nIndex + pTextPortion->GetLen()); + + while(bWrong) + { + if(nStart >= nMaxEnd) + { + break; + } + + if(nStart < nIndex) + { + nStart = nIndex; + } + + if(nEnd > nMaxEnd) + { + nEnd = nMaxEnd; + } + + // add to vector + aWrongSpellVector.push_back(EEngineData::WrongSpellClass(nStart, nEnd)); + + // goto next index + nStart = nEnd + 1; + + if(nEnd < nMaxEnd) + { + bWrong = pWrongs->NextWrong(nStart, nEnd); + } + else + { + bWrong = sal_False; + } + } + } + } + + const SvxFieldData* pFieldData = 0; + + if(PORTIONKIND_FIELD == pTextPortion->GetKind()) + { + EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex); + SvxFieldItem* pFieldItem = PTR_CAST(SvxFieldItem, pAttr->GetItem()); + + if(pFieldItem) + { + pFieldData = pFieldItem->GetField(); + } + } + + // support for EOC, EOW, EOS TEXT comments. To support that, + // the locale is needed. With the locale and a XBreakIterator it is + // possible to re-create the text marking info on primitive level + const lang::Locale aLocale(GetLocale(EditPaM(pPortion->GetNode(), nIndex + 1))); + + // create EOL and EOP bools + const bool bEndOfLine(y == pLine->GetEndPortion()); + const bool bEndOfParagraph(bEndOfLine && nLine + 1 == nLines); + + // get Overline color (from ((const SvxOverlineItem*)GetItem())->GetColor() in + // consequence, but also already set at pOutDev) + const Color aOverlineColor(pOutDev->GetOverlineColor()); + + // get TextLine color (from ((const SvxUnderlineItem*)GetItem())->GetColor() in + // consequence, but also already set at pOutDev) + const Color aTextLineColor(pOutDev->GetTextLineColor()); + + // Unicode code points conversion according to ctl text numeral setting + ImplInitDigitMode( 0, &aText, nTextStart, nTextLen, aTmpFont.GetLanguage() ); + + // StripPortions() data callback + GetEditEnginePtr()->DrawingText( aOutPos, aText, nTextStart, nTextLen, pDXArray, + aTmpFont, n, nIndex, pTextPortion->GetRightToLeft(), + aWrongSpellVector.size() ? &aWrongSpellVector : 0, + pFieldData, + bEndOfLine, bEndOfParagraph, false, // support for EOL/EOP TEXT comments + &aLocale, + aOverlineColor, + aTextLineColor); + } + else + { + short nEsc = aTmpFont.GetEscapement(); + if ( nOrientation ) + { + // Bei Hoch/Tief selbst Hand anlegen: + if ( aTmpFont.GetEscapement() ) + { + long nDiff = aTmpFont.GetSize().Height() * aTmpFont.GetEscapement() / 100L; + if ( !IsVertical() ) + aOutPos.Y() -= nDiff; + else + aOutPos.X() += nDiff; + aRedLineTmpPos = aOutPos; + aTmpFont.SetEscapement( 0 ); + } + + aOutPos = lcl_ImplCalcRotatedPos( aOutPos, aOrigin, nSin, nCos ); + aTmpFont.SetOrientation( aTmpFont.GetOrientation()+nOrientation ); + aTmpFont.SetPhysFont( pOutDev ); + + } + // nur ausgeben, was im sichtbaren Bereich beginnt: + // Wichtig, weil Bug bei einigen Grafikkarten bei transparentem Font, Ausgabe bei neg. + if ( nOrientation || ( !IsVertical() && ( ( aTmpPos.X() + nTxtWidth ) >= nFirstVisXPos ) ) + || ( IsVertical() && ( ( aTmpPos.Y() + nTxtWidth ) >= nFirstVisYPos ) ) ) + { + if ( nEsc && ( ( aTmpFont.GetUnderline() != UNDERLINE_NONE ) ) ) + { + // Das Hoch/Tief ohne Underline malen, das Underline + // auf der BaseLine der Original-Fonthoehe ausgeben... + + // Aber nur, wenn davor auch Unterstrichen! + sal_Bool bSpecialUnderline = sal_False; + EditCharAttrib* pPrev = pPortion->GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex ); + if ( pPrev ) + { + SvxFont aDummy; + // Unterstreichung davor? + if ( pPrev->GetStart() ) + { + SeekCursor( pPortion->GetNode(), pPrev->GetStart(), aDummy ); + if ( aDummy.GetUnderline() != UNDERLINE_NONE ) + bSpecialUnderline = sal_True; + } + if ( !bSpecialUnderline && ( pPrev->GetEnd() < pPortion->GetNode()->Len() ) ) + { + SeekCursor( pPortion->GetNode(), pPrev->GetEnd()+1, aDummy ); + if ( aDummy.GetUnderline() != UNDERLINE_NONE ) + bSpecialUnderline = sal_True; + } + } + if ( bSpecialUnderline ) + { + Size aSz = aTmpFont.GetPhysTxtSize( pOutDev, aText, nTextStart, nTextLen ); + BYTE nProp = aTmpFont.GetPropr(); + aTmpFont.SetEscapement( 0 ); + aTmpFont.SetPropr( 100 ); + aTmpFont.SetPhysFont( pOutDev ); + String aBlanks; + aBlanks.Fill( nTextLen, ' ' ); + Point aUnderlinePos( aOutPos ); + if ( nOrientation ) + aUnderlinePos = lcl_ImplCalcRotatedPos( aTmpPos, aOrigin, nSin, nCos ); + pOutDev->DrawStretchText( aUnderlinePos, aSz.Width(), aBlanks, 0, nTextLen ); + + aTmpFont.SetUnderline( UNDERLINE_NONE ); + if ( !nOrientation ) + aTmpFont.SetEscapement( nEsc ); + aTmpFont.SetPropr( nProp ); + aTmpFont.SetPhysFont( pOutDev ); + } + } + Point aRealOutPos( aOutPos ); + if ( ( pTextPortion->GetKind() == PORTIONKIND_TEXT ) + && pTextPortion->GetExtraInfos() && pTextPortion->GetExtraInfos()->bCompressed + && pTextPortion->GetExtraInfos()->bFirstCharIsRightPunktuation ) + { + aRealOutPos.X() += pTextPortion->GetExtraInfos()->nPortionOffsetX; + } + + // --> FME 2005-06-17 #i37132# RTL portions with + // compressed blank should not paint this blank: + if ( pTextPortion->IsRightToLeft() && nTextLen >= 2 && + pDXArray[ nTextLen - 1 ] == + pDXArray[ nTextLen - 2 ] && + ' ' == aText.GetChar( nTextStart + nTextLen - 1 ) ) + --nTextLen; + // <-- + + // output directly + aTmpFont.QuickDrawText( pOutDev, aRealOutPos, aText, nTextStart, nTextLen, pDXArray ); + + if ( bDrawFrame ) + { + Point aTopLeft( aTmpPos ); + aTopLeft.Y() -= pLine->GetMaxAscent(); + if ( nOrientation ) + aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos ); + Rectangle aRect( aTopLeft, pTextPortion->GetSize() ); + pOutDev->DrawRect( aRect ); + } + + + // PDF export: + if ( pPDFExtOutDevData ) + { + if ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) + { + EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature( nIndex ); + SvxFieldItem* pFieldItem = PTR_CAST( SvxFieldItem, pAttr->GetItem() ); + if( pFieldItem ) + { + const SvxFieldData* pFieldData = pFieldItem->GetField(); + if ( pFieldData->ISA( SvxURLField ) ) + { + Point aTopLeft( aTmpPos ); + aTopLeft.Y() -= pLine->GetMaxAscent(); +// if ( nOrientation ) +// aTopLeft = lcl_ImplCalcRotatedPos( aTopLeft, aOrigin, nSin, nCos ); + + Rectangle aRect( aTopLeft, pTextPortion->GetSize() ); + vcl::PDFExtOutDevBookmarkEntry aBookmark; + aBookmark.nLinkId = pPDFExtOutDevData->CreateLink( aRect ); + aBookmark.aBookmark = ((SvxURLField*)pFieldData)->GetURL(); + std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFExtOutDevData->GetBookmarks(); + rBookmarks.push_back( aBookmark ); + } + } + } + } + + // comment + + + + + } + +#ifndef SVX_LIGHT + if ( GetStatus().DoOnlineSpelling() && pPortion->GetNode()->GetWrongList()->HasWrongs() && pTextPortion->GetLen() ) + { + {//#105750# adjust LinePos for superscript or subscript text + short _nEsc = aTmpFont.GetEscapement(); + if( _nEsc ) + { + long nShift = ((_nEsc*long(aTmpFont.GetSize().Height()))/ 100L); + if( !IsVertical() ) + aRedLineTmpPos.Y() -= nShift; + else + aRedLineTmpPos.X() += nShift; + } + } + Color aOldColor( pOutDev->GetLineColor() ); + pOutDev->SetLineColor( Color( GetColorConfig().GetColorValue( svtools::SPELL ).nColor ) ); + lcl_DrawRedLines( pOutDev, aTmpFont.GetSize().Height(), aRedLineTmpPos, nIndex, nIndex + pTextPortion->GetLen(), pDXArray, pPortion->GetNode()->GetWrongList(), nOrientation, aOrigin, IsVertical(), pTextPortion->IsRightToLeft() ); + pOutDev->SetLineColor( aOldColor ); + } +#endif // !SVX_LIGHT + } + + pOutDev->Pop(); + + if ( pTmpDXArray ) + delete[] pTmpDXArray; + +// R2L if ( !pTextPortion->GetRightToLeft() ) +// R2L { +// R2L if ( !IsVertical() ) +// R2L aTmpPos.X() += nTxtWidth; +// R2L else +// R2L aTmpPos.Y() += nTxtWidth; +// R2L } +// R2L else +// R2L { +// R2L nR2LWidth += nTxtWidth; +// R2L } + + if ( pTextPortion->GetKind() == PORTIONKIND_FIELD ) + { + EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature( nIndex ); + DBG_ASSERT( pAttr, "Feld nicht gefunden" ); + DBG_ASSERT( pAttr && pAttr->GetItem()->ISA( SvxFieldItem ), "Feld vom falschen Typ!" ); + + // add a meta file comment if we record to a metafile + if( bMetafileValid ) + { + SvxFieldItem* pFieldItem = PTR_CAST( SvxFieldItem, pAttr->GetItem() ); + + if( pFieldItem ) + { + const SvxFieldData* pFieldData = pFieldItem->GetField(); + if( pFieldData ) + pMtf->AddAction( pFieldData->createEndComment() ); + } + } + + } + + } + break; +// case PORTIONKIND_EXTRASPACE: + case PORTIONKIND_TAB: + { + if ( pTextPortion->GetExtraValue() && ( pTextPortion->GetExtraValue() != ' ' ) ) + { + SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev ); + aTmpFont.SetTransparent( sal_False ); + aTmpFont.SetEscapement( 0 ); + aTmpFont.SetPhysFont( pOutDev ); + long nCharWidth = aTmpFont.QuickGetTextSize( pOutDev, pTextPortion->GetExtraValue(), 0, 1, NULL ).Width(); + long nChars = 2; + if( nCharWidth ) + nChars = pTextPortion->GetSize().Width() / nCharWidth; + if ( nChars < 2 ) + nChars = 2; // wird durch DrawStretchText gestaucht. + else if ( nChars == 2 ) + nChars = 3; // sieht besser aus + + String aText; + aText.Fill( (USHORT)nChars, pTextPortion->GetExtraValue() ); + pOutDev->DrawStretchText( aTmpPos, pTextPortion->GetSize().Width(), aText ); + } + } + break; + } + nIndex = nIndex + pTextPortion->GetLen(); + } + } + + if ( ( nLine != nLastLine ) && !aStatus.IsOutliner() ) + { + if ( !IsVertical() ) + aStartPos.Y() += nSBL; + else + aStartPos.X() -= nSBL; + } + + // keine sichtbaren Aktionen mehr? + if ( !IsVertical() && ( aStartPos.Y() >= aClipRec.Bottom() ) ) + break; + else if ( IsVertical() && ( aStartPos.X() <= aClipRec.Left() ) ) + break; + } + + if ( !aStatus.IsOutliner() ) + { + const SvxULSpaceItem& rULItem = (const SvxULSpaceItem&)pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + long nUL = GetYValue( rULItem.GetLower() ); + if ( !IsVertical() ) + aStartPos.Y() += nUL; + else + aStartPos.X() -= nUL; + } + } + else + { + if ( !IsVertical() ) + aStartPos.Y() += nParaHeight; + else + aStartPos.X() -= nParaHeight; + } + + if ( pPDFExtOutDevData ) + pPDFExtOutDevData->EndStructureElement(); + + // keine sichtbaren Aktionen mehr? + if ( !IsVertical() && ( aStartPos.Y() > aClipRec.Bottom() ) ) + break; + if ( IsVertical() && ( aStartPos.X() < aClipRec.Left() ) ) + break; + } + if ( aStatus.DoRestoreFont() ) + pOutDev->SetFont( aOldFont ); +} + +void ImpEditEngine::Paint( ImpEditView* pView, const Rectangle& rRec, sal_Bool bUseVirtDev ) +{ + DBG_ASSERT( pView, "Keine View - Kein Paint!" ); + DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 ); + + if ( !GetUpdateMode() || IsInUndo() ) + return; + + // Schnittmenge aus Paintbereich und OutputArea. + Rectangle aClipRec( pView->GetOutputArea() ); + aClipRec.Intersection( rRec ); + + Window* pOutWin = pView->GetWindow(); + + if ( bUseVirtDev ) + { + Rectangle aClipRecPixel( pOutWin->LogicToPixel( aClipRec ) ); + if ( !IsVertical() ) + { + // etwas mehr, falls abgerundet! + aClipRecPixel.Right() += 1; + aClipRecPixel.Bottom() += 1; + } + else + { + aClipRecPixel.Left() -= 1; + aClipRecPixel.Bottom() += 1; + } + + // Wenn aClipRecPixel > XXXX, dann invalidieren ?! + + VirtualDevice* pVDev = GetVirtualDevice( pOutWin->GetMapMode(), pOutWin->GetDrawMode() ); + pVDev->SetDigitLanguage( GetRefDevice()->GetDigitLanguage() ); + + { + Color aBackgroundColor( pView->GetBackgroundColor() ); + // #i47161# Check if text is visible on background + SvxFont aTmpFont; + ContentNode* pNode = GetEditDoc().SaveGetObject( 0 ); + SeekCursor( pNode, 1, aTmpFont ); + Color aFontColor( aTmpFont.GetColor() ); + if( aFontColor == COL_AUTO ) + aFontColor = GetAutoColor(); + + // #i69346# check for reverse color of input method attribute + if( mpIMEInfos && (mpIMEInfos->aPos.GetNode() == pNode && + mpIMEInfos->pAttribs)) + { + sal_uInt16 nAttr = mpIMEInfos->pAttribs[ 0 ]; + if ( nAttr & EXTTEXTINPUT_ATTR_HIGHLIGHT ) + { + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + aFontColor = rStyleSettings.GetHighlightColor() ; + } + } + + UINT8 nColorDiff = aFontColor.GetColorError( aBackgroundColor ); + if( nColorDiff < 8 ) + aBackgroundColor = aFontColor.IsDark() ? COL_WHITE : COL_BLACK; + pVDev->SetBackground( aBackgroundColor ); + } + + sal_Bool bVDevValid = sal_True; + Size aOutSz( pVDev->GetOutputSizePixel() ); + if ( ( aOutSz.Width() < aClipRecPixel.GetWidth() ) || + ( aOutSz.Height() < aClipRecPixel.GetHeight() ) ) + { + bVDevValid = pVDev->SetOutputSizePixel( aClipRecPixel.GetSize() ); + } + else + { + // Das VirtDev kann bei einem Resize sehr gross werden => + // irgendwann mal kleiner machen! + if ( ( aOutSz.Height() > ( aClipRecPixel.GetHeight() + RESDIFF ) ) || + ( aOutSz.Width() > ( aClipRecPixel.GetWidth() + RESDIFF ) ) ) + { + bVDevValid = pVDev->SetOutputSizePixel( aClipRecPixel.GetSize() ); + } + else + { + pVDev->Erase(); + } + } + DBG_ASSERT( bVDevValid, "VDef konnte nicht vergroessert werden!" ); + if ( !bVDevValid ) + { + Paint( pView, rRec, sal_False /* ohne VDev */ ); + return; + } + + // PaintRect fuer VDev nicht mit alignter Groesse, + // da sonst die Zeile darunter auch ausgegeben werden muss: + Rectangle aTmpRec( Point( 0, 0 ), aClipRec.GetSize() ); + + aClipRec = pOutWin->PixelToLogic( aClipRecPixel ); + Point aStartPos; + if ( !IsVertical() ) + { + aStartPos = aClipRec.TopLeft(); + aStartPos = pView->GetDocPos( aStartPos ); + aStartPos.X() *= (-1); + aStartPos.Y() *= (-1); + } + else + { + aStartPos = aClipRec.TopRight(); + Point aDocPos( pView->GetDocPos( aStartPos ) ); + aStartPos.X() = aClipRec.GetSize().Width() + aDocPos.Y(); + aStartPos.Y() = -aDocPos.X(); + } + + Paint( pVDev, aTmpRec, aStartPos ); + + sal_Bool bClipRegion = sal_False; + Region aOldRegion; + MapMode aOldMapMode; + if ( GetTextRanger() ) + { + // Some problems here with push/pop, why?! +// pOutWin->Push( PUSH_CLIPREGION|PUSH_MAPMODE ); + bClipRegion = pOutWin->IsClipRegion(); + aOldRegion = pOutWin->GetClipRegion(); + // Wie bekomme ich das Polygon an die richtige Stelle???? + // Das Polygon bezieht sich auf die View, nicht auf das Window + // => Origin umsetzen... + aOldMapMode = pOutWin->GetMapMode(); + Point aOrigin = aOldMapMode.GetOrigin(); + Point aViewPos = pView->GetOutputArea().TopLeft(); + aOrigin.Move( aViewPos.X(), aViewPos.Y() ); + aClipRec.Move( -aViewPos.X(), -aViewPos.Y() ); + MapMode aNewMapMode( aOldMapMode ); + aNewMapMode.SetOrigin( aOrigin ); + pOutWin->SetMapMode( aNewMapMode ); + pOutWin->SetClipRegion( Region( GetTextRanger()->GetPolyPolygon() ) ); + } + + pOutWin->DrawOutDev( aClipRec.TopLeft(), aClipRec.GetSize(), + Point(0,0), aClipRec.GetSize(), *pVDev ); + + if ( GetTextRanger() ) + { +// pOutWin->Pop(); + if ( bClipRegion ) + pOutWin->SetClipRegion( aOldRegion ); + else + pOutWin->SetClipRegion(); + pOutWin->SetMapMode( aOldMapMode ); + } + + + pView->DrawSelection(); + } + else + { + Point aStartPos; + if ( !IsVertical() ) + { + aStartPos = pView->GetOutputArea().TopLeft(); + aStartPos.X() -= pView->GetVisDocLeft(); + aStartPos.Y() -= pView->GetVisDocTop(); + } + else + { + aStartPos = pView->GetOutputArea().TopRight(); + aStartPos.X() += pView->GetVisDocTop(); + aStartPos.Y() -= pView->GetVisDocLeft(); + } + + // Wenn Doc-Breite < OutputArea,Width, nicht umgebrochene Felder, + // stehen die Felder sonst �ber, wenn > Zeile. + // ( Oben nicht, da dort bereits Doc-Breite von Formatierung mit drin ) + if ( !IsVertical() && ( pView->GetOutputArea().GetWidth() > GetPaperSize().Width() ) ) + { + long nMaxX = pView->GetOutputArea().Left() + GetPaperSize().Width(); + if ( aClipRec.Left() > nMaxX ) + return; + if ( aClipRec.Right() > nMaxX ) + aClipRec.Right() = nMaxX; + } + + sal_Bool bClipRegion = pOutWin->IsClipRegion(); + Region aOldRegion = pOutWin->GetClipRegion(); + pOutWin->IntersectClipRegion( aClipRec ); + + Paint( pOutWin, aClipRec, aStartPos ); + + if ( bClipRegion ) + pOutWin->SetClipRegion( aOldRegion ); + else + pOutWin->SetClipRegion(); + + pView->DrawSelection(); + } + +} + +void ImpEditEngine::InsertContent( ContentNode* pNode, sal_uInt16 nPos ) +{ + DBG_ASSERT( pNode, "NULL-Poointer in InsertContent! " ); + DBG_ASSERT( IsInUndo(), "InsertContent nur fuer Undo()!" ); + ParaPortion* pNew = new ParaPortion( pNode ); + GetParaPortions().Insert( pNew, nPos ); + aEditDoc.Insert( pNode, nPos ); + if ( IsCallParaInsertedOrDeleted() ) + GetEditEnginePtr()->ParagraphInserted( nPos ); +} + +EditPaM ImpEditEngine::SplitContent( sal_uInt16 nNode, sal_uInt16 nSepPos ) +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); + DBG_ASSERT( pNode, "Ungueltiger Node in SplitContent" ); + DBG_ASSERT( IsInUndo(), "SplitContent nur fuer Undo()!" ); + DBG_ASSERT( nSepPos <= pNode->Len(), "Index im Wald: SplitContent" ); + EditPaM aPaM( pNode, nSepPos ); + return ImpInsertParaBreak( aPaM ); +} + +EditPaM ImpEditEngine::ConnectContents( sal_uInt16 nLeftNode, sal_Bool bBackward ) +{ + ContentNode* pLeftNode = aEditDoc.SaveGetObject( nLeftNode ); + ContentNode* pRightNode = aEditDoc.SaveGetObject( nLeftNode+1 ); + DBG_ASSERT( pLeftNode, "Ungueltiger linker Node in ConnectContents" ); + DBG_ASSERT( pRightNode, "Ungueltiger rechter Node in ConnectContents" ); + DBG_ASSERT( IsInUndo(), "ConnectContent nur fuer Undo()!" ); + return ImpConnectParagraphs( pLeftNode, pRightNode, bBackward ); +} + +void ImpEditEngine::SetUpdateMode( sal_Bool bUp, EditView* pCurView, sal_Bool bForceUpdate ) +{ + sal_Bool bChanged = ( GetUpdateMode() != bUp ); + + // Beim Umschalten von sal_True auf sal_False waren alle Selektionen sichtbar, + // => Wegmalen + // Umgekehrt waren alle unsichtbar => malen + +// DrawAllSelections(); sieht im Outliner schlecht aus ! +// EditView* pView = aEditViewList.First(); +// while ( pView ) +// { +// DBG_CHKOBJ( pView, EditView, 0 ); +// pView->pImpEditView->DrawSelection(); +// pView = aEditViewList.Next(); +// } + + // Wenn !bFormatted, also z.B. nach SetText, braucht bei UpdateMode sal_True + // nicht sofort formatiert werden, weil warscheinlich noch Text kommt. + // Spaetestens bei einem Paint / CalcTextWidth wird formatiert. + + bUpdate = bUp; + if ( bUpdate && ( bChanged || bForceUpdate ) ) + FormatAndUpdate( pCurView ); +} + +void ImpEditEngine::ShowParagraph( sal_uInt16 nParagraph, sal_Bool bShow ) +{ + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "ShowParagraph: Absatz existiert nicht!" ); + if ( pPPortion && ( pPPortion->IsVisible() != bShow ) ) + { + pPPortion->SetVisible( bShow ); + + if ( !bShow ) + { + // Als deleted kenzeichnen, damit keine Selektion auf diesem + // Absatz beginnt oder endet... + DeletedNodeInfo* pDelInfo = new DeletedNodeInfo( (sal_uIntPtr)pPPortion->GetNode(), nParagraph ); + aDeletedNodes.Insert( pDelInfo, aDeletedNodes.Count() ); + UpdateSelections(); + // Dann kriege ich den unteren Bereich nicht invalidiert, + // wenn UpdateMode = sal_False! + // Wenn doch, dann vor SetVisible auf sal_False merken! +// nCurTextHeight -= pPPortion->GetHeight(); + } + + if ( bShow && ( pPPortion->IsInvalid() || !pPPortion->nHeight ) ) + { + if ( !GetTextRanger() ) + { + if ( pPPortion->IsInvalid() ) + { + Font aOldFont( GetRefDevice()->GetFont() ); + CreateLines( nParagraph, 0 ); // 0: Kein TextRanger + if ( aStatus.DoRestoreFont() ) + GetRefDevice()->SetFont( aOldFont ); + } + else + { + CalcHeight( pPPortion ); + } + nCurTextHeight += pPPortion->GetHeight(); + } + else + { + nCurTextHeight = 0x7fffffff; + } + } + + pPPortion->SetMustRepaint( sal_True ); + if ( GetUpdateMode() && !IsInUndo() && !GetTextRanger() ) + { + aInvalidRec = Rectangle( Point( 0, GetParaPortions().GetYOffset( pPPortion ) ), + Point( GetPaperSize().Width(), nCurTextHeight ) ); + UpdateViews( GetActiveView() ); + } + } +} + +sal_Bool ImpEditEngine::IsParagraphVisible( sal_uInt16 nParagraph ) +{ + ParaPortion* pPPortion = GetParaPortions().SaveGetObject( nParagraph ); + DBG_ASSERT( pPPortion, "IsParagraphVisible: Absatz existiert nicht!" ); + if ( pPPortion ) + return pPPortion->IsVisible(); + return sal_False; +} + +EditSelection ImpEditEngine::MoveParagraphs( Range aOldPositions, sal_uInt16 nNewPos, EditView* pCurView ) +{ + DBG_ASSERT( GetParaPortions().Count() != 0, "Keine Absaetze gefunden: MoveParagraphs" ); + if ( GetParaPortions().Count() == 0 ) + return EditSelection(); + aOldPositions.Justify(); + + EditSelection aSel( ImpMoveParagraphs( aOldPositions, nNewPos ) ); + + if ( nNewPos >= GetParaPortions().Count() ) + nNewPos = GetParaPortions().Count() - 1; + + // Dort, wo der Absatz eingefuegt wurde, muss richtig gepainted werden: + // Dort, wo der Absatz entfernt wurde, muss richtig gepainted werden: + // ( Und dazwischen entsprechend auch...) + if ( pCurView && ( GetUpdateMode() == sal_True ) ) + { + // in diesem Fall kann ich direkt neu malen, ohne die + // Portions zu Invalidieren. + sal_uInt16 nFirstPortion = Min( (sal_uInt16)aOldPositions.Min(), nNewPos ); + sal_uInt16 nLastPortion = Max( (sal_uInt16)aOldPositions.Max(), nNewPos ); + + ParaPortion* pUpperPortion = GetParaPortions().SaveGetObject( nFirstPortion ); + ParaPortion* pLowerPortion = GetParaPortions().SaveGetObject( nLastPortion ); + + aInvalidRec = Rectangle(); // leermachen + aInvalidRec.Left() = 0; + aInvalidRec.Right() = aPaperSize.Width(); + aInvalidRec.Top() = GetParaPortions().GetYOffset( pUpperPortion ); + aInvalidRec.Bottom() = GetParaPortions().GetYOffset( pLowerPortion ) + pLowerPortion->GetHeight(); + + UpdateViews( pCurView ); + } + else + { + // aber der oberen ungueltigen Position neu painten... + sal_uInt16 nFirstInvPara = Min( (sal_uInt16)aOldPositions.Min(), nNewPos ); + InvalidateFromParagraph( nFirstInvPara ); + } + return aSel; +} + +void ImpEditEngine::InvalidateFromParagraph( sal_uInt16 nFirstInvPara ) +{ + // Es werden nicht die folgenden Absaetze invalidiert, + // da ResetHeight() => Groessenanderung => alles folgende wird + // sowieso neu ausgegeben. + ParaPortion* pTmpPortion; + if ( nFirstInvPara != 0 ) + { + pTmpPortion = GetParaPortions().GetObject( nFirstInvPara-1 ); + pTmpPortion->MarkInvalid( pTmpPortion->GetNode()->Len(), 0 ); + } + else + { + pTmpPortion = GetParaPortions().GetObject( 0 ); + pTmpPortion->MarkSelectionInvalid( 0, pTmpPortion->GetNode()->Len() ); + } + pTmpPortion->ResetHeight(); +} + +IMPL_LINK_INLINE_START( ImpEditEngine, StatusTimerHdl, Timer *, EMPTYARG ) +{ + CallStatusHdl(); + return 0; +} +IMPL_LINK_INLINE_END( ImpEditEngine, StatusTimerHdl, Timer *, EMPTYARG ) + +void ImpEditEngine::CallStatusHdl() +{ + if ( aStatusHdlLink.IsSet() && aStatus.GetStatusWord() ) + { + // Der Status muss vor Call zurueckgesetzt werden, + // da im Hdl evtl. weitere Fags gesetzt werden... + EditStatus aTmpStatus( aStatus ); + aStatus.Clear(); + aStatusHdlLink.Call( &aTmpStatus ); + aStatusTimer.Stop(); // Falls von Hand gerufen... + } +} + +ContentNode* ImpEditEngine::GetPrevVisNode( ContentNode* pCurNode ) +{ + ParaPortion* pPortion = FindParaPortion( pCurNode ); + DBG_ASSERT( pPortion, "GetPrevVisibleNode: Keine passende Portion!" ); + pPortion = GetPrevVisPortion( pPortion ); + if ( pPortion ) + return pPortion->GetNode(); + return 0; +} + +ContentNode* ImpEditEngine::GetNextVisNode( ContentNode* pCurNode ) +{ + ParaPortion* pPortion = FindParaPortion( pCurNode ); + DBG_ASSERT( pPortion, "GetNextVisibleNode: Keine passende Portion!" ); + pPortion = GetNextVisPortion( pPortion ); + if ( pPortion ) + return pPortion->GetNode(); + return 0; +} + +ParaPortion* ImpEditEngine::GetPrevVisPortion( ParaPortion* pCurPortion ) +{ + sal_uInt16 nPara = GetParaPortions().GetPos( pCurPortion ); + DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion nicht gefunden: GetPrevVisPortion" ); + ParaPortion* pPortion = nPara ? GetParaPortions()[--nPara] : 0; + while ( pPortion && !pPortion->IsVisible() ) + pPortion = nPara ? GetParaPortions()[--nPara] : 0; + + return pPortion; +} + +ParaPortion* ImpEditEngine::GetNextVisPortion( ParaPortion* pCurPortion ) +{ + sal_uInt16 nPara = GetParaPortions().GetPos( pCurPortion ); + DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion nicht gefunden: GetPrevVisNode" ); + ParaPortion* pPortion = GetParaPortions().SaveGetObject( ++nPara ); + while ( pPortion && !pPortion->IsVisible() ) + pPortion = GetParaPortions().SaveGetObject( ++nPara ); + + return pPortion; +} + +EditPaM ImpEditEngine::InsertParagraph( sal_uInt16 nPara ) +{ + EditPaM aPaM; + if ( nPara != 0 ) + { + ContentNode* pNode = GetEditDoc().SaveGetObject( nPara-1 ); + if ( !pNode ) + pNode = GetEditDoc().SaveGetObject( GetEditDoc().Count() - 1 ); + DBG_ASSERT( pNode, "Kein einziger Absatz in InsertParagraph ?" ); + aPaM = EditPaM( pNode, pNode->Len() ); + } + else + { + ContentNode* pNode = GetEditDoc().SaveGetObject( 0 ); + aPaM = EditPaM( pNode, 0 ); + } + + return ImpInsertParaBreak( aPaM ); +} + +EditSelection* ImpEditEngine::SelectParagraph( sal_uInt16 nPara ) +{ + EditSelection* pSel = 0; + ContentNode* pNode = GetEditDoc().SaveGetObject( nPara ); + DBG_ASSERTWARNING( pNode, "Absatz existiert nicht: SelectParagraph" ); + if ( pNode ) + pSel = new EditSelection( EditPaM( pNode, 0 ), EditPaM( pNode, pNode->Len() ) ); + + return pSel; +} + +void ImpEditEngine::FormatAndUpdate( EditView* pCurView ) +{ + if ( bDowning ) + return ; + + if ( IsInUndo() ) + IdleFormatAndUpdate( pCurView ); + else + { + FormatDoc(); + UpdateViews( pCurView ); + } +} + +void ImpEditEngine::SetFlatMode( sal_Bool bFlat ) +{ + if ( bFlat != aStatus.UseCharAttribs() ) + return; + + if ( !bFlat ) + aStatus.TurnOnFlags( EE_CNTRL_USECHARATTRIBS ); + else + aStatus.TurnOffFlags( EE_CNTRL_USECHARATTRIBS ); + + aEditDoc.CreateDefFont( !bFlat ); + + FormatFullDoc(); + UpdateViews( (EditView*) 0); + if ( pActiveView ) + pActiveView->ShowCursor(); +} + +void ImpEditEngine::SetCharStretching( sal_uInt16 nX, sal_uInt16 nY ) +{ + if ( !IsVertical() ) + { + nStretchX = nX; + nStretchY = nY; + } + else + { + nStretchX = nY; + nStretchY = nX; + } + + if ( aStatus.DoStretch() ) + { + FormatFullDoc(); + UpdateViews( GetActiveView() ); + } +} + +void ImpEditEngine::DoStretchChars( sal_uInt16 nX, sal_uInt16 nY ) +{ + UndoActionStart( EDITUNDO_STRETCH ); + sal_uInt16 nParas = GetEditDoc().Count(); + for ( sal_uInt16 nPara = 0; nPara < nParas; nPara++ ) + { + ContentNode* pNode = GetEditDoc()[nPara]; + SfxItemSet aTmpSet( pNode->GetContentAttribs().GetItems() ); + + if ( nX != 100 ) + { + // Fontbreite + SvxCharScaleWidthItem* pNewWidth = (SvxCharScaleWidthItem*) pNode->GetContentAttribs().GetItem( EE_CHAR_FONTWIDTH ).Clone(); + sal_uInt32 nProp = pNewWidth->GetValue(); // sal_uInt32, kann temporaer gross werden + nProp *= nX; + nProp /= 100; + pNewWidth->SetValue( (sal_uInt16)nProp ); + aTmpSet.Put( *pNewWidth ); + delete pNewWidth; + + // Kerning: + const SvxKerningItem& rKerningItem = + (const SvxKerningItem&)pNode->GetContentAttribs().GetItem( EE_CHAR_KERNING ); + SvxKerningItem* pNewKerning = (SvxKerningItem*)rKerningItem.Clone(); + long nKerning = pNewKerning->GetValue(); + if ( nKerning > 0 ) + { + nKerning *= nX; + nKerning /= 100; + } + else if ( nKerning < 0 ) + { + // Bei Negativen Werten: + // Bei Stretching > 100 muessen die Werte kleiner werden und umgekehrt. + nKerning *= 100; + nKerning /= nX; + } + pNewKerning->SetValue( (short)nKerning ); + aTmpSet.Put( *pNewKerning); + delete pNewKerning; + } + else + aTmpSet.ClearItem( EE_CHAR_FONTWIDTH ); + + if ( nY != 100 ) + { + // Fonthoehe + for ( int nItem = 0; nItem < 3; nItem++ ) + { + USHORT nItemId = EE_CHAR_FONTHEIGHT; + if ( nItem == 1 ) + nItemId = EE_CHAR_FONTHEIGHT_CJK; + else if ( nItem == 2 ) + nItemId = EE_CHAR_FONTHEIGHT_CTL; + + const SvxFontHeightItem& rHeightItem = + (const SvxFontHeightItem&)pNode->GetContentAttribs().GetItem( nItemId ); + SvxFontHeightItem* pNewHeight = (SvxFontHeightItem*)rHeightItem.Clone(); + sal_uInt32 nHeight = pNewHeight->GetHeight(); + nHeight *= nY; + nHeight /= 100; + pNewHeight->SetHeightValue( nHeight ); + aTmpSet.Put( *pNewHeight ); + delete pNewHeight; + } + + // Absatzabstaende + const SvxULSpaceItem& rULSpaceItem = + (const SvxULSpaceItem&)pNode->GetContentAttribs().GetItem( EE_PARA_ULSPACE ); + SvxULSpaceItem* pNewUL = (SvxULSpaceItem*)rULSpaceItem.Clone(); + sal_uInt32 nUpper = pNewUL->GetUpper(); + nUpper *= nY; + nUpper /= 100; + pNewUL->SetUpper( (sal_uInt16)nUpper ); + sal_uInt32 nLower = pNewUL->GetLower(); + nLower *= nY; + nLower /= 100; + pNewUL->SetLower( (sal_uInt16)nLower ); + aTmpSet.Put( *pNewUL ); + delete pNewUL; + } + else + aTmpSet.ClearItem( EE_CHAR_FONTHEIGHT ); + + SetParaAttribs( nPara, aTmpSet ); + + // harte Attribute: + sal_uInt16 nLastEnd = 0; // damit nach entfernen und neu nicht nochmal + CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs(); + sal_uInt16 nAttribs = rAttribs.Count(); + for ( sal_uInt16 nAttr = 0; nAttr < nAttribs; nAttr++ ) + { + EditCharAttrib* pAttr = rAttribs[nAttr]; + if ( pAttr->GetStart() >= nLastEnd ) + { + sal_uInt16 nWhich = pAttr->Which(); + SfxPoolItem* pNew = 0; + if ( nWhich == EE_CHAR_FONTHEIGHT ) + { + SvxFontHeightItem* pNewHeight = (SvxFontHeightItem*)pAttr->GetItem()->Clone(); + sal_uInt32 nHeight = pNewHeight->GetHeight(); + nHeight *= nY; + nHeight /= 100; + pNewHeight->SetHeightValue( nHeight ); + pNew = pNewHeight; + } + else if ( nWhich == EE_CHAR_FONTWIDTH ) + { + SvxCharScaleWidthItem* pNewWidth = (SvxCharScaleWidthItem*)pAttr->GetItem()->Clone(); + sal_uInt32 nProp = pNewWidth->GetValue(); + nProp *= nX; + nProp /= 100; + pNewWidth->SetValue( (sal_uInt16)nProp ); + pNew = pNewWidth; + } + else if ( nWhich == EE_CHAR_KERNING ) + { + SvxKerningItem* pNewKerning = (SvxKerningItem*)pAttr->GetItem()->Clone(); + long nKerning = pNewKerning->GetValue(); + if ( nKerning > 0 ) + { + nKerning *= nX; + nKerning /= 100; + } + else if ( nKerning < 0 ) + { + // Bei Negativen Werten: + // Bei Stretching > 100 muessen die Werte kleiner werden und umgekehrt. + nKerning *= 100; + nKerning /= nX; + } + pNewKerning->SetValue( (short)nKerning ); + pNew = pNewKerning; + } + if ( pNew ) + { + SfxItemSet _aTmpSet( GetEmptyItemSet() ); + _aTmpSet.Put( *pNew ); + SetAttribs( EditSelection( EditPaM( pNode, pAttr->GetStart() ), + EditPaM( pNode, pAttr->GetEnd() ) ), _aTmpSet ); + + nLastEnd = pAttr->GetEnd(); + delete pNew; + } + } + } + } + UndoActionEnd( EDITUNDO_STRETCH ); +} + +const SvxNumberFormat* ImpEditEngine::GetNumberFormat( const ContentNode *pNode ) const +{ + const SvxNumberFormat *pRes = 0; + + if (pNode) + { + // get index of paragraph + USHORT nPara = GetEditDoc().GetPos( const_cast< ContentNode * >(pNode) ); + DBG_ASSERT( nPara < USHRT_MAX, "node not found in array" ); + if (nPara < USHRT_MAX) + { + // the called function may be overloaded by an OutlinerEditEng object to provide + // access to the SvxNumberFormat of the Outliner. + // The EditEngine implementation will just return 0. + pRes = pEditEngine->GetNumberFormat( nPara ); + } + } + + return pRes; +} + +sal_Int32 ImpEditEngine::GetSpaceBeforeAndMinLabelWidth( + const ContentNode *pNode, + sal_Int32 *pnSpaceBefore, sal_Int32 *pnMinLabelWidth ) const +{ + // nSpaceBefore matches the ODF attribut text:space-before + // nMinLabelWidth matches the ODF attribut text:min-label-width + + const SvxNumberFormat *pNumFmt = GetNumberFormat( pNode ); + + // if no number format was found we have no Outliner or the numbering level + // within the Outliner is -1 which means no number format should be applied. + // Thus the default values to be returned are 0. + sal_Int32 nSpaceBefore = 0; + sal_Int32 nMinLabelWidth = 0; + + if (pNumFmt) + { + nMinLabelWidth = -pNumFmt->GetFirstLineOffset(); + nSpaceBefore = pNumFmt->GetAbsLSpace() - nMinLabelWidth; + DBG_ASSERT( nMinLabelWidth >= 0, "ImpEditEngine::GetSpaceBeforeAndMinLabelWidth: min-label-width < 0 encountered" ); + } + if (pnSpaceBefore) + *pnSpaceBefore = nSpaceBefore; + if (pnMinLabelWidth) + *pnMinLabelWidth = nMinLabelWidth; + + return nSpaceBefore + nMinLabelWidth; +} + +const SvxLRSpaceItem& ImpEditEngine::GetLRSpaceItem( ContentNode* pNode ) +{ + return (const SvxLRSpaceItem&)pNode->GetContentAttribs().GetItem( aStatus.IsOutliner() ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE ); +} + +// Either sets the digit mode at the output device or +// modifies the passed string according to the text numeral setting: +void ImpEditEngine::ImplInitDigitMode( OutputDevice* pOutDev, String* pString, xub_StrLen nStt, xub_StrLen nLen, LanguageType eCurLang ) +{ + // #114278# Also setting up digit language from Svt options + // (cannot reliably inherit the outdev's setting) + if( !pCTLOptions ) + pCTLOptions = new SvtCTLOptions; + + LanguageType eLang = eCurLang; + const SvtCTLOptions::TextNumerals nCTLTextNumerals = pCTLOptions->GetCTLTextNumerals(); + + if ( SvtCTLOptions::NUMERALS_HINDI == nCTLTextNumerals ) + eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; + else if ( SvtCTLOptions::NUMERALS_ARABIC == nCTLTextNumerals ) + eLang = LANGUAGE_ENGLISH; + else if ( SvtCTLOptions::NUMERALS_SYSTEM == nCTLTextNumerals ) + eLang = (LanguageType) Application::GetSettings().GetLanguage(); + + if(pOutDev) + { + pOutDev->SetDigitLanguage( eLang ); + } + else if (pString) + { + // see sallayout.cxx in vcl + int nOffset; + switch( eLang & LANGUAGE_MASK_PRIMARY ) + { + default: + nOffset = 0; + break; + case LANGUAGE_ARABIC_SAUDI_ARABIA & LANGUAGE_MASK_PRIMARY: + nOffset = 0x0660 - '0'; // arabic-indic digits + break; + case LANGUAGE_URDU & LANGUAGE_MASK_PRIMARY: + case LANGUAGE_PUNJABI & LANGUAGE_MASK_PRIMARY: //??? + case LANGUAGE_SINDHI & LANGUAGE_MASK_PRIMARY: + nOffset = 0x06F0 - '0'; // eastern arabic-indic digits + break; + } + if (nOffset) + { + const xub_StrLen nEnd = nStt + nLen; + for( xub_StrLen nIdx = nStt; nIdx < nEnd; ++nIdx ) + { + sal_Unicode nChar = pString->GetChar( nIdx ); + if( (nChar < '0') || ('9' < nChar) ) + continue; + nChar = (sal_Unicode)(nChar + nOffset); + pString->SetChar( nIdx, nChar ); + } + } + } +} + +void ImpEditEngine::ImplInitLayoutMode( OutputDevice* pOutDev, USHORT nPara, USHORT nIndex ) +{ + BOOL bCTL = FALSE; + BYTE bR2L = FALSE; + if ( nIndex == 0xFFFF ) + { + bCTL = HasScriptType( nPara, i18n::ScriptType::COMPLEX ); + bR2L = IsRightToLeft( nPara ); + } + else + { + ContentNode* pNode = GetEditDoc().SaveGetObject( nPara ); + short nScriptType = GetScriptType( EditPaM( pNode, nIndex+1 ) ); + bCTL = nScriptType == i18n::ScriptType::COMPLEX; + bR2L = GetRightToLeft( nPara, nIndex + 1); // this change was discussed in issue 37190 + // it also works for issue 55927 + } + + ULONG nLayoutMode = pOutDev->GetLayoutMode(); + + // We always use the left postion for DrawText() + nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL); + + if ( !bCTL && !bR2L) + { + // No CTL/Bidi checking neccessary + nLayoutMode |= ( TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG ); + } + else + { + // CTL/Bidi checking neccessary + // Don't use BIDI_STRONG, VCL must do some checks. + nLayoutMode &= ~( TEXT_LAYOUT_COMPLEX_DISABLED | TEXT_LAYOUT_BIDI_STRONG ); + + if ( bR2L ) + nLayoutMode |= TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_TEXTORIGIN_LEFT; + } + + pOutDev->SetLayoutMode( nLayoutMode ); + + // #114278# Also setting up digit language from Svt options + // (cannot reliably inherit the outdev's setting) + LanguageType eLang; + + if( !pCTLOptions ) + pCTLOptions = new SvtCTLOptions; + + if ( SvtCTLOptions::NUMERALS_HINDI == pCTLOptions->GetCTLTextNumerals() ) + eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; + else if ( SvtCTLOptions::NUMERALS_ARABIC == pCTLOptions->GetCTLTextNumerals() ) + eLang = LANGUAGE_ENGLISH; + else + eLang = (LanguageType) Application::GetSettings().GetLanguage(); + + pOutDev->SetDigitLanguage( eLang ); +} + +Reference < i18n::XBreakIterator > ImpEditEngine::ImplGetBreakIterator() const +{ + if ( !xBI.is() ) + { + Reference< lang::XMultiServiceFactory > xMSF( ::comphelper::getProcessServiceFactory() ); + xBI.set( xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.BreakIterator" ) ), UNO_QUERY ); + } + return xBI; +} + +Reference < i18n::XExtendedInputSequenceChecker > ImpEditEngine::ImplGetInputSequenceChecker() const +{ + if ( !xISC.is() ) + { + Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + Reference < XInterface > xI = xMSF->createInstance( OUString::createFromAscii( "com.sun.star.i18n.InputSequenceChecker" ) ); + if ( xI.is() ) + { + Any x = xI->queryInterface( ::getCppuType((const Reference< i18n::XExtendedInputSequenceChecker >*)0) ); + x >>= xISC; + } + } + return xISC; +} + +Color ImpEditEngine::GetAutoColor() const +{ + Color aColor = const_cast<ImpEditEngine*>(this)->GetColorConfig().GetColorValue( svtools::FONTCOLOR ).nColor; + + if ( GetBackgroundColor() != COL_AUTO ) + { + if ( GetBackgroundColor().IsDark() && aColor.IsDark() ) + aColor = COL_WHITE; + else if ( GetBackgroundColor().IsBright() && aColor.IsBright() ) + aColor = COL_BLACK; + } + + return aColor; +} + + +BOOL ImpEditEngine::ImplCalcAsianCompression( ContentNode* pNode, TextPortion* pTextPortion, USHORT nStartPos, sal_Int32* pDXArray, USHORT n100thPercentFromMax, BOOL bManipulateDXArray ) +{ + DBG_ASSERT( GetAsianCompressionMode(), "ImplCalcAsianCompression - Why?" ); + DBG_ASSERT( pTextPortion->GetLen(), "ImplCalcAsianCompression - Empty Portion?" ); + + // Percent is 1/100 Percent... + + if ( n100thPercentFromMax == 10000 ) + pTextPortion->SetExtraInfos( NULL ); + + BOOL bCompressed = FALSE; + + if ( GetScriptType( EditPaM( pNode, nStartPos+1 ) ) == i18n::ScriptType::ASIAN ) + { + long nNewPortionWidth = pTextPortion->GetSize().Width(); + USHORT nPortionLen = pTextPortion->GetLen(); + for ( USHORT n = 0; n < nPortionLen; n++ ) + { + BYTE nType = GetCharTypeForCompression( pNode->GetChar( n+nStartPos ) ); + + BOOL bCompressPunctuation = ( nType == CHAR_PUNCTUATIONLEFT ) || ( nType == CHAR_PUNCTUATIONRIGHT ); + BOOL bCompressKana = ( nType == CHAR_KANA ) && ( GetAsianCompressionMode() == text::CharacterCompressionType::PUNCTUATION_AND_KANA ); + + // create Extra infos only if needed... + if ( bCompressPunctuation || bCompressKana ) + { + if ( !pTextPortion->GetExtraInfos() ) + { + ExtraPortionInfo* pExtraInfos = new ExtraPortionInfo; + pTextPortion->SetExtraInfos( pExtraInfos ); + pExtraInfos->nOrgWidth = pTextPortion->GetSize().Width(); + pExtraInfos->nAsianCompressionTypes = CHAR_NORMAL; + } + pTextPortion->GetExtraInfos()->nMaxCompression100thPercent = n100thPercentFromMax; + pTextPortion->GetExtraInfos()->nAsianCompressionTypes |= nType; +// pTextPortion->GetExtraInfos()->nCompressedChars++; + + long nOldCharWidth; + if ( (n+1) < nPortionLen ) + { + nOldCharWidth = pDXArray[n]; + } + else + { + if ( bManipulateDXArray ) + nOldCharWidth = nNewPortionWidth - pTextPortion->GetExtraInfos()->nPortionOffsetX; + else + nOldCharWidth = pTextPortion->GetExtraInfos()->nOrgWidth; + } + nOldCharWidth -= ( n ? pDXArray[n-1] : 0 ); + + long nCompress = 0; + + if ( bCompressPunctuation ) + { + // pTextPortion->GetExtraInfos()->nComressionWeight += 5; + nCompress = nOldCharWidth / 2; + } + else // Kana + { + // pTextPortion->GetExtraInfos()->nComressionWeight += 1; + nCompress = nOldCharWidth / 10; + } + + if ( n100thPercentFromMax != 10000 ) + { + nCompress *= n100thPercentFromMax; + nCompress /= 10000; + } + + if ( nCompress ) + { + bCompressed = TRUE; + nNewPortionWidth -= nCompress; + pTextPortion->GetExtraInfos()->bCompressed = TRUE; + + + // Special handling for rightpunctuation: For the 'compression' we must + // start th eoutput before the normal char position.... + if ( bManipulateDXArray && ( pTextPortion->GetLen() > 1 ) ) + { + if ( !pTextPortion->GetExtraInfos()->pOrgDXArray ) + pTextPortion->GetExtraInfos()->SaveOrgDXArray( pDXArray, pTextPortion->GetLen()-1 ); + + if ( nType == CHAR_PUNCTUATIONRIGHT ) + { + // If it's the first char, I must handle it in Paint()... + if ( n ) + { + // -1: No entry for the last character + for ( USHORT i = n-1; i < (nPortionLen-1); i++ ) + pDXArray[i] -= nCompress; + } + else + { + pTextPortion->GetExtraInfos()->bFirstCharIsRightPunktuation = TRUE; + pTextPortion->GetExtraInfos()->nPortionOffsetX = -nCompress; + } + } + else + { + // -1: No entry for the last character + for ( USHORT i = n; i < (nPortionLen-1); i++ ) + pDXArray[i] -= nCompress; + } + } + } + } + } + + if ( bCompressed && ( n100thPercentFromMax == 10000 ) ) + pTextPortion->GetExtraInfos()->nWidthFullCompression = nNewPortionWidth; + + pTextPortion->GetSize().Width() = nNewPortionWidth; + + if ( pTextPortion->GetExtraInfos() && ( n100thPercentFromMax != 10000 ) ) + { + // Maybe rounding errors in nNewPortionWidth, assure that width not bigger than expected + long nShrink = pTextPortion->GetExtraInfos()->nOrgWidth - pTextPortion->GetExtraInfos()->nWidthFullCompression; + nShrink *= n100thPercentFromMax; + nShrink /= 10000; + long nNewWidth = pTextPortion->GetExtraInfos()->nOrgWidth - nShrink; + if ( nNewWidth < pTextPortion->GetSize().Width() ) + pTextPortion->GetSize().Width() = nNewWidth; + } + } + return bCompressed; +} + + +void ImpEditEngine::ImplExpandCompressedPortions( EditLine* pLine, ParaPortion* pParaPortion, long nRemainingWidth ) +{ + BOOL bFoundCompressedPortion = FALSE; + long nCompressed = 0; +// long nCompressWeight = 0; + TextPortionList aCompressedPortions; + + USHORT nPortion = pLine->GetEndPortion(); + TextPortion* pTP = pParaPortion->GetTextPortions()[ nPortion ]; + while ( pTP && ( pTP->GetKind() == PORTIONKIND_TEXT ) ) + { + if ( pTP->GetExtraInfos() && pTP->GetExtraInfos()->bCompressed ) + { + bFoundCompressedPortion = TRUE; + nCompressed += pTP->GetExtraInfos()->nOrgWidth - pTP->GetSize().Width(); + aCompressedPortions.Insert( pTP, aCompressedPortions.Count() ); + } + pTP = ( nPortion > pLine->GetStartPortion() ) ? pParaPortion->GetTextPortions()[ --nPortion ] : NULL; + } + + if ( bFoundCompressedPortion ) + { + long nCompressPercent = 0; + if ( nCompressed > nRemainingWidth ) + { + nCompressPercent = nCompressed - nRemainingWidth; + DBG_ASSERT( nCompressPercent < 200000, "ImplExpandCompressedPortions - Overflow!" ); + nCompressPercent *= 10000; + nCompressPercent /= nCompressed; + } + + for ( USHORT n = 0; n < aCompressedPortions.Count(); n++ ) + { + pTP = aCompressedPortions[n]; + pTP->GetExtraInfos()->bCompressed = FALSE; + pTP->GetSize().Width() = pTP->GetExtraInfos()->nOrgWidth; + if ( nCompressPercent ) + { + USHORT nTxtPortion = pParaPortion->GetTextPortions().GetPos( pTP ); + USHORT nTxtPortionStart = pParaPortion->GetTextPortions().GetStartPos( nTxtPortion ); + DBG_ASSERT( nTxtPortionStart >= pLine->GetStart(), "Portion doesn't belong to the line!!!" ); + sal_Int32* pDXArray = const_cast< sal_Int32* >( pLine->GetCharPosArray().GetData()+( nTxtPortionStart-pLine->GetStart() ) ); + if ( pTP->GetExtraInfos()->pOrgDXArray ) + memcpy( pDXArray, pTP->GetExtraInfos()->pOrgDXArray, (pTP->GetLen()-1)*sizeof(sal_Int32) ); + ImplCalcAsianCompression( pParaPortion->GetNode(), pTP, nTxtPortionStart, pDXArray, (USHORT)nCompressPercent, TRUE ); + } + } + } + + aCompressedPortions.Remove( 0, aCompressedPortions.Count() ); +} + +// redesigned to work with TextMarkingVector +void ImpEditEngine::ImplFillTextMarkingVector(const lang::Locale& rLocale, EEngineData::TextMarkingVector& rTextMarkingVector, const String& rTxt, const USHORT nIdx, const USHORT nLen) const +{ + // determine relevant logical text elements for the just-rendered + // string of characters. + Reference< i18n::XBreakIterator > _xBI(ImplGetBreakIterator()); + + if(_xBI.is()) + { + sal_Int32 nDone; + sal_Int32 nNextCellBreak(_xBI->nextCharacters(rTxt, nIdx, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); + i18n::Boundary nNextWordBoundary(_xBI->getWordBoundary(rTxt, nIdx, rLocale, i18n::WordType::ANY_WORD, sal_True)); + sal_Int32 nNextSentenceBreak(_xBI->endOfSentence(rTxt, nIdx, rLocale)); + + const sal_Int32 nEndPos(nIdx + nLen); + sal_Int32 i; + + for(i = nIdx; i < nEndPos; i++) + { + // create the entries for the respective break positions + if(i == nNextCellBreak) + { + rTextMarkingVector.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfCaracter, i - nIdx)); + nNextCellBreak = _xBI->nextCharacters(rTxt, i, rLocale, i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); + } + if(i == nNextWordBoundary.endPos) + { + rTextMarkingVector.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfWord, i - nIdx)); + nNextWordBoundary = _xBI->getWordBoundary(rTxt, i + 1, rLocale, i18n::WordType::ANY_WORD, sal_True); + } + if(i == nNextSentenceBreak) + { + rTextMarkingVector.push_back(EEngineData::TextMarkingClass(EEngineData::EndOfSentence, i - nIdx)); + nNextSentenceBreak = _xBI->endOfSentence(rTxt, i + 1, rLocale); + } + } + } +} + +// eof diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx new file mode 100644 index 000000000000..8f3f03c5394d --- /dev/null +++ b/editeng/source/editeng/impedit4.cxx @@ -0,0 +1,2958 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: impedit4.cxx,v $ + * $Revision: 1.78.54.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <svl/srchitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/tstpitem.hxx> + +#include <eertfpar.hxx> +#include <editeng/editeng.hxx> +#include <impedit.hxx> +#include <editeng/editview.hxx> +#include <eehtml.hxx> +#include <editobj2.hxx> +#include <i18npool/lang.h> + +#include "editxml.hxx" + +#include <editeng/akrnitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/emphitem.hxx> +#include <textconv.hxx> +#include <rtl/tencinfo.h> +#include <svtools/rtfout.hxx> +#include <edtspell.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <com/sun/star/linguistic2/XThesaurus.hpp> +#include <com/sun/star/linguistic2/XMeaning.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <unotools/transliterationwrapper.hxx> +#include <unotools/textsearch.hxx> +#include <comphelper/processfactory.hxx> +#include <vcl/help.hxx> +#include <svtools/rtfkeywd.hxx> +#include <editeng/edtdlg.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::linguistic2; + +void SwapUSHORTs( sal_uInt16& rX, sal_uInt16& rY ) +{ + sal_uInt16 n = rX; + rX = rY; + rY = n; +} + +EditPaM ImpEditEngine::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ + sal_Bool _bUpdate = GetUpdateMode(); + SetUpdateMode( sal_False ); + EditPaM aPaM; + if ( eFormat == EE_FORMAT_TEXT ) + aPaM = ReadText( rInput, aSel ); + else if ( eFormat == EE_FORMAT_RTF ) + aPaM = ReadRTF( rInput, aSel ); + else if ( eFormat == EE_FORMAT_XML ) + aPaM = ReadXML( rInput, aSel ); + else if ( eFormat == EE_FORMAT_HTML ) + aPaM = ReadHTML( rInput, rBaseURL, aSel, pHTTPHeaderAttrs ); + else if ( eFormat == EE_FORMAT_BIN) + aPaM = ReadBin( rInput, aSel ); + else + { + DBG_ERROR( "Read: Unbekanntes Format" ); + } + + FormatFullDoc(); // reicht vielleicht auch ein einfaches Format? + SetUpdateMode( _bUpdate ); + + return aPaM; +} + +EditPaM ImpEditEngine::ReadText( SvStream& rInput, EditSelection aSel ) +{ + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + EditPaM aPaM = aSel.Max(); + + XubString aTmpStr, aStr; + sal_Bool bDone = rInput.ReadByteStringLine( aTmpStr ); + while ( bDone ) + { + aTmpStr.Erase( MAXCHARSINPARA ); + aPaM = ImpInsertText( EditSelection( aPaM, aPaM ), aTmpStr ); + aPaM = ImpInsertParaBreak( aPaM ); + bDone = rInput.ReadByteStringLine( aTmpStr ); + } + return aPaM; +} + +EditPaM ImpEditEngine::ReadXML( SvStream& rInput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + + ESelection aESel = CreateESel( aSel ); + + ::SvxReadXML( *GetEditEnginePtr(), rInput, aESel ); + + return aSel.Max(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadRTF( SvStream& rInput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + +#if defined (EDITDEBUG) && !defined( UNX ) + SvFileStream aRTFOut( String( RTL_CONSTASCII_USTRINGPARAM ( "d:\\rtf_in.rtf" ) ), STREAM_WRITE ); + aRTFOut << rInput; + aRTFOut.Close(); + rInput.Seek( 0 ); +#endif + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + +// sal_Bool bCharsBeforeInsertPos = ( aSel.Min().GetIndex() ) ? sal_True : sal_False; +// sal_Bool bCharsBehindInsertPos = ( aSel.Min().GetIndex() < aSel.Min().GetNode()->Len() ) ? sal_True : sal_False; + + // Der SvRTF-Parser erwartet, dass das Which-Mapping am uebergebenen Pool, + // nicht an einem Secondary haengt. + SfxItemPool* pPool = &aEditDoc.GetItemPool(); + while ( pPool->GetSecondaryPool() && !pPool->GetName().EqualsAscii( "EditEngineItemPool" ) ) + { + pPool = pPool->GetSecondaryPool(); + + } + DBG_ASSERT( pPool && pPool->GetName().EqualsAscii( "EditEngineItemPool" ), "ReadRTF: Kein EditEnginePool!" ); + + EditRTFParserRef xPrsr = new EditRTFParser( rInput, aSel, *pPool, this ); + SvParserState eState = xPrsr->CallParser(); + if ( ( eState != SVPAR_ACCEPTED ) && ( !rInput.GetError() ) ) + { + rInput.SetError( EE_READWRITE_WRONGFORMAT ); + return aSel.Min(); + } + return xPrsr->GetCurPaM(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadHTML( SvStream& rInput, const String& rBaseURL, EditSelection aSel, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ +#ifndef SVX_LIGHT + + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + +// sal_Bool bCharsBeforeInsertPos = ( aSel.Min().GetIndex() ) ? sal_True : sal_False; +// sal_Bool bCharsBehindInsertPos = ( aSel.Min().GetIndex() < aSel.Min().GetNode()->Len() ) ? sal_True : sal_False; + + EditHTMLParserRef xPrsr = new EditHTMLParser( rInput, rBaseURL, pHTTPHeaderAttrs ); + SvParserState eState = xPrsr->CallParser( this, aSel.Max() ); + if ( ( eState != SVPAR_ACCEPTED ) && ( !rInput.GetError() ) ) + { + rInput.SetError( EE_READWRITE_WRONGFORMAT ); + return aSel.Min(); + } + return xPrsr->GetCurSelection().Max(); +#else + return EditPaM(); +#endif +} + +EditPaM ImpEditEngine::ReadBin( SvStream& rInput, EditSelection aSel ) +{ + // Einfach ein temporaeres TextObject missbrauchen... + EditTextObject* pObj = EditTextObject::Create( rInput, NULL ); + + EditPaM aLastPaM = aSel.Max(); + if ( pObj ) + aLastPaM = InsertText( *pObj, aSel ).Max(); + + delete pObj; + return aLastPaM; +} + +#ifndef SVX_LIGHT +void ImpEditEngine::Write( SvStream& rOutput, EETextFormat eFormat, EditSelection aSel ) +{ + if ( !rOutput.IsWritable() ) + rOutput.SetError( SVSTREAM_WRITE_ERROR ); + + if ( !rOutput.GetError() ) + { + if ( eFormat == EE_FORMAT_TEXT ) + WriteText( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_RTF ) + WriteRTF( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_XML ) + WriteXML( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_HTML ) + WriteHTML( rOutput, aSel ); + else if ( eFormat == EE_FORMAT_BIN) + WriteBin( rOutput, aSel ); + else + { + DBG_ERROR( "Write: Unbekanntes Format" ); + } + } +} +#endif + +sal_uInt32 ImpEditEngine::WriteText( SvStream& rOutput, EditSelection aSel ) +{ + sal_uInt16 nStartNode, nEndNode; + sal_Bool bRange = aSel.HasRange(); + if ( bRange ) + { + aSel.Adjust( aEditDoc ); + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + } + else + { + nStartNode = 0; + nEndNode = aEditDoc.Count()-1; + } + + // ueber die Absaetze iterieren... + for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + if ( bRange ) + { + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + } + XubString aTmpStr = aEditDoc.GetParaAsString( pNode, nStartPos, nEndPos ); + rOutput.WriteByteStringLine( aTmpStr ); + } + + return rOutput.GetError(); +} + +sal_Bool ImpEditEngine::WriteItemListAsRTF( ItemList& rLst, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ) +{ + const SfxPoolItem* pAttrItem = rLst.First(); + while ( pAttrItem ) + { + WriteItemAsRTF( *pAttrItem, rOutput, nPara, nPos,rFontTable, rColorList ); + pAttrItem = rLst.Next(); + } + return ( rLst.Count() ? sal_True : sal_False ); +} + +void lcl_FindValidAttribs( ItemList& rLst, ContentNode* pNode, sal_uInt16 nIndex, USHORT nScriptType ) +{ + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr && ( pAttr->GetStart() <= nIndex ) ) + { + // Start wird in While ueberprueft... + if ( pAttr->GetEnd() > nIndex ) + { + if ( IsScriptItemValid( pAttr->GetItem()->Which(), nScriptType ) ) + rLst.Insert( pAttr->GetItem(), LIST_APPEND ); + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } +} + +sal_uInt32 ImpEditEngine::WriteBin( SvStream& rOutput, EditSelection aSel, BOOL bStoreUnicodeStrings ) const +{ + BinTextObject* pObj = (BinTextObject*)CreateBinTextObject( aSel, NULL ); + pObj->StoreUnicodeStrings( bStoreUnicodeStrings ); + pObj->Store( rOutput ); + delete pObj; + return 0; +} + +#ifndef SVX_LIGHT +sal_uInt32 ImpEditEngine::WriteXML( SvStream& rOutput, EditSelection aSel ) +{ + ESelection aESel = CreateESel( aSel ); + + SvxWriteXML( *GetEditEnginePtr(), rOutput, aESel ); + + return 0; +} +#endif + +static sal_uInt16 getStylePos( const SfxStyles& rStyles, SfxStyleSheet* pSheet ) +{ + sal_uInt16 nNumber = 0; + SfxStyles::const_iterator iter( rStyles.begin() ); + while( iter != rStyles.end() ) + { + if( (*iter++).get() == pSheet ) + return nNumber; + ++nNumber; + } + return 0; +} + +sal_uInt32 ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel ) +{ +#ifndef SVX_LIGHT + DBG_ASSERT( GetUpdateMode(), "WriteRTF bei UpdateMode = sal_False!" ); + CheckIdleFormatter(); + if ( !IsFormatted() ) + FormatDoc(); + + sal_uInt16 nStartNode, nEndNode; + aSel.Adjust( aEditDoc ); + + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + // RTF-Vorspann... + rOutput << '{' ; + + rOutput << OOO_STRING_SVTOOLS_RTF_RTF; + + rOutput << OOO_STRING_SVTOOLS_RTF_ANSI; + rtl_TextEncoding eDestEnc = RTL_TEXTENCODING_MS_1252; + + // Fonttabelle erzeugen und rausschreiben... + SvxFontTable aFontTable; + // DefaultFont muss ganz vorne stehen, damit DEF-Font im RTF + aFontTable.Insert( 0, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO ) ) ); + aFontTable.Insert( 1, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CJK ) ) ); + aFontTable.Insert( 2, new SvxFontItem( (const SvxFontItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_FONTINFO_CTL ) ) ); + for ( USHORT nScriptType = 0; nScriptType < 3; nScriptType++ ) + { + USHORT nWhich = EE_CHAR_FONTINFO; + if ( nScriptType == 1 ) + nWhich = EE_CHAR_FONTINFO_CJK; + else if ( nScriptType == 2 ) + nWhich = EE_CHAR_FONTINFO_CTL; + + sal_uInt16 i = 0; + SvxFontItem* pFontItem = (SvxFontItem*)aEditDoc.GetItemPool().GetItem( nWhich, i ); + while ( pFontItem ) + { + bool bAlreadyExist = false; + ULONG nTestMax = nScriptType ? aFontTable.Count() : 1; + for ( ULONG nTest = 0; !bAlreadyExist && ( nTest < nTestMax ); nTest++ ) + { + bAlreadyExist = *aFontTable.Get( nTest ) == *pFontItem; + } + + if ( !bAlreadyExist ) + aFontTable.Insert( aFontTable.Count(), new SvxFontItem( *pFontItem ) ); + + pFontItem = (SvxFontItem*)aEditDoc.GetItemPool().GetItem( nWhich, ++i ); + } + } + + rOutput << endl << '{' << OOO_STRING_SVTOOLS_RTF_FONTTBL; + sal_uInt16 j; + for ( j = 0; j < aFontTable.Count(); j++ ) + { + SvxFontItem* pFontItem = aFontTable.Get( j ); + rOutput << '{'; + rOutput << OOO_STRING_SVTOOLS_RTF_F; + rOutput.WriteNumber( j ); + switch ( pFontItem->GetFamily() ) + { + case FAMILY_DONTKNOW: rOutput << OOO_STRING_SVTOOLS_RTF_FNIL; + break; + case FAMILY_DECORATIVE: rOutput << OOO_STRING_SVTOOLS_RTF_FDECOR; + break; + case FAMILY_MODERN: rOutput << OOO_STRING_SVTOOLS_RTF_FMODERN; + break; + case FAMILY_ROMAN: rOutput << OOO_STRING_SVTOOLS_RTF_FROMAN; + break; + case FAMILY_SCRIPT: rOutput << OOO_STRING_SVTOOLS_RTF_FSCRIPT; + break; + case FAMILY_SWISS: rOutput << OOO_STRING_SVTOOLS_RTF_FSWISS; + break; + default: + break; + } + rOutput << OOO_STRING_SVTOOLS_RTF_FPRQ; + sal_uInt16 nVal = 0; + switch( pFontItem->GetPitch() ) + { + case PITCH_FIXED: nVal = 1; break; + case PITCH_VARIABLE: nVal = 2; break; + default: + break; + } + rOutput.WriteNumber( nVal ); + + CharSet eChrSet = pFontItem->GetCharSet(); + DBG_ASSERT( eChrSet != 9, "SystemCharSet?!" ); + if( RTL_TEXTENCODING_DONTKNOW == eChrSet ) + eChrSet = gsl_getSystemTextEncoding(); + rOutput << OOO_STRING_SVTOOLS_RTF_FCHARSET; + rOutput.WriteNumber( rtl_getBestWindowsCharsetFromTextEncoding( eChrSet ) ); + + rOutput << ' '; + RTFOutFuncs::Out_String( rOutput, pFontItem->GetFamilyName(), eDestEnc ); + rOutput << ";}"; + } + rOutput << '}'; + rOutput << endl; + + // ColorList rausschreiben... + SvxColorList aColorList; + sal_uInt16 i = 0; + SvxColorItem* pColorItem = (SvxColorItem*)aEditDoc.GetItemPool().GetItem( EE_CHAR_COLOR, i ); + while ( pColorItem ) + { + USHORT nPos = i; + if ( pColorItem->GetValue() == COL_AUTO ) + nPos = 0; + aColorList.Insert( new SvxColorItem( *pColorItem ), nPos ); + pColorItem = (SvxColorItem*)aEditDoc.GetItemPool().GetItem( EE_CHAR_COLOR, ++i ); + } + aColorList.Insert( new SvxColorItem( (const SvxColorItem&)aEditDoc.GetItemPool().GetDefaultItem( EE_CHAR_COLOR) ), (sal_uInt32)i ); + + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_COLORTBL; + for ( j = 0; j < aColorList.Count(); j++ ) + { + pColorItem = aColorList.GetObject( j ); + if ( !j || ( pColorItem->GetValue() != COL_AUTO ) ) + { + rOutput << OOO_STRING_SVTOOLS_RTF_RED; + rOutput.WriteNumber( pColorItem->GetValue().GetRed() ); + rOutput << OOO_STRING_SVTOOLS_RTF_GREEN; + rOutput.WriteNumber( pColorItem->GetValue().GetGreen() ); + rOutput << OOO_STRING_SVTOOLS_RTF_BLUE; + rOutput.WriteNumber( pColorItem->GetValue().GetBlue() ); + } + rOutput << ';'; + } + rOutput << '}'; + rOutput << endl; + + // StyleSheets... + if ( GetStyleSheetPool() ) + { + sal_uInt16 nStyles = (sal_uInt16)GetStyleSheetPool()->GetStyles().size(); + if ( nStyles ) + { + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_STYLESHEET; + + for ( sal_uInt16 nStyle = 0; nStyle < nStyles; nStyle++ ) + { + + SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->GetStyles()[ nStyle ].get(); + + rOutput << endl << '{' << OOO_STRING_SVTOOLS_RTF_S; + sal_uInt16 nNumber = (sal_uInt16) (nStyle + 1); + rOutput.WriteNumber( nNumber ); + + // Attribute, auch aus Parent! + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { + if ( pStyle->GetItemSet().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pStyle->GetItemSet().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList ); + } + } + + // Parent...(nur wenn noetig) + if ( pStyle->GetParent().Len() && ( pStyle->GetParent() != pStyle->GetName() ) ) + { + SfxStyleSheet* pParent = (SfxStyleSheet*)GetStyleSheetPool()->Find( pStyle->GetParent(), pStyle->GetFamily() ); + DBG_ASSERT( pParent, "Parent nicht gefunden!" ); + rOutput << OOO_STRING_SVTOOLS_RTF_SBASEDON; + nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pParent ) + 1; + rOutput.WriteNumber( nNumber ); + } + + // Folgevorlage...(immer) + SfxStyleSheet* pNext = pStyle; + if ( pStyle->GetFollow().Len() && ( pStyle->GetFollow() != pStyle->GetName() ) ) + pNext = (SfxStyleSheet*)GetStyleSheetPool()->Find( pStyle->GetFollow(), pStyle->GetFamily() ); + + DBG_ASSERT( pNext, "Naechsten nicht gefunden!" ); + rOutput << OOO_STRING_SVTOOLS_RTF_SNEXT; + nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pNext ) + 1; + rOutput.WriteNumber( nNumber ); + + // Namen der Vorlage... + rOutput << " " << ByteString( pStyle->GetName(), eDestEnc ).GetBuffer(); + rOutput << ";}"; + } + rOutput << '}'; + rOutput << endl; + } + } + + // Die Pool-Defaults vorweg schreiben... + rOutput << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << "\\EditEnginePoolDefaults"; + for ( sal_uInt16 nPoolDefItem = EE_PARA_START; nPoolDefItem <= EE_CHAR_END; nPoolDefItem++) + { + const SfxPoolItem& rItem = aEditDoc.GetItemPool().GetDefaultItem( nPoolDefItem ); + WriteItemAsRTF( rItem, rOutput, 0, 0, aFontTable, aColorList ); + } + rOutput << '}' << endl; + + // Def-Hoehe vorweg, da sonst 12Pt + // Doch nicht, onst in jedem Absatz hart! + // SfxItemSet aTmpSet( GetEmptyItemSet() ); + // const SvxFontHeightItem& rDefFontHeight = (const SvxFontHeightItem&)aTmpSet.Get( EE_CHAR_FONTHEIGHT ); + // WriteItemAsRTF( rDefFontHeight, rOutput, aFontTable, aColorList ); + // rOutput << '{' << OOO_STRING_SVTOOLS_RTF_IGNORE << "\\EditEnginePoolDefaultHeight}" << endl; + + // DefTab: + MapMode aTwpMode( MAP_TWIP ); + sal_uInt16 nDefTabTwps = (sal_uInt16) GetRefDevice()->LogicToLogic( + Point( aEditDoc.GetDefTab(), 0 ), + &GetRefMapMode(), &aTwpMode ).X(); + rOutput << OOO_STRING_SVTOOLS_RTF_DEFTAB; + rOutput.WriteNumber( nDefTabTwps ); + rOutput << endl; + + // ueber die Absaetze iterieren... + rOutput << '{' << endl; + for ( sal_uInt16 nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + // Die Absatzattribute vorweg... + sal_Bool bAttr = sal_False; + + // Vorlage ? + if ( pNode->GetStyleSheet() ) + { + // Nummer der Vorlage + rOutput << OOO_STRING_SVTOOLS_RTF_S; + sal_uInt16 nNumber = (sal_uInt16) getStylePos( GetStyleSheetPool()->GetStyles(), pNode->GetStyleSheet() ) + 1; + rOutput.WriteNumber( nNumber ); + + // Alle Attribute + // Attribute, auch aus Parent! + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { + if ( pNode->GetStyleSheet()->GetItemSet().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pNode->GetStyleSheet()->GetItemSet().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList ); + bAttr = sal_True; + } + } + } + + for ( sal_uInt16 nParAttr = EE_PARA_START; nParAttr <= EE_CHAR_END; nParAttr++ ) + { +// const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nParAttr ); + // Jetzt, wo StyleSheet-Verarbeitung, nur noch harte Absatzattribute! + if ( pNode->GetContentAttribs().GetItems().GetItemState( nParAttr ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nParAttr ); + WriteItemAsRTF( rItem, rOutput, nNode, 0, aFontTable, aColorList ); + bAttr = sal_True; + } + } + if ( bAttr ) + rOutput << ' '; // Separator + + ItemList aAttribItems; + ParaPortion* pParaPortion = FindParaPortion( pNode ); + DBG_ASSERT( pParaPortion, "Portion nicht gefunden: WriteRTF" ); + + sal_uInt16 nIndex = 0; + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + sal_uInt16 nStartPortion = 0; + sal_uInt16 nEndPortion = (sal_uInt16)pParaPortion->GetTextPortions().Count() - 1; + sal_Bool bFinishPortion = sal_False; + sal_uInt16 nPortionStart; + + if ( nNode == nStartNode ) + { + nStartPos = aSel.Min().GetIndex(); + nStartPortion = pParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart ); + if ( nStartPos != 0 ) + { + aAttribItems.Clear(); + lcl_FindValidAttribs( aAttribItems, pNode, nStartPos, GetScriptType( EditPaM( pNode, 0 ) ) ); + if ( aAttribItems.Count() ) + { + // Diese Attribute duerfen nicht fuer den gesamten + // Absatz gelten: + rOutput << '{'; + WriteItemListAsRTF( aAttribItems, rOutput, nNode, nStartPos, aFontTable, aColorList ); + bFinishPortion = sal_True; + } + aAttribItems.Clear(); + } + } + if ( nNode == nEndNode ) // kann auch == nStart sein! + { + nEndPos = aSel.Max().GetIndex(); + nEndPortion = pParaPortion->GetTextPortions().FindPortion( nEndPos, nPortionStart ); + } + + EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( nIndex ); + // Bei 0 anfangen, damit der Index richtig ist... + + for ( sal_uInt16 n = 0; n <= nEndPortion; n++ ) + { + TextPortion* pTextPortion = pParaPortion->GetTextPortions().GetObject(n); + if ( n < nStartPortion ) + { + nIndex = nIndex + pTextPortion->GetLen(); + continue; + } + + if ( pNextFeature && ( pNextFeature->GetStart() == nIndex ) && ( pNextFeature->GetItem()->Which() != EE_FEATURE_FIELD ) ) + { + WriteItemAsRTF( *pNextFeature->GetItem(), rOutput, nNode, nIndex, aFontTable, aColorList ); + pNextFeature = pNode->GetCharAttribs().FindFeature( pNextFeature->GetStart() + 1 ); + } + else + { + aAttribItems.Clear(); + USHORT nScriptType = GetScriptType( EditPaM( pNode, nIndex+1 ) ); + if ( !n || IsScriptChange( EditPaM( pNode, nIndex ) ) ) + { + SfxItemSet aAttribs = GetAttribs( nNode, nIndex+1, nIndex+1 ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTINFO, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_FONTHEIGHT, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_WEIGHT, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_ITALIC, nScriptType ) ), LIST_APPEND ); + aAttribItems.Insert( &aAttribs.Get( GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ) ), LIST_APPEND ); + } + // #96298# Insert hard attribs AFTER CJK attribs... + lcl_FindValidAttribs( aAttribItems, pNode, nIndex, nScriptType ); + + rOutput << '{'; + if ( WriteItemListAsRTF( aAttribItems, rOutput, nNode, nIndex, aFontTable, aColorList ) ) + rOutput << ' '; + + USHORT nS = nIndex; + USHORT nE = nIndex + pTextPortion->GetLen(); + if ( n == nStartPortion ) + nS = nStartPos; + if ( n == nEndPortion ) + nE = nEndPos; + + XubString aRTFStr = aEditDoc.GetParaAsString( pNode, nS, nE); + RTFOutFuncs::Out_String( rOutput, aRTFStr, eDestEnc ); + rOutput << '}'; + } + if ( bFinishPortion ) + { + rOutput << '}'; + bFinishPortion = sal_False; + } + + nIndex = nIndex + pTextPortion->GetLen(); + } + + rOutput << OOO_STRING_SVTOOLS_RTF_PAR << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_PLAIN;; + rOutput << endl; + } + // RTF-Nachspann... + rOutput << "}}"; // 1xKlammerung Absaetze, 1x Klammerung RTF-Dokument + rOutput.Flush(); + +#if defined (EDITDEBUG) && !defined( UNX ) + { + SvFileStream aStream( String( RTL_CONSTASCII_USTRINGPARAM ( "d:\\rtf_out.rtf" ) ), STREAM_WRITE|STREAM_TRUNC ); + ULONG nP = rOutput.Tell(); + rOutput.Seek( 0 ); + aStream << rOutput; + rOutput.Seek( nP ); + } +#endif + + return rOutput.GetError(); +#else + return 0; +#endif +} + + +void ImpEditEngine::WriteItemAsRTF( const SfxPoolItem& rItem, SvStream& rOutput, sal_uInt16 nPara, sal_uInt16 nPos, + SvxFontTable& rFontTable, SvxColorList& rColorList ) +{ + sal_uInt16 nWhich = rItem.Which(); + switch ( nWhich ) + { + case EE_PARA_WRITINGDIR: + { + const SvxFrameDirectionItem& rWritingMode = (const SvxFrameDirectionItem&)rItem; + if ( rWritingMode.GetValue() == FRMDIR_HORI_RIGHT_TOP ) + rOutput << "\\rtlpar"; + else + rOutput << "\\ltrpar"; + } + break; + case EE_PARA_OUTLLEVEL: + { + sal_Int16 nLevel = ((const SfxInt16Item&)rItem).GetValue(); + if( nLevel >= 0 ) + { + rOutput << "\\level"; + rOutput.WriteNumber( nLevel ); + } + } + break; + case EE_PARA_OUTLLRSPACE: + case EE_PARA_LRSPACE: + { +// const ContentNode *pNode = aEditDoc.GetObject( nPara ); + + rOutput << OOO_STRING_SVTOOLS_RTF_FI; + short nTxtFirst = ((const SvxLRSpaceItem&)rItem).GetTxtFirstLineOfst(); + nTxtFirst = (short)LogicToTwips( nTxtFirst ); + rOutput.WriteNumber( nTxtFirst ); + rOutput << OOO_STRING_SVTOOLS_RTF_LI; + sal_uInt16 nTxtLeft = static_cast< sal_uInt16 >(((const SvxLRSpaceItem&)rItem).GetTxtLeft()); + nTxtLeft = (sal_uInt16)LogicToTwips( nTxtLeft ); + rOutput.WriteNumber( nTxtLeft ); + rOutput << OOO_STRING_SVTOOLS_RTF_RI; + sal_uInt32 nTxtRight = ((const SvxLRSpaceItem&)rItem).GetRight(); + nTxtRight = LogicToTwips( nTxtRight); + rOutput.WriteNumber( nTxtRight ); + } + break; + case EE_PARA_ULSPACE: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SB; + sal_uInt16 nUpper = ((const SvxULSpaceItem&)rItem).GetUpper(); + nUpper = (sal_uInt16)LogicToTwips( nUpper ); + rOutput.WriteNumber( nUpper ); + rOutput << OOO_STRING_SVTOOLS_RTF_SA; + sal_uInt16 nLower = ((const SvxULSpaceItem&)rItem).GetLower(); + nLower = (sal_uInt16)LogicToTwips( nLower ); + rOutput.WriteNumber( nLower ); + } + break; + case EE_PARA_SBL: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SL; + long nVal = ((const SvxLineSpacingItem&)rItem).GetLineHeight(); + char cMult = '0'; + if ( ((const SvxLineSpacingItem&)rItem).GetInterLineSpaceRule() == SVX_INTER_LINE_SPACE_PROP ) + { + // Woher kriege ich jetzt den Wert? + // Der SwRTF-Parser geht von einem 240er Font aus! + nVal = ((const SvxLineSpacingItem&)rItem).GetPropLineSpace(); + nVal *= 240; + nVal /= 100; + cMult = '1'; + } + rOutput.WriteNumber( nVal ); + rOutput << OOO_STRING_SVTOOLS_RTF_SLMULT << cMult; + } + break; + case EE_PARA_JUST: + { + SvxAdjust eJustification = ((const SvxAdjustItem&)rItem).GetAdjust(); + switch ( eJustification ) + { + case SVX_ADJUST_CENTER: rOutput << OOO_STRING_SVTOOLS_RTF_QC; + break; + case SVX_ADJUST_RIGHT: rOutput << OOO_STRING_SVTOOLS_RTF_QR; + break; + default: rOutput << OOO_STRING_SVTOOLS_RTF_QL; + break; + } + } + break; + case EE_PARA_TABS: + { + const SvxTabStopItem& rTabs = (const SvxTabStopItem&) rItem; + for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ ) + { + const SvxTabStop& rTab = rTabs[i]; + rOutput << OOO_STRING_SVTOOLS_RTF_TX; + rOutput.WriteNumber( LogicToTwips( rTab.GetTabPos() ) ); + } + } + break; + case EE_CHAR_COLOR: + { + sal_uInt32 n = rColorList.GetId( (const SvxColorItem&)rItem ); + rOutput << OOO_STRING_SVTOOLS_RTF_CF; + rOutput.WriteNumber( n ); + } + break; + case EE_CHAR_FONTINFO: + case EE_CHAR_FONTINFO_CJK: + case EE_CHAR_FONTINFO_CTL: + { + sal_uInt32 n = rFontTable.GetId( (const SvxFontItem&)rItem ); + rOutput << OOO_STRING_SVTOOLS_RTF_F; + rOutput.WriteNumber( n ); + } + break; + case EE_CHAR_FONTHEIGHT: + case EE_CHAR_FONTHEIGHT_CJK: + case EE_CHAR_FONTHEIGHT_CTL: + { + rOutput << OOO_STRING_SVTOOLS_RTF_FS; + long nHeight = ((const SvxFontHeightItem&)rItem).GetHeight(); + nHeight = LogicToTwips( nHeight ); + // Twips => HalfPoints + nHeight /= 10; + rOutput.WriteNumber( nHeight ); + } + break; + case EE_CHAR_WEIGHT: + case EE_CHAR_WEIGHT_CJK: + case EE_CHAR_WEIGHT_CTL: + { + FontWeight e = ((const SvxWeightItem&)rItem).GetWeight(); + switch ( e ) + { + case WEIGHT_BOLD: rOutput << OOO_STRING_SVTOOLS_RTF_B; break; + default: rOutput << OOO_STRING_SVTOOLS_RTF_B << '0'; break; + } + } + break; + case EE_CHAR_UNDERLINE: + { + // muesste bei WordLineMode ggf. ulw werden, + // aber die Information fehlt hier + FontUnderline e = ((const SvxUnderlineItem&)rItem).GetLineStyle(); + switch ( e ) + { + case UNDERLINE_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_ULNONE; break; + case UNDERLINE_SINGLE: rOutput << OOO_STRING_SVTOOLS_RTF_UL; break; + case UNDERLINE_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_ULDB; break; + case UNDERLINE_DOTTED: rOutput << OOO_STRING_SVTOOLS_RTF_ULD; break; + default: + break; + } + } + break; + case EE_CHAR_OVERLINE: + { + FontUnderline e = ((const SvxOverlineItem&)rItem).GetLineStyle(); + switch ( e ) + { + case UNDERLINE_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_OLNONE; break; + case UNDERLINE_SINGLE: rOutput << OOO_STRING_SVTOOLS_RTF_OL; break; + case UNDERLINE_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_OLDB; break; + case UNDERLINE_DOTTED: rOutput << OOO_STRING_SVTOOLS_RTF_OLD; break; + default: + break; + } + } + break; + case EE_CHAR_STRIKEOUT: + { + FontStrikeout e = ((const SvxCrossedOutItem&)rItem).GetStrikeout(); + switch ( e ) + { + case STRIKEOUT_SINGLE: + case STRIKEOUT_DOUBLE: rOutput << OOO_STRING_SVTOOLS_RTF_STRIKE; break; + case STRIKEOUT_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_STRIKE << '0'; break; + default: + break; + } + } + break; + case EE_CHAR_ITALIC: + case EE_CHAR_ITALIC_CJK: + case EE_CHAR_ITALIC_CTL: + { + FontItalic e = ((const SvxPostureItem&)rItem).GetPosture(); + switch ( e ) + { + case ITALIC_OBLIQUE: + case ITALIC_NORMAL: rOutput << OOO_STRING_SVTOOLS_RTF_I; break; + case ITALIC_NONE: rOutput << OOO_STRING_SVTOOLS_RTF_I << '0'; break; + default: + break; + } + } + break; + case EE_CHAR_OUTLINE: + { + rOutput << OOO_STRING_SVTOOLS_RTF_OUTL; + if ( ((const SvxContourItem&)rItem).GetValue() == 0 ) + rOutput << '0'; + } + break; + case EE_CHAR_RELIEF: + { + USHORT nRelief = ((const SvxCharReliefItem&)rItem).GetValue(); + if ( nRelief == RELIEF_EMBOSSED ) + rOutput << OOO_STRING_SVTOOLS_RTF_EMBO; + if ( nRelief == RELIEF_ENGRAVED ) + rOutput << OOO_STRING_SVTOOLS_RTF_IMPR; + } + break; + case EE_CHAR_EMPHASISMARK: + { + USHORT nMark = ((const SvxEmphasisMarkItem&)rItem).GetValue(); + if ( nMark == EMPHASISMARK_NONE ) + rOutput << OOO_STRING_SVTOOLS_RTF_ACCNONE; + else if ( nMark == EMPHASISMARK_SIDE_DOTS ) + rOutput << OOO_STRING_SVTOOLS_RTF_ACCCOMMA; + else + rOutput << OOO_STRING_SVTOOLS_RTF_ACCDOT; + } + break; + case EE_CHAR_SHADOW: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SHAD; + if ( ((const SvxShadowedItem&)rItem).GetValue() == 0 ) + rOutput << '0'; + } + break; + case EE_FEATURE_TAB: + { + rOutput << OOO_STRING_SVTOOLS_RTF_TAB; + } + break; + case EE_FEATURE_LINEBR: + { + rOutput << OOO_STRING_SVTOOLS_RTF_SL; + } + break; + case EE_CHAR_KERNING: + { + rOutput << OOO_STRING_SVTOOLS_RTF_EXPNDTW; + rOutput.WriteNumber( LogicToTwips( + ((const SvxKerningItem&)rItem).GetValue() ) ); + } + break; + case EE_CHAR_PAIRKERNING: + { + rOutput << OOO_STRING_SVTOOLS_RTF_KERNING; + rOutput.WriteNumber( ((const SvxAutoKernItem&)rItem).GetValue() ? 1 : 0 ); + } + break; + case EE_CHAR_ESCAPEMENT: + { + SvxFont aFont; + ContentNode* pNode = aEditDoc.GetObject( nPara ); + SeekCursor( pNode, nPos, aFont ); + MapMode aPntMode( MAP_POINT ); + long nFontHeight = GetRefDevice()->LogicToLogic( + aFont.GetSize(), &GetRefMapMode(), &aPntMode ).Height(); + nFontHeight *=2; // HalfPoints + sal_uInt16 nProp = ((const SvxEscapementItem&)rItem).GetProp(); + sal_uInt16 nProp100 = nProp*100; // Fuer SWG-Token Prop in 100tel Prozent. + short nEsc = ((const SvxEscapementItem&)rItem).GetEsc(); + if ( nEsc == DFLT_ESC_AUTO_SUPER ) + { + nEsc = 100 - nProp; + nProp100++; // Eine 1 hinten bedeutet 'automatisch'. + } + else if ( nEsc == DFLT_ESC_AUTO_SUB ) + { + nEsc = sal::static_int_cast< short >( -( 100 - nProp ) ); + nProp100++; + } + // SWG: + if ( nEsc ) + rOutput << "{\\*\\updnprop" << ByteString::CreateFromInt32( nProp100 ).GetBuffer() << '}'; + long nUpDown = nFontHeight * Abs( nEsc ) / 100; + ByteString aUpDown = ByteString::CreateFromInt32( nUpDown ); + if ( nEsc < 0 ) + rOutput << OOO_STRING_SVTOOLS_RTF_DN << aUpDown.GetBuffer(); + else if ( nEsc > 0 ) + rOutput << OOO_STRING_SVTOOLS_RTF_UP << aUpDown.GetBuffer(); + } + break; + } +} + +sal_uInt32 ImpEditEngine::WriteHTML( SvStream&, EditSelection ) +{ + return 0; +} + + +EditTextObject* ImpEditEngine::CreateTextObject() +{ + EditSelection aCompleteSelection; + aCompleteSelection.Min() = aEditDoc.GetStartPaM(); + aCompleteSelection.Max() = aEditDoc.GetEndPaM(); + + return CreateTextObject( aCompleteSelection ); +} + +EditTextObject* ImpEditEngine::CreateTextObject( EditSelection aSel ) +{ + return CreateBinTextObject( aSel, GetEditTextObjectPool(), aStatus.AllowBigObjects(), nBigTextObjectStart ); +} + +EditTextObject* ImpEditEngine::CreateBinTextObject( EditSelection aSel, SfxItemPool* pPool, sal_Bool bAllowBigObjects, sal_uInt16 nBigObjectStart ) const +{ + BinTextObject* pTxtObj = new BinTextObject( pPool ); + pTxtObj->SetVertical( IsVertical() ); + MapUnit eMapUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); + pTxtObj->SetMetric( (sal_uInt16) eMapUnit ); + if ( pTxtObj->IsOwnerOfPool() ) + pTxtObj->GetPool()->SetDefaultMetric( (SfxMapUnit) eMapUnit ); + + sal_uInt16 nStartNode, nEndNode; + sal_uInt32 nTextPortions = 0; + + aSel.Adjust( aEditDoc ); + nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + sal_Bool bOnlyFullParagraphs = ( aSel.Min().GetIndex() || + ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) ) ? + sal_False : sal_True; + + // Vorlagen werden nicht gespeichert! + // ( Nur Name und Familie, Vorlage selbst muss in App stehen! ) + + pTxtObj->SetScriptType( GetScriptType( aSel ) ); + + // ueber die Absaetze iterieren... + sal_uInt16 nNode; + for ( nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.SaveGetObject( nNode ); + DBG_ASSERT( pNode, "Node nicht gefunden: Search&Replace" ); + + if ( bOnlyFullParagraphs ) + { + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + nTextPortions += pParaPortion->GetTextPortions().Count(); + } + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + + sal_Bool bEmptyPara = nEndPos ? sal_False : sal_True; + + if ( ( nNode == nStartNode ) && !bOnlyFullParagraphs ) + nStartPos = aSel.Min().GetIndex(); + if ( ( nNode == nEndNode ) && !bOnlyFullParagraphs ) + nEndPos = aSel.Max().GetIndex(); + + + ContentInfo* pC = pTxtObj->CreateAndInsertContent(); + + // Die Absatzattribute... + pC->GetParaAttribs().Set( pNode->GetContentAttribs().GetItems() ); + + // Das StyleSheet... + if ( pNode->GetStyleSheet() ) + { + pC->GetStyle() = pNode->GetStyleSheet()->GetName(); + pC->GetFamily() = pNode->GetStyleSheet()->GetFamily(); + } + + // Der Text... + pC->GetText() = pNode->Copy( nStartPos, nEndPos-nStartPos ); + + // und die Attribute... + sal_uInt16 nAttr = 0; + EditCharAttrib* pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr ) + { + // In einem leeren Absatz die Attribute behalten! + if ( bEmptyPara || + ( ( pAttr->GetEnd() > nStartPos ) && ( pAttr->GetStart() < nEndPos ) ) ) + { + XEditAttribute* pX = pTxtObj->CreateAttrib( *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() ); + // Evtl. korrigieren... + if ( ( nNode == nStartNode ) && ( nStartPos != 0 ) ) + { + pX->GetStart() = ( pX->GetStart() > nStartPos ) ? pX->GetStart()-nStartPos : 0; + pX->GetEnd() = pX->GetEnd() - nStartPos; + + } + if ( nNode == nEndNode ) + { + if ( pX->GetEnd() > (nEndPos-nStartPos) ) + pX->GetEnd() = nEndPos-nStartPos; + } + DBG_ASSERT( pX->GetEnd() <= (nEndPos-nStartPos), "CreateBinTextObject: Attribut zu lang!" ); + if ( !pX->GetLen() && !bEmptyPara ) + pTxtObj->DestroyAttrib( pX ); + else + pC->GetAttribs().Insert( pX, pC->GetAttribs().Count() ); + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + +#ifndef SVX_LIGHT + // ggf. Online-Spelling + if ( bAllowBigObjects && bOnlyFullParagraphs && pNode->GetWrongList() ) + pC->SetWrongList( pNode->GetWrongList()->Clone() ); +#endif // !SVX_LIGHT + + } + + // Bei grossen Textobjekten die PortionInfos merken: + // Schwelle rauf setzen, wenn Olli die Absaetze nicht mehr zerhackt! + if ( bAllowBigObjects && bOnlyFullParagraphs && IsFormatted() && GetUpdateMode() && ( nTextPortions >= nBigObjectStart ) ) + { + XParaPortionList* pXList = new XParaPortionList( GetRefDevice(), aPaperSize.Width() ); + pTxtObj->SetPortionInfo( pXList ); + for ( nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + XParaPortion* pX = new XParaPortion; + pXList->Insert( pX, pXList->Count() ); + + pX->nHeight = pParaPortion->GetHeight(); + pX->nFirstLineOffset = pParaPortion->GetFirstLineOffset(); + + // Die TextPortions + sal_uInt16 nCount = pParaPortion->GetTextPortions().Count(); + sal_uInt16 n; + for ( n = 0; n < nCount; n++ ) + { + TextPortion* pTextPortion = pParaPortion->GetTextPortions()[n]; + TextPortion* pNew = new TextPortion( *pTextPortion ); + pX->aTextPortions.Insert( pNew, pX->aTextPortions.Count() ); + } + + // Die Zeilen + nCount = pParaPortion->GetLines().Count(); + for ( n = 0; n < nCount; n++ ) + { + EditLine* pLine = pParaPortion->GetLines()[n]; + EditLine* pNew = pLine->Clone(); + pX->aLines.Insert( pNew, pX->aLines.Count() ); + } +#ifdef DBG_UTIL + USHORT nTest; + int nTPLen = 0, nTxtLen = 0; + for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) + nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); + for ( nTest = pParaPortion->GetLines().Count(); nTest; ) + nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); + DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "CreateBinTextObject: ParaPortion not completely formatted!" ); +#endif + } + } + return pTxtObj; +} + +void ImpEditEngine::SetText( const EditTextObject& rTextObject ) +{ + // Da Setzen eines TextObject ist nicht Undo-faehig! + ResetUndoManager(); + sal_Bool _bUpdate = GetUpdateMode(); + sal_Bool _bUndo = IsUndoEnabled(); + + SetText( XubString() ); + EditPaM aPaM = aEditDoc.GetStartPaM(); + + SetUpdateMode( sal_False ); + EnableUndo( sal_False ); + + InsertText( rTextObject, EditSelection( aPaM, aPaM ) ); + SetVertical( rTextObject.IsVertical() ); + +#ifndef SVX_LIGHT + DBG_ASSERT( !HasUndoManager() || !GetUndoManager().GetUndoActionCount(), "Woher kommt das Undo in SetText ?!" ); +#endif + SetUpdateMode( _bUpdate ); + EnableUndo( _bUndo ); +} + +EditSelection ImpEditEngine::InsertText( const EditTextObject& rTextObject, EditSelection aSel ) +{ + EnterBlockNotifications(); + aSel.Adjust( aEditDoc ); + if ( aSel.HasRange() ) + aSel = ImpDeleteSelection( aSel ); + EditSelection aNewSel = InsertBinTextObject( (BinTextObject&)rTextObject, aSel.Max() ); + LeaveBlockNotifications(); + return aNewSel; + + // MT 05/00: InsertBinTextObject direkt hier machen... +} + +EditSelection ImpEditEngine::InsertBinTextObject( BinTextObject& rTextObject, EditPaM aPaM ) +{ + // Optimieren: + // Kein GetPos undFindParaportion, sondern Index berechnen! + EditSelection aSel( aPaM, aPaM ); + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); + + sal_Bool bUsePortionInfo = sal_False; +// sal_Bool bFields = sal_False; + XParaPortionList* pPortionInfo = rTextObject.GetPortionInfo(); + + if ( pPortionInfo && ( (long)pPortionInfo->GetPaperWidth() == aPaperSize.Width() ) + && ( pPortionInfo->GetRefMapMode() == GetRefDevice()->GetMapMode() ) ) + { + if ( ( pPortionInfo->GetRefDevPtr() == (sal_uIntPtr)GetRefDevice() ) || + ( ( pPortionInfo->GetRefDevType() == OUTDEV_VIRDEV ) && + ( GetRefDevice()->GetOutDevType() == OUTDEV_VIRDEV ) ) ) + bUsePortionInfo = sal_True; + } + + sal_Bool bConvertItems = sal_False; + MapUnit eSourceUnit = MapUnit(), eDestUnit = MapUnit(); + if ( rTextObject.HasMetric() ) + { + eSourceUnit = (MapUnit)rTextObject.GetMetric(); + eDestUnit = (MapUnit)aEditDoc.GetItemPool().GetMetric( DEF_METRIC ); + if ( eSourceUnit != eDestUnit ) + bConvertItems = sal_True; + } + + sal_uInt16 nContents = rTextObject.GetContents().Count(); + sal_uInt16 nPara = aEditDoc.GetPos( aPaM.GetNode() ); + + for ( sal_uInt16 n = 0; n < nContents; n++, nPara++ ) + { + ContentInfo* pC = rTextObject.GetContents().GetObject( n ); + sal_Bool bNewContent = aPaM.GetNode()->Len() ? sal_False: sal_True; + sal_uInt16 nStartPos = aPaM.GetIndex(); + + aPaM = ImpFastInsertText( aPaM, pC->GetText() ); + + ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() ); + DBG_ASSERT( pPortion, "Blinde Portion in FastInsertText" ); + pPortion->MarkInvalid( nStartPos, pC->GetText().Len() ); + + // Zeicheattribute... + sal_Bool bAllreadyHasAttribs = aPaM.GetNode()->GetCharAttribs().Count() ? sal_True : sal_False; + sal_uInt16 nNewAttribs = pC->GetAttribs().Count(); + if ( nNewAttribs ) + { + BOOL bUpdateFields = FALSE; + for ( sal_uInt16 nAttr = 0; nAttr < nNewAttribs; nAttr++ ) + { + XEditAttribute* pX = pC->GetAttribs().GetObject( nAttr ); + // Kann passieren wenn Absaetze >16K entstehen, dann wird einfach umgebrochen. + if ( pX->GetEnd() <= aPaM.GetNode()->Len() ) + { + if ( !bAllreadyHasAttribs || pX->IsFeature() ) + { + // Normale Attribute gehen dann schneller... + // Features duerfen nicht ueber EditDoc::InsertAttrib + // eingefuegt werden, sie sind bei FastInsertText schon im TextFluss + DBG_ASSERT( pX->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut zu gross!" ); + EditCharAttrib* pAttr; + if ( !bConvertItems ) + pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *(pX->GetItem()), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); + else + { + SfxPoolItem* pNew = pX->GetItem()->Clone(); + ConvertItem( *pNew, eSourceUnit, eDestUnit ); + pAttr = MakeCharAttrib( aEditDoc.GetItemPool(), *pNew, pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos ); + delete pNew; + } + DBG_ASSERT( pAttr->GetEnd() <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (1)" ); + aPaM.GetNode()->GetCharAttribs().InsertAttrib( pAttr ); + if ( pAttr->Which() == EE_FEATURE_FIELD ) + bUpdateFields = TRUE; + } + else + { + DBG_ASSERT( pX->GetEnd()+nStartPos <= aPaM.GetNode()->Len(), "InsertBinTextObject: Attribut passt nicht! (2)" ); + // Tabs und andere Features koennen nicht ueber InsertAttrib eingefuegt werden: + aEditDoc.InsertAttrib( aPaM.GetNode(), pX->GetStart()+nStartPos, pX->GetEnd()+nStartPos, *pX->GetItem() ); + } + } + } + if ( bUpdateFields ) + UpdateFields(); + + // Sonst QuickFormat => Keine Attribute! + pPortion->MarkSelectionInvalid( nStartPos, pC->GetText().Len() ); + } + + DBG_ASSERT( CheckOrderedList( aPaM.GetNode()->GetCharAttribs().GetAttribs(), sal_True ), "InsertBinTextObject: Start-Liste verdreht" ); + + sal_Bool bParaAttribs = sal_False; + if ( bNewContent || ( ( n > 0 ) && ( n < (nContents-1) ) ) ) + { + bParaAttribs = sal_False; + // #101512# Don't overwrite level/style from existing paragraph in OutlineView + // MT 10/2002: Removed because of #103874#, handled in Outliner::EndPasteOrDropHdl now. +// if ( !aStatus.IsOutliner() || n ) + { + // nur dann Style und ParaAttribs, wenn neuer Absatz, oder + // komplett inneliegender... + bParaAttribs = pC->GetParaAttribs().Count() ? sal_True : sal_False; + if ( GetStyleSheetPool() && pC->GetStyle().Len() ) + { + SfxStyleSheet* pStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( pC->GetStyle(), pC->GetFamily() ); + DBG_ASSERT( pStyle, "InsertBinTextObject - Style not found!" ); + SetStyleSheet( nPara, pStyle ); + } + if ( !bConvertItems ) + SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), pC->GetParaAttribs() ); + else + { + SfxItemSet aAttribs( GetEmptyItemSet() ); + ConvertAndPutItems( aAttribs, pC->GetParaAttribs(), &eSourceUnit, &eDestUnit ); + SetParaAttribs( aEditDoc.GetPos( aPaM.GetNode() ), aAttribs ); + } + } + if ( bNewContent && bUsePortionInfo ) + { + XParaPortion* pXP = pPortionInfo->GetObject( n ); + DBG_ASSERT( pXP, "InsertBinTextObject: PortionInfo?" ); + ParaPortion* pParaPortion = GetParaPortions()[ nPara ]; + DBG_ASSERT( pParaPortion, "InsertBinTextObject: ParaPortion?" ); + pParaPortion->nHeight = pXP->nHeight; + pParaPortion->nFirstLineOffset = pXP->nFirstLineOffset; + pParaPortion->bForceRepaint = sal_True; + pParaPortion->SetValid(); // Nicht formatieren + + // Die TextPortions + pParaPortion->GetTextPortions().Reset(); + sal_uInt16 nCount = pXP->aTextPortions.Count(); + for ( sal_uInt16 _n = 0; _n < nCount; _n++ ) + { + TextPortion* pTextPortion = pXP->aTextPortions[_n]; + TextPortion* pNew = new TextPortion( *pTextPortion ); + pParaPortion->GetTextPortions().Insert( pNew, _n ); + } + + // Die Zeilen + pParaPortion->GetLines().Reset(); + nCount = pXP->aLines.Count(); + for ( sal_uInt16 m = 0; m < nCount; m++ ) + { + EditLine* pLine = pXP->aLines[m]; + EditLine* pNew = pLine->Clone(); + pNew->SetInvalid(); // neu Painten! + pParaPortion->GetLines().Insert( pNew, m ); + } +#ifdef DBG_UTIL + USHORT nTest; + int nTPLen = 0, nTxtLen = 0; + for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; ) + nTPLen += pParaPortion->GetTextPortions().GetObject( --nTest )->GetLen(); + for ( nTest = pParaPortion->GetLines().Count(); nTest; ) + nTxtLen += pParaPortion->GetLines().GetObject( --nTest )->GetLen(); + DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "InsertBinTextObject: ParaPortion not completely formatted!" ); +#endif + } + } + if ( !bParaAttribs ) // DefFont wird bei FastInsertParagraph nicht berechnet + { + aPaM.GetNode()->GetCharAttribs().GetDefFont() = aEditDoc.GetDefFont(); + if ( aStatus.UseCharAttribs() ) + aPaM.GetNode()->CreateDefFont(); + } + +#ifndef SVX_LIGHT + if ( bNewContent && GetStatus().DoOnlineSpelling() && pC->GetWrongList() ) + { + aPaM.GetNode()->DestroyWrongList(); // otherwise MLK, if list exists... + aPaM.GetNode()->SetWrongList( pC->GetWrongList()->Clone() ); + } +#endif // !SVX_LIGHT + + // Zeilenumbruch, wenn weitere folgen... + if ( n < ( nContents-1) ) + { + if ( bNewContent ) + aPaM = ImpFastInsertParagraph( nPara+1 ); + else + aPaM = ImpInsertParaBreak( aPaM, sal_False ); + } + } + + aSel.Max() = aPaM; + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "InsertBibTextObject: Selektion kaput!(1)" ); + return aSel; +} + +LanguageType ImpEditEngine::GetLanguage( const EditPaM& rPaM, USHORT* pEndPos ) const +{ + short nScriptType = GetScriptType( rPaM, pEndPos ); // pEndPos will be valid now, pointing to ScriptChange or NodeLen + USHORT nLangId = GetScriptItemId( EE_CHAR_LANGUAGE, nScriptType ); + const SvxLanguageItem* pLangItem = &(const SvxLanguageItem&)rPaM.GetNode()->GetContentAttribs().GetItem( nLangId ); + EditCharAttrib* pAttr = rPaM.GetNode()->GetCharAttribs().FindAttrib( nLangId, rPaM.GetIndex() ); + if ( pAttr ) + pLangItem = (const SvxLanguageItem*)pAttr->GetItem(); + + if ( pEndPos && pAttr && ( pAttr->GetEnd() < *pEndPos ) ) + *pEndPos = pAttr->GetEnd(); + + return pLangItem->GetLanguage(); +} + +::com::sun::star::lang::Locale ImpEditEngine::GetLocale( const EditPaM& rPaM ) const +{ + return SvxCreateLocale( GetLanguage( rPaM ) ); +} + +Reference< XSpellChecker1 > ImpEditEngine::GetSpeller() +{ +#ifndef SVX_LIGHT + if ( !xSpeller.is() ) + xSpeller = SvxGetSpellChecker(); +#endif + return xSpeller; +} + +EESpellState ImpEditEngine::Spell( EditView* pEditView, sal_Bool bMultipleDoc ) +{ +#ifdef SVX_LIGHT + return EE_SPELL_NOSPELLER; +#else + + DBG_ASSERTWARNING( xSpeller.is(), "Kein Speller gesetzt!" ); + + if ( !xSpeller.is() ) + return EE_SPELL_NOSPELLER; + + aOnlineSpellTimer.Stop(); + + // Bei MultipleDoc immer von vorne/hinten... + if ( bMultipleDoc ) + { + pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + } + + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = bMultipleDoc; + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); + + sal_Bool bIsStart = sal_False; + if ( bMultipleDoc ) + bIsStart = sal_True; // Immer von Vorne bzw. von hinten... + else if ( ( CreateEPaM( aEditDoc.GetStartPaM() ) == pSpellInfo->aSpellStart ) ) + bIsStart = sal_True; + + EditSpellWrapper* pWrp = new EditSpellWrapper( Application::GetDefDialogParent(), + xSpeller, bIsStart, sal_False, pEditView ); + pWrp->SpellDocument(); + delete pWrp; + + if ( !bMultipleDoc ) + { + pEditView->pImpEditView->DrawSelection(); + if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) + aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); + aCurSel.Min() = aCurSel.Max(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + EESpellState eState = pSpellInfo->eState; + delete pSpellInfo; + pSpellInfo = 0; + return eState; +#endif +} + + +sal_Bool ImpEditEngine::HasConvertibleTextPortion( LanguageType nSrcLang ) +{ +#ifdef SVX_LIGHT + return sal_False; +#else + sal_Bool bHasConvTxt = sal_False; + + USHORT nParas = pEditEngine->GetParagraphCount(); + for (USHORT k = 0; k < nParas; ++k) + { + SvUShorts aPortions; + pEditEngine->GetPortions( k, aPortions ); + for ( USHORT nPos = 0; nPos < aPortions.Count(); ++nPos ) + { + USHORT nEnd = aPortions.GetObject( nPos ); + USHORT nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; + + // if the paragraph is not empty we need to increase the index + // by one since the attribute of the character left to the + // specified position is evaluated. + if (nEnd > nStart) // empty para? + ++nStart; + LanguageType nLangFound = pEditEngine->GetLanguage( k, nStart ); +#ifdef DEBUG + lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); +#endif + bHasConvTxt = (nSrcLang == nLangFound) || + (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && + editeng::HangulHanjaConversion::IsChinese( nSrcLang )); + if (bHasConvTxt) + return bHasConvTxt; + } + } + +#endif + return bHasConvTxt; +} + + +void ImpEditEngine::Convert( EditView* pEditView, + LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, + INT32 nOptions, sal_Bool bIsInteractive, sal_Bool bMultipleDoc ) +{ + // modified version of ImpEditEngine::Spell + +#ifdef SVX_LIGHT +#else + + // Bei MultipleDoc immer von vorne/hinten... + if ( bMultipleDoc ) + pEditView->pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + + // + // initialize pConvInfo + // + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + aCurSel.Adjust( aEditDoc ); + pConvInfo = new ConvInfo; + pConvInfo->bMultipleDoc = bMultipleDoc; + pConvInfo->aConvStart = CreateEPaM( aCurSel.Min() ); + // + // if it is not just a selection and we are about to begin + // with the current conversion for the very first time + // we need to find the start of the current (initial) + // convertible unit in order for the text conversion to give + // the correct result for that. Since it is easier to obtain + // the start of the word we use that though. + if (!aCurSel.HasRange() && ImplGetBreakIterator().is()) + { + EditPaM aWordStartPaM( SelectWord( aCurSel, i18n::WordType::DICTIONARY_WORD ).Min() ); + + // since #118246 / #117803 still occurs if the cursor is placed + // between the two chinese characters to be converted (because both + // of them are words on their own!) using the word boundary here does + // not work. Thus since chinese conversion is not interactive we start + // at the begin of the paragraph to solve the problem, i.e. have the + // TextConversion service get those characters together in the same call. + USHORT nStartIdx = ( editeng::HangulHanjaConversion::IsChinese( nSrcLang ) ) ? + 0 : aWordStartPaM.GetIndex(); + pConvInfo->aConvStart.nIndex = nStartIdx; + } + // + pConvInfo->aConvContinue = pConvInfo->aConvStart; + + sal_Bool bIsStart = sal_False; + if ( bMultipleDoc ) + bIsStart = sal_True; // Immer von Vorne bzw. von hinten... + else if ( CreateEPaM( aEditDoc.GetStartPaM() ) == pConvInfo->aConvStart ) + bIsStart = sal_True; + + bImpConvertFirstCall = sal_True; // next ImpConvert call is the very first in this conversion turn + + Reference< lang::XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + TextConvWrapper aWrp( Application::GetDefDialogParent(), xMSF, + SvxCreateLocale( nSrcLang ), SvxCreateLocale( nDestLang ), + pDestFont, + nOptions, bIsInteractive, + bIsStart, pEditView ); + + // + //!! optimization does not work since when update mode is false + //!! the object is 'lying' about it portions, paragraphs, + //!! EndPaM... later on. + //!! Should not be a great problem since text boxes or cells in + //!! Calc usually have only a rather short text. + // + // disallow formatting, updating the view, ... while + // non-interactively converting the document. (saves time) + //if (!bIsInteractive) + // SetUpdateMode( FALSE ); + + aWrp.Convert(); + + //if (!bIsInteractive) + //SetUpdateMode( TRUE, 0, TRUE ); + + if ( !bMultipleDoc ) + { + pEditView->pImpEditView->DrawSelection(); + if ( aCurSel.Max().GetIndex() > aCurSel.Max().GetNode()->Len() ) + aCurSel.Max().GetIndex() = aCurSel.Max().GetNode()->Len(); + aCurSel.Min() = aCurSel.Max(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + delete pConvInfo; + pConvInfo = 0; +#endif +} + + +void ImpEditEngine::SetLanguageAndFont( + const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ) +{ + ESelection aOldSel = pActiveView->GetSelection(); + pActiveView->SetSelection( rESel ); + + // set new language attribute + SfxItemSet aNewSet( pActiveView->GetEmptyItemSet() ); + aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) ); + + // new font to be set? + DBG_ASSERT( pFont, "target font missing?" ); + if (pFont) + { + // set new font attribute + SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId ); + aFontItem.GetFamilyName() = pFont->GetName(); + aFontItem.GetFamily() = pFont->GetFamily(); + aFontItem.GetStyleName() = pFont->GetStyleName(); + aFontItem.GetPitch() = pFont->GetPitch(); + aFontItem.GetCharSet() = pFont->GetCharSet(); + aNewSet.Put( aFontItem ); + } + + // apply new attributes + pActiveView->SetAttribs( aNewSet ); + + pActiveView->SetSelection( aOldSel ); +} + + +void ImpEditEngine::ImpConvert( rtl::OUString &rConvTxt, LanguageType &rConvTxtLang, + EditView* pEditView, LanguageType nSrcLang, const ESelection &rConvRange, + sal_Bool bAllowImplicitChangesForNotConvertibleText, + LanguageType nTargetLang, const Font *pTargetFont ) +{ + // modified version of ImpEditEngine::ImpSpell + + // looks for next convertible text portion to be passed on to the wrapper + + String aRes; + LanguageType nResLang = LANGUAGE_NONE; + +#ifdef SVX_LIGHT + rConvTxt = rtl::OUString(); + rConvTxtLang = LANGUAGE_NONE; +#else + + /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( aEditDoc.Count()-1 ); + + EditPaM aPos( CreateEditPaM( pConvInfo->aConvContinue ) ); + EditSelection aCurSel = EditSelection( aPos, aPos ); + + String aWord; + + while (!aRes.Len()) + { + // empty paragraph found that needs to have language and font set? + if (bAllowImplicitChangesForNotConvertibleText && + !pEditEngine->GetText( pConvInfo->aConvContinue.nPara ).Len()) + { + USHORT nPara = pConvInfo->aConvContinue.nPara; + ESelection aESel( nPara, 0, nPara, 0 ); + // see comment for below same function call + SetLanguageAndFont( aESel, + nTargetLang, EE_CHAR_LANGUAGE_CJK, + pTargetFont, EE_CHAR_FONTINFO_CJK ); + } + + + if (pConvInfo->aConvContinue.nPara == pConvInfo->aConvTo.nPara && + pConvInfo->aConvContinue.nIndex >= pConvInfo->aConvTo.nIndex) + break; + +/* + // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss + // Current bei jeder Ersetzung korrigiert werden, sonst passt + // das Ende evtl. nicht mehr genau... + if ( pConvInfo->bConvToEnd || pConvInfo->bMultipleDoc ) + { + if ( aCurSel.Max().GetNode() == pLastNode && + aCurSel.Max().GetIndex() >= pLastNode->Len() ) + break; + } +*/ + + USHORT nAttribStart = USHRT_MAX; + USHORT nAttribEnd = USHRT_MAX; + USHORT nCurPos = USHRT_MAX; + EPaM aCurStart = CreateEPaM( aCurSel.Min() ); + SvUShorts aPortions; + pEditEngine->GetPortions( (USHORT)aCurStart.nPara, aPortions ); + for ( USHORT nPos = 0; nPos < aPortions.Count(); ++nPos ) + { + USHORT nEnd = aPortions.GetObject( nPos ); + USHORT nStart = nPos > 0 ? aPortions.GetObject( nPos - 1 ) : 0; + + // the language attribute is obtained from the left character + // (like usually all other attributes) + // thus we usually have to add 1 in order to get the language + // of the text right to the cursor position + USHORT nLangIdx = nEnd > nStart ? nStart + 1 : nStart; + LanguageType nLangFound = pEditEngine->GetLanguage( aCurStart.nPara, nLangIdx ); +#ifdef DEBUG + lang::Locale aLocale( SvxCreateLocale( nLangFound ) ); +#endif + sal_Bool bLangOk = (nLangFound == nSrcLang) || + (editeng::HangulHanjaConversion::IsChinese( nLangFound ) && + editeng::HangulHanjaConversion::IsChinese( nSrcLang )); + + if (nAttribEnd != USHRT_MAX) // start already found? + { + DBG_ASSERT(nEnd >= aCurStart.nIndex, "error while scanning attributes (a)" ); + DBG_ASSERT(nEnd >= nAttribEnd, "error while scanning attributes (b)" ); + if (/*nEnd >= aCurStart.nIndex &&*/ nLangFound == nResLang) + nAttribEnd = nEnd; + else // language attrib has changed + break; + } + if (nAttribStart == USHRT_MAX && // start not yet found? + nEnd > aCurStart.nIndex && bLangOk) + { + nAttribStart = nStart; + nAttribEnd = nEnd; + nResLang = nLangFound; + } + //! the list of portions may have changed compared to the previous + //! call to this function (because of possibly changed language + //! attribute!) + //! But since we don't want to start in the already processed part + //! we clip the start accordingly. + if (nAttribStart < aCurStart.nIndex) + { + nAttribStart = aCurStart.nIndex; + } + + // check script type to the right of the start of the current portion + EditPaM aPaM( CreateEditPaM( EPaM(aCurStart.nPara, nLangIdx) ) ); + sal_Bool bIsAsianScript = (i18n::ScriptType::ASIAN == GetScriptType( aPaM )); + // not yet processed text part with for conversion + // not suitable language found that needs to be changed? + if (bAllowImplicitChangesForNotConvertibleText && + !bLangOk && !bIsAsianScript && nEnd > aCurStart.nIndex) + { + ESelection aESel( aCurStart.nPara, nStart, aCurStart.nPara, nEnd ); + // set language and font to target language and font of conversion + //! Now this especially includes all non convertible text e.g. + //! spaces, empty paragraphs and western text. + // This is in order for every *new* text entered at *any* position to + // have the correct language and font attributes set. + SetLanguageAndFont( aESel, + nTargetLang, EE_CHAR_LANGUAGE_CJK, + pTargetFont, EE_CHAR_FONTINFO_CJK ); + } + + nCurPos = nEnd; + } + + if (nAttribStart != USHRT_MAX && nAttribEnd != USHRT_MAX) + { + aCurSel.Min().SetIndex( nAttribStart ); + aCurSel.Max().SetIndex( nAttribEnd ); + } + else if (nCurPos != USHRT_MAX) + { + // set selection to end of scanned text + // (used to set the position where to continue from later on) + aCurSel.Min().SetIndex( nCurPos ); + aCurSel.Max().SetIndex( nCurPos ); + } + + if ( !pConvInfo->bConvToEnd ) + { + EPaM aEPaM( CreateEPaM( aCurSel.Min() ) ); + if ( !( aEPaM < pConvInfo->aConvTo ) ) + break; + } + + // clip selected word to the converted area + // (main use when conversion starts/ends **within** a word) + EditPaM aPaM( CreateEditPaM( pConvInfo->aConvStart ) ); + if (pConvInfo->bConvToEnd && + aCurSel.Min().GetNode() == aPaM.GetNode() && + aCurSel.Min().GetIndex() < aPaM.GetIndex()) + aCurSel.Min().SetIndex( aPaM.GetIndex() ); + aPaM = CreateEditPaM( pConvInfo->aConvContinue ); + if (aCurSel.Min().GetNode() == aPaM.GetNode() && + aCurSel.Min().GetIndex() < aPaM.GetIndex()) + aCurSel.Min().SetIndex( aPaM.GetIndex() ); + aPaM = CreateEditPaM( pConvInfo->aConvTo ); + if ((!pConvInfo->bConvToEnd || rConvRange.HasRange())&& + aCurSel.Max().GetNode() == aPaM.GetNode() && + aCurSel.Max().GetIndex() > aPaM.GetIndex()) + aCurSel.Max().SetIndex( aPaM.GetIndex() ); + + aWord = GetSelected( aCurSel ); + + if ( aWord.Len() > 0 /* && bLangOk */) + aRes = aWord; + + // move to next word/paragraph if necessary + if ( !aRes.Len() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + + pConvInfo->aConvContinue = CreateEPaM( aCurSel.Max() ); + } + + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + + rConvTxt = aRes; + if (rConvTxt.getLength()) + rConvTxtLang = nResLang; +#endif +} + + +Reference< XSpellAlternatives > ImpEditEngine::ImpSpell( EditView* pEditView ) +{ +#ifdef SVX_LIGHT + return Reference< XSpellAlternatives >(); +#else + + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + + ContentNode* pLastNode = aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + aCurSel.Min() = aCurSel.Max(); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while (!xSpellAlt.is()) + { + + // Bekannter (wahrscheinlicher) Bug: Wenn SpellToCurrent, muss + // Current bei jeder Ersetzung korrigiert werden, sonst passt + // das Ende evtl. nicht mehr genau... + if ( pSpellInfo->bSpellToEnd || pSpellInfo->bMultipleDoc ) + { + if ( aCurSel.Max().GetNode() == pLastNode ) + { + if ( ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) + break; + } + } + else if ( !pSpellInfo->bSpellToEnd ) + { + EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); + if ( !( aEPaM < pSpellInfo->aSpellTo ) ) + break; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) + { + sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aCurSel.Max().GetIndex()++; + aWord += cNext; + } + } + + if ( aWord.Len() > 0 ) + { + LanguageType eLang = GetLanguage( aCurSel.Max() ); + SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); + xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); + } + + if ( !xSpellAlt.is() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + else + pSpellInfo->eState = EE_SPELL_ERRORFOUND; + } + + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + return xSpellAlt; +#endif +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::EndSpelling() +{ + DELETEZ(pSpellInfo); +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc) +{ + DBG_ASSERT(!pSpellInfo, "pSpellInfo already set?"); + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = bMultipleDoc; + rEditView.pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + Search for the next wrong word within the given selection + -----------------------------------------------------------------------*/ +Reference< XSpellAlternatives > ImpEditEngine::ImpFindNextError(EditSelection& rSelection) +{ + /* ContentNode* pLastNode = */ aEditDoc.SaveGetObject( (aEditDoc.Count()-1) ); + EditSelection aCurSel( rSelection.Min() ); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while (!xSpellAlt.is()) + { + //check if the end of the selection has been reached + { + EPaM aEPaM( CreateEPaM( aCurSel.Max() ) ); + if ( !( aEPaM < CreateEPaM( rSelection.Max()) ) ) + break; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + if ( aWord.Len() && ( aCurSel.Max().GetIndex() < aCurSel.Max().GetNode()->Len() ) ) + { + sal_Unicode cNext = aCurSel.Max().GetNode()->GetChar( aCurSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aCurSel.Max().GetIndex()++; + aWord += cNext; + } + } + + if ( aWord.Len() > 0 ) + xSpellAlt = xSpeller->spell( aWord, GetLanguage( aCurSel.Max() ), aEmptySeq ); + + if ( !xSpellAlt.is() ) + aCurSel = WordRight( aCurSel.Min(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + else + { + pSpellInfo->eState = EE_SPELL_ERRORFOUND; + rSelection = aCurSel; + } + } + return xSpellAlt; +} +/*-- 13.10.2003 16:43:27--------------------------------------------------- + + -----------------------------------------------------------------------*/ +bool ImpEditEngine::SpellSentence(EditView& rEditView, ::svx::SpellPortions& rToFill, bool /*bIsGrammarChecking*/ ) +{ +#ifdef SVX_LIGHT +#else + bool bRet = false; + //the pSpellInfo has to be created on demand + if(!pSpellInfo) + { + pSpellInfo = new SpellInfo; + pSpellInfo->bMultipleDoc = sal_True; + rEditView.pImpEditView->SetEditSelection( aEditDoc.GetStartPaM() ); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + pSpellInfo->aSpellStart = CreateEPaM( SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ).Min() ); + } + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + pSpellInfo->aLastSpellPortions.clear(); + pSpellInfo->aLastSpellContentSelections.clear(); + rToFill.clear(); + EditSelection aCurSel( rEditView.pImpEditView->GetEditSelection() ); + //if no selection previously exists the range is extended to the end of the object + if(aCurSel.Min() == aCurSel.Max()) + { + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count()-1); + aCurSel.Max() = EditPaM(pLastNode, pLastNode->Len()); + } + Reference< XSpellAlternatives > xAlt = ImpFindNextError(aCurSel); + if(xAlt.is()) + { + bRet = true; + //find the sentence boundaries + EditSelection aSentencePaM = SelectSentence(aCurSel); + //make sure that the sentence is never smaller than the error range! + if(aSentencePaM.Max().GetIndex() < aCurSel.Max().GetIndex()) + aSentencePaM.Max() = aCurSel.Max(); + //add the portion preceeding the error + EditSelection aStartSelection(aSentencePaM.Min(), aCurSel.Min()); + if(aStartSelection.HasRange()) + AddPortionIterated(rEditView, aStartSelection, 0, rToFill); + //add the error portion + AddPortionIterated(rEditView, aCurSel, xAlt, rToFill); + //find the end of the sentence + //search for all errors in the rest of the sentence and add all the portions + do + { + EditSelection aNextSel = EditSelection(aCurSel.Max(), aSentencePaM.Max()); + xAlt = ImpFindNextError(aNextSel); + if(xAlt.is()) + { + //add the part between the previous and the current error + AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aNextSel.Min()), 0, rToFill); + //add the current error + AddPortionIterated(rEditView, aNextSel, xAlt, rToFill); + } + else + AddPortionIterated(rEditView, EditSelection(aCurSel.Max(), aSentencePaM.Max()), xAlt, rToFill); + aCurSel = aNextSel; + } + while( xAlt.is() ); + //set the selection to the end of the current sentence + rEditView.pImpEditView->SetEditSelection(aSentencePaM.Max()); + } +#endif + return bRet; +} + +/*-- 15.10.2003 16:09:12--------------------------------------------------- + adds one portion to the SpellPortions + -----------------------------------------------------------------------*/ +void ImpEditEngine::AddPortion( + const EditSelection rSel, + uno::Reference< XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill, + bool bIsField) +{ +#ifdef SVX_LIGHT +#else + if(rSel.HasRange()) + { + svx::SpellPortion aPortion; + aPortion.sText = GetSelected( rSel ); + aPortion.eLanguage = GetLanguage( rSel.Min() ); + aPortion.xAlternatives = xAlt; + aPortion.bIsField = bIsField; + rToFill.push_back(aPortion); + + //save the spelled portions for later use + pSpellInfo->aLastSpellPortions.push_back(aPortion); + pSpellInfo->aLastSpellContentSelections.push_back(rSel); + + } +#endif +} + +/*-- 15.10.2003 16:07:47--------------------------------------------------- + adds one or more portions of text to the SpellPortions depending on language changes + -----------------------------------------------------------------------*/ +void ImpEditEngine::AddPortionIterated( + EditView& rEditView, + const EditSelection rSel, + Reference< XSpellAlternatives > xAlt, + ::svx::SpellPortions& rToFill) +{ +#ifdef SVX_LIGHT +#else + if(rSel.Min() != rSel.Max()) + { + if(xAlt.is()) + { + AddPortion(rSel, xAlt, rToFill, false); + } + else + { + //iterate and search for language attribute changes + //save the start and end positions + bool bTest = rSel.Min().GetIndex() <= rSel.Max().GetIndex(); + EditPaM aStart(bTest ? rSel.Min() : rSel.Max()); + EditPaM aEnd(bTest ? rSel.Max() : rSel.Min()); + //iterate over the text to find changes in language + //set the mark equal to the point + EditPaM aCursor(aStart); + rEditView.pImpEditView->SetEditSelection( aCursor ); + LanguageType eStartLanguage = GetLanguage( aCursor ); + //search for a field attribute at the beginning - only the end position + //of this field is kept to end a portion at that position + const EditCharAttrib* pFieldAttr = aCursor.GetNode()->GetCharAttribs(). + FindFeature( aCursor.GetIndex() ); + bool bIsField = pFieldAttr && + pFieldAttr->GetStart() == aCursor.GetIndex() && + pFieldAttr->GetStart() != pFieldAttr->GetEnd() && + pFieldAttr->Which() == EE_FEATURE_FIELD; + USHORT nEndField = bIsField ? pFieldAttr->GetEnd() : USHRT_MAX; + bool bIsEndField = false; + do + { + aCursor = CursorRight( aCursor); + //determine whether a field and has been reached + bIsEndField = nEndField == aCursor.GetIndex(); + //search for a new field attribute + EditCharAttrib* _pFieldAttr = aCursor.GetNode()->GetCharAttribs(). + FindFeature( aCursor.GetIndex() ); + bIsField = _pFieldAttr && + _pFieldAttr->GetStart() == aCursor.GetIndex() && + _pFieldAttr->GetStart() != _pFieldAttr->GetEnd() && + _pFieldAttr->Which() == EE_FEATURE_FIELD; + //on every new field move the end position + if(bIsField) + nEndField = bIsField ? _pFieldAttr->GetEnd() : USHRT_MAX; + + LanguageType eCurLanguage = GetLanguage( aCursor ); + if(eCurLanguage != eStartLanguage || bIsField || bIsEndField) + { + eStartLanguage = eCurLanguage; + //go one step back - the cursor currently selects the first character + //with a different language + //create a selection from start to the current Cursor + EditSelection aSelection(aStart, aCursor); + AddPortion(aSelection, xAlt, rToFill, bIsEndField); + aStart = aCursor; + } + } + while(aCursor.GetIndex() < aEnd.GetIndex()); + EditSelection aSelection(aStart, aCursor); + AddPortion(aSelection, xAlt, rToFill, bIsField); + } + } +#endif +} + +/*-- 13.10.2003 16:43:33--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::ApplyChangedSentence(EditView& rEditView, const ::svx::SpellPortions& rNewPortions, bool /*bIsGrammarChecking*/ ) +{ +#ifdef SVX_LIGHT +#else + DBG_ASSERT(pSpellInfo, "pSpellInfo not initialized"); + if(pSpellInfo) + { + UndoActionStart( EDITUNDO_INSERT ); + if(pSpellInfo->aLastSpellPortions.size() == rNewPortions.size()) + { + //the simple case: the same number of elements on both sides + //each changed element has to be applied to the corresponding source element + svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.end(); + svx::SpellPortions::const_iterator aCurrentOldPortion = pSpellInfo->aLastSpellPortions.end(); + SpellContentSelections::const_iterator aCurrentOldPosition = pSpellInfo->aLastSpellContentSelections.end(); + bool bSetToEnd = false; + do + { + --aCurrentNewPortion; + --aCurrentOldPortion; + --aCurrentOldPosition; + //set the cursor to the end of the sentence - necessary to + //resume there at the next step + if(!bSetToEnd) + { + bSetToEnd = true; + rEditView.pImpEditView->SetEditSelection( aCurrentOldPosition->Max() ); + } + + USHORT nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); +// LanguageType eTextLanguage = GetLanguage( aCurrentOldPosition->Min() ); + + USHORT nLangWhichId = EE_CHAR_LANGUAGE; + switch(nScriptType) + { + case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; + case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; + } + if(aCurrentNewPortion->sText != aCurrentOldPortion->sText) + { + //change text and apply language + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( *aCurrentOldPosition, aSet ); + ImpInsertText( *aCurrentOldPosition, aCurrentNewPortion->sText ); + } + else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage) + { + //apply language + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( *aCurrentOldPosition, aSet ); + } + if(aCurrentNewPortion == rNewPortions.begin()) + break; + } + while(aCurrentNewPortion != rNewPortions.begin()); + } + else + { + //select the complete sentence + SpellContentSelections::const_iterator aCurrentEndPosition = pSpellInfo->aLastSpellContentSelections.end(); + --aCurrentEndPosition; + SpellContentSelections::const_iterator aCurrentStartPosition = pSpellInfo->aLastSpellContentSelections.begin(); + EditSelection aAllSentence(aCurrentStartPosition->Min(), aCurrentEndPosition->Max()); + + //delete the sentence completely + ImpDeleteSelection( aAllSentence ); + svx::SpellPortions::const_iterator aCurrentNewPortion = rNewPortions.begin(); + EditPaM aCurrentPaM = aAllSentence.Min(); + while(aCurrentNewPortion != rNewPortions.end()) + { + //set the language attribute + LanguageType eCurLanguage = GetLanguage( aCurrentPaM ); + if(eCurLanguage != aCurrentNewPortion->eLanguage) + { + USHORT nScriptType = GetI18NScriptTypeOfLanguage( aCurrentNewPortion->eLanguage ); + USHORT nLangWhichId = EE_CHAR_LANGUAGE; + switch(nScriptType) + { + case SCRIPTTYPE_ASIAN : nLangWhichId = EE_CHAR_LANGUAGE_CJK; break; + case SCRIPTTYPE_COMPLEX : nLangWhichId = EE_CHAR_LANGUAGE_CTL; break; + } + SfxItemSet aSet( aEditDoc.GetItemPool(), nLangWhichId, nLangWhichId); + aSet.Put(SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId)); + SetAttribs( aCurrentPaM, aSet ); + } + //insert the new string and set the cursor to the end of the inserted string + aCurrentPaM = ImpInsertText( aCurrentPaM , aCurrentNewPortion->sText ); + ++aCurrentNewPortion; + } + } + UndoActionEnd( EDITUNDO_INSERT ); + } + FormatAndUpdate(); + aEditDoc.SetModified(TRUE); +#endif +} +/*-- 08.09.2008 11:33:02--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void ImpEditEngine::PutSpellingToSentenceStart( EditView& rEditView ) +{ +#ifdef SVX_LIGHT +#else + if( pSpellInfo && pSpellInfo->aLastSpellContentSelections.size() ) + { + rEditView.pImpEditView->SetEditSelection( pSpellInfo->aLastSpellContentSelections.begin()->Min() ); + } + +#endif +} + + +void ImpEditEngine::DoOnlineSpelling( ContentNode* pThisNodeOnly, sal_Bool bSpellAtCursorPos, sal_Bool bInteruptable ) +{ +#ifndef SVX_LIGHT + /* + Er wird ueber alle Absaetze iteriert, nur Absaetze mit invalidierter + WrongList werden geprueft... + + Es werden alle Woerter im invalidierten Bereich geprueft. + Ist ein Wort falsch, aber noch nicht in der WrongList, oder umgekehrt, + wird der Bereich des Wortes invalidiert + ( kein Invalidate, sondern wenn nur Uebergaenge von richtig=>falsch, + einfaches Paint, bei Uebergaengen von falsch=>richtig mit VDev + ueberplaetten ) + */ + + if ( !xSpeller.is() ) + return; + + EditPaM aCursorPos; + if( pActiveView && !bSpellAtCursorPos ) + { + DBG_CHKOBJ( pActiveView, EditView, 0 ); + aCursorPos = pActiveView->pImpEditView->GetEditSelection().Max(); + } + sal_Bool bRestartTimer = sal_False; + + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); + sal_uInt16 nNodes = GetEditDoc().Count(); + sal_uInt16 nInvalids = 0; + Sequence< PropertyValue > aEmptySeq; + for ( sal_uInt16 n = 0; n < nNodes; n++ ) + { + ContentNode* pNode = GetEditDoc().GetObject( n ); + if ( pThisNodeOnly ) + pNode = pThisNodeOnly; + + if ( pNode->GetWrongList()->IsInvalid() ) + { + WrongList* pWrongList = pNode->GetWrongList(); + sal_uInt16 nInvStart = pWrongList->GetInvalidStart(); + sal_uInt16 nInvEnd = pWrongList->GetInvalidEnd(); + + sal_uInt16 nWrongs = 0; // Auch im Absatz mal die Kontrolle abgeben... +// sal_Bool bStop = sal_False; + + sal_uInt16 nPaintFrom = 0xFFFF, nPaintTo = 0; + sal_Bool bSimpleRepaint = sal_True; + + pWrongList->SetValid(); + + EditPaM aPaM( pNode, nInvStart ); + EditSelection aSel( aPaM, aPaM ); + while ( ( aSel.Max().GetNode() == pNode ) /* && !bStop */ ) + { + if ( ( aSel.Min().GetIndex() > nInvEnd ) + || ( ( aSel.Max().GetNode() == pLastNode ) && ( aSel.Max().GetIndex() >= pLastNode->Len() ) ) ) + break; // Dokument- oder Ungueltigkeitsbereich-Ende + + aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + String aWord( GetSelected( aSel ) ); + // Wenn Punkt dahinter, muss dieser mit uebergeben werden ! + // Falls Abkuerzung... + sal_Bool bDottAdded = sal_False; + if ( aSel.Max().GetIndex() < aSel.Max().GetNode()->Len() ) + { + sal_Unicode cNext = aSel.Max().GetNode()->GetChar( aSel.Max().GetIndex() ); + if ( cNext == '.' ) + { + aSel.Max().GetIndex()++; + aWord += cNext; + bDottAdded = sal_True; + } + } + + + sal_Bool bChanged = sal_False; + if ( aWord.Len() > 0 ) + { + sal_uInt16 nWStart = aSel.Min().GetIndex(); + sal_uInt16 nWEnd= aSel.Max().GetIndex(); + if ( !xSpeller->isValid( aWord, GetLanguage( EditPaM( aSel.Min().GetNode(), nWStart+1 ) ), aEmptySeq ) ) + { + // Pruefen, ob schon richtig markiert... + nWrongs++; + // Nur bei SimpleRepaint stoppen, sonst zu oft VDev + // if ( ( nWrongs > 8 ) && bSimpleRepaint ) + // { + // bStop = sal_True; + // pWrongList->MarkInvalid( aSel.Max().GetIndex(), nInvEnd ); + // } + sal_uInt16 nXEnd = bDottAdded ? nWEnd -1 : nWEnd; + if ( !pWrongList->HasWrong( nWStart, nXEnd ) ) + { + // Wort als falsch markieren... + // Aber nur, wenn nicht an Cursor-Position... + sal_Bool bCursorPos = sal_False; + if ( aCursorPos.GetNode() == pNode ) + { + if ( ( nWStart <= aCursorPos.GetIndex() ) && nWEnd >= aCursorPos.GetIndex() ) + bCursorPos = sal_True; + } + if ( bCursorPos ) + { + // Dann weiter als ungueltig markieren... + pWrongList->GetInvalidStart() = nWStart; + pWrongList->GetInvalidEnd() = nWEnd; + bRestartTimer = sal_True; + } + else + { + // Es kann sein, dass die Wrongs in der Liste nicht + // genau ueber Woerter aufgespannt sind, weil die + // WordDelimiters beim Expandieren nicht ausgewrtet werden. + pWrongList->InsertWrong( nWStart, nXEnd, sal_True ); + bChanged = sal_True; + } + } + } + else + { + // Pruefen, ob nicht als als falsch markiert.... + if ( pWrongList->HasAnyWrong( nWStart, nWEnd ) ) + { + pWrongList->ClearWrongs( nWStart, nWEnd, pNode ); + bSimpleRepaint = sal_False; + bChanged = sal_True; + } + } + if ( bChanged ) + { + if ( nPaintFrom == 0xFFFF ) + nPaintFrom = nWStart; + nPaintTo = nWEnd; + } + } + + EditPaM aLastEnd( aSel.Max() ); + aSel = WordRight( aSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + if ( bChanged && ( aSel.Min().GetNode() == pNode ) && + ( ( aSel.Min().GetIndex()-aLastEnd.GetIndex() > 1 ) ) ) + { + // Wenn zwei Worte durch mehr Zeichen als ein Blank getrennt + // sind, kann es passieren, dass beim Aufsplitten eines Wrongs + // der Start den zweiten Wortes vor dem tatsaechlich Wort liegt + pWrongList->ClearWrongs( aLastEnd.GetIndex(), aSel.Min().GetIndex(), pNode ); + } + } + + // Invalidieren? + if ( ( nPaintFrom != 0xFFFF ) ) + { + aStatus.GetStatusWord() |= EE_STAT_WRONGWORDCHANGED; + CallStatusHdl(); + + if ( aEditViews.Count() ) + { + // Bei SimpleRepaint wuerde ein uebermalen ohne VDev reichen, + // aber dann muesste ich ueber alle Views, Intersecten, + // Clippen, ... + // Lohnt wahrscheinlich nicht. + EditPaM aStartPaM( pNode, nPaintFrom ); + EditPaM aEndPaM( pNode, nPaintTo ); + Rectangle aStartCursor( PaMtoEditCursor( aStartPaM ) ); + Rectangle aEndCursor( PaMtoEditCursor( aEndPaM ) ); + DBG_ASSERT( aInvalidRec.IsEmpty(), "InvalidRect gesetzt!" ); + aInvalidRec.Left() = 0; + aInvalidRec.Right() = GetPaperSize().Width(); + aInvalidRec.Top() = aStartCursor.Top(); + aInvalidRec.Bottom() = aEndCursor.Bottom(); + if ( pActiveView && pActiveView->HasSelection() ) + { + // Dann darf nicht ueber VDev ausgegeben werden + UpdateViews( NULL ); + } + else if ( bSimpleRepaint ) + { + for ( sal_uInt16 nView = 0; nView < aEditViews.Count(); nView++ ) + { + EditView* pView = aEditViews[nView]; + Rectangle aClipRec( aInvalidRec ); + aClipRec.Intersection( pView->GetVisArea() ); + if ( !aClipRec.IsEmpty() ) + { + // in Fensterkoordinaten umwandeln.... + aClipRec.SetPos( pView->pImpEditView->GetWindowPos( aClipRec.TopLeft() ) ); + // Wenn Selektion, dann VDev... + Paint( pView->pImpEditView, aClipRec, pView->HasSelection() ); + } + } + } + else + { + UpdateViews( pActiveView ); + } + aInvalidRec = Rectangle(); + } + } + // Nach zwei korrigierten Nodes die Kontrolle abgeben... + nInvalids++; + if ( bInteruptable && ( nInvalids >= 2 ) ) + { + bRestartTimer = sal_True; + break; + } + } + + if ( pThisNodeOnly ) + break; + } + if ( bRestartTimer ) + aOnlineSpellTimer.Start(); +#endif // !SVX_LIGHT +} + + +EESpellState ImpEditEngine::HasSpellErrors() +{ + DBG_ASSERT( xSpeller.is(), "Kein Speller gesetzt!" ); + +#ifndef SVX_LIGHT + ContentNode* pLastNode = aEditDoc.SaveGetObject( aEditDoc.Count() - 1 ); + EditSelection aCurSel( aEditDoc.GetStartPaM() ); + + String aWord; + Reference< XSpellAlternatives > xSpellAlt; + Sequence< PropertyValue > aEmptySeq; + while ( !xSpellAlt.is() ) + { + if ( ( aCurSel.Max().GetNode() == pLastNode ) && + ( aCurSel.Max().GetIndex() >= pLastNode->Len() ) ) + { + return EE_SPELL_OK; + } + + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + aWord = GetSelected( aCurSel ); + if ( aWord.Len() > 0 ) + { + LanguageType eLang = GetLanguage( aCurSel.Max() ); + SvxSpellWrapper::CheckSpellLang( xSpeller, eLang ); + xSpellAlt = xSpeller->spell( aWord, eLang, aEmptySeq ); + } + aCurSel = WordRight( aCurSel.Max(), ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + } +#endif + + return EE_SPELL_ERRORFOUND; +} + +EESpellState ImpEditEngine::StartThesaurus( EditView* pEditView ) +{ +#ifndef SVX_LIGHT + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + if ( !aCurSel.HasRange() ) + aCurSel = SelectWord( aCurSel, ::com::sun::star::i18n::WordType::DICTIONARY_WORD ); + String aWord( GetSelected( aCurSel ) ); + + Reference< XThesaurus > xThes( SvxGetThesaurus() ); + if (!xThes.is()) + return EE_SPELL_ERRORFOUND; + + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pEditView->GetWindow(), xThes, aWord, GetLanguage( aCurSel.Max() ) ); + if ( pDlg->Execute() == RET_OK ) + { + // Wort ersetzen... + pEditView->pImpEditView->DrawSelection(); + pEditView->pImpEditView->SetEditSelection( aCurSel ); + pEditView->pImpEditView->DrawSelection(); + pEditView->InsertText( pDlg->GetWord() ); + pEditView->ShowCursor( sal_True, sal_False ); + } + + delete pDlg; + return EE_SPELL_OK; +#else + return EE_SPELL_NOSPELLER; +#endif +} + +sal_uInt16 ImpEditEngine::StartSearchAndReplace( EditView* pEditView, const SvxSearchItem& rSearchItem ) +{ + sal_uInt16 nFound = 0; + +#ifndef SVX_LIGHT + EditSelection aCurSel( pEditView->pImpEditView->GetEditSelection() ); + + // FIND_ALL ohne Mehrfachselektion nicht moeglich. + if ( ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND ) || + ( rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL ) ) + { + if ( Search( rSearchItem, pEditView ) ) + nFound++; + } + else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE ) + { + // Das Wort ist selektiert, wenn der Anwender die Selektion + // nicht zwischendurch manipuliert: + if ( aCurSel.HasRange() ) + { + pEditView->InsertText( rSearchItem.GetReplaceString() ); + nFound = 1; + } + else + if( Search( rSearchItem, pEditView ) ) + nFound = 1; + } + else if ( rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL ) + { + // Der Writer ersetzt alle, vorn Anfang bis Ende... + SvxSearchItem aTmpItem( rSearchItem ); + aTmpItem.SetBackward( sal_False ); + + pEditView->pImpEditView->DrawSelection(); + + aCurSel.Adjust( aEditDoc ); + EditPaM aStartPaM = aTmpItem.GetSelection() ? aCurSel.Min() : aEditDoc.GetStartPaM(); + EditSelection aFoundSel( aCurSel.Max() ); + sal_Bool bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); + if ( bFound ) + UndoActionStart( EDITUNDO_REPLACEALL ); + while ( bFound ) + { + nFound++; + aStartPaM = ImpInsertText( aFoundSel, rSearchItem.GetReplaceString() ); + bFound = ImpSearch( aTmpItem, aCurSel, aStartPaM, aFoundSel ); + } + if ( nFound ) + { + EditPaM aNewPaM( aFoundSel.Max() ); + if ( aNewPaM.GetIndex() > aNewPaM.GetNode()->Len() ) + aNewPaM.GetIndex() = aNewPaM.GetNode()->Len(); + pEditView->pImpEditView->SetEditSelection( aNewPaM ); + FormatAndUpdate( pEditView ); + UndoActionEnd( EDITUNDO_REPLACEALL ); + } + else + { + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( sal_True, sal_False ); + } + } +#endif // !SVX_LIGHT + return nFound; +} + +BOOL ImpEditEngine::Search( const SvxSearchItem& rSearchItem, EditView* pEditView ) +{ + EditSelection aSel( pEditView->pImpEditView->GetEditSelection() ); + aSel.Adjust( aEditDoc ); + EditPaM aStartPaM( aSel.Max() ); + if ( rSearchItem.GetSelection() && !rSearchItem.GetBackward() ) + aStartPaM = aSel.Min(); + + EditSelection aFoundSel; + BOOL bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); + if ( bFound && ( aFoundSel == aSel ) ) // Bei Rueckwaetssuche + { + aStartPaM = aSel.Min(); + bFound = ImpSearch( rSearchItem, aSel, aStartPaM, aFoundSel ); + } + + pEditView->pImpEditView->DrawSelection(); + if ( bFound ) + { + // Erstmal das Min einstellen, damit das ganze Wort in den sichtbaren Bereich kommt. + pEditView->pImpEditView->SetEditSelection( aFoundSel.Min() ); + pEditView->ShowCursor( TRUE, FALSE ); + pEditView->pImpEditView->SetEditSelection( aFoundSel ); + } + else + pEditView->pImpEditView->SetEditSelection( aSel.Max() ); + + pEditView->pImpEditView->DrawSelection(); + pEditView->ShowCursor( TRUE, FALSE ); + return bFound; +} + +sal_Bool ImpEditEngine::ImpSearch( const SvxSearchItem& rSearchItem, + const EditSelection& rSearchSelection, const EditPaM& rStartPos, EditSelection& rFoundSel ) +{ +#ifndef SVX_LIGHT + util::SearchOptions aSearchOptions( rSearchItem.GetSearchOptions() ); + aSearchOptions.Locale = GetLocale( rStartPos ); + + sal_Bool bBack = rSearchItem.GetBackward(); + sal_Bool bSearchInSelection = rSearchItem.GetSelection(); + sal_uInt16 nStartNode = aEditDoc.GetPos( rStartPos.GetNode() ); + sal_uInt16 nEndNode; + if ( bSearchInSelection ) + { + nEndNode = aEditDoc.GetPos( bBack ? rSearchSelection.Min().GetNode() : rSearchSelection.Max().GetNode() ); + } + else + { + nEndNode = bBack ? 0 : aEditDoc.Count()-1; + } + + utl::TextSearch aSearcher( aSearchOptions ); + + // ueber die Absaetze iterieren... + for ( sal_uInt16 nNode = nStartNode; + bBack ? ( nNode >= nEndNode ) : ( nNode <= nEndNode) ; + bBack ? nNode-- : nNode++ ) + { + // Bei rueckwaertsuche, wenn nEndNode = 0: + if ( nNode >= 0xFFFF ) + return sal_False; + + ContentNode* pNode = aEditDoc.GetObject( nNode ); + + sal_uInt16 nStartPos = 0; + sal_uInt16 nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + { + if ( bBack ) + nEndPos = rStartPos.GetIndex(); + else + nStartPos = rStartPos.GetIndex(); + } + if ( ( nNode == nEndNode ) && bSearchInSelection ) + { + if ( bBack ) + nStartPos = rSearchSelection.Min().GetIndex(); + else + nEndPos = rSearchSelection.Max().GetIndex(); + } + + // Suchen... + XubString aParaStr( GetEditDoc().GetParaAsString( pNode ) ); + bool bFound = false; + if ( bBack ) + { + SwapUSHORTs( nStartPos, nEndPos ); + bFound = aSearcher.SearchBkwrd( aParaStr, &nStartPos, &nEndPos); + } + else + bFound = aSearcher.SearchFrwrd( aParaStr, &nStartPos, &nEndPos); + + if ( bFound ) + { + rFoundSel.Min().SetNode( pNode ); + rFoundSel.Min().SetIndex( nStartPos ); + rFoundSel.Max().SetNode( pNode ); + rFoundSel.Max().SetIndex( nEndPos ); + return sal_True; + } + } +#endif // !SVX_LIGHT + return sal_False; +} + +sal_Bool ImpEditEngine::HasText( const SvxSearchItem& rSearchItem ) +{ +#ifndef SVX_LIGHT + SvxSearchItem aTmpItem( rSearchItem ); + aTmpItem.SetBackward( sal_False ); + aTmpItem.SetSelection( sal_False ); + + EditPaM aStartPaM( aEditDoc.GetStartPaM() ); + EditSelection aDummySel( aStartPaM ); + EditSelection aFoundSel; + return ImpSearch( aTmpItem, aDummySel, aStartPaM, aFoundSel ); +#else + return sal_False; +#endif +} + +void ImpEditEngine::SetAutoCompleteText( const String& rStr, sal_Bool bClearTipWindow ) +{ +#ifndef SVX_LIGHT + aAutoCompleteText = rStr; + if ( bClearTipWindow && pActiveView ) + Help::ShowQuickHelp( pActiveView->GetWindow(), Rectangle(), String(), 0 ); +#endif // !SVX_LIGHT +} + +EditSelection ImpEditEngine::TransliterateText( const EditSelection& rSelection, sal_Int32 nTransliterationMode ) +{ + EditSelection aSel( rSelection ); + aSel.Adjust( aEditDoc ); + + if ( !aSel.HasRange() ) + aSel = SelectWord( aSel ); + + EditSelection aNewSel( aSel ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + BOOL bChanges = FALSE; + BOOL bLenChanged = FALSE; + EditUndoTransliteration* pUndo = NULL; + + utl::TransliterationWrapper aTranslitarationWrapper( ::comphelper::getProcessServiceFactory(), nTransliterationMode ); + BOOL bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode(); + + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + USHORT nCurrentStart = nStartPos; + USHORT nCurrentEnd = nEndPos; + sal_uInt16 nLanguage = LANGUAGE_SYSTEM; + + do + { + if ( bConsiderLanguage ) + { + nLanguage = GetLanguage( EditPaM( pNode, nCurrentStart+1 ), &nCurrentEnd ); + if ( nCurrentEnd > nEndPos ) + nCurrentEnd = nEndPos; + } + + xub_StrLen nLen = nCurrentEnd - nCurrentStart; + + Sequence <sal_Int32> aOffsets; + String aNewText( aTranslitarationWrapper.transliterate( *pNode, nLanguage, nCurrentStart, nLen, &aOffsets ) ); + + if( ( nLen != aNewText.Len() ) || !pNode->Equals( aNewText, nCurrentStart, nLen ) ) + { + bChanges = TRUE; + if ( nLen != aNewText.Len() ) + bLenChanged = TRUE; + +#ifndef SVX_LIGHT + // Create UndoAction on Demand.... + if ( !pUndo && IsUndoEnabled() && !IsInUndo() ) + { + ESelection aESel( CreateESel( aSel ) ); + pUndo = new EditUndoTransliteration( this, aESel, nTransliterationMode ); + + if ( ( nStartNode == nEndNode ) && !aSel.Min().GetNode()->GetCharAttribs().HasAttrib( aSel.Min().GetIndex(), aSel.Max().GetIndex() ) ) + pUndo->SetText( aSel.Min().GetNode()->Copy( aSel.Min().GetIndex(), aSel.Max().GetIndex()-aSel.Min().GetIndex() ) ); + else + pUndo->SetText( CreateBinTextObject( aSel, NULL ) ); + } +#endif + + // Change text without loosing the attributes + USHORT nCharsAfterTransliteration = + sal::static_int_cast< USHORT >(aOffsets.getLength()); + const sal_Int32* pOffsets = aOffsets.getConstArray(); + short nDiffs = 0; + for ( USHORT n = 0; n < nCharsAfterTransliteration; n++ ) + { + USHORT nCurrentPos = nCurrentStart+n; + sal_Int32 nDiff = (nCurrentPos-nDiffs) - pOffsets[n]; + + if ( !nDiff ) + { + DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); + pNode->SetChar( nCurrentPos, aNewText.GetChar(n) ); + } + else if ( nDiff < 0 ) + { + // Replace first char, delete the rest... + DBG_ASSERT( nCurrentPos < pNode->Len(), "TransliterateText - String smaller than expected!" ); + pNode->SetChar( nCurrentPos, aNewText.GetChar(n) ); + + DBG_ASSERT( (nCurrentPos+1) < pNode->Len(), "TransliterateText - String smaller than expected!" ); + GetEditDoc().RemoveChars( EditPaM( pNode, nCurrentPos+1 ), sal::static_int_cast< USHORT >(-nDiff) ); + } + else + { + DBG_ASSERT( nDiff == 1, "TransliterateText - Diff other than expected! But should work..." ); + GetEditDoc().InsertText( EditPaM( pNode, nCurrentPos ), aNewText.GetChar(n) ); + + } + nDiffs = sal::static_int_cast< short >(nDiffs + nDiff); + } + + if ( nNode == nEndNode ) + aNewSel.Max().GetIndex() = + aNewSel.Max().GetIndex() + nDiffs; + + ParaPortion* pParaPortion = GetParaPortions()[nNode]; + pParaPortion->MarkSelectionInvalid( nCurrentStart, std::max< USHORT >( nCurrentStart+nLen, nCurrentStart+aNewText.Len() ) ); + + } + nCurrentStart = nCurrentEnd; + } while( nCurrentEnd < nEndPos ); + } + +#ifndef SVX_LIGHT + if ( pUndo ) + { + ESelection aESel( CreateESel( aNewSel ) ); + pUndo->SetNewSelection( aESel ); + InsertUndo( pUndo ); + } +#endif + + if ( bChanges ) + { + TextModified(); + SetModifyFlag( sal_True ); + if ( bLenChanged ) + UpdateSelections(); + FormatAndUpdate(); + } + + return aNewSel; +} + +void ImpEditEngine::SetAsianCompressionMode( USHORT n ) +{ + if ( n != nAsianCompressionMode ) + { + nAsianCompressionMode = n; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +} + +void ImpEditEngine::SetKernAsianPunctuation( BOOL b ) +{ + if ( b != bKernAsianPunctuation ) + { + bKernAsianPunctuation = b; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +} + +void ImpEditEngine::SetAddExtLeading( BOOL bExtLeading ) +{ + if ( IsAddExtLeading() != bExtLeading ) + { + bAddExtLeading = bExtLeading; + if ( ImplHasText() ) + { + FormatFullDoc(); + UpdateViews(); + } + } +}; + + + +BOOL ImpEditEngine::ImplHasText() const +{ + return ( ( GetEditDoc().Count() > 1 ) || GetEditDoc().GetObject(0)->Len() ); +} + +long ImpEditEngine::LogicToTwips( long n ) +{ + Size aSz( n, 0 ); + MapMode aTwipsMode( MAP_TWIP ); + aSz = pRefDev->LogicToLogic( aSz, NULL, &aTwipsMode ); + return aSz.Width(); +} + + diff --git a/editeng/source/editeng/impedit5.cxx b/editeng/source/editeng/impedit5.cxx new file mode 100644 index 000000000000..6d901be6e775 --- /dev/null +++ b/editeng/source/editeng/impedit5.cxx @@ -0,0 +1,914 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: impedit5.cxx,v $ + * $Revision: 1.34 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <eeng_pch.hxx> + +#include <impedit.hxx> +#include <editeng/editeng.hxx> +#include <editdbg.hxx> + +#include <svl/smplhint.hxx> + + +#include <editeng/lrspitem.hxx> + +void ImpEditEngine::SetStyleSheetPool( SfxStyleSheetPool* pSPool ) +{ + if ( pStylePool != pSPool ) + { +// if ( pStylePool ) +// EndListening( *pStylePool, TRUE ); + + pStylePool = pSPool; + +// if ( pStylePool ) +// StartListening( *pStylePool, TRUE ); + } +} + +SfxStyleSheet* ImpEditEngine::GetStyleSheet( USHORT nPara ) const +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + return pNode ? pNode->GetContentAttribs().GetStyleSheet() : NULL; +} + +void ImpEditEngine::SetStyleSheet( EditSelection aSel, SfxStyleSheet* pStyle ) +{ + aSel.Adjust( aEditDoc ); + + USHORT nStartPara = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndPara = aEditDoc.GetPos( aSel.Max().GetNode() ); + + BOOL _bUpdate = GetUpdateMode(); + SetUpdateMode( FALSE ); + + for ( USHORT n = nStartPara; n <= nEndPara; n++ ) + SetStyleSheet( n, pStyle ); + + SetUpdateMode( _bUpdate, 0 ); +} + +void ImpEditEngine::SetStyleSheet( USHORT nPara, SfxStyleSheet* pStyle ) +{ + DBG_ASSERT( GetStyleSheetPool() || !pStyle, "SetStyleSheet: No StyleSheetPool registered!" ); + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + SfxStyleSheet* pCurStyle = pNode->GetStyleSheet(); + if ( pStyle != pCurStyle ) + { + if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) + { + XubString aPrevStyleName; + if ( pCurStyle ) + aPrevStyleName = pCurStyle->GetName(); + + XubString aNewStyleName; + if ( pStyle ) + aNewStyleName = pStyle->GetName(); + + InsertUndo( + new EditUndoSetStyleSheet( this, aEditDoc.GetPos( pNode ), + aPrevStyleName, pCurStyle ? pCurStyle->GetFamily() : SFX_STYLE_FAMILY_PARA, + aNewStyleName, pStyle ? pStyle->GetFamily() : SFX_STYLE_FAMILY_PARA, + pNode->GetContentAttribs().GetItems() ) ); + } + if ( pCurStyle ) + EndListening( *pCurStyle, FALSE ); + pNode->SetStyleSheet( pStyle, aStatus.UseCharAttribs() ); + if ( pStyle ) + StartListening( *pStyle, FALSE ); + ParaAttribsChanged( pNode ); + } + FormatAndUpdate(); +} + +void ImpEditEngine::UpdateParagraphsWithStyleSheet( SfxStyleSheet* pStyle ) +{ + SvxFont aFontFromStyle; + CreateFont( aFontFromStyle, pStyle->GetItemSet() ); + + BOOL bUsed = FALSE; + for ( USHORT nNode = 0; nNode < aEditDoc.Count(); nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + if ( pNode->GetStyleSheet() == pStyle ) + { + bUsed = TRUE; + if ( aStatus.UseCharAttribs() ) + pNode->SetStyleSheet( pStyle, aFontFromStyle ); + else + pNode->SetStyleSheet( pStyle, FALSE ); + + ParaAttribsChanged( pNode ); + } + } + if ( bUsed ) + { + GetEditEnginePtr()->StyleSheetChanged( pStyle ); + FormatAndUpdate(); + } +} + +void ImpEditEngine::RemoveStyleFromParagraphs( SfxStyleSheet* pStyle ) +{ + for ( USHORT nNode = 0; nNode < aEditDoc.Count(); nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject(nNode); + if ( pNode->GetStyleSheet() == pStyle ) + { + pNode->SetStyleSheet( NULL ); + ParaAttribsChanged( pNode ); + } + } + FormatAndUpdate(); +} + +void ImpEditEngine::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + // Damit nicht beim Destruieren unnoetig formatiert wird: + if ( !bDowning ) + { + DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 ); + + SfxStyleSheet* pStyle = NULL; + ULONG nId = 0; + + if ( rHint.ISA( SfxStyleSheetHint ) ) + { + const SfxStyleSheetHint& rH = (const SfxStyleSheetHint&) rHint; + DBG_ASSERT( rH.GetStyleSheet()->ISA( SfxStyleSheet ), "Kein SfxStyleSheet!" ); + pStyle = (SfxStyleSheet*) rH.GetStyleSheet(); + nId = rH.GetHint(); + } + else if ( ( rHint.Type() == TYPE(SfxSimpleHint ) ) && ( rBC.ISA( SfxStyleSheet ) ) ) + { + pStyle = (SfxStyleSheet*)&rBC; + nId = ((SfxSimpleHint&)rHint).GetId(); + } + + if ( pStyle ) + { + if ( ( nId == SFX_HINT_DYING ) || + ( nId == SFX_STYLESHEET_INDESTRUCTION ) || + ( nId == SFX_STYLESHEET_ERASED ) ) + { + RemoveStyleFromParagraphs( pStyle ); + } + else if ( ( nId == SFX_HINT_DATACHANGED ) || + ( nId == SFX_STYLESHEET_MODIFIED ) ) + { + UpdateParagraphsWithStyleSheet( pStyle ); + + // Alle Absaetze mit EditStyles, die das geaenderte Style + // irgendwie als Parent haben, muessen formatiert werden. + // ULONG nStyles = pMyStylePool->GetStyles().Count(); + // for ( ULONG nStyle = 0; nStyle < nStyles; nStyle++ ) + // { + // EditStyleSheet* pES = (EditStyleSheet*)pMyStylePool->GetStyles().GetObject( nStyle ); + // DBG_ASSERT( pES, "NULL-Pointer im StyleSheetPool!" ); + // if ( pES->IsUsed() && pES->HasStyleAsAnyParent( *pStyle ) ) + // UpdateParagraphsWithStyleSheet( pES ); + // } + } + } + } +} + +EditUndoSetAttribs* ImpEditEngine::CreateAttribUndo( EditSelection aSel, const SfxItemSet& rSet ) +{ + DBG_ASSERT( !aSel.DbgIsBuggy( aEditDoc ), "CreateAttribUndo: Fehlerhafte Selektion" ); + aSel.Adjust( aEditDoc ); + + ESelection aESel( CreateESel( aSel ) ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + DBG_ASSERT( nStartNode <= nEndNode, "CreateAttribUndo: Start > End ?!" ); + + EditUndoSetAttribs* pUndo = NULL; + if ( rSet.GetPool() != &aEditDoc.GetItemPool() ) + { + SfxItemSet aTmpSet( GetEmptyItemSet() ); + aTmpSet.Put( rSet ); + pUndo = new EditUndoSetAttribs( this, aESel, aTmpSet ); + } + else + { + pUndo = new EditUndoSetAttribs( this, aESel, rSet ); + } + + SfxItemPool* pPool = pUndo->GetNewAttribs().GetPool(); + + for ( USHORT nPara = nStartNode; nPara <= nEndNode; nPara++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nPara ); + DBG_ASSERT( aEditDoc.SaveGetObject( nPara ), "Node nicht gefunden: CreateAttribUndo" ); + ContentAttribsInfo* pInf = new ContentAttribsInfo( pNode->GetContentAttribs().GetItems() ); + pUndo->GetContentInfos().Insert( pInf, pUndo->GetContentInfos().Count() ); + + for ( USHORT nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ ) + { + EditCharAttribPtr pAttr = pNode->GetCharAttribs().GetAttribs()[ nAttr ]; + if ( pAttr->GetLen() ) + { + EditCharAttribPtr pNew = MakeCharAttrib( *pPool, *pAttr->GetItem(), pAttr->GetStart(), pAttr->GetEnd() ); + pInf->GetPrevCharAttribs().Insert( pNew, pInf->GetPrevCharAttribs().Count() ); + } + } + } + return pUndo; +} + +void ImpEditEngine::UndoActionStart( USHORT nId, const ESelection& aSel ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), XubString(), nId ); + DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" ); + pUndoMarkSelection = new ESelection( aSel ); + } +} + +void ImpEditEngine::UndoActionStart( USHORT nId ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + GetUndoManager().EnterListAction( GetEditEnginePtr()->GetUndoComment( nId ), XubString(), nId ); + DBG_ASSERT( !pUndoMarkSelection, "UndoAction SelectionMarker?" ); + } +} + +void ImpEditEngine::UndoActionEnd( USHORT ) +{ + if ( IsUndoEnabled() && !IsInUndo() ) + { + GetUndoManager().LeaveListAction(); + delete pUndoMarkSelection; + pUndoMarkSelection = NULL; + } +} + +void ImpEditEngine::InsertUndo( EditUndo* pUndo, BOOL bTryMerge ) +{ + DBG_ASSERT( !IsInUndo(), "InsertUndo im Undomodus!" ); + if ( pUndoMarkSelection ) + { + EditUndoMarkSelection* pU = new EditUndoMarkSelection( this, *pUndoMarkSelection ); + GetUndoManager().AddUndoAction( pU, FALSE ); + delete pUndoMarkSelection; + pUndoMarkSelection = NULL; + } + GetUndoManager().AddUndoAction( pUndo, bTryMerge ); + + mbLastTryMerge = bTryMerge; +} + +void ImpEditEngine::ResetUndoManager() +{ + if ( HasUndoManager() ) + GetUndoManager().Clear(); +} + +void ImpEditEngine::EnableUndo( BOOL bEnable ) +{ + // Beim Umschalten des Modus Liste loeschen: + if ( bEnable != IsUndoEnabled() ) + ResetUndoManager(); + + bUndoEnabled = bEnable; +} + +BOOL ImpEditEngine::Undo( EditView* pView ) +{ + if ( HasUndoManager() && GetUndoManager().GetUndoActionCount() ) + { + SetActiveView( pView ); + GetUndoManager().Undo( 1 ); + return TRUE; + } + return FALSE; +} + +BOOL ImpEditEngine::Redo( EditView* pView ) +{ + if ( HasUndoManager() && GetUndoManager().GetRedoActionCount() ) + { + SetActiveView( pView ); + GetUndoManager().Redo( 0 ); + return TRUE; + } + return FALSE; +} + +BOOL ImpEditEngine::Repeat( EditView* /* pView */ ) +{ + if ( HasUndoManager() && GetUndoManager().GetRepeatActionCount() ) + { + DBG_WARNING( "Repeat nicht implementiert!" ); + return TRUE; + } + return FALSE; +} + +SfxItemSet ImpEditEngine::GetAttribs( EditSelection aSel, BOOL bOnlyHardAttrib ) +{ + DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 ); + + aSel.Adjust( aEditDoc ); + +#if OSL_DEBUG_LEVEL > 1 +// if ( ( aSel.Min().GetNode() == aSel.Max().GetNode() ) && ( bOnlyHardAttrib == EditEngineAttribs_All ) ) +// return GetAttribs( aEditDoc.GetPos( aSel.Min().GetNode() ), aSel.Min().GetIndex(), aSel.Max().GetIndex(), GETATTRIBS_ALL ); +#endif + + + SfxItemSet aCurSet( GetEmptyItemSet() ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + // ueber die Absaetze iterieren... + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: GetAttrib" ); + + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + // Problem: Vorlagen.... + // => Andersrum: + // 1) Harte Zeichenattribute, wie gehabt... + // 2) Nur wenn OFF, Style and Absatzattr. pruefen... + + // Erst die ganz harte Formatierung... + aEditDoc.FindAttribs( pNode, nStartPos, nEndPos, aCurSet ); + + if( bOnlyHardAttrib != EditEngineAttribs_OnlyHard ) + { + // Und dann Absatzformatierung und Vorlage... + // SfxStyleSheet* pStyle = pNode->GetStyleSheet(); + for ( USHORT nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++) + { + if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + if ( bOnlyHardAttrib == EditEngineAttribs_All ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich ); + aCurSet.Put( rItem ); + } + else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItems().Get( nWhich ); + aCurSet.Put( rItem ); + } + } + else if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem* pItem = NULL; + if ( bOnlyHardAttrib == EditEngineAttribs_All ) + { + pItem = &pNode->GetContentAttribs().GetItem( nWhich ); + } + else if ( pNode->GetContentAttribs().GetItems().GetItemState( nWhich ) == SFX_ITEM_ON ) + { + pItem = &pNode->GetContentAttribs().GetItems().Get( nWhich ); + } + // pItem can only be NULL when bOnlyHardAttrib... + if ( !pItem || ( *pItem != aCurSet.Get( nWhich ) ) ) + { + // Problem: Wenn Absatzvorlage mit z.B. Font, + // aber Font hart und anders und komplett in Selektion + // Falsch, wenn invalidiert.... + // => Lieber nicht invalidieren, UMSTELLEN! + // Besser waere, Absatzweise ein ItemSet zu fuellen + // und dieses mit dem gesmten vergleichen. + // aCurSet.InvalidateItem( nWhich ); + if ( nWhich <= EE_PARA_END ) + aCurSet.InvalidateItem( nWhich ); + } + } + } + } + } + + // Leere Slots mit Defaults fuellen... + if ( bOnlyHardAttrib == EditEngineAttribs_All ) + { + for ( USHORT nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + if ( aCurSet.GetItemState( nWhich ) == SFX_ITEM_OFF ) + { + aCurSet.Put( aEditDoc.GetItemPool().GetDefaultItem( nWhich ) ); + } + } + } + return aCurSet; +} + + +SfxItemSet ImpEditEngine::GetAttribs( USHORT nPara, USHORT nStart, USHORT nEnd, sal_uInt8 nFlags ) const +{ + // MT: #94002# Optimized function with less Puts(), which cause unnecessary cloning from default items. + // If this works, change GetAttribs( EditSelection ) to use this for each paragraph and merge the results! + + DBG_CHKOBJ( GetEditEnginePtr(), EditEngine, 0 ); + + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + DBG_ASSERT( pNode, "GetAttribs - unknown paragraph!" ); + DBG_ASSERT( nStart <= nEnd, "getAttribs: Start > End not supported!" ); + + SfxItemSet aAttribs( ((ImpEditEngine*)this)->GetEmptyItemSet() ); + + if ( pNode ) + { + if ( nEnd > pNode->Len() ) + nEnd = pNode->Len(); + + if ( nStart > nEnd ) + nStart = nEnd; + + // StyleSheet / Parattribs... + + if ( pNode->GetStyleSheet() && ( nFlags & GETATTRIBS_STYLESHEET ) ) + aAttribs.Set( pNode->GetStyleSheet()->GetItemSet(), TRUE ); + + if ( nFlags & GETATTRIBS_PARAATTRIBS ) + aAttribs.Put( pNode->GetContentAttribs().GetItems() ); + + // CharAttribs... + + if ( nFlags & GETATTRIBS_CHARATTRIBS ) + { + // Make testing easier... + pNode->GetCharAttribs().OptimizeRanges( ((ImpEditEngine*)this)->GetEditDoc().GetItemPool() ); + + const CharAttribArray& rAttrs = pNode->GetCharAttribs().GetAttribs(); + for ( USHORT nAttr = 0; nAttr < rAttrs.Count(); nAttr++ ) + { + EditCharAttrib* pAttr = rAttrs.GetObject( nAttr ); + + if ( nStart == nEnd ) + { + USHORT nCursorPos = nStart; + if ( ( pAttr->GetStart() <= nCursorPos ) && ( pAttr->GetEnd() >= nCursorPos ) ) + { + // To be used the attribute has to start BEFORE the position, or it must be a + // new empty attr AT the position, or we are on position 0. + if ( ( pAttr->GetStart() < nCursorPos ) || pAttr->IsEmpty() || !nCursorPos ) + { + // maybe this attrib ends here and a new attrib with 0 Len may follow and be valid here, + // but that s no problem, the empty item will come later and win. + aAttribs.Put( *pAttr->GetItem() ); + } + } + } + else + { + // Check every attribute covering the area, partial or full. + if ( ( pAttr->GetStart() < nEnd ) && ( pAttr->GetEnd() > nStart ) ) + { + if ( ( pAttr->GetStart() <= nStart ) && ( pAttr->GetEnd() >= nEnd ) ) + { + // full coverage + aAttribs.Put( *pAttr->GetItem() ); + } + else + { + // OptimizeRagnge() assures that not the same attr can follow for full coverage + // only partial, check with current, when using para/styhe, otherwise invalid. + if ( !( nFlags & (GETATTRIBS_PARAATTRIBS|GETATTRIBS_STYLESHEET) ) || + ( *pAttr->GetItem() != aAttribs.Get( pAttr->Which() ) ) ) + { + aAttribs.InvalidateItem( pAttr->Which() ); + } + } + } + } + + if ( pAttr->GetStart() > nEnd ) + { + break; + } + } + } + } + + return aAttribs; +} + + +void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, BYTE nSpecial ) +{ + aSel.Adjust( aEditDoc ); + + // Wenn keine Selektion => die Attribute aufs Wort anwenden. + // ( Der RTF-Perser sollte die Methode eigentlich nie ohne Range rufen ) + if ( ( nSpecial == ATTRSPECIAL_WHOLEWORD ) && !aSel.HasRange() ) + aSel = SelectWord( aSel, ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, FALSE ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) + { + EditUndoSetAttribs* pUndo = CreateAttribUndo( aSel, rSet ); + pUndo->SetSpecial( nSpecial ); + InsertUndo( pUndo ); + } + + BOOL bCheckLanguage = FALSE; + if ( GetStatus().DoOnlineSpelling() ) + { + bCheckLanguage = ( rSet.GetItemState( EE_CHAR_LANGUAGE ) == SFX_ITEM_ON ) || + ( rSet.GetItemState( EE_CHAR_LANGUAGE_CJK ) == SFX_ITEM_ON ) || + ( rSet.GetItemState( EE_CHAR_LANGUAGE_CTL ) == SFX_ITEM_ON ); + } + + // ueber die Absaetze iterieren... + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + BOOL bParaAttribFound = FALSE; + BOOL bCharAttribFound = FALSE; + + ContentNode* pNode = aEditDoc.GetObject( nNode ); + ParaPortion* pPortion = GetParaPortions().GetObject( nNode ); + + DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: SetAttribs" ); + DBG_ASSERT( GetParaPortions().GetObject( nNode ), "Portion nicht gefunden: SetAttribs" ); + + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + // ueber die Items iterieren... +#ifdef EDITDEBUG +// FILE* fp = fopen( "d:\\debug.log", "a" ); +// if ( fp ) +// { +// fprintf( fp, "\n\n=> Zeichen-Attribute: Absatz %i, %i-%i\n", nNode, nStartPos, nEndPos ); +// DbgOutItemSet( fp, rSet, TRUE, FALSE ); +// fclose( fp ); +// } +#endif + + for ( USHORT nWhich = EE_ITEMS_START; nWhich <= EE_CHAR_END; nWhich++) + { + if ( rSet.GetItemState( nWhich ) == SFX_ITEM_ON ) + { + const SfxPoolItem& rItem = rSet.Get( nWhich ); + if ( nWhich <= EE_PARA_END ) + { + pNode->GetContentAttribs().GetItems().Put( rItem ); + bParaAttribFound = TRUE; + } + else + { + aEditDoc.InsertAttrib( pNode, nStartPos, nEndPos, rItem ); + bCharAttribFound = TRUE; + if ( nSpecial == ATTRSPECIAL_EDGE ) + { + CharAttribArray& rAttribs = pNode->GetCharAttribs().GetAttribs(); + USHORT nAttrs = rAttribs.Count(); + for ( USHORT n = 0; n < nAttrs; n++ ) + { + EditCharAttrib* pAttr = rAttribs.GetObject( n ); + if ( pAttr->GetStart() > nEndPos ) + break; + + if ( ( pAttr->GetEnd() == nEndPos ) && ( pAttr->Which() == nWhich ) ) + { + pAttr->SetEdge( TRUE ); + break; + } + } + } + } + } + } + + if ( bParaAttribFound ) + { + ParaAttribsChanged( pPortion->GetNode() ); + } + else if ( bCharAttribFound ) + { + bFormatted = FALSE; + if ( !pNode->Len() || ( nStartPos != nEndPos ) ) + { + pPortion->MarkSelectionInvalid( nStartPos, nEndPos-nStartPos ); + if ( bCheckLanguage ) + pNode->GetWrongList()->MarkInvalid( nStartPos, nEndPos ); + } + } + } +} + +void ImpEditEngine::RemoveCharAttribs( EditSelection aSel, BOOL bRemoveParaAttribs, USHORT nWhich ) +{ + aSel.Adjust( aEditDoc ); + + USHORT nStartNode = aEditDoc.GetPos( aSel.Min().GetNode() ); + USHORT nEndNode = aEditDoc.GetPos( aSel.Max().GetNode() ); + + const SfxItemSet* _pEmptyItemSet = bRemoveParaAttribs ? &GetEmptyItemSet() : 0; + + if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) + { + // Eventuel spezielles Undo, oder ItemSet* + EditUndoSetAttribs* pUndo = CreateAttribUndo( aSel, GetEmptyItemSet() ); + pUndo->SetRemoveAttribs( TRUE ); + pUndo->SetRemoveParaAttribs( bRemoveParaAttribs ); + pUndo->SetRemoveWhich( nWhich ); + InsertUndo( pUndo ); + } + + // ueber die Absaetze iterieren... + for ( USHORT nNode = nStartNode; nNode <= nEndNode; nNode++ ) + { + ContentNode* pNode = aEditDoc.GetObject( nNode ); + ParaPortion* pPortion = GetParaPortions().GetObject( nNode ); + + DBG_ASSERT( aEditDoc.SaveGetObject( nNode ), "Node nicht gefunden: SetAttribs" ); + DBG_ASSERT( GetParaPortions().SaveGetObject( nNode ), "Portion nicht gefunden: SetAttribs" ); + + xub_StrLen nStartPos = 0; + xub_StrLen nEndPos = pNode->Len(); + if ( nNode == nStartNode ) + nStartPos = aSel.Min().GetIndex(); + if ( nNode == nEndNode ) // kann auch == nStart sein! + nEndPos = aSel.Max().GetIndex(); + + // Optimieren: Wenn ganzer Absatz, dann RemoveCharAttribs( nPara )?! + BOOL bChanged = aEditDoc.RemoveAttribs( pNode, nStartPos, nEndPos, nWhich ); + if ( bRemoveParaAttribs ) + { + SetParaAttribs( nNode, *_pEmptyItemSet ); // Invalidiert + } + else + { + // Bei 'Format-Standard' sollen auch die Zeichenattribute verschwinden, + // die von der DrawingEngine als Absatzattribute eingestellt wurden. + // Diese koennen sowieso nicht vom Anwender eingestellt worden sein. + + // #106871# Not when nWhich + // Would have been better to offer a separate method for format/standard... + if ( !nWhich ) + { + SfxItemSet aAttribs( GetParaAttribs( nNode ) ); + for ( USHORT nW = EE_CHAR_START; nW <= EE_CHAR_END; nW++ ) + aAttribs.ClearItem( nW ); + SetParaAttribs( nNode, aAttribs ); + } + } + + if ( bChanged && !bRemoveParaAttribs ) + { + bFormatted = FALSE; + pPortion->MarkSelectionInvalid( nStartPos, nEndPos-nStartPos ); + } + } +} + +typedef EditCharAttrib* EditCharAttribPtr; + +void ImpEditEngine::RemoveCharAttribs( USHORT nPara, USHORT nWhich, BOOL bRemoveFeatures ) +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + ParaPortion* pPortion = GetParaPortions().SaveGetObject( nPara ); + + DBG_ASSERT( pNode, "Node nicht gefunden: RemoveCharAttribs" ); + DBG_ASSERT( pPortion, "Portion nicht gefunden: RemoveCharAttribs" ); + + if ( !pNode ) + return; + + USHORT nAttr = 0; + EditCharAttribPtr pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + while ( pAttr ) + { + if ( ( !pAttr->IsFeature() || bRemoveFeatures ) && + ( !nWhich || ( pAttr->GetItem()->Which() == nWhich ) ) ) + { + pNode->GetCharAttribs().GetAttribs().Remove( nAttr ); + delete pAttr; + nAttr--; + } + nAttr++; + pAttr = GetAttrib( pNode->GetCharAttribs().GetAttribs(), nAttr ); + } + + pPortion->MarkSelectionInvalid( 0, pNode->Len() ); +} + +void ImpEditEngine::SetParaAttribs( USHORT nPara, const SfxItemSet& rSet ) +{ + ContentNode* pNode = aEditDoc.SaveGetObject( nPara ); + + if ( !pNode ) + return; + +#ifdef EDITDEBUG +// FILE* fp = fopen( "d:\\debug.log", "a" ); +// if ( fp ) +// { +// fprintf( fp, "\n\n=> Absatz-Attribute: Absatz %i\n", nPara ); +// DbgOutItemSet( fp, rSet, TRUE, FALSE ); +// fclose( fp ); +// } +#endif + + if ( !( pNode->GetContentAttribs().GetItems() == rSet ) ) + { + if ( IsUndoEnabled() && !IsInUndo() && aStatus.DoUndoAttribs() ) + { + if ( rSet.GetPool() != &aEditDoc.GetItemPool() ) + { + SfxItemSet aTmpSet( GetEmptyItemSet() ); + aTmpSet.Put( rSet ); + InsertUndo( new EditUndoSetParaAttribs( this, nPara, pNode->GetContentAttribs().GetItems(), aTmpSet ) ); + } + else + { + InsertUndo( new EditUndoSetParaAttribs( this, nPara, pNode->GetContentAttribs().GetItems(), rSet ) ); + } + } + pNode->GetContentAttribs().GetItems().Set( rSet ); + if ( aStatus.UseCharAttribs() ) + pNode->CreateDefFont(); + + ParaAttribsChanged( pNode ); + } +} + +const SfxItemSet& ImpEditEngine::GetParaAttribs( USHORT nPara ) const +{ + ContentNode* pNode = aEditDoc.GetObject( nPara ); + DBG_ASSERT( pNode, "Node nicht gefunden: GetParaAttribs" ); + return pNode->GetContentAttribs().GetItems(); +} + +BOOL ImpEditEngine::HasParaAttrib( USHORT nPara, USHORT nWhich ) const +{ + ContentNode* pNode = aEditDoc.GetObject( nPara ); + DBG_ASSERT( pNode, "Node nicht gefunden: HasParaAttrib" ); + + return pNode->GetContentAttribs().HasItem( nWhich ); +} + +const SfxPoolItem& ImpEditEngine::GetParaAttrib( USHORT nPara, USHORT nWhich ) const +{ + ContentNode* pNode = aEditDoc.GetObject( nPara ); + DBG_ASSERT( pNode, "Node nicht gefunden: GetParaAttrib" ); + + return pNode->GetContentAttribs().GetItem( nWhich ); +} + +void ImpEditEngine::GetCharAttribs( USHORT nPara, EECharAttribArray& rLst ) const +{ + rLst.Remove( 0, rLst.Count() ); + ContentNode* pNode = aEditDoc.GetObject( nPara ); + if ( pNode ) + { + for ( USHORT nAttr = 0; nAttr < pNode->GetCharAttribs().Count(); nAttr++ ) + { + EditCharAttribPtr pAttr = pNode->GetCharAttribs().GetAttribs()[ nAttr ]; + EECharAttrib aEEAttr; + aEEAttr.pAttr = pAttr->GetItem(); + aEEAttr.nPara = nPara; + aEEAttr.nStart = pAttr->GetStart(); + aEEAttr.nEnd = pAttr->GetEnd(); + rLst.Insert( aEEAttr, rLst.Count() ); + } + } +} + +void ImpEditEngine::ParaAttribsToCharAttribs( ContentNode* pNode ) +{ + pNode->GetCharAttribs().DeleteEmptyAttribs( GetEditDoc().GetItemPool() ); + xub_StrLen nEndPos = pNode->Len(); + for ( USHORT nWhich = EE_CHAR_START; nWhich <= EE_CHAR_END; nWhich++ ) + { + if ( pNode->GetContentAttribs().HasItem( nWhich ) ) + { + const SfxPoolItem& rItem = pNode->GetContentAttribs().GetItem( nWhich ); + // Die Luecken auffuellen: + USHORT nLastEnd = 0; + EditCharAttrib* pAttr = pNode->GetCharAttribs().FindNextAttrib( nWhich, nLastEnd ); + while ( pAttr ) + { + nLastEnd = pAttr->GetEnd(); + if ( pAttr->GetStart() > nLastEnd ) + aEditDoc.InsertAttrib( pNode, nLastEnd, pAttr->GetStart(), rItem ); + // #112831# Last Attr might go from 0xffff to 0x0000 + pAttr = nLastEnd ? pNode->GetCharAttribs().FindNextAttrib( nWhich, nLastEnd ) : NULL; + } + + // Und den Rest: + if ( nLastEnd < nEndPos ) + aEditDoc.InsertAttrib( pNode, nLastEnd, nEndPos, rItem ); + } + } + bFormatted = FALSE; + // Portion braucht hier nicht invalidiert werden, geschieht woanders. +} + +IdleFormattter::IdleFormattter() +{ + pView = 0; + nRestarts = 0; +} + +IdleFormattter::~IdleFormattter() +{ + pView = 0; +} + +void IdleFormattter::DoIdleFormat( EditView* pV ) +{ + pView = pV; + + if ( IsActive() ) + nRestarts++; + + if ( nRestarts > 4 ) + ForceTimeout(); + else + Start(); +} + +void IdleFormattter::ForceTimeout() +{ + if ( IsActive() ) + { + Stop(); + ((Link&)GetTimeoutHdl()).Call( this ); + } +} + +ImplIMEInfos::ImplIMEInfos( const EditPaM& rPos, const String& rOldTextAfterStartPos ) + : aOldTextAfterStartPos( rOldTextAfterStartPos ) +{ + aPos = rPos; + nLen = 0; + bCursor = TRUE; + pAttribs = NULL; + bWasCursorOverwrite = FALSE; +} + +ImplIMEInfos::~ImplIMEInfos() +{ + delete[] pAttribs; +} + +void ImplIMEInfos::CopyAttribs( const USHORT* pA, USHORT nL ) +{ + nLen = nL; + delete pAttribs; + pAttribs = new USHORT[ nL ]; + memcpy( pAttribs, pA, nL*sizeof(USHORT) ); +} + +void ImplIMEInfos::DestroyAttribs() +{ + delete[] pAttribs; + pAttribs = NULL; + nLen = 0; +} diff --git a/editeng/source/editeng/makefile.mk b/editeng/source/editeng/makefile.mk new file mode 100644 index 000000000000..83ce10567c67 --- /dev/null +++ b/editeng/source/editeng/makefile.mk @@ -0,0 +1,84 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.18 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/.. + +PRJNAME=editeng +TARGET=editeng +AUTOSEG=true + +#PROJECTPCH4DLL=TRUE +#PROJECTPCH=eeng_pch +#PROJECTPCHSOURCE=eeng_pch + +ENABLE_EXCEPTIONS=TRUE + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Allgemein ---------------------------------------------------------- + +.IF "$(editdebug)" != "" || "$(EDITDEBUG)" != "" +CDEFS+=-DEDITDEBUG +.ENDIF + +SLOFILES = \ + $(SLO)$/textconv.obj \ + $(SLO)$/editattr.obj \ + $(SLO)$/editdbg.obj \ + $(SLO)$/editdoc.obj \ + $(SLO)$/editdoc2.obj \ + $(SLO)$/editeng.obj \ + $(SLO)$/editobj.obj \ + $(SLO)$/editsel.obj \ + $(SLO)$/editundo.obj \ + $(SLO)$/editview.obj \ + $(SLO)$/edtspell.obj \ + $(SLO)$/eehtml.obj \ + $(SLO)$/eerdll.obj \ + $(SLO)$/eeobj.obj \ + $(SLO)$/eertfpar.obj \ + $(SLO)$/impedit.obj \ + $(SLO)$/impedit2.obj \ + $(SLO)$/impedit3.obj \ + $(SLO)$/impedit4.obj \ + $(SLO)$/impedit5.obj + +SRS1NAME=$(TARGET) +SRC1FILES= editeng.src + +EXCEPTIONSFILES= \ + $(SLO)$/unolingu.obj + +.INCLUDE : target.mk + diff --git a/editeng/source/editeng/textconv.cxx b/editeng/source/editeng/textconv.cxx new file mode 100644 index 000000000000..e7d10a6d6650 --- /dev/null +++ b/editeng/source/editeng/textconv.cxx @@ -0,0 +1,632 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textconv.cxx,v $ + * $Revision: 1.14 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <vcl/wrkwin.hxx> +#include <vcl/dialog.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/svapp.hxx> + +#include <impedit.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> +#include <editeng/unolingu.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <editeng/langitem.hxx> +#include <editeng/fontitem.hxx> +#include <textconv.hxx> + + +using ::rtl::OUString; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::linguistic2; + +#define C2U(cChar) OUString::createFromAscii(cChar) + +////////////////////////////////////////////////////////////////////// + +TextConvWrapper::TextConvWrapper( Window* pWindow, + const Reference< XMultiServiceFactory >& rxMSF, + const Locale& rSourceLocale, + const Locale& rTargetLocale, + const Font* pTargetFont, + sal_Int32 nOptions, + sal_Bool bIsInteractive, + BOOL bIsStart, + EditView* pView ) : + HangulHanjaConversion( pWindow, rxMSF, rSourceLocale, rTargetLocale, pTargetFont, nOptions, bIsInteractive ) +{ + DBG_ASSERT( pWindow, "TextConvWrapper: window missing" ); + + nConvTextLang = LANGUAGE_NONE; + nUnitOffset = 0; + + bStartChk = sal_False; + bStartDone = bIsStart; + bEndDone = sal_False; + pWin = pWindow; + pEditView = pView; + + aConvSel = pEditView->GetSelection(); + aConvSel.Adjust(); // make Start <= End + + bAllowChange = sal_False; +} + + +TextConvWrapper::~TextConvWrapper() +{ +} + + +sal_Bool TextConvWrapper::ConvNext_impl() +{ + // modified version of SvxSpellWrapper::SpellNext + + if( bStartChk ) + bStartDone = sal_True; + else + bEndDone = sal_True; + + if ( bStartDone && bEndDone ) + { + if ( ConvMore_impl() ) // ein weiteres Dokument pruefen? + { + bStartDone = sal_True; + bEndDone = sal_False; + ConvStart_impl( SVX_SPELL_BODY ); + return sal_True; + } + return sal_False; + + } + + //ResMgr* pMgr = DIALOG_MGR(); + sal_Bool bGoOn = sal_False; + + if ( bStartDone && bEndDone ) + { + if ( ConvMore_impl() ) // ein weiteres Dokument pruefen? + { + bStartDone = sal_True; + bEndDone = sal_False; + ConvStart_impl( SVX_SPELL_BODY ); + return sal_True; + } + } + else + { + // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich +/* + pWin->LeaveWait(); + + sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE; + QueryBox aBox( pWin, ResId( nResId, pMgr ) ); + if ( aBox.Execute() != RET_YES ) + { + // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich + pWin->EnterWait(); + bStartDone = bEndDone = sal_True; + return ConvNext_impl(); + } + else + { +*/ + if (!aConvSel.HasRange()) + { + bStartChk = !bStartDone; + ConvStart_impl( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END ); + bGoOn = sal_True; + } +/* + } + pWin->EnterWait(); +*/ + } + return bGoOn; +} + + +sal_Bool TextConvWrapper::FindConvText_impl() +{ + // modified version of SvxSpellWrapper::FindSpellError + + //ShowLanguageErrors(); + + sal_Bool bFound = sal_False; + + pWin->EnterWait(); + sal_Bool bConvert = sal_True; + + while ( bConvert ) + { + bFound = ConvContinue_impl(); + if (bFound) + { + bConvert = sal_False; + } + else + { + ConvEnd_impl(); + bConvert = ConvNext_impl(); + } + } + pWin->LeaveWait(); + return bFound; +} + + +sal_Bool TextConvWrapper::ConvMore_impl() +{ + // modified version of SvxSpellWrapper::SpellMore + + sal_Bool bMore = sal_False; + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + ConvInfo* pConvInfo = pImpEE->GetConvInfo(); + if ( pConvInfo->bMultipleDoc ) + { + bMore = pImpEE->GetEditEnginePtr()->ConvertNextDocument(); + if ( bMore ) + { + // Der Text wurde in diese Engine getreten... + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetStartPaM() ); + } + } + return bMore; +} + + +void TextConvWrapper::ConvStart_impl( SvxSpellArea eArea ) +{ + // modified version of EditSpellWrapper::SpellStart + + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + ConvInfo* pConvInfo = pImpEE->GetConvInfo(); + + if ( eArea == SVX_SPELL_BODY_START ) + { + // Wird gerufen, wenn Spell-Forwad am Ende angekomment ist + // und soll von vorne beginnen + if ( bEndDone ) + { + pConvInfo->bConvToEnd = sal_False; + pConvInfo->aConvTo = pConvInfo->aConvStart; + pConvInfo->aConvContinue = EPaM( 0, 0 ); + pEditView->GetImpEditView()->SetEditSelection( + pImpEE->GetEditDoc().GetStartPaM() ); + } + else + { + pConvInfo->bConvToEnd = sal_True; + pConvInfo->aConvTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetStartPaM() ); + } + } + else if ( eArea == SVX_SPELL_BODY_END ) + { + // Wird gerufen, wenn Spell-Forwad gestartet wird + pConvInfo->bConvToEnd = sal_True; + if (aConvSel.HasRange()) + { + // user selection: convert to end of selection + pConvInfo->aConvTo.nPara = aConvSel.nEndPara; + pConvInfo->aConvTo.nIndex = aConvSel.nEndPos; + pConvInfo->bConvToEnd = sal_False; + } + else + { + // nothing selected: convert to end of document + pConvInfo->aConvTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetEndPaM() ); + } + } + else if ( eArea == SVX_SPELL_BODY ) + { + // called by ConvNext_impl... + pConvInfo->aConvContinue = pConvInfo->aConvStart; + pConvInfo->aConvTo = pImpEE->CreateEPaM( + pImpEE->GetEditDoc().GetEndPaM() ); + // pSpellInfo->bSpellToEnd = sal_True; + } + else + { + DBG_ERROR( "ConvStart_impl: Unknown Area!" ); + } +} + + +void TextConvWrapper::ConvEnd_impl() +{ +} + + +sal_Bool TextConvWrapper::ConvContinue_impl() +{ + // modified version of EditSpellWrapper::SpellContinue + + // get next convertible text portion and its language + aConvText = rtl::OUString(); + nConvTextLang = LANGUAGE_NONE; + pEditView->GetImpEditEngine()->ImpConvert( aConvText, nConvTextLang, + pEditView, GetSourceLanguage(), aConvSel, + bAllowChange, GetTargetLanguage(), GetTargetFont() ); + return aConvText.getLength() != 0; +} + + +void TextConvWrapper::SetLanguageAndFont( const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ) +{ + ESelection aOldSel = pEditView->GetSelection(); + pEditView->SetSelection( rESel ); + + // set new language attribute + SfxItemSet aNewSet( pEditView->GetEmptyItemSet() ); + aNewSet.Put( SvxLanguageItem( nLang, nLangWhichId ) ); + + // new font to be set? + DBG_ASSERT( pFont, "target font missing?" ); + if (pFont) + { + // set new font attribute + SvxFontItem aFontItem = (SvxFontItem&) aNewSet.Get( nFontWhichId ); + aFontItem.GetFamilyName() = pFont->GetName(); + aFontItem.GetFamily() = pFont->GetFamily(); + aFontItem.GetStyleName() = pFont->GetStyleName(); + aFontItem.GetPitch() = pFont->GetPitch(); + aFontItem.GetCharSet() = pFont->GetCharSet(); + aNewSet.Put( aFontItem ); + } + + // apply new attributes + pEditView->SetAttribs( aNewSet ); + + pEditView->SetSelection( aOldSel ); +} + + +void TextConvWrapper::SelectNewUnit_impl( + const sal_Int32 nUnitStart, + const sal_Int32 nUnitEnd ) +{ + BOOL bOK = 0 <= nUnitStart && 0 <= nUnitEnd && nUnitStart <= nUnitEnd; + DBG_ASSERT( bOK, "invalid arguments" ); + if (!bOK) + return; + + ESelection aSelection = pEditView->GetSelection(); + DBG_ASSERT( aSelection.nStartPara == aSelection.nEndPara, + "paragraph mismatch in selection" ); + aSelection.nStartPos = (USHORT) (nLastPos + nUnitOffset + nUnitStart); + aSelection.nEndPos = (USHORT) (nLastPos + nUnitOffset + nUnitEnd); + pEditView->SetSelection( aSelection ); +} + + +void TextConvWrapper::GetNextPortion( + ::rtl::OUString& /* [out] */ rNextPortion, + LanguageType& /* [out] */ rLangOfPortion, + sal_Bool /* [in] */ _bAllowImplicitChangesForNotConvertibleText ) +{ + bAllowChange = _bAllowImplicitChangesForNotConvertibleText; + + FindConvText_impl(); + rNextPortion = aConvText; + rLangOfPortion = nConvTextLang; + nUnitOffset = 0; + + ESelection aSelection = pEditView->GetSelection(); + DBG_ASSERT( aSelection.nStartPara == aSelection.nEndPara, + "paragraph mismatch in selection" ); + DBG_ASSERT( aSelection.nStartPos <= aSelection.nEndPos, + "start pos > end pos" ); + nLastPos = aSelection.nStartPos; +} + + +void TextConvWrapper::HandleNewUnit( + const sal_Int32 nUnitStart, + const sal_Int32 nUnitEnd ) +{ + SelectNewUnit_impl( nUnitStart, nUnitEnd ); +} + + +void TextConvWrapper::ReplaceUnit( + const sal_Int32 nUnitStart, const sal_Int32 nUnitEnd, + const ::rtl::OUString& rOrigText, + const ::rtl::OUString& rReplaceWith, + const ::com::sun::star::uno::Sequence< sal_Int32 > &rOffsets, + ReplacementAction eAction, + LanguageType *pNewUnitLanguage ) +{ + BOOL bOK = 0 <= nUnitStart && 0 <= nUnitEnd && nUnitStart <= nUnitEnd; + DBG_ASSERT( bOK, "invalid arguments" ); + if (!bOK) + return; + + static OUString aBracketedStart( C2U( "(" ) ); + static OUString aBracketedEnd( C2U( ")" ) ); + + // select current unit + SelectNewUnit_impl( nUnitStart, nUnitEnd ); + + OUString aOrigTxt( pEditView->GetSelected() ); + OUString aNewTxt( rReplaceWith ); + String aNewOrigText; + switch (eAction) + { + case eExchange : + break; + case eReplacementBracketed : + (((aNewTxt = aOrigTxt) += aBracketedStart) += rReplaceWith) += aBracketedEnd; + break; + case eOriginalBracketed : + (((aNewTxt = rReplaceWith) += aBracketedStart) += aOrigTxt) += aBracketedEnd; + break; + case eReplacementAbove : + case eOriginalAbove : + case eReplacementBelow : + case eOriginalBelow : + DBG_ERROR( "Rubies not supported" ); + break; + default: + DBG_ERROR( "unexpected case" ); + } + nUnitOffset = sal::static_int_cast< USHORT >( + nUnitOffset + nUnitStart + aNewTxt.getLength()); + + // remember current original language for kater use + ImpEditEngine *pImpEditEng = pEditView->GetImpEditEngine(); + ESelection _aOldSel = pEditView->GetSelection(); + //EditSelection aOldEditSel = pEditView->GetImpEditView()->GetEditSelection(); + +#ifdef DBG_UTIL + LanguageType nOldLang = pImpEditEng->GetLanguage( pImpEditEng->CreateSel( _aOldSel ).Min() ); +#endif + + pImpEditEng->UndoActionStart( EDITUNDO_INSERT ); + + // according to FT we should currently not bother about keeping + // attributes in Hangul/Hanja conversion and leave that untouched. + // Thus we do this only for Chinese translation... + sal_Bool bIsChineseConversion = IsChinese( GetSourceLanguage() ); + if (bIsChineseConversion) + ChangeText( aNewTxt, rOrigText, &rOffsets, &_aOldSel ); + else + ChangeText( aNewTxt, rOrigText, NULL, NULL ); + + // change language and font if necessary + if (bIsChineseConversion) + { + DBG_ASSERT( GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED || GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL, + "TextConvWrapper::ReplaceUnit : unexpected target language" ); + + ESelection aOldSel = pEditView->GetSelection(); + ESelection aNewSel( aOldSel ); + aNewSel.nStartPos = sal::static_int_cast< xub_StrLen >( + aNewSel.nStartPos - aNewTxt.getLength()); +// DBG_ASSERT( aOldSel.nEndPos >= 0, "error while building selection" ); + + if (pNewUnitLanguage) + { + DBG_ASSERT(!IsSimilarChinese( *pNewUnitLanguage, nOldLang ), + "similar language should not be changed!"); + SetLanguageAndFont( aNewSel, *pNewUnitLanguage, EE_CHAR_LANGUAGE_CJK, + GetTargetFont(), EE_CHAR_FONTINFO_CJK ); + } + } + + pImpEditEng->UndoActionEnd( EDITUNDO_INSERT ); + + // adjust ConvContinue / ConvTo if necessary + ImpEditEngine* pImpEE = pEditView->GetImpEditEngine(); + ConvInfo* pConvInfo = pImpEE->GetConvInfo(); + sal_Int32 nDelta = aNewTxt.getLength() - aOrigTxt.getLength(); + if (nDelta != 0) + { + // Note: replacement is always done in the current paragraph + // which is the one ConvContinue points to + pConvInfo->aConvContinue.nIndex = sal::static_int_cast< USHORT >( + pConvInfo->aConvContinue.nIndex + nDelta); + + // if that is the same as the one where the conversions ends + // the end needs to be updated also + if (pConvInfo->aConvTo.nPara == pConvInfo->aConvContinue.nPara) + pConvInfo->aConvTo.nIndex = sal::static_int_cast< USHORT >( + pConvInfo->aConvTo.nIndex + nDelta); + } +} + + +void TextConvWrapper::ChangeText( const String &rNewText, + const OUString& rOrigText, + const uno::Sequence< sal_Int32 > *pOffsets, + ESelection *pESelection ) +{ + //!! code is a modifed copy of SwHHCWrapper::ChangeText from sw !! + + DBG_ASSERT( rNewText.Len() != 0, "unexpected empty string" ); + if (rNewText.Len() == 0) + return; + + if (pOffsets && pESelection) // try to keep as much attributation as possible ? + { + pESelection->Adjust(); + + // remember cursor start position for later setting of the cursor + const xub_StrLen nStartIndex = pESelection->nStartPos; + + const sal_Int32 nIndices = pOffsets->getLength(); + const sal_Int32 *pIndices = pOffsets->getConstArray(); + xub_StrLen nConvTextLen = rNewText.Len(); + xub_StrLen nPos = 0; + xub_StrLen nChgPos = STRING_NOTFOUND; + xub_StrLen nChgLen = 0; + xub_StrLen nConvChgPos = STRING_NOTFOUND; + xub_StrLen nConvChgLen = 0; + + // offset to calculate the position in the text taking into + // account that text may have been replaced with new text of + // different length. Negative values allowed! + long nCorrectionOffset = 0; + + DBG_ASSERT(nIndices == 0 || nIndices == nConvTextLen, + "mismatch between string length and sequence length!" ); + + // find all substrings that need to be replaced (and only those) + while (sal_True) + { + // get index in original text that matches nPos in new text + xub_StrLen nIndex; + if (nPos < nConvTextLen) + nIndex = (sal_Int32) nPos < nIndices ? (xub_StrLen) pIndices[nPos] : nPos; + else + { + nPos = nConvTextLen; + nIndex = static_cast< xub_StrLen >( rOrigText.getLength() ); + } + + if (rOrigText.getStr()[nIndex] == rNewText.GetChar(nPos) || + nPos == nConvTextLen /* end of string also terminates non-matching char sequence */) + { + // substring that needs to be replaced found? + if (nChgPos != STRING_NOTFOUND && nConvChgPos != STRING_NOTFOUND) + { + nChgLen = nIndex - nChgPos; + nConvChgLen = nPos - nConvChgPos; +#ifdef DEBUG + String aInOrig( rOrigText.copy( nChgPos, nChgLen ) ); +#endif + String aInNew( rNewText.Copy( nConvChgPos, nConvChgLen ) ); + + // set selection to sub string to be replaced in original text + ESelection aSel( *pESelection ); + xub_StrLen nChgInNodeStartIndex = static_cast< xub_StrLen >( nStartIndex + nCorrectionOffset + nChgPos ); + aSel.nStartPos = nChgInNodeStartIndex; + aSel.nEndPos = nChgInNodeStartIndex + nChgLen; + pEditView->SetSelection( aSel ); +#ifdef DEBUG + String aSelTxt1( pEditView->GetSelected() ); +#endif + + // replace selected sub string with the corresponding + // sub string from the new text while keeping as + // much from the attributes as possible + ChangeText_impl( aInNew, sal_True ); + + nCorrectionOffset += nConvChgLen - nChgLen; + + nChgPos = STRING_NOTFOUND; + nConvChgPos = STRING_NOTFOUND; + } + } + else + { + // begin of non-matching char sequence found ? + if (nChgPos == STRING_NOTFOUND && nConvChgPos == STRING_NOTFOUND) + { + nChgPos = nIndex; + nConvChgPos = nPos; + } + } + if (nPos >= nConvTextLen) + break; + ++nPos; + } + + // set cursor to the end of the inserted text + // (as it would happen after ChangeText_impl (Delete and Insert) + // of the whole text in the 'else' branch below) + pESelection->nStartPos = pESelection->nEndPos = nStartIndex + nConvTextLen; + } + else + { + ChangeText_impl( rNewText, sal_False ); + } +} + + +void TextConvWrapper::ChangeText_impl( const String &rNewText, sal_Bool bKeepAttributes ) +{ + if (bKeepAttributes) + { + // save attributes to be restored + SfxItemSet aSet( pEditView->GetAttribs() ); + +#ifdef DEBUG + String aSelTxt1( pEditView->GetSelected() ); +#endif + // replace old text and select new text + pEditView->InsertText( rNewText, sal_True ); +#ifdef DEBUG + String aSelTxt2( pEditView->GetSelected() ); +#endif + + // since 'SetAttribs' below function like merging with the attributes + // from the itemset with any existing ones we have to get rid of all + // all attributes now. (Those attributes that may take effect left + // to the position where the new text gets inserted after the old text + // was deleted) + pEditView->RemoveAttribs(); + // apply saved attributes to new inserted text + pEditView->SetAttribs( aSet ); + } + else + { + pEditView->InsertText( rNewText ); + } +} + + +void TextConvWrapper::Convert() +{ + bStartChk = sal_False; + ConvStart_impl( SVX_SPELL_BODY_END ); + ConvertDocument(); + ConvEnd_impl(); +} + + +sal_Bool TextConvWrapper::HasRubySupport() const +{ + return sal_False; +} + +////////////////////////////////////////////////////////////////////// + diff --git a/editeng/source/editeng/textconv.hxx b/editeng/source/editeng/textconv.hxx new file mode 100644 index 000000000000..aec6116a9680 --- /dev/null +++ b/editeng/source/editeng/textconv.hxx @@ -0,0 +1,125 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textconv.hxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _TEXTCONV_HXX +#define _TEXTCONV_HXX + +#include <editeng/splwrap.hxx> +#include <editeng/svxacorr.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Sequence.hxx> +#include <editeng/hangulhanja.hxx> + +class EditView; +class ImpEditEngine; +class ContentNode; + +class TextConvWrapper : public editeng::HangulHanjaConversion +{ + rtl::OUString aConvText; // convertible text part found last time + LanguageType nConvTextLang; // language of aConvText + USHORT nLastPos; // starting position of the last found text portion (word) + USHORT nUnitOffset; // offset of current unit in the current text portion (word) + + ESelection aConvSel; // selection to be converted if + // 'HasRange' is true, other conversion + // starts from the cursor position + + EditView * pEditView; + Window * pWin; + + sal_Bool bStartChk; + sal_Bool bStartDone; + sal_Bool bEndDone; + sal_Bool bAllowChange; // storage for _bAllowImplicitChangesForNotConvertibleText + // paramters value of function GetNextPortion. + // used to transport the value to where it is needed. + + + // from SvxSpellWrapper copied and modified + sal_Bool ConvNext_impl(); // former SpellNext + sal_Bool FindConvText_impl(); // former FindSpellError + sal_Bool ConvMore_impl(); // former SpellMore + + // from EditSpellWrapper copied and modified + void ConvStart_impl( SvxSpellArea eSpell ); // former SpellStart + void ConvEnd_impl(); // former SpellEnd + sal_Bool ConvContinue_impl(); // former SpellContinue + + void SelectNewUnit_impl( const sal_Int32 nUnitStart, + const sal_Int32 nUnitEnd ); + + void ChangeText( const String &rNewText, + const ::rtl::OUString& rOrigText, + const ::com::sun::star::uno::Sequence< sal_Int32 > *pOffsets, + ESelection *pESelection ); + void ChangeText_impl( const String &rNewText, sal_Bool bKeepAttributes ); + + // Forbidden and not implemented. + TextConvWrapper (const TextConvWrapper &); + TextConvWrapper & operator= (const TextConvWrapper &); + +protected: + virtual void GetNextPortion( ::rtl::OUString& /* [out] */ rNextPortion, + LanguageType& /* [out] */ rLangOfPortion, + sal_Bool /* [in] */ _bAllowImplicitChangesForNotConvertibleText ); + virtual void HandleNewUnit( const sal_Int32 nUnitStart, + const sal_Int32 nUnitEnd ); + virtual void ReplaceUnit( + const sal_Int32 nUnitStart, const sal_Int32 nUnitEnd, + const ::rtl::OUString& rOrigText, + const ::rtl::OUString& rReplaceWith, + const ::com::sun::star::uno::Sequence< sal_Int32 > &rOffsets, + ReplacementAction eAction, + LanguageType *pNewUnitLanguage ); + + virtual sal_Bool HasRubySupport() const; + + void SetLanguageAndFont( const ESelection &rESel, + LanguageType nLang, USHORT nLangWhichId, + const Font *pFont, USHORT nFontWhichId ); + + +public: + TextConvWrapper( Window* pWindow, + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& rxMSF, + const ::com::sun::star::lang::Locale& rSourceLocale, + const ::com::sun::star::lang::Locale& rTargetLocale, + const Font* pTargetFont, + INT32 nOptions, + sal_Bool bIsInteractive, + BOOL bIsStart, EditView* pView ); + + virtual ~TextConvWrapper(); + + void Convert(); +}; + +#endif + diff --git a/editeng/source/items/bulitem.cxx b/editeng/source/items/bulitem.cxx new file mode 100644 index 000000000000..d4b4beaa24b3 --- /dev/null +++ b/editeng/source/items/bulitem.cxx @@ -0,0 +1,537 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: bulitem.cxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +// include --------------------------------------------------------------- +#include <tools/stream.hxx> +#include <vcl/outdev.hxx> + +#define _SVX_BULITEM_CXX + +#include <editeng/bulitem.hxx> +#include <editeng/editrids.hrc> + +// #90477# +#include <tools/tenccvt.hxx> + +#define BULITEM_VERSION ((USHORT)2) + +// ----------------------------------------------------------------------- + +TYPEINIT1(SvxBulletItem,SfxPoolItem); + +// ----------------------------------------------------------------------- + +void SvxBulletItem::StoreFont( SvStream& rStream, const Font& rFont ) +{ + USHORT nTemp; + + rStream << rFont.GetColor(); + nTemp = (USHORT)rFont.GetFamily(); rStream << nTemp; + + // #90477# nTemp = (USHORT)GetStoreCharSet( rFont.GetCharSet(), rStream.GetVersion() ); + nTemp = (USHORT)GetSOStoreTextEncoding((rtl_TextEncoding)rFont.GetCharSet(), (sal_uInt16)rStream.GetVersion()); + rStream << nTemp; + + nTemp = (USHORT)rFont.GetPitch(); rStream << nTemp; + nTemp = (USHORT)rFont.GetAlign(); rStream << nTemp; + nTemp = (USHORT)rFont.GetWeight(); rStream << nTemp; + nTemp = (USHORT)rFont.GetUnderline(); rStream << nTemp; + nTemp = (USHORT)rFont.GetStrikeout(); rStream << nTemp; + nTemp = (USHORT)rFont.GetItalic(); rStream << nTemp; + + // UNICODE: rStream << rFont.GetName(); + rStream.WriteByteString(rFont.GetName()); + + rStream << rFont.IsOutline(); + rStream << rFont.IsShadow(); + rStream << rFont.IsTransparent(); +} + +// ----------------------------------------------------------------------- + +Font SvxBulletItem::CreateFont( SvStream& rStream, USHORT nVer ) +{ + Font aFont; + Color aColor; + rStream >> aColor; aFont.SetColor( aColor ); + USHORT nTemp; + rStream >> nTemp; aFont.SetFamily((FontFamily)nTemp); + + // #90477# + rStream >> nTemp; + nTemp = (sal_uInt16)GetSOLoadTextEncoding((rtl_TextEncoding)nTemp, (sal_uInt16)rStream.GetVersion()); + aFont.SetCharSet((rtl_TextEncoding)nTemp); + + rStream >> nTemp; aFont.SetPitch((FontPitch)nTemp); + rStream >> nTemp; aFont.SetAlign((FontAlign)nTemp); + rStream >> nTemp; aFont.SetWeight((FontWeight)nTemp); + rStream >> nTemp; aFont.SetUnderline((FontUnderline)nTemp); + rStream >> nTemp; aFont.SetStrikeout((FontStrikeout)nTemp); + rStream >> nTemp; aFont.SetItalic((FontItalic)nTemp); + + // UNICODE: rStream >> aName; aFont.SetName( aName ); + String aName; + rStream.ReadByteString(aName); + aFont.SetName( aName ); + + if( nVer == 1 ) + { + long nHeight, nWidth; + rStream >> nHeight; rStream >> nWidth; Size aSize( nWidth, nHeight ); + aFont.SetSize( aSize ); + } + + BOOL bTemp; + rStream >> bTemp; aFont.SetOutline( bTemp ); + rStream >> bTemp; aFont.SetShadow( bTemp ); + rStream >> bTemp; aFont.SetTransparent( bTemp ); + return aFont; +} + + +// ----------------------------------------------------------------------- + +SvxBulletItem::SvxBulletItem( USHORT _nWhich ) : SfxPoolItem( _nWhich ) +{ + SetDefaultFont_Impl(); + SetDefaults_Impl(); + nValidMask = 0xFFFF; +} + +// ----------------------------------------------------------------------- + +SvxBulletItem::SvxBulletItem( BYTE nNewStyle, const Font& rFont, USHORT /*nStart*/, USHORT _nWhich ) : SfxPoolItem( _nWhich ) +{ + SetDefaults_Impl(); + nStyle = nNewStyle; + aFont = rFont; + nValidMask = 0xFFFF; +} + +// ----------------------------------------------------------------------- + +SvxBulletItem::SvxBulletItem( const Font& rFont, xub_Unicode cSymb, USHORT _nWhich ) : SfxPoolItem( _nWhich ) +{ + SetDefaults_Impl(); + aFont = rFont; + cSymbol = cSymb; + nStyle = BS_BULLET; + nValidMask = 0xFFFF; +} + +// ----------------------------------------------------------------------- + +SvxBulletItem::SvxBulletItem( const Bitmap& rBmp, USHORT _nWhich ) : SfxPoolItem( _nWhich ) +{ + SetDefaults_Impl(); + + if( !rBmp.IsEmpty() ) + { + pGraphicObject = new GraphicObject( rBmp ); + nStyle = BS_BMP; + } + + nValidMask = 0xFFFF; +} + +// ----------------------------------------------------------------------- + +SvxBulletItem::SvxBulletItem( const GraphicObject& rGraphicObject, USHORT _nWhich ) : SfxPoolItem( _nWhich ) +{ + SetDefaults_Impl(); + + if( ( GRAPHIC_NONE != pGraphicObject->GetType() ) && ( GRAPHIC_DEFAULT != pGraphicObject->GetType() ) ) + { + pGraphicObject = new GraphicObject( rGraphicObject ); + nStyle = BS_BMP; + } + + nValidMask = 0xFFFF; +} + +// ----------------------------------------------------------------------- + +SvxBulletItem::SvxBulletItem( SvStream& rStrm, USHORT _nWhich ) : + SfxPoolItem( _nWhich ), + pGraphicObject( NULL ) +{ + rStrm >> nStyle; + + if( nStyle != BS_BMP ) + aFont = CreateFont( rStrm, BULITEM_VERSION ); + else + { + // Sicheres Laden mit Test auf leere Bitmap + Bitmap aBmp; + const UINT32 nOldPos = rStrm.Tell(); + // #69345# Errorcode beim Bitmap lesen ignorieren, + // siehe Kommentar #67581# in SvxBulletItem::Store() + BOOL bOldError = rStrm.GetError() ? TRUE : FALSE; + rStrm >> aBmp; + if ( !bOldError && rStrm.GetError() ) + { + rStrm.ResetError(); + // #71493# Keine Warnung: Das BulletItem interessiert seit 5.0 im Dateiformat nicht mehr. + // rStrm.SetError(ERRCODE_CLASS_READ | ERRCODE_SVX_BULLETITEM_NOBULLET | ERRCODE_WARNING_MASK); + } + + if( aBmp.IsEmpty() ) + { + rStrm.Seek( nOldPos ); + nStyle = BS_NONE; + } + else + pGraphicObject = new GraphicObject( aBmp ); + } + + rStrm >> nWidth; + rStrm >> nStart; + rStrm >> nJustify; + + char cTmpSymbol; + rStrm >> cTmpSymbol; + cSymbol = ByteString::ConvertToUnicode( cTmpSymbol, aFont.GetCharSet() ); + + rStrm >> nScale; + + // UNICODE: rStrm >> aPrevText; + rStrm.ReadByteString(aPrevText); + + // UNICODE: rStrm >> aFollowText; + rStrm.ReadByteString(aFollowText); + + nValidMask = 0xFFFF; +} + +// ----------------------------------------------------------------------- + +SvxBulletItem::SvxBulletItem( const SvxBulletItem& rItem) : SfxPoolItem( rItem ) +{ + aFont = rItem.aFont; + pGraphicObject = ( rItem.pGraphicObject ? new GraphicObject( *rItem.pGraphicObject ) : NULL ); + aPrevText = rItem.aPrevText; + aFollowText = rItem.aFollowText; + nStart = rItem.nStart; + nStyle = rItem.nStyle; + nWidth = rItem.nWidth; + nScale = rItem.nScale; + cSymbol = rItem.cSymbol; + nJustify = rItem.nJustify; + nValidMask = rItem.nValidMask; +} + +// ----------------------------------------------------------------------- + +SvxBulletItem::~SvxBulletItem() +{ + if( pGraphicObject ) + delete pGraphicObject; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBulletItem::Clone( SfxItemPool * /*pPool*/ ) const +{ + return new SvxBulletItem( *this ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBulletItem::Create( SvStream& rStrm, USHORT /*nVersion*/ ) const +{ + return new SvxBulletItem( rStrm, Which() ); +} + +// ----------------------------------------------------------------------- + +void SvxBulletItem::SetDefaultFont_Impl() +{ + aFont = OutputDevice::GetDefaultFont( DEFAULTFONT_FIXED, LANGUAGE_SYSTEM, 0 ); + aFont.SetAlign( ALIGN_BOTTOM); + aFont.SetTransparent( TRUE ); +} + +// ----------------------------------------------------------------------- + +void SvxBulletItem::SetDefaults_Impl() +{ + pGraphicObject = NULL; + nWidth = 1200; // 1.2cm + nStart = 1; + nStyle = BS_123; + nJustify = BJ_HLEFT | BJ_VCENTER; + cSymbol = sal_Unicode(' '); + nScale = 75; +} + +// ----------------------------------------------------------------------- + +USHORT SvxBulletItem::GetVersion( USHORT /*nVersion*/ ) const +{ + return BULITEM_VERSION; +} + +// ----------------------------------------------------------------------- + +void SvxBulletItem::CopyValidProperties( const SvxBulletItem& rCopyFrom ) +{ + Font _aFont = GetFont(); + Font aNewFont = rCopyFrom.GetFont(); + if ( rCopyFrom.IsValid( VALID_FONTNAME ) ) + { + _aFont.SetName( aNewFont.GetName() ); + _aFont.SetFamily( aNewFont.GetFamily() ); + _aFont.SetStyleName( aNewFont.GetStyleName() ); + } + if ( rCopyFrom.IsValid( VALID_FONTCOLOR ) ) + _aFont.SetColor( aNewFont.GetColor() ); + if ( rCopyFrom.IsValid( VALID_SYMBOL ) ) + SetSymbol( rCopyFrom.GetSymbol() ); + if ( rCopyFrom.IsValid( VALID_BITMAP ) ) + SetGraphicObject( rCopyFrom.GetGraphicObject() ); + if ( rCopyFrom.IsValid( VALID_SCALE ) ) + SetScale( rCopyFrom.GetScale() ); + if ( rCopyFrom.IsValid( VALID_START ) ) + SetStart( rCopyFrom.GetStart() ); + if ( rCopyFrom.IsValid( VALID_STYLE ) ) + SetStyle( rCopyFrom.GetStyle() ); + if ( rCopyFrom.IsValid( VALID_PREVTEXT ) ) + SetPrevText( rCopyFrom.GetPrevText() ); + if ( rCopyFrom.IsValid( VALID_FOLLOWTEXT ) ) + SetFollowText( rCopyFrom.GetFollowText() ); + + SetFont( _aFont ); +} + + +// ----------------------------------------------------------------------- + +int SvxBulletItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT(rItem.ISA(SvxBulletItem),"operator==Types not matching"); + const SvxBulletItem& rBullet = (const SvxBulletItem&)rItem; + // ValidMask mitvergleichen, da sonst kein Putten in ein AttrSet moeglich, + // wenn sich das Item nur in der ValidMask von einem existierenden unterscheidet. + if( nValidMask != rBullet.nValidMask || + nStyle != rBullet.nStyle || + nScale != rBullet.nScale || + nJustify != rBullet.nJustify || + nWidth != rBullet.nWidth || + nStart != rBullet.nStart || + cSymbol != rBullet.cSymbol || + aPrevText != rBullet.aPrevText || + aFollowText != rBullet.aFollowText ) + return 0; + + if( ( nStyle != BS_BMP ) && ( aFont != rBullet.aFont ) ) + return 0; + + if( nStyle == BS_BMP ) + { + if( ( pGraphicObject && !rBullet.pGraphicObject ) || ( !pGraphicObject && rBullet.pGraphicObject ) ) + return 0; + + if( ( pGraphicObject && rBullet.pGraphicObject ) && + ( ( *pGraphicObject != *rBullet.pGraphicObject ) || + ( pGraphicObject->GetPrefSize() != rBullet.pGraphicObject->GetPrefSize() ) ) ) + { + return 0; + } + } + + return 1; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxBulletItem::Store( SvStream& rStrm, USHORT /*nItemVersion*/ ) const +{ + // Korrektur bei leerer Bitmap + if( ( nStyle == BS_BMP ) && + ( !pGraphicObject || ( GRAPHIC_NONE == pGraphicObject->GetType() ) || ( GRAPHIC_DEFAULT == pGraphicObject->GetType() ) ) ) + { + if( pGraphicObject ) + { + delete( const_cast< SvxBulletItem* >( this )->pGraphicObject ); + const_cast< SvxBulletItem* >( this )->pGraphicObject = NULL; + } + + const_cast< SvxBulletItem* >( this )->nStyle = BS_NONE; + } + + rStrm << nStyle; + + if( nStyle != BS_BMP ) + StoreFont( rStrm, aFont ); + else + { + ULONG _nStart = rStrm.Tell(); + + // Kleine Vorab-Schaetzung der Groesse... + USHORT nFac = ( rStrm.GetCompressMode() != COMPRESSMODE_NONE ) ? 3 : 1; + const Bitmap aBmp( pGraphicObject->GetGraphic().GetBitmap() ); + ULONG nBytes = aBmp.GetSizeBytes(); + if ( nBytes < ULONG(0xFF00*nFac) ) + rStrm << aBmp; + + ULONG nEnd = rStrm.Tell(); + // #67581# Item darf mit Overhead nicht mehr als 64K schreiben, + // sonst platzt der SfxMultiRecord + // Dann lieber auf die Bitmap verzichten, ist nur fuer Outliner + // und auch nur fuer <= 5.0 wichtig. + // Beim Einlesen merkt der Stream-Operator der Bitmap, dass dort keine steht. + // Hiermit funktioniert jetzt der Fall das die grosse Bitmap aus einem anderen + // Fileformat entstanden ist, welches keine 64K belegt, aber wenn eine + // Bitmap > 64K verwendet wird, hat das SvxNumBulletItem beim Laden ein Problem, + // stuerzt aber nicht ab. + + if ( (nEnd-_nStart) > 0xFF00 ) + rStrm.Seek( _nStart ); + } + rStrm << nWidth; + rStrm << nStart; + rStrm << nJustify; + rStrm << (char)ByteString::ConvertFromUnicode( cSymbol, aFont.GetCharSet() ); + rStrm << nScale; + + // UNICODE: rStrm << aPrevText; + rStrm.WriteByteString(aPrevText); + + // UNICODE: rStrm << aFollowText; + rStrm.WriteByteString(aFollowText); + + return rStrm; +} + +//------------------------------------------------------------------------ + +XubString SvxBulletItem::GetFullText() const +{ + XubString aStr( aPrevText ); + aStr += cSymbol; + aStr += aFollowText; + return aStr; +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxBulletItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ + SfxItemPresentation eRet = SFX_ITEM_PRESENTATION_NONE; + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + eRet = SFX_ITEM_PRESENTATION_NONE; + break; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetFullText(); + eRet = SFX_ITEM_PRESENTATION_COMPLETE; + break; + default: ; //prevent warning + } + return eRet; +} + +//------------------------------------------------------------------------ + +Bitmap SvxBulletItem::GetBitmap() const +{ + if( pGraphicObject ) + return pGraphicObject->GetGraphic().GetBitmap(); + else + { + const Bitmap aDefaultBitmap; + return aDefaultBitmap; + } +} + +//------------------------------------------------------------------------ + +void SvxBulletItem::SetBitmap( const Bitmap& rBmp ) +{ + if( rBmp.IsEmpty() ) + { + if( pGraphicObject ) + { + delete pGraphicObject; + pGraphicObject = NULL; + } + } + else + { + delete pGraphicObject; + pGraphicObject = new GraphicObject( rBmp ); + + } +} + +//------------------------------------------------------------------------ + +const GraphicObject& SvxBulletItem::GetGraphicObject() const +{ + if( pGraphicObject ) + return *pGraphicObject; + else + { + static const GraphicObject aDefaultObject; + return aDefaultObject; + } +} + +//------------------------------------------------------------------------ + +void SvxBulletItem::SetGraphicObject( const GraphicObject& rGraphicObject ) +{ + if( ( GRAPHIC_NONE == rGraphicObject.GetType() ) || ( GRAPHIC_DEFAULT == rGraphicObject.GetType() ) ) + { + if( pGraphicObject ) + { + delete pGraphicObject; + pGraphicObject = NULL; + } + } + else + { + delete pGraphicObject; + pGraphicObject = new GraphicObject( rGraphicObject ); + } +} diff --git a/editeng/source/items/charhiddenitem.cxx b/editeng/source/items/charhiddenitem.cxx new file mode 100644 index 000000000000..94ae397a188c --- /dev/null +++ b/editeng/source/items/charhiddenitem.cxx @@ -0,0 +1,85 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: charhiddenitem.cxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + + +#include <editeng/charhiddenitem.hxx> +#include <editeng/editrids.hrc> +#include <editeng/eerdll.hxx> + +TYPEINIT1_FACTORY(SvxCharHiddenItem, SfxBoolItem, new SvxCharHiddenItem(sal_False, 0)); + +/*-- 16.12.2003 15:24:25--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxCharHiddenItem::SvxCharHiddenItem( const sal_Bool bHidden, const USHORT nId ) : + SfxBoolItem( nId, bHidden ) +{ +} +/*-- 16.12.2003 15:24:25--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SfxPoolItem* SvxCharHiddenItem::Clone( SfxItemPool * ) const +{ + return new SvxCharHiddenItem( *this ); +} +/*-- 16.12.2003 15:24:25--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SfxItemPresentation SvxCharHiddenItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + USHORT nId = RID_SVXITEMS_CHARHIDDEN_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_CHARHIDDEN_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + diff --git a/editeng/source/items/flditem.cxx b/editeng/source/items/flditem.cxx new file mode 100644 index 000000000000..f8b702109018 --- /dev/null +++ b/editeng/source/items/flditem.cxx @@ -0,0 +1,1101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: flditem.cxx,v $ + * $Revision: 1.29 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <vcl/metaact.hxx> +#include <svl/zforlist.hxx> +#include <tools/urlobj.hxx> + +#define _SVX_FLDITEM_CXX +#include <unotools/localfilehelper.hxx> + +#include <editeng/flditem.hxx> + +#include <editeng/measfld.hxx> + +// #90477# +#include <tools/tenccvt.hxx> + +#define FRAME_MARKER (sal_uInt32)0x21981357 +#define CHARSET_MARKER (FRAME_MARKER+1) + +// ----------------------------------------------------------------------- + +TYPEINIT1( SvxFieldItem, SfxPoolItem ); + +SV_IMPL_PERSIST1( SvxFieldData, SvPersistBase ); + +// ----------------------------------------------------------------------- + +SvxFieldData::SvxFieldData() +{ +} + +// ----------------------------------------------------------------------- + +SvxFieldData::~SvxFieldData() +{ +} + +// ----------------------------------------------------------------------- + +SvxFieldData* SvxFieldData::Clone() const +{ + return new SvxFieldData; +} + +// ----------------------------------------------------------------------- + +int SvxFieldData::operator==( const SvxFieldData& rFld ) const +{ + DBG_ASSERT( Type() == rFld.Type(), "==: Verschiedene Typen" ); + (void)rFld; + return TRUE; // Basicklasse immer gleich. +} + +// ----------------------------------------------------------------------- + +void SvxFieldData::Load( SvPersistStream & /*rStm*/ ) +{ +} + +// ----------------------------------------------------------------------- + +void SvxFieldData::Save( SvPersistStream & /*rStm*/ ) +{ +} + + +MetaAction* SvxFieldData::createBeginComment() const +{ + return new MetaCommentAction( "FIELD_SEQ_BEGIN" ); +} + +MetaAction* SvxFieldData::createEndComment() const +{ + return new MetaCommentAction( "FIELD_SEQ_END" ); +} + +// ----------------------------------------------------------------------- + +SvxFieldItem::SvxFieldItem( SvxFieldData* pFld, const USHORT nId ) : + SfxPoolItem( nId ) +{ + pField = pFld; // gehoert direkt dem Item +} + +// ----------------------------------------------------------------------- + +SvxFieldItem::SvxFieldItem( const SvxFieldData& rField, const USHORT nId ) : + SfxPoolItem( nId ) +{ + pField = rField.Clone(); +} + +// ----------------------------------------------------------------------- + +SvxFieldItem::SvxFieldItem( const SvxFieldItem& rItem ) : + SfxPoolItem ( rItem ) +{ + pField = rItem.GetField() ? rItem.GetField()->Clone() : 0; +} + +// ----------------------------------------------------------------------- + +SvxFieldItem::~SvxFieldItem() +{ + delete pField; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFieldItem::Clone( SfxItemPool* ) const +{ + return new SvxFieldItem(*this); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFieldItem::Create( SvStream& rStrm, USHORT ) const +{ + SvxFieldData* pData = 0; + SvPersistStream aPStrm( GetClassManager(), &rStrm ); + aPStrm >> pData; + + if( aPStrm.IsEof() ) + aPStrm.SetError( SVSTREAM_GENERALERROR ); + + if ( aPStrm.GetError() == ERRCODE_IO_NOFACTORY ) + aPStrm.ResetError(); // Eigentlich einen Code, dass nicht alle Attr gelesen wurden... + + return new SvxFieldItem( pData, Which() ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxFieldItem::Store( SvStream& rStrm, USHORT /*nItemVersion*/ ) const +{ + DBG_ASSERT( pField, "SvxFieldItem::Store: Feld?!" ); + SvPersistStream aPStrm( GetClassManager(), &rStrm ); + // Das ResetError in der obigen Create-Methode gab es in 3.1 noch nicht, + // deshalb duerfen beim 3.x-Export neuere Items nicht gespeichert werden! + if ( ( rStrm.GetVersion() <= SOFFICE_FILEFORMAT_31 ) && pField && + pField->GetClassId() == 50 /* SdrMeasureField */ ) + { + // SvxFieldData reicht nicht, weil auch nicht am ClassMgr angemeldet + SvxURLField aDummyData; + aPStrm << &aDummyData; + } + else + aPStrm << pField; + + return rStrm; +} + +// ----------------------------------------------------------------------- + +int SvxFieldItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal which or type" ); + + const SvxFieldData* pOtherFld = ((const SvxFieldItem&)rItem).GetField(); + if ( !pField && !pOtherFld ) + return TRUE; + + if ( ( !pField && pOtherFld ) || ( pField && !pOtherFld ) ) + return FALSE; + + return ( ( pField->Type() == pOtherFld->Type() ) + && ( *pField == *pOtherFld ) ); +} + +// ================================================================= +// Es folgen die Ableitungen von SvxFieldData... +// ================================================================= + +SV_IMPL_PERSIST1( SvxDateField, SvxFieldData ); + +// ----------------------------------------------------------------------- + +SvxDateField::SvxDateField() +{ + nFixDate = Date().GetDate(); + eType = SVXDATETYPE_VAR; + eFormat = SVXDATEFORMAT_STDSMALL; +} + +// ----------------------------------------------------------------------- + +SvxDateField::SvxDateField( const Date& rDate, SvxDateType eT, SvxDateFormat eF ) +{ + nFixDate = rDate.GetDate(); + eType = eT; + eFormat = eF; +} + +// ----------------------------------------------------------------------- + +SvxFieldData* SvxDateField::Clone() const +{ + return new SvxDateField( *this ); +} + +// ----------------------------------------------------------------------- + +int SvxDateField::operator==( const SvxFieldData& rOther ) const +{ + if ( rOther.Type() != Type() ) + return FALSE; + + const SvxDateField& rOtherFld = (const SvxDateField&) rOther; + return ( ( nFixDate == rOtherFld.nFixDate ) && + ( eType == rOtherFld.eType ) && + ( eFormat == rOtherFld.eFormat ) ); +} + +// ----------------------------------------------------------------------- + +void SvxDateField::Load( SvPersistStream & rStm ) +{ + USHORT nType, nFormat; + + rStm >> nFixDate; + rStm >> nType; + rStm >> nFormat; + + eType = (SvxDateType)nType; + eFormat= (SvxDateFormat)nFormat; +} + +// ----------------------------------------------------------------------- + +void SvxDateField::Save( SvPersistStream & rStm ) +{ + rStm << nFixDate; + rStm << (USHORT)eType; + rStm << (USHORT)eFormat; +} + +// ----------------------------------------------------------------------- + +String SvxDateField::GetFormatted( SvNumberFormatter& rFormatter, LanguageType eLang ) const +{ + Date aDate; // current date + if ( eType == SVXDATETYPE_FIX ) + aDate.SetDate( nFixDate ); + + return GetFormatted( aDate, eFormat, rFormatter, eLang ); +} + +String SvxDateField::GetFormatted( Date& aDate, SvxDateFormat eFormat, SvNumberFormatter& rFormatter, LanguageType eLang ) +{ + if ( eFormat == SVXDATEFORMAT_SYSTEM ) + { + DBG_ERROR( "SVXDATEFORMAT_SYSTEM nicht implementiert!" ); + eFormat = SVXDATEFORMAT_STDSMALL; + } + else if ( eFormat == SVXDATEFORMAT_APPDEFAULT ) + { + DBG_ERROR( "SVXDATEFORMAT_APPDEFAULT: Woher nehmen?" ); + eFormat = SVXDATEFORMAT_STDSMALL; + } + + ULONG nFormatKey; + + switch( eFormat ) + { + case SVXDATEFORMAT_STDSMALL: + // short + nFormatKey = rFormatter.GetFormatIndex( NF_DATE_SYSTEM_SHORT, eLang ); + break; + case SVXDATEFORMAT_STDBIG: + // long + nFormatKey = rFormatter.GetFormatIndex( NF_DATE_SYSTEM_LONG, eLang ); + break; + case SVXDATEFORMAT_A: + // 13.02.96 + nFormatKey = rFormatter.GetFormatIndex( NF_DATE_SYS_DDMMYY, eLang ); + break; + case SVXDATEFORMAT_B: + // 13.02.1996 + nFormatKey = rFormatter.GetFormatIndex( NF_DATE_SYS_DDMMYYYY, eLang ); + break; + case SVXDATEFORMAT_C: + // 13. Feb 1996 + nFormatKey = rFormatter.GetFormatIndex( NF_DATE_SYS_DMMMYYYY, eLang ); + break; + case SVXDATEFORMAT_D: + // 13. Februar 1996 + nFormatKey = rFormatter.GetFormatIndex( NF_DATE_SYS_DMMMMYYYY, eLang ); + break; + case SVXDATEFORMAT_E: + // Die, 13. Februar 1996 + nFormatKey = rFormatter.GetFormatIndex( NF_DATE_SYS_NNDMMMMYYYY, eLang ); + break; + case SVXDATEFORMAT_F: + // Dienstag, 13. Februar 1996 + nFormatKey = rFormatter.GetFormatIndex( NF_DATE_SYS_NNNNDMMMMYYYY, eLang ); + break; + default: + nFormatKey = rFormatter.GetStandardFormat( NUMBERFORMAT_DATE, eLang ); + } + + double fDiffDate = aDate - *(rFormatter.GetNullDate()); + String aStr; + Color* pColor = NULL; + rFormatter.GetOutputString( fDiffDate, nFormatKey, aStr, &pColor ); + return aStr; +} + +MetaAction* SvxDateField::createBeginComment() const +{ + return new MetaCommentAction( "FIELD_SEQ_BEGIN" ); +} + +SV_IMPL_PERSIST1( SvxURLField, SvxFieldData ); + +// ----------------------------------------------------------------------- + +SvxURLField::SvxURLField() +{ + eFormat = SVXURLFORMAT_URL; +} + +// ----------------------------------------------------------------------- + +SvxURLField::SvxURLField( const XubString& rURL, const XubString& rRepres, SvxURLFormat eFmt ) + : aURL( rURL ), aRepresentation( rRepres ) +{ + eFormat = eFmt; +} + +// ----------------------------------------------------------------------- + +SvxFieldData* SvxURLField::Clone() const +{ + return new SvxURLField( *this ); +} + +// ----------------------------------------------------------------------- + +int SvxURLField::operator==( const SvxFieldData& rOther ) const +{ + if ( rOther.Type() != Type() ) + return FALSE; + + const SvxURLField& rOtherFld = (const SvxURLField&) rOther; + return ( ( eFormat == rOtherFld.eFormat ) && + ( aURL == rOtherFld.aURL ) && + ( aRepresentation == rOtherFld.aRepresentation ) && + ( aTargetFrame == rOtherFld.aTargetFrame ) ); +} + +// ----------------------------------------------------------------------- + +void SvxURLField::Load( SvPersistStream & rStm ) +{ + USHORT nFormat; + sal_uInt32 nFrameMarker, nCharSetMarker; + long nUlongSize = (long)sizeof(sal_uInt32); + String aTmpURL; + + rStm >> nFormat; + + // UNICODE: rStm >> aTmpURL; + rStm.ReadByteString(aTmpURL); + + // UNICODE: rStm >> aRepresentation; + // read to a temp string first, read text encoding and + // convert later to stay compatible to fileformat + ByteString aTempString; + rtl_TextEncoding aTempEncoding = RTL_TEXTENCODING_MS_1252; // #101493# Init for old documents + rStm.ReadByteString(aTempString); + + rStm >> nFrameMarker; + if ( nFrameMarker == FRAME_MARKER ) + { + // UNICODE: rStm >> aTargetFrame; + rStm.ReadByteString(aTargetFrame); + + rStm >> nCharSetMarker; + if ( nCharSetMarker == CHARSET_MARKER ) + { + USHORT nCharSet; + rStm >> nCharSet; + + // remember encoding + aTempEncoding = (rtl_TextEncoding)nCharSet; + } + else + rStm.SeekRel( -nUlongSize ); + } + else + rStm.SeekRel( -nUlongSize ); + + // now build representation string due to known encoding + aRepresentation = String(aTempString, aTempEncoding); + + eFormat= (SvxURLFormat)nFormat; + + // Relatives Speichern => Beim laden absolut machen. + DBG_ERROR("No BaseURL!"); + // TODO/MBA: no BaseURL + aURL = INetURLObject::GetAbsURL( String(), aTmpURL ); +} + +// ----------------------------------------------------------------------- + +void SvxURLField::Save( SvPersistStream & rStm ) +{ + // Relatives Speichern der URL + DBG_ERROR("No BaseURL!"); + // TODO/MBA: no BaseURL + String aTmpURL = INetURLObject::GetRelURL( String(), aURL ); + + rStm << (USHORT)eFormat; + + // UNICODE: rStm << aTmpURL; + rStm.WriteByteString(aTmpURL); + + // UNICODE: rStm << aRepresentation; + rStm.WriteByteString(aRepresentation); + + rStm << FRAME_MARKER; + + // UNICODE: rStm << aTargetFrame; + rStm.WriteByteString(aTargetFrame); + + rStm << CHARSET_MARKER; + + // #90477# rStm << (USHORT)GetStoreCharSet(gsl_getSystemTextEncoding(), rStm.GetVersion()); + rStm << (USHORT)GetSOStoreTextEncoding(gsl_getSystemTextEncoding(), (sal_uInt16)rStm.GetVersion()); +} + +MetaAction* SvxURLField::createBeginComment() const +{ + // #i46618# Adding target URL to metafile comment + return new MetaCommentAction( "FIELD_SEQ_BEGIN", + 0, + reinterpret_cast<const BYTE*>(aURL.GetBuffer()), + 2*aURL.Len() ); +} + +// ================================================================= +// Die Felder, die aus Calc ausgebaut wurden: +// ================================================================= + +SV_IMPL_PERSIST1( SvxPageField, SvxFieldData ); + +SvxFieldData* __EXPORT SvxPageField::Clone() const +{ + return new SvxPageField; // leer +} + +int __EXPORT SvxPageField::operator==( const SvxFieldData& rCmp ) const +{ + return ( rCmp.Type() == TYPE(SvxPageField) ); +} + +void __EXPORT SvxPageField::Load( SvPersistStream & /*rStm*/ ) +{ +} + +void __EXPORT SvxPageField::Save( SvPersistStream & /*rStm*/ ) +{ +} + +MetaAction* SvxPageField::createBeginComment() const +{ + return new MetaCommentAction( "FIELD_SEQ_BEGIN;PageField" ); +} + + +SV_IMPL_PERSIST1( SvxPagesField, SvxFieldData ); + +SvxFieldData* __EXPORT SvxPagesField::Clone() const +{ + return new SvxPagesField; // leer +} + +int __EXPORT SvxPagesField::operator==( const SvxFieldData& rCmp ) const +{ + return ( rCmp.Type() == TYPE(SvxPagesField) ); +} + +void __EXPORT SvxPagesField::Load( SvPersistStream & /*rStm*/ ) +{ +} + +void __EXPORT SvxPagesField::Save( SvPersistStream & /*rStm*/ ) +{ +} + +SV_IMPL_PERSIST1( SvxTimeField, SvxFieldData ); + +SvxFieldData* __EXPORT SvxTimeField::Clone() const +{ + return new SvxTimeField; // leer +} + +int __EXPORT SvxTimeField::operator==( const SvxFieldData& rCmp ) const +{ + return ( rCmp.Type() == TYPE(SvxTimeField) ); +} + +void __EXPORT SvxTimeField::Load( SvPersistStream & /*rStm*/ ) +{ +} + +void __EXPORT SvxTimeField::Save( SvPersistStream & /*rStm*/ ) +{ +} + +MetaAction* SvxTimeField::createBeginComment() const +{ + return new MetaCommentAction( "FIELD_SEQ_BEGIN" ); +} + +SV_IMPL_PERSIST1( SvxFileField, SvxFieldData ); + +SvxFieldData* __EXPORT SvxFileField::Clone() const +{ + return new SvxFileField; // leer +} + +int __EXPORT SvxFileField::operator==( const SvxFieldData& rCmp ) const +{ + return ( rCmp.Type() == TYPE(SvxFileField) ); +} + +void __EXPORT SvxFileField::Load( SvPersistStream & /*rStm*/ ) +{ +} + +void __EXPORT SvxFileField::Save( SvPersistStream & /*rStm*/ ) +{ +} + +SV_IMPL_PERSIST1( SvxTableField, SvxFieldData ); + +SvxFieldData* __EXPORT SvxTableField::Clone() const +{ + return new SvxTableField; // leer +} + +int __EXPORT SvxTableField::operator==( const SvxFieldData& rCmp ) const +{ + return ( rCmp.Type() == TYPE(SvxTableField) ); +} + +void __EXPORT SvxTableField::Load( SvPersistStream & /*rStm*/ ) +{ +} + +void __EXPORT SvxTableField::Save( SvPersistStream & /*rStm*/ ) +{ +} + +//---------------------------------------------------------------------------- +// SvxExtTimeField +//---------------------------------------------------------------------------- + +SV_IMPL_PERSIST1( SvxExtTimeField, SvxFieldData ); + +//---------------------------------------------------------------------------- + +SvxExtTimeField::SvxExtTimeField() +{ + nFixTime = Time().GetTime(); + eType = SVXTIMETYPE_VAR; + eFormat = SVXTIMEFORMAT_STANDARD; +} + +//---------------------------------------------------------------------------- + +SvxExtTimeField::SvxExtTimeField( const Time& rTime, SvxTimeType eT, SvxTimeFormat eF ) +{ + nFixTime = rTime.GetTime(); + eType = eT; + eFormat = eF; +} + +//---------------------------------------------------------------------------- + +SvxFieldData* SvxExtTimeField::Clone() const +{ + return new SvxExtTimeField( *this ); +} + +//---------------------------------------------------------------------------- + +int SvxExtTimeField::operator==( const SvxFieldData& rOther ) const +{ + if ( rOther.Type() != Type() ) + return FALSE; + + const SvxExtTimeField& rOtherFld = (const SvxExtTimeField&) rOther; + return ( ( nFixTime == rOtherFld.nFixTime ) && + ( eType == rOtherFld.eType ) && + ( eFormat == rOtherFld.eFormat ) ); +} + +//---------------------------------------------------------------------------- + +void SvxExtTimeField::Load( SvPersistStream & rStm ) +{ + USHORT nType, nFormat; + + rStm >> nFixTime; + rStm >> nType; + rStm >> nFormat; + + eType = (SvxTimeType) nType; + eFormat= (SvxTimeFormat) nFormat; +} + +//---------------------------------------------------------------------------- + +void SvxExtTimeField::Save( SvPersistStream & rStm ) +{ + rStm << nFixTime; + rStm << (USHORT) eType; + rStm << (USHORT) eFormat; +} + +//---------------------------------------------------------------------------- + +String SvxExtTimeField::GetFormatted( SvNumberFormatter& rFormatter, LanguageType eLang ) const +{ + Time aTime; // current time + if ( eType == SVXTIMETYPE_FIX ) + aTime.SetTime( nFixTime ); + return GetFormatted( aTime, eFormat, rFormatter, eLang ); +} + +String SvxExtTimeField::GetFormatted( Time& aTime, SvxTimeFormat eFormat, SvNumberFormatter& rFormatter, LanguageType eLang ) +{ + switch( eFormat ) + { + case SVXTIMEFORMAT_SYSTEM : + DBG_ERROR( "SVXTIMEFORMAT_SYSTEM: not implemented" ); + eFormat = SVXTIMEFORMAT_STANDARD; + break; + case SVXTIMEFORMAT_APPDEFAULT : + DBG_ERROR( "SVXTIMEFORMAT_APPDEFAULT: not implemented" ); + eFormat = SVXTIMEFORMAT_STANDARD; + break; + default: ;//prevent warning + } + + sal_uInt32 nFormatKey; + + switch( eFormat ) + { + case SVXTIMEFORMAT_12_HM: + nFormatKey = rFormatter.GetFormatIndex( NF_TIME_HHMMAMPM, eLang ); + break; + case SVXTIMEFORMAT_12_HMSH: + { // no builtin format available, try to insert or reuse + String aFormatCode( RTL_CONSTASCII_USTRINGPARAM( "HH:MM:SS.00 AM/PM" ) ); + xub_StrLen nCheckPos; + short nType; + /*BOOL bInserted = */rFormatter.PutandConvertEntry( aFormatCode, + nCheckPos, nType, nFormatKey, LANGUAGE_ENGLISH_US, eLang ); + DBG_ASSERT( nCheckPos == 0, "SVXTIMEFORMAT_12_HMSH: could not insert format code" ); + if ( nCheckPos ) + nFormatKey = rFormatter.GetFormatIndex( NF_TIME_HH_MMSS00, eLang ); + } + break; + case SVXTIMEFORMAT_24_HM: + nFormatKey = rFormatter.GetFormatIndex( NF_TIME_HHMM, eLang ); + break; + case SVXTIMEFORMAT_24_HMSH: + nFormatKey = rFormatter.GetFormatIndex( NF_TIME_HH_MMSS00, eLang ); + break; + case SVXTIMEFORMAT_12_HMS: + nFormatKey = rFormatter.GetFormatIndex( NF_TIME_HHMMSSAMPM, eLang ); + break; + case SVXTIMEFORMAT_24_HMS: + nFormatKey = rFormatter.GetFormatIndex( NF_TIME_HHMMSS, eLang ); + break; + case SVXTIMEFORMAT_STANDARD: + default: + nFormatKey = rFormatter.GetStandardFormat( NUMBERFORMAT_TIME, eLang ); + } + + double fFracTime = aTime.GetTimeInDays(); + String aStr; + Color* pColor = NULL; + rFormatter.GetOutputString( fFracTime, nFormatKey, aStr, &pColor ); + return aStr; +} + +MetaAction* SvxExtTimeField::createBeginComment() const +{ + return new MetaCommentAction( "FIELD_SEQ_BEGIN" ); +} + +//---------------------------------------------------------------------------- +// SvxExtFileField +//---------------------------------------------------------------------------- + +SV_IMPL_PERSIST1( SvxExtFileField, SvxFieldData ); + +//---------------------------------------------------------------------------- + +SvxExtFileField::SvxExtFileField() +{ + eType = SVXFILETYPE_VAR; + eFormat = SVXFILEFORMAT_FULLPATH; +} + +//---------------------------------------------------------------------------- + +SvxExtFileField::SvxExtFileField( const XubString& rStr, SvxFileType eT, SvxFileFormat eF ) +{ + aFile = rStr; + eType = eT; + eFormat = eF; +} + +//---------------------------------------------------------------------------- + +SvxFieldData* SvxExtFileField::Clone() const +{ + return new SvxExtFileField( *this ); +} + +//---------------------------------------------------------------------------- + +int SvxExtFileField::operator==( const SvxFieldData& rOther ) const +{ + if ( rOther.Type() != Type() ) + return FALSE; + + const SvxExtFileField& rOtherFld = (const SvxExtFileField&) rOther; + return ( ( aFile == rOtherFld.aFile ) && + ( eType == rOtherFld.eType ) && + ( eFormat == rOtherFld.eFormat ) ); +} + +//---------------------------------------------------------------------------- + +void SvxExtFileField::Load( SvPersistStream & rStm ) +{ + USHORT nType, nFormat; + + // UNICODE: rStm >> aFile; + rStm.ReadByteString(aFile); + + rStm >> nType; + rStm >> nFormat; + + eType = (SvxFileType) nType; + eFormat= (SvxFileFormat) nFormat; +} + +//---------------------------------------------------------------------------- + +void SvxExtFileField::Save( SvPersistStream & rStm ) +{ + // UNICODE: rStm << aFile; + rStm.WriteByteString(aFile); + + rStm << (USHORT) eType; + rStm << (USHORT) eFormat; +} + +//---------------------------------------------------------------------------- + +XubString SvxExtFileField::GetFormatted() const +{ + XubString aString; + + INetURLObject aURLObj( aFile ); + + if( INET_PROT_NOT_VALID == aURLObj.GetProtocol() ) + { + // invalid? try to interpret string as system file name + String aURLStr; + + ::utl::LocalFileHelper::ConvertPhysicalNameToURL( aFile, aURLStr ); + + aURLObj.SetURL( aURLStr ); + } + + // #92009# Be somewhat liberate when trying to + // get formatted content out of the FileField + if( INET_PROT_NOT_VALID == aURLObj.GetProtocol() ) + { + // still not valid? Then output as is + aString = aFile; + } + else if( INET_PROT_FILE == aURLObj.GetProtocol() ) + { + switch( eFormat ) + { + case SVXFILEFORMAT_FULLPATH: + aString = aURLObj.getFSysPath(INetURLObject::FSYS_DETECT); + break; + + case SVXFILEFORMAT_PATH: + aURLObj.removeSegment(INetURLObject::LAST_SEGMENT, false); + // #101742# Leave trailing slash at the pathname + aURLObj.setFinalSlash(); + aString = aURLObj.getFSysPath(INetURLObject::FSYS_DETECT); + break; + + case SVXFILEFORMAT_NAME: + aString = aURLObj.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DECODE_UNAMBIGUOUS); + break; + + case SVXFILEFORMAT_NAME_EXT: + aString = aURLObj.getName(INetURLObject::LAST_SEGMENT,true,INetURLObject::DECODE_UNAMBIGUOUS); + break; + } + } + else + { + switch( eFormat ) + { + case SVXFILEFORMAT_FULLPATH: + aString = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + break; + + case SVXFILEFORMAT_PATH: + aURLObj.removeSegment(INetURLObject::LAST_SEGMENT, false); + // #101742# Leave trailing slash at the pathname + aURLObj.setFinalSlash(); + aString = aURLObj.GetMainURL( INetURLObject::DECODE_TO_IURI ); + break; + + case SVXFILEFORMAT_NAME: + aString = aURLObj.getBase(); + break; + + case SVXFILEFORMAT_NAME_EXT: + aString = aURLObj.getName(); + break; + } + } + + return( aString ); +} + +//---------------------------------------------------------------------------- +// SvxAuthorField +//---------------------------------------------------------------------------- + +SV_IMPL_PERSIST1( SvxAuthorField, SvxFieldData ); + +//---------------------------------------------------------------------------- + +SvxAuthorField::SvxAuthorField() +{ + eType = SVXAUTHORTYPE_VAR; + eFormat = SVXAUTHORFORMAT_FULLNAME; +} + +//---------------------------------------------------------------------------- + +SvxAuthorField::SvxAuthorField( const XubString& rFirstName, + const XubString& rLastName, + const XubString& rShortName, + SvxAuthorType eT, SvxAuthorFormat eF ) +{ + aName = rLastName; + aFirstName = rFirstName; + aShortName = rShortName; + eType = eT; + eFormat = eF; +} + +//---------------------------------------------------------------------------- + +SvxFieldData* SvxAuthorField::Clone() const +{ + return new SvxAuthorField( *this ); +} + +//---------------------------------------------------------------------------- + +int SvxAuthorField::operator==( const SvxFieldData& rOther ) const +{ + if ( rOther.Type() != Type() ) + return FALSE; + + const SvxAuthorField& rOtherFld = (const SvxAuthorField&) rOther; + return ( ( aName == rOtherFld.aName ) && + ( aFirstName == rOtherFld.aFirstName ) && + ( aShortName == rOtherFld.aShortName ) && + ( eType == rOtherFld.eType ) && + ( eFormat == rOtherFld.eFormat ) ); +} + +//---------------------------------------------------------------------------- + +void SvxAuthorField::Load( SvPersistStream & rStm ) +{ + USHORT nType, nFormat; + + // UNICODE: rStm >> aName; + rStm.ReadByteString(aName); + + // UNICODE: rStm >> aFirstName; + rStm.ReadByteString(aFirstName); + + // UNICODE: rStm >> aShortName; + rStm.ReadByteString(aShortName); + + rStm >> nType; + rStm >> nFormat; + + eType = (SvxAuthorType) nType; + eFormat= (SvxAuthorFormat) nFormat; +} + +//---------------------------------------------------------------------------- + +void SvxAuthorField::Save( SvPersistStream & rStm ) +{ + // UNICODE: rStm << aName; + rStm.WriteByteString(aName); + + // UNICODE: rStm << aFirstName; + rStm.WriteByteString(aFirstName); + + // UNICODE: rStm << aShortName; + rStm.WriteByteString(aShortName); + + rStm << (USHORT) eType; + rStm << (USHORT) eFormat; +} + +//---------------------------------------------------------------------------- + +XubString SvxAuthorField::GetFormatted() const +{ + XubString aString; + + switch( eFormat ) + { + case SVXAUTHORFORMAT_FULLNAME: + aString = aFirstName; + aString += sal_Unicode(' '); + aString += aName; + break; + + case SVXAUTHORFORMAT_NAME: + aString = aName; + break; + + case SVXAUTHORFORMAT_FIRSTNAME: + aString = aFirstName; + break; + + case SVXAUTHORFORMAT_SHORTNAME: + aString = aShortName; + break; + } + + return( aString ); +} + +static SvClassManager* pClassMgr=0; + +SvClassManager& SvxFieldItem::GetClassManager() +{ + if ( !pClassMgr ) + { + pClassMgr = new SvClassManager; + pClassMgr->SV_CLASS_REGISTER( SvxFieldData ); + pClassMgr->SV_CLASS_REGISTER( SvxURLField ); + pClassMgr->SV_CLASS_REGISTER( SvxDateField ); + pClassMgr->SV_CLASS_REGISTER( SvxPageField ); + pClassMgr->SV_CLASS_REGISTER( SvxTimeField ); + pClassMgr->SV_CLASS_REGISTER( SvxExtTimeField ); + pClassMgr->SV_CLASS_REGISTER( SvxExtFileField ); + pClassMgr->SV_CLASS_REGISTER( SvxAuthorField ); + } + + return *pClassMgr; +} + +/////////////////////////////////////////////////////////////////////// + +SV_IMPL_PERSIST1( SvxHeaderField, SvxFieldData ); + +SvxFieldData* __EXPORT SvxHeaderField::Clone() const +{ + return new SvxHeaderField; // leer +} + +int __EXPORT SvxHeaderField::operator==( const SvxFieldData& rCmp ) const +{ + return ( rCmp.Type() == TYPE(SvxHeaderField) ); +} + +void __EXPORT SvxHeaderField::Load( SvPersistStream & /*rStm*/ ) +{ +} + +void __EXPORT SvxHeaderField::Save( SvPersistStream & /*rStm*/ ) +{ +} + +/////////////////////////////////////////////////////////////////////// + +SV_IMPL_PERSIST1( SvxFooterField, SvxFieldData ); + +SvxFieldData* __EXPORT SvxFooterField::Clone() const +{ + return new SvxFooterField; // leer +} + +int __EXPORT SvxFooterField::operator==( const SvxFieldData& rCmp ) const +{ + return ( rCmp.Type() == TYPE(SvxFooterField) ); +} + +void __EXPORT SvxFooterField::Load( SvPersistStream & /*rStm*/ ) +{ +} + +void __EXPORT SvxFooterField::Save( SvPersistStream & /*rStm*/ ) +{ +} + +/////////////////////////////////////////////////////////////////////// + +SV_IMPL_PERSIST1( SvxDateTimeField, SvxFieldData ); + +SvxFieldData* __EXPORT SvxDateTimeField::Clone() const +{ + return new SvxDateTimeField; // leer +} + +int __EXPORT SvxDateTimeField::operator==( const SvxFieldData& rCmp ) const +{ + return ( rCmp.Type() == TYPE(SvxDateTimeField) ); +} + +void __EXPORT SvxDateTimeField::Load( SvPersistStream & /*rStm*/ ) +{ +} + +void __EXPORT SvxDateTimeField::Save( SvPersistStream & /*rStm*/ ) +{ +} + +String SvxDateTimeField::GetFormatted( Date& rDate, Time& rTime, int eFormat, SvNumberFormatter& rFormatter, LanguageType eLanguage ) +{ + String aRet; + + SvxDateFormat eDateFormat = (SvxDateFormat)(eFormat & 0x0f); + + if(eDateFormat) + { + aRet = SvxDateField::GetFormatted( rDate, eDateFormat, rFormatter, eLanguage ); + } + + SvxTimeFormat eTimeFormat = (SvxTimeFormat)((eFormat >> 4) & 0x0f); + + if(eTimeFormat) + { + if(aRet.Len()) + aRet += sal_Unicode(' '); + + aRet += SvxExtTimeField::GetFormatted( rTime, eTimeFormat, rFormatter, eLanguage ); + } + + return aRet; +} + diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx new file mode 100644 index 000000000000..97cd3a500a53 --- /dev/null +++ b/editeng/source/items/frmitems.cxx @@ -0,0 +1,4470 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: frmitems.cxx,v $ + * $Revision: 1.53 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +// include --------------------------------------------------------------- +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/script/XTypeConverter.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/table/CellVertJustify.hpp> +#include <com/sun/star/table/ShadowLocation.hpp> +#include <com/sun/star/table/TableBorder.hpp> +#include <com/sun/star/table/ShadowFormat.hpp> +#include <com/sun/star/table/CellRangeAddress.hpp> +#include <com/sun/star/table/CellContentType.hpp> +#include <com/sun/star/table/TableOrientation.hpp> +#include <com/sun/star/table/CellHoriJustify.hpp> +#include <com/sun/star/util/SortField.hpp> +#include <com/sun/star/util/SortFieldType.hpp> +#include <com/sun/star/table/CellOrientation.hpp> +#include <com/sun/star/table/CellAddress.hpp> +#include <com/sun/star/style/PageStyleLayout.hpp> +#include <com/sun/star/style/BreakType.hpp> +#include <com/sun/star/style/GraphicLocation.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/awt/Selection.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/text/WritingMode2.hpp> +#include <com/sun/star/frame/status/UpperLowerMarginScale.hpp> + +#include <unotools/ucbstreamhelper.hxx> +#include <limits.h> +#include <comphelper/processfactory.hxx> +#include <svtools/grfmgr.hxx> +#include <tools/urlobj.hxx> +#include <comphelper/types.hxx> +#include <svl/memberid.hrc> +#include <svtools/wallitem.hxx> +#include <svl/cntwall.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <svtools/filter.hxx> + +#define GLOBALOVERFLOW3 + +#define _SVX_FRMITEMS_CXX + +#include <editeng/editids.hrc> +#include <editeng/editrids.hrc> +#include <editeng/pbinitem.hxx> +#include <editeng/sizeitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/prntitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/bolnitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/itemtype.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/unoprnms.hxx> +#include <editeng/memberids.hrc> +#include <editeng/editerr.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star; + + +// Konvertierung fuer UNO +#define TWIP_TO_MM100(TWIP) ((TWIP) >= 0 ? (((TWIP)*127L+36L)/72L) : (((TWIP)*127L-36L)/72L)) +#define MM100_TO_TWIP(MM100) ((MM100) >= 0 ? (((MM100)*72L+63L)/127L) : (((MM100)*72L-63L)/127L)) +#define TWIP_TO_MM100_UNSIGNED(TWIP) ((((TWIP)*127L+36L)/72L)) +#define MM100_TO_TWIP_UNSIGNED(MM100) ((((MM100)*72L+63L)/127L)) + +// STATIC DATA ----------------------------------------------------------- + + +inline void SetValueProp( XubString& rStr, const sal_uInt16 nValue, + const sal_uInt16 nProp ) +{ + if( 100 == nProp ) + rStr += String::CreateFromInt32( nValue ); + else + ( rStr += String::CreateFromInt32( nProp )) += sal_Unicode('%'); +} + +inline void SetValueProp( XubString& rStr, const short nValue, + const sal_uInt16 nProp ) +{ + if( 100 == nProp ) + rStr += String::CreateFromInt32( nValue ); + else + ( rStr += String::CreateFromInt32( nProp )) += sal_Unicode('%'); +} + +// ----------------------------------------------------------------------- + +TYPEINIT1_FACTORY(SvxPaperBinItem, SfxByteItem, new SvxPaperBinItem(0)); +TYPEINIT1_FACTORY(SvxSizeItem, SfxPoolItem, new SvxSizeItem(0)); +TYPEINIT1_FACTORY(SvxLRSpaceItem, SfxPoolItem, new SvxLRSpaceItem(0)); +TYPEINIT1_FACTORY(SvxULSpaceItem, SfxPoolItem, new SvxULSpaceItem(0)); +TYPEINIT1_FACTORY(SvxPrintItem, SfxBoolItem, new SvxPrintItem(0)); +TYPEINIT1_FACTORY(SvxOpaqueItem, SfxBoolItem, new SvxOpaqueItem(0)); +TYPEINIT1_FACTORY(SvxProtectItem, SfxPoolItem, new SvxProtectItem(0)); +TYPEINIT1_FACTORY(SvxBrushItem, SfxPoolItem, new SvxBrushItem(0)); +TYPEINIT1_FACTORY(SvxShadowItem, SfxPoolItem, new SvxShadowItem(0)); +TYPEINIT1_FACTORY(SvxBoxItem, SfxPoolItem, new SvxBoxItem(0)); +TYPEINIT1_FACTORY(SvxBoxInfoItem, SfxPoolItem, new SvxBoxInfoItem(0)); +TYPEINIT1_FACTORY(SvxFmtBreakItem, SfxEnumItem, new SvxFmtBreakItem(SVX_BREAK_NONE, 0)); +TYPEINIT1_FACTORY(SvxFmtKeepItem, SfxBoolItem, new SvxFmtKeepItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxLineItem, SfxPoolItem, new SvxLineItem(0)); +TYPEINIT1_FACTORY(SvxFrameDirectionItem, SfxUInt16Item, new SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, 0)); + + +// class SvxPaperBinItem ------------------------------------------------ + +SfxPoolItem* SvxPaperBinItem::Clone( SfxItemPool* ) const +{ + return new SvxPaperBinItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxPaperBinItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxPaperBinItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 nBin; + rStrm >> nBin; + return new SvxPaperBinItem( Which(), nBin ); +} + +// ----------------------------------------------------------------------- + +SfxItemPresentation SvxPaperBinItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + + case SFX_ITEM_PRESENTATION_NAMELESS: + rText = String::CreateFromInt32( GetValue() ); + return SFX_ITEM_PRESENTATION_NAMELESS; + + case SFX_ITEM_PRESENTATION_COMPLETE: + { + BYTE nValue = GetValue(); + + if ( PAPERBIN_PRINTER_SETTINGS == nValue ) + rText = EE_RESSTR(RID_SVXSTR_PAPERBIN_SETTINGS); + else + { + rText = EE_RESSTR(RID_SVXSTR_PAPERBIN); + rText += sal_Unicode(' '); + rText += String::CreateFromInt32( nValue ); + } + return SFX_ITEM_PRESENTATION_COMPLETE; + } + //no break necessary + default: ;//prevent warning + } + + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxSizeItem ----------------------------------------------------- + +SvxSizeItem::SvxSizeItem( const sal_uInt16 nId, const Size& rSize ) : + + SfxPoolItem( nId ), + + aSize( rSize ) +{ +} + +// ----------------------------------------------------------------------- +sal_Bool SvxSizeItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + + awt::Size aTmp(aSize.Width(), aSize.Height()); + if( bConvert ) + { + aTmp.Height = TWIP_TO_MM100(aTmp.Height); + aTmp.Width = TWIP_TO_MM100(aTmp.Width); + } + + switch( nMemberId ) + { + case MID_SIZE_SIZE: rVal <<= aTmp; break; + case MID_SIZE_WIDTH: rVal <<= aTmp.Width; break; + case MID_SIZE_HEIGHT: rVal <<= aTmp.Height; break; + default: DBG_ERROR("Wrong MemberId!"); return sal_False; + } + + return sal_True; +} +// ----------------------------------------------------------------------- +sal_Bool SvxSizeItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + + switch( nMemberId ) + { + case MID_SIZE_SIZE: + { + awt::Size aTmp; + if( rVal >>= aTmp ) + { + if(bConvert) + { + aTmp.Height = MM100_TO_TWIP(aTmp.Height); + aTmp.Width = MM100_TO_TWIP(aTmp.Width); + } + aSize = Size( aTmp.Width, aTmp.Height ); + } + else + { + return sal_False; + } + } + break; + case MID_SIZE_WIDTH: + { + sal_Int32 nVal = 0; + if(!(rVal >>= nVal )) + return sal_False; + + aSize.Width() = bConvert ? MM100_TO_TWIP(nVal) : nVal; + } + break; + case MID_SIZE_HEIGHT: + { + sal_Int32 nVal = 0; + if(!(rVal >>= nVal)) + return sal_True; + + aSize.Height() = bConvert ? MM100_TO_TWIP(nVal) : nVal; + } + break; + default: DBG_ERROR("Wrong MemberId!"); + return sal_False; + } + return sal_True; +} + +// ----------------------------------------------------------------------- + +SvxSizeItem::SvxSizeItem( const sal_uInt16 nId ) : + + SfxPoolItem( nId ) +{ +} + +// ----------------------------------------------------------------------- + +int SvxSizeItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( aSize == ( (SvxSizeItem&)rAttr ).GetSize() ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxSizeItem::Clone( SfxItemPool* ) const +{ + return new SvxSizeItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxSizeItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, const IntlWrapper *pIntl +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + + case SFX_ITEM_PRESENTATION_NAMELESS: + rText = GetMetricText( aSize.Width(), eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + rText += GetMetricText( aSize.Height(), eCoreUnit, ePresUnit, pIntl ); + return SFX_ITEM_PRESENTATION_NAMELESS; + + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = EE_RESSTR(RID_SVXITEMS_SIZE_WIDTH); + rText += GetMetricText( aSize.Width(), eCoreUnit, ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + rText += cpDelim; + rText += EE_RESSTR(RID_SVXITEMS_SIZE_HEIGHT); + rText += GetMetricText( aSize.Height(), eCoreUnit, ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + return SFX_ITEM_PRESENTATION_COMPLETE; + //no break necessary + default: ;//prevent warning + + } +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxSizeItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << aSize.Width(); + rStrm << aSize.Height(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +int SvxSizeItem::ScaleMetrics( long nMult, long nDiv ) +{ + aSize.Width() = Scale( aSize.Width(), nMult, nDiv ); + aSize.Height() = Scale( aSize.Height(), nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxSizeItem::HasMetrics() const +{ + return 1; +} + +// ----------------------------------------------------------------------- + + +SfxPoolItem* SvxSizeItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + long nWidth, nHeight; + rStrm >> nWidth >> nHeight; + + SvxSizeItem* pAttr = new SvxSizeItem( Which() ); + pAttr->SetSize(Size(nWidth, nHeight)); + + return pAttr; +} + +// class SvxLRSpaceItem -------------------------------------------------- + +SvxLRSpaceItem::SvxLRSpaceItem( const sal_uInt16 nId ) : + + SfxPoolItem( nId ), + + nFirstLineOfst ( 0 ), + nTxtLeft ( 0 ), + nLeftMargin ( 0 ), + nRightMargin ( 0 ), + nPropFirstLineOfst( 100 ), + nPropLeftMargin( 100 ), + nPropRightMargin( 100 ), + bAutoFirst ( 0 ) +{ +} + +// ----------------------------------------------------------------------- + +SvxLRSpaceItem::SvxLRSpaceItem( const long nLeft, const long nRight, + const long nTLeft, const short nOfset, + const sal_uInt16 nId ) : + + SfxPoolItem( nId ), + + nFirstLineOfst ( nOfset ), + nTxtLeft ( nTLeft ), + nLeftMargin ( nLeft ), + nRightMargin ( nRight ), + nPropFirstLineOfst( 100 ), + nPropLeftMargin( 100 ), + nPropRightMargin( 100 ), + bAutoFirst ( 0 ) +{ +} + +// ----------------------------------------------------------------------- +sal_Bool SvxLRSpaceItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Bool bRet = sal_True; + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + // jetzt alles signed + case MID_L_MARGIN: + rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100(nLeftMargin) : nLeftMargin); + break; + + case MID_TXT_LMARGIN : + rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100(nTxtLeft) : nTxtLeft); + break; + case MID_R_MARGIN: + rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100(nRightMargin) : nRightMargin); + break; + case MID_L_REL_MARGIN: + rVal <<= (sal_Int16)nPropLeftMargin; + break; + case MID_R_REL_MARGIN: + rVal <<= (sal_Int16)nPropRightMargin; + break; + + case MID_FIRST_LINE_INDENT: + rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100(nFirstLineOfst) : nFirstLineOfst); + break; + + case MID_FIRST_LINE_REL_INDENT: + rVal <<= (sal_Int16)(nPropFirstLineOfst); + break; + + case MID_FIRST_AUTO: + rVal = Bool2Any(IsAutoFirst()); + break; + + default: + bRet = sal_False; + DBG_ERROR("unknown MemberId"); + } + return bRet; +} + +// ----------------------------------------------------------------------- +sal_Bool SvxLRSpaceItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Int32 nVal = 0; + if( nMemberId != MID_FIRST_AUTO && + nMemberId != MID_L_REL_MARGIN && nMemberId != MID_R_REL_MARGIN) + if(!(rVal >>= nVal)) + return sal_False; + + switch( nMemberId ) + { + case MID_L_MARGIN: + SetLeft((sal_Int32)bConvert ? MM100_TO_TWIP(nVal) : nVal); + break; + + case MID_TXT_LMARGIN : + SetTxtLeft((sal_Int32)bConvert ? MM100_TO_TWIP(nVal) : nVal); + break; + + case MID_R_MARGIN: + SetRight((sal_Int32) bConvert ? MM100_TO_TWIP(nVal) : nVal); + break; + case MID_L_REL_MARGIN: + case MID_R_REL_MARGIN: + { + sal_Int32 nRel = 0; + if((rVal >>= nRel) && nRel >= 0 && nRel < USHRT_MAX) + { + if(MID_L_REL_MARGIN== nMemberId) + nPropLeftMargin = (USHORT)nRel; + else + nPropRightMargin = (USHORT)nRel; + } + else + return FALSE; + } + break; + case MID_FIRST_LINE_INDENT : + SetTxtFirstLineOfst((short)(bConvert ? MM100_TO_TWIP(nVal) : nVal)); + break; + + case MID_FIRST_LINE_REL_INDENT: + SetPropTxtFirstLineOfst ( (USHORT)nVal ); + break; + + case MID_FIRST_AUTO: + SetAutoFirst( Any2Bool(rVal) ); + break; + + default: + DBG_ERROR("unknown MemberId"); + return sal_False; + } + return sal_True; +} + +// ----------------------------------------------------------------------- + +// nLeftMargin und nTxtLeft anpassen. + +void SvxLRSpaceItem::AdjustLeft() +{ + if ( 0 > nFirstLineOfst ) + nLeftMargin = nTxtLeft + nFirstLineOfst; + else + nLeftMargin = nTxtLeft; +} + +// ----------------------------------------------------------------------- + +int SvxLRSpaceItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( + nLeftMargin == ((SvxLRSpaceItem&)rAttr).GetLeft() && + nRightMargin == ((SvxLRSpaceItem&)rAttr).GetRight() && + nFirstLineOfst == ((SvxLRSpaceItem&)rAttr).GetTxtFirstLineOfst() && + nPropLeftMargin == ((SvxLRSpaceItem&)rAttr).GetPropLeft() && + nPropRightMargin == ((SvxLRSpaceItem&)rAttr).GetPropRight() && + nPropFirstLineOfst == ((SvxLRSpaceItem&)rAttr).GetPropTxtFirstLineOfst() && + bAutoFirst == ((SvxLRSpaceItem&)rAttr).IsAutoFirst() ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxLRSpaceItem::Clone( SfxItemPool* ) const +{ + return new SvxLRSpaceItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxLRSpaceItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, const IntlWrapper* pIntl +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + case SFX_ITEM_PRESENTATION_NAMELESS: + { + if ( 100 != nPropLeftMargin ) + ( rText = String::CreateFromInt32( nPropLeftMargin )) += sal_Unicode('%'); + else + rText = GetMetricText( (long)nLeftMargin, + eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + if ( 100 != nPropFirstLineOfst ) + ( rText += String::CreateFromInt32( nPropFirstLineOfst )) += sal_Unicode('%'); + else + rText += GetMetricText( (long)nFirstLineOfst, + eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + if ( 100 != nRightMargin ) + ( rText += String::CreateFromInt32( nRightMargin )) += sal_Unicode('%'); + else + rText += GetMetricText( (long)nRightMargin, + eCoreUnit, ePresUnit, pIntl ); + return SFX_ITEM_PRESENTATION_NAMELESS; + } + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR(RID_SVXITEMS_LRSPACE_LEFT); + if ( 100 != nPropLeftMargin ) + ( rText += String::CreateFromInt32( nPropLeftMargin )) += sal_Unicode('%'); + else + { + rText += GetMetricText( (long)nLeftMargin, + eCoreUnit, ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + } + rText += cpDelim; + if ( 100 != nPropFirstLineOfst || nFirstLineOfst ) + { + rText += EE_RESSTR(RID_SVXITEMS_LRSPACE_FLINE); + if ( 100 != nPropFirstLineOfst ) + ( rText += String::CreateFromInt32( nPropFirstLineOfst )) + += sal_Unicode('%'); + else + { + rText += GetMetricText( (long)nFirstLineOfst, + eCoreUnit, ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + } + rText += cpDelim; + } + rText += EE_RESSTR(RID_SVXITEMS_LRSPACE_RIGHT); + if ( 100 != nPropRightMargin ) + ( rText += String::CreateFromInt32( nPropRightMargin )) += sal_Unicode('%'); + else + { + rText += GetMetricText( (long)nRightMargin, + eCoreUnit, ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + } + return SFX_ITEM_PRESENTATION_COMPLETE; + } + default: ;//prevent warning + } +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +// MT: BulletFI: Vor 501 wurde im Outliner das Bullet nicht auf der Position des +// FI positioniert, deshalb muss in aelteren Dokumenten der FI auf 0 stehen. + +#define BULLETLR_MARKER 0x599401FE + +SvStream& SvxLRSpaceItem::Store( SvStream& rStrm , sal_uInt16 nItemVersion ) const +{ + short nSaveFI = nFirstLineOfst; + ((SvxLRSpaceItem*)this)->SetTxtFirstLineOfst( 0 ); // nLeftMargin wird mitmanipuliert, siehe Create() + + sal_uInt16 nMargin = 0; + if( nLeftMargin > 0 ) + nMargin = sal_uInt16( nLeftMargin ); + rStrm << nMargin; + rStrm << nPropLeftMargin; + if( nRightMargin > 0 ) + nMargin = sal_uInt16( nRightMargin ); + else + nMargin = 0; + rStrm << nMargin; + rStrm << nPropRightMargin; + rStrm << nFirstLineOfst; + rStrm << nPropFirstLineOfst; + if( nTxtLeft > 0 ) + nMargin = sal_uInt16( nTxtLeft ); + else + nMargin = 0; + rStrm << nMargin; + if( nItemVersion >= LRSPACE_AUTOFIRST_VERSION ) + { + sal_Int8 nAutoFirst = bAutoFirst ? 1 : 0; + if( nItemVersion >= LRSPACE_NEGATIVE_VERSION && + ( nLeftMargin < 0 || nRightMargin < 0 || nTxtLeft < 0 ) ) + nAutoFirst |= 0x80; + rStrm << nAutoFirst; + + // Ab 6.0 keine Magicnumber schreiben... + DBG_ASSERT( rStrm.GetVersion() <= SOFFICE_FILEFORMAT_50, "MT: Fileformat SvxLRSpaceItem aendern!" ); + rStrm << (sal_uInt32) BULLETLR_MARKER; + rStrm << nSaveFI; + + if( 0x80 & nAutoFirst ) + { + rStrm << nLeftMargin; + rStrm << nRightMargin; + } + } + + ((SvxLRSpaceItem*)this)->SetTxtFirstLineOfst( nSaveFI ); + + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxLRSpaceItem::Create( SvStream& rStrm, sal_uInt16 nVersion ) const +{ + sal_uInt16 left, prpleft, right, prpright, prpfirstline, txtleft; + short firstline; + sal_Int8 autofirst = 0; + + if ( nVersion >= LRSPACE_AUTOFIRST_VERSION ) + { + rStrm >> left >> prpleft >> right >> prpright >> firstline >> + prpfirstline >> txtleft >> autofirst; + + sal_uInt32 nPos = rStrm.Tell(); + sal_uInt32 nMarker; + rStrm >> nMarker; + if ( nMarker == BULLETLR_MARKER ) + { + rStrm >> firstline; + if ( firstline < 0 ) + left = left + static_cast<sal_uInt16>(firstline); // s.u.: txtleft = ... + } + else + rStrm.Seek( nPos ); + } + else if ( nVersion == LRSPACE_TXTLEFT_VERSION ) + { + rStrm >> left >> prpleft >> right >> prpright >> firstline >> + prpfirstline >> txtleft; + } + else if ( nVersion == LRSPACE_16_VERSION ) + { + rStrm >> left >> prpleft >> right >> prpright >> firstline >> + prpfirstline; + } + else + { + sal_Int8 nL, nR, nFL; + rStrm >> left >> nL >> right >> nR >> firstline >> nFL; + prpleft = (sal_uInt16)nL; + prpright = (sal_uInt16)nR; + prpfirstline = (sal_uInt16)nFL; + } + + txtleft = firstline >= 0 ? left : left - firstline; + SvxLRSpaceItem* pAttr = new SvxLRSpaceItem( Which() ); + + pAttr->nLeftMargin = left; + pAttr->nPropLeftMargin = prpleft; + pAttr->nRightMargin = right; + pAttr->nPropRightMargin = prpright; + pAttr->nFirstLineOfst = firstline; + pAttr->nPropFirstLineOfst = prpfirstline; + pAttr->nTxtLeft = txtleft; + pAttr->bAutoFirst = autofirst & 0x01; + if( nVersion >= LRSPACE_NEGATIVE_VERSION && ( autofirst & 0x80 ) ) + { + sal_Int32 nMargin; + rStrm >> nMargin; + pAttr->nLeftMargin = nMargin; + pAttr->nTxtLeft = firstline >= 0 ? nMargin : nMargin - firstline; + rStrm >> nMargin; + pAttr->nRightMargin = nMargin; + } + return pAttr; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxLRSpaceItem::GetVersion( sal_uInt16 nFileVersion ) const +{ + return (nFileVersion == SOFFICE_FILEFORMAT_31) + ? LRSPACE_TXTLEFT_VERSION + : LRSPACE_NEGATIVE_VERSION; +} + +// ----------------------------------------------------------------------- + +int SvxLRSpaceItem::ScaleMetrics( long nMult, long nDiv ) +{ + nFirstLineOfst = (short)Scale( nFirstLineOfst, nMult, nDiv ); + nTxtLeft = Scale( nTxtLeft, nMult, nDiv ); + nLeftMargin = Scale( nLeftMargin, nMult, nDiv ); + nRightMargin = Scale( nRightMargin, nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxLRSpaceItem::HasMetrics() const +{ + return 1; +} + +// class SvxULSpaceItem -------------------------------------------------- + +SvxULSpaceItem::SvxULSpaceItem( const sal_uInt16 nId ) : + + SfxPoolItem( nId ), + + nUpper( 0 ), + nLower( 0 ), + nPropUpper( 100 ), + nPropLower( 100 ) +{ +} + +// ----------------------------------------------------------------------- + +SvxULSpaceItem::SvxULSpaceItem( const sal_uInt16 nUp, const sal_uInt16 nLow, + const sal_uInt16 nId ) : + + SfxPoolItem( nId ), + + nUpper( nUp ), + nLower( nLow ), + nPropUpper( 100 ), + nPropLower( 100 ) +{ +} + +// ----------------------------------------------------------------------- +sal_Bool SvxULSpaceItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + // jetzt alles signed + case 0: + { + ::com::sun::star::frame::status::UpperLowerMarginScale aUpperLowerMarginScale; + aUpperLowerMarginScale.Upper = (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED(nUpper) : nUpper); + aUpperLowerMarginScale.Lower = (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED(nLower) : nPropUpper); + aUpperLowerMarginScale.ScaleUpper = (sal_Int16)nPropUpper; + aUpperLowerMarginScale.ScaleLower = (sal_Int16)nPropLower; + rVal <<= aUpperLowerMarginScale; + break; + } + case MID_UP_MARGIN: rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED(nUpper) : nUpper); break; + case MID_LO_MARGIN: rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED(nLower) : nLower); break; + case MID_UP_REL_MARGIN: rVal <<= (sal_Int16) nPropUpper; break; + case MID_LO_REL_MARGIN: rVal <<= (sal_Int16) nPropLower; break; + } + return sal_True; +} + +// ----------------------------------------------------------------------- +sal_Bool SvxULSpaceItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Int32 nVal = 0; + switch( nMemberId ) + { + case 0: + { + ::com::sun::star::frame::status::UpperLowerMarginScale aUpperLowerMarginScale; + if ( !(rVal >>= aUpperLowerMarginScale )) + return sal_False; + { + SetUpper((sal_uInt16)(bConvert ? MM100_TO_TWIP( aUpperLowerMarginScale.Upper ) : aUpperLowerMarginScale.Upper)); + SetLower((sal_uInt16)(bConvert ? MM100_TO_TWIP( aUpperLowerMarginScale.Lower ) : aUpperLowerMarginScale.Lower)); + if( aUpperLowerMarginScale.ScaleUpper > 1 ) + nPropUpper = aUpperLowerMarginScale.ScaleUpper; + if( aUpperLowerMarginScale.ScaleLower > 1 ) + nPropUpper = aUpperLowerMarginScale.ScaleLower; + } + } + + case MID_UP_MARGIN : + if(!(rVal >>= nVal) || nVal < 0) + return sal_False; + SetUpper((USHORT)(bConvert ? MM100_TO_TWIP(nVal) : nVal)); + break; + case MID_LO_MARGIN : + if(!(rVal >>= nVal) || nVal < 0) + return sal_False; + SetLower((USHORT)(bConvert ? MM100_TO_TWIP(nVal) : nVal)); + break; + case MID_UP_REL_MARGIN: + case MID_LO_REL_MARGIN: + { + sal_Int32 nRel = 0; + if((rVal >>= nRel) && nRel > 1 ) + { + if(MID_UP_REL_MARGIN == nMemberId) + nPropUpper = (USHORT)nRel; + else + nPropLower = (USHORT)nRel; + } + else + return FALSE; + } + break; + + + default: + DBG_ERROR("unknown MemberId"); + return sal_False; + } + return sal_True; +} + +// ----------------------------------------------------------------------- + +int SvxULSpaceItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( nUpper == ( (SvxULSpaceItem&)rAttr ).nUpper && + nLower == ( (SvxULSpaceItem&)rAttr ).nLower && + nPropUpper == ( (SvxULSpaceItem&)rAttr ).nPropUpper && + nPropLower == ( (SvxULSpaceItem&)rAttr ).nPropLower ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxULSpaceItem::Clone( SfxItemPool* ) const +{ + return new SvxULSpaceItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxULSpaceItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, const IntlWrapper *pIntl +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + case SFX_ITEM_PRESENTATION_NAMELESS: + { + if ( 100 != nPropUpper ) + ( rText = String::CreateFromInt32( nPropUpper )) += sal_Unicode('%'); + else + rText = GetMetricText( (long)nUpper, eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + if ( 100 != nPropLower ) + ( rText += String::CreateFromInt32( nPropLower )) += sal_Unicode('%'); + else + rText += GetMetricText( (long)nLower, eCoreUnit, ePresUnit, pIntl ); + return SFX_ITEM_PRESENTATION_NAMELESS; + } + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR(RID_SVXITEMS_ULSPACE_UPPER); + if ( 100 != nPropUpper ) + ( rText += String::CreateFromInt32( nPropUpper )) += sal_Unicode('%'); + else + { + rText += GetMetricText( (long)nUpper, eCoreUnit, ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + } + rText += cpDelim; + rText += EE_RESSTR(RID_SVXITEMS_ULSPACE_LOWER); + if ( 100 != nPropLower ) + ( rText += String::CreateFromInt32( nPropLower )) += sal_Unicode('%'); + else + { + rText += GetMetricText( (long)nLower, eCoreUnit, ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + } + return SFX_ITEM_PRESENTATION_COMPLETE; + } + default: ;//prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxULSpaceItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << GetUpper() + << GetPropUpper() + << GetLower() + << GetPropLower(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxULSpaceItem::Create( SvStream& rStrm, sal_uInt16 nVersion ) const +{ + sal_uInt16 upper, lower, nPL = 0, nPU = 0; + + if ( nVersion == ULSPACE_16_VERSION ) + rStrm >> upper >> nPU >> lower >> nPL; + else + { + sal_Int8 nU, nL; + rStrm >> upper >> nU >> lower >> nL; + nPL = (sal_uInt16)nL; + nPU = (sal_uInt16)nU; + } + + SvxULSpaceItem* pAttr = new SvxULSpaceItem( Which() ); + pAttr->SetUpperValue( upper ); + pAttr->SetLowerValue( lower ); + pAttr->SetPropUpper( nPU ); + pAttr->SetPropLower( nPL ); + return pAttr; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxULSpaceItem::GetVersion( sal_uInt16 /*nFileVersion*/ ) const +{ + return ULSPACE_16_VERSION; +} + +// ----------------------------------------------------------------------- + +int SvxULSpaceItem::ScaleMetrics( long nMult, long nDiv ) +{ + nUpper = (sal_uInt16)Scale( nUpper, nMult, nDiv ); + nLower = (sal_uInt16)Scale( nLower, nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxULSpaceItem::HasMetrics() const +{ + return 1; +} + + +// class SvxPrintItem ---------------------------------------------------- + +SfxPoolItem* SvxPrintItem::Clone( SfxItemPool* ) const +{ + return new SvxPrintItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxPrintItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxPrintItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 bIsPrint; + rStrm >> bIsPrint; + return new SvxPrintItem( Which(), sal_Bool( bIsPrint != 0 ) ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxPrintItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + sal_uInt16 nId = RID_SVXITEMS_PRINT_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_PRINT_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ;//prevent warning + } +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxOpaqueItem --------------------------------------------------- + +SfxPoolItem* SvxOpaqueItem::Clone( SfxItemPool* ) const +{ + return new SvxOpaqueItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxOpaqueItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxOpaqueItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 bIsOpaque; + rStrm >> bIsOpaque; + return new SvxOpaqueItem( Which(), sal_Bool( bIsOpaque != 0 ) ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxOpaqueItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + sal_uInt16 nId = RID_SVXITEMS_OPAQUE_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_OPAQUE_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ;//prevent warning + } +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxProtectItem -------------------------------------------------- + +int SvxProtectItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( bCntnt == ( (SvxProtectItem&)rAttr ).bCntnt && + bSize == ( (SvxProtectItem&)rAttr ).bSize && + bPos == ( (SvxProtectItem&)rAttr ).bPos ); +} + +/*-----------------16.03.98 12:42------------------- +--------------------------------------------------*/ +sal_Bool SvxProtectItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bValue; + switch(nMemberId) + { + case MID_PROTECT_CONTENT : bValue = bCntnt; break; + case MID_PROTECT_SIZE : bValue = bSize; break; + case MID_PROTECT_POSITION: bValue = bPos; break; + default: + DBG_ERROR("falsche MemberId"); + return sal_False; + } + + rVal = Bool2Any( bValue ); + return sal_True; +} +/*-----------------16.03.98 12:42------------------- + +--------------------------------------------------*/ +sal_Bool SvxProtectItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bVal( Any2Bool(rVal) ); + switch(nMemberId) + { + case MID_PROTECT_CONTENT : bCntnt = bVal; break; + case MID_PROTECT_SIZE : bSize = bVal; break; + case MID_PROTECT_POSITION: bPos = bVal; break; + default: + DBG_ERROR("falsche MemberId"); + return sal_False; + } + return sal_True; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxProtectItem::Clone( SfxItemPool* ) const +{ + return new SvxProtectItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxProtectItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + sal_uInt16 nId = RID_SVXITEMS_PROT_CONTENT_FALSE; + + if ( bCntnt ) + nId = RID_SVXITEMS_PROT_CONTENT_TRUE; + rText = EE_RESSTR(nId); + rText += cpDelim; + nId = RID_SVXITEMS_PROT_SIZE_FALSE; + + if ( bSize ) + nId = RID_SVXITEMS_PROT_SIZE_TRUE; + rText += EE_RESSTR(nId); + rText += cpDelim; + nId = RID_SVXITEMS_PROT_POS_FALSE; + + if ( bPos ) + nId = RID_SVXITEMS_PROT_POS_TRUE; + rText += EE_RESSTR(nId); + return ePres; + } + default: ;//prevent warning + } +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxProtectItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + sal_Int8 cProt = 0; + if( IsPosProtected() ) cProt |= 0x01; + if( IsSizeProtected() ) cProt |= 0x02; + if( IsCntntProtected() ) cProt |= 0x04; + rStrm << (sal_Int8) cProt; + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxProtectItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 cFlags; + rStrm >> cFlags; + SvxProtectItem* pAttr = new SvxProtectItem( Which() ); + pAttr->SetPosProtect( sal_Bool( ( cFlags & 0x01 ) != 0 ) ); + pAttr->SetSizeProtect( sal_Bool( ( cFlags & 0x02 ) != 0 ) ); + pAttr->SetCntntProtect( sal_Bool( ( cFlags & 0x04 ) != 0 ) ); + return pAttr; +} + +// class SvxShadowItem --------------------------------------------------- + +SvxShadowItem::SvxShadowItem( const USHORT nId, + const Color *pColor, const USHORT nW, + const SvxShadowLocation eLoc ) : + SfxEnumItemInterface( nId ), + aShadowColor(COL_GRAY), + nWidth ( nW ), + eLocation ( eLoc ) +{ + if ( pColor ) + aShadowColor = *pColor; +} + +// ----------------------------------------------------------------------- +sal_Bool SvxShadowItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + + table::ShadowFormat aShadow; + table::ShadowLocation eSet = table::ShadowLocation_NONE; + switch( eLocation ) + { + case SVX_SHADOW_TOPLEFT : eSet = table::ShadowLocation_TOP_LEFT ; break; + case SVX_SHADOW_TOPRIGHT : eSet = table::ShadowLocation_TOP_RIGHT ; break; + case SVX_SHADOW_BOTTOMLEFT : eSet = table::ShadowLocation_BOTTOM_LEFT ; break; + case SVX_SHADOW_BOTTOMRIGHT: eSet = table::ShadowLocation_BOTTOM_RIGHT; break; + default: ;//prevent warning + } + aShadow.Location = eSet; + aShadow.ShadowWidth = bConvert ? TWIP_TO_MM100_UNSIGNED(nWidth) : nWidth; + aShadow.IsTransparent = aShadowColor.GetTransparency() > 0; + aShadow.Color = aShadowColor.GetRGBColor(); + + switch ( nMemberId ) + { + case MID_LOCATION: rVal <<= aShadow.Location; break; + case MID_WIDTH: rVal <<= aShadow.ShadowWidth; break; + case MID_TRANSPARENT: rVal <<= aShadow.IsTransparent; break; + case MID_BG_COLOR: rVal <<= aShadow.Color; break; + case 0: rVal <<= aShadow; break; + default: DBG_ERROR("Wrong MemberId!"); return sal_False; + } + + return sal_True; +} +// ----------------------------------------------------------------------- +sal_Bool SvxShadowItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + + table::ShadowFormat aShadow; + uno::Any aAny; + sal_Bool bRet = QueryValue( aAny, bConvert ? CONVERT_TWIPS : 0 ) && ( aAny >>= aShadow ); + switch ( nMemberId ) + { + case MID_LOCATION: + { + bRet = (rVal >>= aShadow.Location); + if ( !bRet ) + { + sal_Int16 nVal = 0; + bRet = (rVal >>= nVal); + aShadow.Location = (table::ShadowLocation) nVal; + } + + break; + } + + case MID_WIDTH: rVal >>= aShadow.ShadowWidth; break; + case MID_TRANSPARENT: rVal >>= aShadow.IsTransparent; break; + case MID_BG_COLOR: rVal >>= aShadow.Color; break; + case 0: rVal >>= aShadow; break; + default: DBG_ERROR("Wrong MemberId!"); return sal_False; + } + + if ( bRet ) + { +// SvxShadowLocation eSet = SVX_SHADOW_NONE; + switch( aShadow.Location ) + { + case table::ShadowLocation_TOP_LEFT : eLocation = SVX_SHADOW_TOPLEFT; break; + case table::ShadowLocation_TOP_RIGHT : eLocation = SVX_SHADOW_TOPRIGHT; break; + case table::ShadowLocation_BOTTOM_LEFT : eLocation = SVX_SHADOW_BOTTOMLEFT ; break; + case table::ShadowLocation_BOTTOM_RIGHT: eLocation = SVX_SHADOW_BOTTOMRIGHT; break; + default: ;//prevent warning + } + + nWidth = bConvert ? MM100_TO_TWIP(aShadow.ShadowWidth) : aShadow.ShadowWidth; + Color aSet(aShadow.Color); + aSet.SetTransparency(aShadow.IsTransparent ? 0xff : 0); + aShadowColor = aSet; + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +int SvxShadowItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( ( aShadowColor == ( (SvxShadowItem&)rAttr ).aShadowColor ) && + ( nWidth == ( (SvxShadowItem&)rAttr ).GetWidth() ) && + ( eLocation == ( (SvxShadowItem&)rAttr ).GetLocation() ) ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxShadowItem::Clone( SfxItemPool* ) const +{ + return new SvxShadowItem( *this ); +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxShadowItem::CalcShadowSpace( sal_uInt16 nShadow ) const +{ + sal_uInt16 nSpace = 0; + + switch ( nShadow ) + { + case SHADOW_TOP: + if ( eLocation == SVX_SHADOW_TOPLEFT || + eLocation == SVX_SHADOW_TOPRIGHT ) + nSpace = nWidth; + break; + + case SHADOW_BOTTOM: + if ( eLocation == SVX_SHADOW_BOTTOMLEFT || + eLocation == SVX_SHADOW_BOTTOMRIGHT ) + nSpace = nWidth; + break; + + case SHADOW_LEFT: + if ( eLocation == SVX_SHADOW_TOPLEFT || + eLocation == SVX_SHADOW_BOTTOMLEFT ) + nSpace = nWidth; + break; + + case SHADOW_RIGHT: + if ( eLocation == SVX_SHADOW_TOPRIGHT || + eLocation == SVX_SHADOW_BOTTOMRIGHT ) + nSpace = nWidth; + break; + + default: + DBG_ERROR( "wrong shadow" ); + } + return nSpace; +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxShadowItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, const IntlWrapper *pIntl +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + + case SFX_ITEM_PRESENTATION_NAMELESS: + { + rText = ::GetColorString( aShadowColor ); + rText += cpDelim; + sal_uInt16 nId = RID_SVXITEMS_TRANSPARENT_FALSE; + + if ( aShadowColor.GetTransparency() ) + nId = RID_SVXITEMS_TRANSPARENT_TRUE; + rText += EE_RESSTR(nId); + rText += cpDelim; + rText += GetMetricText( (long)nWidth, eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + rText += EE_RESSTR(RID_SVXITEMS_SHADOW_BEGIN + eLocation); + return ePres; + } + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR(RID_SVXITEMS_SHADOW_COMPLETE); + rText += ::GetColorString( aShadowColor ); + rText += cpDelim; + + sal_uInt16 nId = RID_SVXITEMS_TRANSPARENT_FALSE; + if ( aShadowColor.GetTransparency() ) + nId = RID_SVXITEMS_TRANSPARENT_TRUE; + rText += EE_RESSTR(nId); + rText += cpDelim; + rText += GetMetricText( (long)nWidth, eCoreUnit, ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + rText += cpDelim; + rText += EE_RESSTR(RID_SVXITEMS_SHADOW_BEGIN + eLocation); + return ePres; + } + default: ;//prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxShadowItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8) GetLocation() + << (sal_uInt16) GetWidth() + << (sal_Bool)(aShadowColor.GetTransparency() > 0) + << GetColor() + << GetColor() + << (sal_Int8)(aShadowColor.GetTransparency() > 0 ? 0 : 1); //BRUSH_NULL : BRUSH_SOLID + return rStrm; +} + +// ----------------------------------------------------------------------- + +int SvxShadowItem::ScaleMetrics( long nMult, long nDiv ) +{ + nWidth = (sal_uInt16)Scale( nWidth, nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxShadowItem::HasMetrics() const +{ + return 1; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxShadowItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 cLoc; + sal_uInt16 _nWidth; + sal_Bool bTrans; + Color aColor; + Color aFillColor; + sal_Int8 nStyle; + rStrm >> cLoc >> _nWidth + >> bTrans >> aColor >> aFillColor >> nStyle; + aColor.SetTransparency(bTrans ? 0xff : 0); + return new SvxShadowItem( Which(), &aColor, _nWidth, (SvxShadowLocation)cLoc ); +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxShadowItem::GetValueCount() const +{ + return SVX_SHADOW_END; // SVX_SHADOW_BOTTOMRIGHT + 1 +} + +// ----------------------------------------------------------------------- + +XubString SvxShadowItem::GetValueTextByPos( sal_uInt16 nPos ) const +{ + DBG_ASSERT( nPos < SVX_SHADOW_END, "enum overflow!" ); + return XubString( EditResId( RID_SVXITEMS_SHADOW_BEGIN + nPos ) ); +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxShadowItem::GetEnumValue() const +{ + return (sal_uInt16)GetLocation(); +} + +// ----------------------------------------------------------------------- + +void SvxShadowItem::SetEnumValue( sal_uInt16 nVal ) +{ + SetLocation( (const SvxShadowLocation)nVal ); +} + +// class SvxBorderLine -------------------------------------------------- + +SvxBorderLine::SvxBorderLine( const Color *pCol, sal_uInt16 nOut, sal_uInt16 nIn, sal_uInt16 nDist ) +: nOutWidth( nOut ) +, nInWidth ( nIn ) +, nDistance( nDist ) +{ + if ( pCol ) + aColor = *pCol; +} + +// ----------------------------------------------------------------------- + +SvxBorderLine::SvxBorderLine( const SvxBorderLine& r ) +{ + *this = r; +} + +// ----------------------------------------------------------------------- + +SvxBorderLine& SvxBorderLine::operator=( const SvxBorderLine& r ) +{ + aColor = r.aColor; + nOutWidth = r.nOutWidth; + nInWidth = r.nInWidth; + nDistance = r.nDistance; + return *this; +} + +// ----------------------------------------------------------------------- + +void SvxBorderLine::ScaleMetrics( long nMult, long nDiv ) +{ + nOutWidth = (sal_uInt16)Scale( nOutWidth, nMult, nDiv ); + nInWidth = (sal_uInt16)Scale( nInWidth, nMult, nDiv ); + nDistance = (sal_uInt16)Scale( nDistance, nMult, nDiv ); +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxBorderLine::operator==( const SvxBorderLine& rCmp ) const +{ + return ( ( aColor == rCmp.GetColor() ) && + ( nInWidth == rCmp.GetInWidth() ) && + ( nOutWidth == rCmp.GetOutWidth() ) && + ( nDistance == rCmp.GetDistance() ) ); +} + +// ----------------------------------------------------------------------- + +XubString SvxBorderLine::GetValueString( SfxMapUnit eSrcUnit, + SfxMapUnit eDestUnit, + const IntlWrapper* pIntl, + sal_Bool bMetricStr) const +{ +#ifndef SVX_LIGHT + sal_uInt16 nResId = 0; + + if ( 0 == nDistance ) + { + // einfach Linie + if ( DEF_LINE_WIDTH_0 == nOutWidth ) + nResId = RID_SINGLE_LINE0; + else if ( DEF_LINE_WIDTH_1 == nOutWidth ) + nResId = RID_SINGLE_LINE1; + else if ( DEF_LINE_WIDTH_2 == nOutWidth ) + nResId = RID_SINGLE_LINE2; + else if ( DEF_LINE_WIDTH_3 == nOutWidth ) + nResId = RID_SINGLE_LINE3; + else if ( DEF_LINE_WIDTH_4 == nOutWidth ) + nResId = RID_SINGLE_LINE4; + } + else if ( DEF_LINE_WIDTH_1 == nDistance ) + { + // doppelte Linie, kleiner Abstand + if ( DEF_LINE_WIDTH_0 == nOutWidth && DEF_LINE_WIDTH_0 == nInWidth ) + nResId = RID_DOUBLE_LINE0; + else if ( DEF_LINE_WIDTH_1 == nOutWidth && + DEF_LINE_WIDTH_1 == nInWidth ) + nResId = RID_DOUBLE_LINE2; + else if ( DEF_LINE_WIDTH_1 == nOutWidth && + DEF_LINE_WIDTH_2 == nInWidth ) + nResId = RID_DOUBLE_LINE8; + } + else if ( DEF_LINE_WIDTH_2 == nDistance ) + { + // doppelte Linie, gro\ser Abstand + if ( DEF_LINE_WIDTH_0 == nOutWidth && DEF_LINE_WIDTH_0 == nInWidth ) + nResId = RID_DOUBLE_LINE1; + else if ( DEF_LINE_WIDTH_2 == nOutWidth && + DEF_LINE_WIDTH_2 == nInWidth ) + nResId = RID_DOUBLE_LINE3; + else if ( DEF_LINE_WIDTH_1 == nOutWidth && + DEF_LINE_WIDTH_0 == nInWidth ) + nResId = RID_DOUBLE_LINE4; + else if ( DEF_LINE_WIDTH_2 == nOutWidth && + DEF_LINE_WIDTH_0 == nInWidth ) + nResId = RID_DOUBLE_LINE5; + else if ( DEF_LINE_WIDTH_3 == nOutWidth && + DEF_LINE_WIDTH_0 == nInWidth ) + nResId = RID_DOUBLE_LINE6; + else if ( DEF_LINE_WIDTH_2 == nOutWidth && + DEF_LINE_WIDTH_1 == nInWidth ) + nResId = RID_DOUBLE_LINE7; + else if ( DEF_LINE_WIDTH_3 == nOutWidth && + DEF_LINE_WIDTH_2 == nInWidth ) + nResId = RID_DOUBLE_LINE9; + else if ( DEF_LINE_WIDTH_2 == nOutWidth && + DEF_LINE_WIDTH_3 == nInWidth ) + nResId = RID_DOUBLE_LINE10; + } + String aStr; + aStr += sal_Unicode('('); + aStr += ::GetColorString( aColor ); + aStr += cpDelim; + + if ( nResId ) + aStr += EE_RESSTR(nResId); + else + { + String sMetric = EE_RESSTR(GetMetricId( eDestUnit )); + aStr += GetMetricText( (long)nInWidth, eSrcUnit, eDestUnit, pIntl ); + if ( bMetricStr ) + aStr += sMetric; + aStr += cpDelim; + aStr += GetMetricText( (long)nOutWidth, eSrcUnit, eDestUnit, pIntl ); + if ( bMetricStr ) + aStr += sMetric; + aStr += cpDelim; + aStr += GetMetricText( (long)nDistance, eSrcUnit, eDestUnit, pIntl ); + if ( bMetricStr ) + aStr += sMetric; + } + aStr += sal_Unicode(')'); + return aStr; +#else + return UniString(); +#endif +} + +bool SvxBorderLine::HasPriority( const SvxBorderLine& rOtherLine ) const +{ + const USHORT nThisSize = GetOutWidth() + GetDistance() + GetInWidth(); + const USHORT nOtherSize = rOtherLine.GetOutWidth() + rOtherLine.GetDistance() + rOtherLine.GetInWidth(); + + if (nThisSize > nOtherSize) + { + return true; + } + else if (nThisSize < nOtherSize) + { + return false; + } + else + { + if ( rOtherLine.GetInWidth() && !GetInWidth() ) + { + return true; + } + else if ( GetInWidth() && !rOtherLine.GetInWidth() ) + { + return false; + } + else + { + return false; + } + } +} + +// class SvxBoxItem ------------------------------------------------------ + +SvxBoxItem::SvxBoxItem( const SvxBoxItem& rCpy ) : + + SfxPoolItem ( rCpy ), + nTopDist ( rCpy.nTopDist ), + nBottomDist ( rCpy.nBottomDist ), + nLeftDist ( rCpy.nLeftDist ), + nRightDist ( rCpy.nRightDist ) + +{ + pTop = rCpy.GetTop() ? new SvxBorderLine( *rCpy.GetTop() ) : 0; + pBottom = rCpy.GetBottom() ? new SvxBorderLine( *rCpy.GetBottom() ) : 0; + pLeft = rCpy.GetLeft() ? new SvxBorderLine( *rCpy.GetLeft() ) : 0; + pRight = rCpy.GetRight() ? new SvxBorderLine( *rCpy.GetRight() ) : 0; +} + +// ----------------------------------------------------------------------- + +SvxBoxItem::SvxBoxItem( const sal_uInt16 nId ) : + SfxPoolItem( nId ), + + pTop ( 0 ), + pBottom ( 0 ), + pLeft ( 0 ), + pRight ( 0 ), + nTopDist ( 0 ), + nBottomDist ( 0 ), + nLeftDist ( 0 ), + nRightDist ( 0 ) + +{ +} + +// ----------------------------------------------------------------------- + +SvxBoxItem::~SvxBoxItem() +{ + delete pTop; + delete pBottom; + delete pLeft; + delete pRight; +} + +// ----------------------------------------------------------------------- + +SvxBoxItem& SvxBoxItem::operator=( const SvxBoxItem& rBox ) +{ + nTopDist = rBox.nTopDist; + nBottomDist = rBox.nBottomDist; + nLeftDist = rBox.nLeftDist; + nRightDist = rBox.nRightDist; + SetLine( rBox.GetTop(), BOX_LINE_TOP ); + SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM ); + SetLine( rBox.GetLeft(), BOX_LINE_LEFT ); + SetLine( rBox.GetRight(), BOX_LINE_RIGHT ); + return *this; +} + +// ----------------------------------------------------------------------- + +inline sal_Bool CmpBrdLn( const SvxBorderLine* pBrd1, const SvxBorderLine* pBrd2 ) +{ + sal_Bool bRet; + if( 0 != pBrd1 ? 0 == pBrd2 : 0 != pBrd2 ) + bRet = sal_False; + else + if( !pBrd1 ) + bRet = sal_True; + else + bRet = (*pBrd1 == *pBrd2); + return bRet; +} + +// ----------------------------------------------------------------------- + +int SvxBoxItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( + ( nTopDist == ( (SvxBoxItem&)rAttr ).nTopDist ) && + ( nBottomDist == ( (SvxBoxItem&)rAttr ).nBottomDist ) && + ( nLeftDist == ( (SvxBoxItem&)rAttr ).nLeftDist ) && + ( nRightDist == ( (SvxBoxItem&)rAttr ).nRightDist ) && + CmpBrdLn( pTop, ( (SvxBoxItem&)rAttr ).GetTop() ) && + CmpBrdLn( pBottom, ( (SvxBoxItem&)rAttr ).GetBottom() ) && + CmpBrdLn( pLeft, ( (SvxBoxItem&)rAttr ).GetLeft() ) && + CmpBrdLn( pRight, ( (SvxBoxItem&)rAttr ).GetRight() ) ); +} + +// ----------------------------------------------------------------------- +table::BorderLine SvxBoxItem::SvxLineToLine(const SvxBorderLine* pLine, sal_Bool bConvert) +{ + table::BorderLine aLine; + if(pLine) + { + aLine.Color = pLine->GetColor().GetColor() ; + aLine.InnerLineWidth = sal_uInt16( bConvert ? TWIP_TO_MM100_UNSIGNED(pLine->GetInWidth() ): pLine->GetInWidth() ); + aLine.OuterLineWidth = sal_uInt16( bConvert ? TWIP_TO_MM100_UNSIGNED(pLine->GetOutWidth()): pLine->GetOutWidth() ); + aLine.LineDistance = sal_uInt16( bConvert ? TWIP_TO_MM100_UNSIGNED(pLine->GetDistance()): pLine->GetDistance() ); + } + else + aLine.Color = aLine.InnerLineWidth = aLine.OuterLineWidth = aLine.LineDistance = 0; + return aLine; +} +// ----------------------------------------------------------------------- +sal_Bool SvxBoxItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + table::BorderLine aRetLine; + sal_uInt16 nDist = 0; + sal_Bool bDistMember = sal_False; + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bSerialize = sal_False; + switch(nMemberId) + { + case 0: + { + // 4 Borders and 5 distances + uno::Sequence< uno::Any > aSeq( 9 ); + aSeq[0] = uno::makeAny( SvxBoxItem::SvxLineToLine(GetLeft(), bConvert) ); + aSeq[1] = uno::makeAny( SvxBoxItem::SvxLineToLine(GetRight(), bConvert) ); + aSeq[2] = uno::makeAny( SvxBoxItem::SvxLineToLine(GetBottom(), bConvert) ); + aSeq[3] = uno::makeAny( SvxBoxItem::SvxLineToLine(GetTop(), bConvert) ); + aSeq[4] <<= uno::makeAny( (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED( GetDistance()) : GetDistance())); + aSeq[5] <<= uno::makeAny( (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED( nTopDist ) : nTopDist )); + aSeq[6] <<= uno::makeAny( (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED( nBottomDist ) : nBottomDist )); + aSeq[7] <<= uno::makeAny( (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED( nLeftDist ) : nLeftDist )); + aSeq[8] <<= uno::makeAny( (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED( nRightDist ) : nRightDist )); + rVal = uno::makeAny( aSeq ); + return sal_True; + } + case MID_LEFT_BORDER: + bSerialize = sal_True; // intentionally no break! + case LEFT_BORDER: + aRetLine = SvxBoxItem::SvxLineToLine(GetLeft(), bConvert); + break; + case MID_RIGHT_BORDER: + bSerialize = sal_True; // intentionally no break! + case RIGHT_BORDER: + aRetLine = SvxBoxItem::SvxLineToLine(GetRight(), bConvert); + break; + case MID_BOTTOM_BORDER: + bSerialize = sal_True; // intentionally no break! + case BOTTOM_BORDER: + aRetLine = SvxBoxItem::SvxLineToLine(GetBottom(), bConvert); + break; + case MID_TOP_BORDER: + bSerialize = sal_True; // intentionally no break! + case TOP_BORDER: + aRetLine = SvxBoxItem::SvxLineToLine(GetTop(), bConvert); + break; + case BORDER_DISTANCE: + nDist = GetDistance(); + bDistMember = sal_True; + break; + case TOP_BORDER_DISTANCE: + nDist = nTopDist; + bDistMember = sal_True; + break; + case BOTTOM_BORDER_DISTANCE: + nDist = nBottomDist; + bDistMember = sal_True; + break; + case LEFT_BORDER_DISTANCE: + nDist = nLeftDist; + bDistMember = sal_True; + break; + case RIGHT_BORDER_DISTANCE: + nDist = nRightDist; + bDistMember = sal_True; + break; + } + + if( bDistMember ) + rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED(nDist) : nDist); + else + { +/* + if ( bSerialize ) + { + ::com::sun::star::uno::Sequence < ::com::sun::star::uno::Any > aSeq(4); + aSeq[0] <<= aRetLine.Color; + aSeq[1] <<= aRetLine.InnerLineWidth; + aSeq[2] <<= aRetLine.OuterLineWidth; + aSeq[3] <<= aRetLine.LineDistance; + rVal <<= aSeq; + } + else +*/ + rVal <<= aRetLine; + } + + return sal_True; +} + +// ----------------------------------------------------------------------- +sal_Bool SvxBoxItem::LineToSvxLine(const ::com::sun::star::table::BorderLine& rLine, SvxBorderLine& rSvxLine, sal_Bool bConvert) +{ + rSvxLine.SetColor( Color(rLine.Color)); + rSvxLine.SetInWidth( sal_uInt16( bConvert ? MM100_TO_TWIP(rLine.InnerLineWidth) : rLine.InnerLineWidth )); + rSvxLine.SetOutWidth( sal_uInt16( bConvert ? MM100_TO_TWIP(rLine.OuterLineWidth) : rLine.OuterLineWidth )); + rSvxLine.SetDistance( sal_uInt16( bConvert ? MM100_TO_TWIP(rLine.LineDistance ) : rLine.LineDistance )); + sal_Bool bRet = rLine.InnerLineWidth > 0 || rLine.OuterLineWidth > 0; + return bRet; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxBoxItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + sal_uInt16 nLine = BOX_LINE_TOP; + sal_Bool bDistMember = sal_False; + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case 0: + { + uno::Sequence< uno::Any > aSeq; + if (( rVal >>= aSeq ) && ( aSeq.getLength() == 9 )) + { + // 4 Borders and 5 distances + sal_Int32 nDist = 0; + SvxBorderLine aLine; + table::BorderLine aBorderLine; + if ( aSeq[0] >>= aBorderLine ) + { + sal_Bool bSet = SvxBoxItem::LineToSvxLine(aBorderLine, aLine, bConvert); + SetLine(bSet ? &aLine : 0, BOX_LINE_LEFT ); + } + else + return sal_False; + + if ( aSeq[1] >>= aBorderLine ) + { + sal_Bool bSet = SvxBoxItem::LineToSvxLine(aBorderLine, aLine, bConvert); + SetLine(bSet ? &aLine : 0, BOX_LINE_RIGHT ); + } + else + return sal_False; + + if ( aSeq[2] >>= aBorderLine ) + { + sal_Bool bSet = SvxBoxItem::LineToSvxLine(aBorderLine, aLine, bConvert); + SetLine(bSet ? &aLine : 0, BOX_LINE_BOTTOM ); + } + else + return sal_False; + + if ( aSeq[3] >>= aBorderLine ) + { + sal_Bool bSet = SvxBoxItem::LineToSvxLine(aBorderLine, aLine, bConvert); + SetLine(bSet ? &aLine : 0, BOX_LINE_TOP ); + } + else + return sal_False; + + sal_uInt16 nLines[4] = { BOX_LINE_TOP, BOX_LINE_BOTTOM, BOX_LINE_LEFT, BOX_LINE_RIGHT }; + for ( sal_Int32 n = 4; n < 9; n++ ) + { + if ( aSeq[n] >>= nDist ) + { + if( bConvert ) + nDist = MM100_TO_TWIP(nDist); + if ( n == 4 ) + SetDistance( sal_uInt16( nDist )); + else + SetDistance( sal_uInt16( nDist ), nLines[n-5] ); + } + else + return sal_False; + } + + return sal_True; + } + else + return sal_False; + } + case LEFT_BORDER_DISTANCE: + bDistMember = sal_True; + case LEFT_BORDER: + case MID_LEFT_BORDER: + nLine = BOX_LINE_LEFT; + break; + case RIGHT_BORDER_DISTANCE: + bDistMember = sal_True; + case RIGHT_BORDER: + case MID_RIGHT_BORDER: + nLine = BOX_LINE_RIGHT; + break; + case BOTTOM_BORDER_DISTANCE: + bDistMember = sal_True; + case BOTTOM_BORDER: + case MID_BOTTOM_BORDER: + nLine = BOX_LINE_BOTTOM; + break; + case TOP_BORDER_DISTANCE: + bDistMember = sal_True; + case TOP_BORDER: + case MID_TOP_BORDER: + nLine = BOX_LINE_TOP; + break; + } + + if( bDistMember || nMemberId == BORDER_DISTANCE ) + { + sal_Int32 nDist = 0; + if(!(rVal >>= nDist)) + return sal_False; + + if(nDist >= 0) + { + if( bConvert ) + nDist = MM100_TO_TWIP(nDist); + if( nMemberId == BORDER_DISTANCE ) + SetDistance( sal_uInt16( nDist )); + else + SetDistance( sal_uInt16( nDist ), nLine ); + } + } + else + { + SvxBorderLine aLine; + if( !rVal.hasValue() ) + return sal_False; + + table::BorderLine aBorderLine; + if( rVal >>= aBorderLine ) + { + // usual struct + } + else if (rVal.getValueTypeClass() == uno::TypeClass_SEQUENCE ) + { + // serialization for basic macro recording + uno::Reference < script::XTypeConverter > xConverter + ( ::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.script.Converter")), + uno::UNO_QUERY ); + uno::Sequence < uno::Any > aSeq; + uno::Any aNew; + try { aNew = xConverter->convertTo( rVal, ::getCppuType((const uno::Sequence < uno::Any >*)0) ); } + catch (uno::Exception&) {} + + aNew >>= aSeq; + if ( aSeq.getLength() == 4 ) + { + sal_Int32 nVal = 0; + if ( aSeq[0] >>= nVal ) + aBorderLine.Color = nVal; + if ( aSeq[1] >>= nVal ) + aBorderLine.InnerLineWidth = (sal_Int16) nVal; + if ( aSeq[2] >>= nVal ) + aBorderLine.OuterLineWidth = (sal_Int16) nVal; + if ( aSeq[3] >>= nVal ) + aBorderLine.LineDistance = (sal_Int16) nVal; + } + else + return sal_False; + } + else + return sal_False; + + sal_Bool bSet = SvxBoxItem::LineToSvxLine(aBorderLine, aLine, bConvert); + SetLine(bSet ? &aLine : 0, nLine); + } + + return sal_True; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBoxItem::Clone( SfxItemPool* ) const +{ + return new SvxBoxItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxBoxItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, const IntlWrapper *pIntl +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + + case SFX_ITEM_PRESENTATION_NAMELESS: + { + rText.Erase(); + + if ( pTop ) + { + rText = pTop->GetValueString( eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + } + if( !(pTop && pBottom && pLeft && pRight && + *pTop == *pBottom && *pTop == *pLeft && *pTop == *pRight) ) + { + if ( pBottom ) + { + rText += pBottom->GetValueString( eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + } + if ( pLeft ) + { + rText += pLeft->GetValueString( eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + } + if ( pRight ) + { + rText += pRight->GetValueString( eCoreUnit, ePresUnit, pIntl ); + rText += cpDelim; + } + } + rText += GetMetricText( (long)nTopDist, eCoreUnit, ePresUnit, pIntl ); + if( nTopDist != nBottomDist || nTopDist != nLeftDist || + nTopDist != nRightDist ) + { + (((((rText += cpDelim) + += GetMetricText( (long)nBottomDist, eCoreUnit, + ePresUnit, pIntl )) + += cpDelim) + += GetMetricText( (long)nLeftDist, eCoreUnit, ePresUnit, pIntl )) + += cpDelim) + += GetMetricText( (long)nRightDist, eCoreUnit, + ePresUnit, pIntl ); + } + return SFX_ITEM_PRESENTATION_NAMELESS; + } + case SFX_ITEM_PRESENTATION_COMPLETE: + { + if( !(pTop || pBottom || pLeft || pRight) ) + { + rText = EE_RESSTR(RID_SVXITEMS_BORDER_NONE); + rText += cpDelim; + } + else + { + rText = EE_RESSTR(RID_SVXITEMS_BORDER_COMPLETE); + if( pTop && pBottom && pLeft && pRight && + *pTop == *pBottom && *pTop == *pLeft && *pTop == *pRight ) + { + rText += pTop->GetValueString( eCoreUnit, ePresUnit, pIntl, sal_True ); + rText += cpDelim; + } + else + { + if ( pTop ) + { + rText += EE_RESSTR(RID_SVXITEMS_BORDER_TOP); + rText += pTop->GetValueString( eCoreUnit, ePresUnit, pIntl, sal_True ); + rText += cpDelim; + } + if ( pBottom ) + { + rText += EE_RESSTR(RID_SVXITEMS_BORDER_BOTTOM); + rText += pBottom->GetValueString( eCoreUnit, ePresUnit, pIntl, sal_True ); + rText += cpDelim; + } + if ( pLeft ) + { + rText += EE_RESSTR(RID_SVXITEMS_BORDER_LEFT); + rText += pLeft->GetValueString( eCoreUnit, ePresUnit, pIntl, sal_True ); + rText += cpDelim; + } + if ( pRight ) + { + rText += EE_RESSTR(RID_SVXITEMS_BORDER_RIGHT); + rText += pRight->GetValueString( eCoreUnit, ePresUnit, pIntl, sal_True ); + rText += cpDelim; + } + } + } + + rText += EE_RESSTR(RID_SVXITEMS_BORDER_DISTANCE); + if( nTopDist == nBottomDist && nTopDist == nLeftDist && + nTopDist == nRightDist ) + { + rText += GetMetricText( (long)nTopDist, eCoreUnit, + ePresUnit, pIntl ); + rText += EE_RESSTR(GetMetricId(ePresUnit)); + } + else + { + (((rText += EE_RESSTR(RID_SVXITEMS_BORDER_TOP)) + += GetMetricText( (long)nTopDist, eCoreUnit, + ePresUnit, pIntl )) + += EE_RESSTR(GetMetricId(ePresUnit))) + += cpDelim; + (((rText += EE_RESSTR(RID_SVXITEMS_BORDER_BOTTOM)) + += GetMetricText( (long)nBottomDist, eCoreUnit, + ePresUnit, pIntl )) + += EE_RESSTR(GetMetricId(ePresUnit))) + += cpDelim; + (((rText += EE_RESSTR(RID_SVXITEMS_BORDER_LEFT)) + += GetMetricText( (long)nLeftDist, eCoreUnit, + ePresUnit, pIntl )) + += EE_RESSTR(GetMetricId(ePresUnit))) + += cpDelim; + ((rText += EE_RESSTR(RID_SVXITEMS_BORDER_RIGHT)) + += GetMetricText( (long)nRightDist, eCoreUnit, + ePresUnit, pIntl )) + += EE_RESSTR(GetMetricId(ePresUnit)); + } + return SFX_ITEM_PRESENTATION_COMPLETE; + } + default: ;//prevent warning + } +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxBoxItem::Store( SvStream& rStrm , sal_uInt16 nItemVersion ) const +{ + rStrm << (sal_uInt16) GetDistance(); + const SvxBorderLine* pLine[ 4 ]; // top, left, right, bottom + pLine[ 0 ] = GetTop(); + pLine[ 1 ] = GetLeft(); + pLine[ 2 ] = GetRight(); + pLine[ 3 ] = GetBottom(); + + for( int i = 0; i < 4; i++ ) + { + const SvxBorderLine* l = pLine[ i ]; + if( l ) + { + rStrm << (sal_Int8) i + << l->GetColor() + << (sal_uInt16) l->GetOutWidth() + << (sal_uInt16) l->GetInWidth() + << (sal_uInt16) l->GetDistance(); + } + } + sal_Int8 cLine = 4; + if( nItemVersion >= BOX_4DISTS_VERSION && + !(nTopDist == nLeftDist && + nTopDist == nRightDist && + nTopDist == nBottomDist) ) + { + cLine |= 0x10; + } + + rStrm << cLine; + + if( nItemVersion >= BOX_4DISTS_VERSION && (cLine & 0x10) != 0 ) + { + rStrm << (sal_uInt16)nTopDist + << (sal_uInt16)nLeftDist + << (sal_uInt16)nRightDist + << (sal_uInt16)nBottomDist; + } + + return rStrm; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxBoxItem::GetVersion( sal_uInt16 nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxBoxItem: Gibt es ein neues Fileformat?" ); + return SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer ? 0 : BOX_4DISTS_VERSION; +} + +// ----------------------------------------------------------------------- + +int SvxBoxItem::ScaleMetrics( long nMult, long nDiv ) +{ + if ( pTop ) pTop->ScaleMetrics( nMult, nDiv ); + if ( pBottom ) pBottom->ScaleMetrics( nMult, nDiv ); + if ( pLeft ) pLeft->ScaleMetrics( nMult, nDiv ); + if ( pRight ) pBottom->ScaleMetrics( nMult, nDiv ); + nTopDist = (sal_uInt16)Scale( nTopDist, nMult, nDiv ); + nBottomDist = (sal_uInt16)Scale( nBottomDist, nMult, nDiv ); + nLeftDist = (sal_uInt16)Scale( nLeftDist, nMult, nDiv ); + nRightDist = (sal_uInt16)Scale( nRightDist, nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxBoxItem::HasMetrics() const +{ + return 1; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBoxItem::Create( SvStream& rStrm, sal_uInt16 nIVersion ) const +{ + sal_uInt16 nDistance; + rStrm >> nDistance; + SvxBoxItem* pAttr = new SvxBoxItem( Which() ); + + sal_uInt16 aLineMap[4] = { BOX_LINE_TOP, BOX_LINE_LEFT, + BOX_LINE_RIGHT, BOX_LINE_BOTTOM }; + + sal_Int8 cLine; + while( sal_True ) + { + rStrm >> cLine; + + if( cLine > 3 ) + break; + sal_uInt16 nOutline, nInline, _nDistance; + Color aColor; + rStrm >> aColor >> nOutline >> nInline >> _nDistance; + SvxBorderLine aBorder( &aColor, nOutline, nInline, _nDistance ); + + pAttr->SetLine( &aBorder, aLineMap[cLine] ); + } + + if( nIVersion >= BOX_4DISTS_VERSION && (cLine&0x10) != 0 ) + { + for( sal_uInt16 i=0; i < 4; i++ ) + { + sal_uInt16 nDist; + rStrm >> nDist; + pAttr->SetDistance( nDist, aLineMap[i] ); + } + } + else + { + pAttr->SetDistance( nDistance ); + } + + return pAttr; +} + +// ----------------------------------------------------------------------- + +const SvxBorderLine *SvxBoxItem::GetLine( sal_uInt16 nLine ) const +{ + const SvxBorderLine *pRet = 0; + + switch ( nLine ) + { + case BOX_LINE_TOP: + pRet = pTop; + break; + case BOX_LINE_BOTTOM: + pRet = pBottom; + break; + case BOX_LINE_LEFT: + pRet = pLeft; + break; + case BOX_LINE_RIGHT: + pRet = pRight; + break; + default: + DBG_ERROR( "wrong line" ); + break; + } + + return pRet; +} + +// ----------------------------------------------------------------------- + +void SvxBoxItem::SetLine( const SvxBorderLine* pNew, sal_uInt16 nLine ) +{ + SvxBorderLine* pTmp = pNew ? new SvxBorderLine( *pNew ) : 0; + + switch ( nLine ) + { + case BOX_LINE_TOP: + delete pTop; + pTop = pTmp; + break; + case BOX_LINE_BOTTOM: + delete pBottom; + pBottom = pTmp; + break; + case BOX_LINE_LEFT: + delete pLeft; + pLeft = pTmp; + break; + case BOX_LINE_RIGHT: + delete pRight; + pRight = pTmp; + break; + default: + DBG_ERROR( "wrong line" ); + } +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxBoxItem::GetDistance() const +{ + // The smallest distance that is not 0 will be returned. + sal_uInt16 nDist = nTopDist; + if( nBottomDist && (!nDist || nBottomDist < nDist) ) + nDist = nBottomDist; + if( nLeftDist && (!nDist || nLeftDist < nDist) ) + nDist = nLeftDist; + if( nRightDist && (!nDist || nRightDist < nDist) ) + nDist = nRightDist; + + return nDist; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxBoxItem::GetDistance( sal_uInt16 nLine ) const +{ + sal_uInt16 nDist = 0; + switch ( nLine ) + { + case BOX_LINE_TOP: + nDist = nTopDist; + break; + case BOX_LINE_BOTTOM: + nDist = nBottomDist; + break; + case BOX_LINE_LEFT: + nDist = nLeftDist; + break; + case BOX_LINE_RIGHT: + nDist = nRightDist; + break; + default: + DBG_ERROR( "wrong line" ); + } + + return nDist; +} + +// ----------------------------------------------------------------------- + +void SvxBoxItem::SetDistance( sal_uInt16 nNew, sal_uInt16 nLine ) +{ + switch ( nLine ) + { + case BOX_LINE_TOP: + nTopDist = nNew; + break; + case BOX_LINE_BOTTOM: + nBottomDist = nNew; + break; + case BOX_LINE_LEFT: + nLeftDist = nNew; + break; + case BOX_LINE_RIGHT: + nRightDist = nNew; + break; + default: + DBG_ERROR( "wrong line" ); + } +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxBoxItem::CalcLineSpace( sal_uInt16 nLine, sal_Bool bIgnoreLine ) const +{ + SvxBorderLine* pTmp = 0; + sal_uInt16 nDist = 0; + switch ( nLine ) + { + case BOX_LINE_TOP: + pTmp = pTop; + nDist = nTopDist; + break; + case BOX_LINE_BOTTOM: + pTmp = pBottom; + nDist = nBottomDist; + break; + case BOX_LINE_LEFT: + pTmp = pLeft; + nDist = nLeftDist; + break; + case BOX_LINE_RIGHT: + pTmp = pRight; + nDist = nRightDist; + break; + default: + DBG_ERROR( "wrong line" ); + } + + if( pTmp ) + { + nDist = nDist + (sal_uInt16)(pTmp->GetOutWidth()) + (sal_uInt16)(pTmp->GetInWidth()) + (sal_uInt16)(pTmp->GetDistance()); + } + else if( !bIgnoreLine ) + nDist = 0; + return nDist; +} + +// class SvxBoxInfoItem -------------------------------------------------- + +SvxBoxInfoItem::SvxBoxInfoItem( const sal_uInt16 nId ) : + SfxPoolItem( nId ), + pHori ( 0 ), + pVert ( 0 ), + mbEnableHor( false ), + mbEnableVer( false ), + nDefDist( 0 ) +{ + bDist = bMinDist = sal_False; + ResetFlags(); +} + +// ----------------------------------------------------------------------- + +SvxBoxInfoItem::SvxBoxInfoItem( const SvxBoxInfoItem& rCpy ) : + SfxPoolItem( rCpy ), + mbEnableHor( rCpy.mbEnableHor ), + mbEnableVer( rCpy.mbEnableVer ) +{ + pHori = rCpy.GetHori() ? new SvxBorderLine( *rCpy.GetHori() ) : 0; + pVert = rCpy.GetVert() ? new SvxBorderLine( *rCpy.GetVert() ) : 0; + bDist = rCpy.IsDist(); + bMinDist = rCpy.IsMinDist(); + nValidFlags = rCpy.nValidFlags; + nDefDist = rCpy.GetDefDist(); +} + +// ----------------------------------------------------------------------- + +SvxBoxInfoItem::~SvxBoxInfoItem() +{ + delete pHori; + delete pVert; +} + +// ----------------------------------------------------------------------- + +SvxBoxInfoItem &SvxBoxInfoItem::operator=( const SvxBoxInfoItem& rCpy ) +{ + delete pHori; + delete pVert; + pHori = rCpy.GetHori() ? new SvxBorderLine( *rCpy.GetHori() ) : 0; + pVert = rCpy.GetVert() ? new SvxBorderLine( *rCpy.GetVert() ) : 0; + mbEnableHor = rCpy.mbEnableHor; + mbEnableVer = rCpy.mbEnableVer; + bDist = rCpy.IsDist(); + bMinDist = rCpy.IsMinDist(); + nValidFlags = rCpy.nValidFlags; + nDefDist = rCpy.GetDefDist(); + return *this; +} + +// ----------------------------------------------------------------------- + +int SvxBoxInfoItem::operator==( const SfxPoolItem& rAttr ) const +{ + SvxBoxInfoItem& rBoxInfo = (SvxBoxInfoItem&)rAttr; + + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( mbEnableHor == rBoxInfo.mbEnableHor + && mbEnableVer == rBoxInfo.mbEnableVer + && bDist == rBoxInfo.IsDist() + && bMinDist == rBoxInfo.IsMinDist() + && nValidFlags == rBoxInfo.nValidFlags + && nDefDist == rBoxInfo.GetDefDist() + && CmpBrdLn( pHori, rBoxInfo.GetHori() ) + && CmpBrdLn( pVert, rBoxInfo.GetVert() ) + ); +} + +// ----------------------------------------------------------------------- + +void SvxBoxInfoItem::SetLine( const SvxBorderLine* pNew, sal_uInt16 nLine ) +{ + SvxBorderLine* pTmp = pNew ? new SvxBorderLine( *pNew ) : 0; + + if ( BOXINFO_LINE_HORI == nLine ) + { + delete pHori; + pHori = pTmp; + } + else if ( BOXINFO_LINE_VERT == nLine ) + { + delete pVert; + pVert = pTmp; + } + else + { + DBG_ERROR( "wrong line" ); + } +} + + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBoxInfoItem::Clone( SfxItemPool* ) const +{ + return new SvxBoxInfoItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxBoxInfoItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ +#ifndef SVX_LIGHT +/*!!! + ResMgr* pMgr = DIALOG_MGR(); + if ( pHori ) + { + rText += pHori->GetValueString(); + rText += cpDelim; + } + if ( pVert ) + { + rText += pVert->GetValueString(); + rText += cpDelim; + } + if ( bTable ) + rText += String( ResId( RID_SVXITEMS_BOXINF_TABLE_TRUE, pMgr ) ); + else + rText += String( ResId( RID_SVXITEMS_BOXINF_TABLE_FALSE, pMgr ) ); + rText += cpDelim; + if ( bDist ) + rText += String( ResId( RID_SVXITEMS_BOXINF_DIST_TRUE, pMgr ) ); + else + rText += String( ResId( RID_SVXITEMS_BOXINF_DIST_FALSE, pMgr ) ); + rText += cpDelim; + if ( bMinDist ) + rText += String( ResId( RID_SVXITEMS_BOXINF_MDIST_TRUE, pMgr ) ); + else + rText += String( ResId( RID_SVXITEMS_BOXINF_MDIST_FALSE, pMgr ) ); + rText += cpDelim; + rText += nDefDist; + return SFX_ITEM_PRESENTATION_NAMELESS; +*/ + rText.Erase(); +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxBoxInfoItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + sal_Int8 cFlags = 0; + + if ( IsTable() ) + cFlags |= 0x01; + if ( IsDist() ) + cFlags |= 0x02; + if ( IsMinDist() ) + cFlags |= 0x04; + rStrm << (sal_Int8) cFlags + << (sal_uInt16) GetDefDist(); + const SvxBorderLine* pLine[ 2 ]; + pLine[ 0 ] = GetHori(); + pLine[ 1 ] = GetVert(); + + for( int i = 0; i < 2; i++ ) + { + const SvxBorderLine* l = pLine[ i ]; + if( l ) + { + rStrm << (char) i + << l->GetColor() + << (short) l->GetOutWidth() + << (short) l->GetInWidth() + << (short) l->GetDistance(); + } + } + rStrm << (char) 2; + return rStrm; +} + +// ----------------------------------------------------------------------- + +int SvxBoxInfoItem::ScaleMetrics( long nMult, long nDiv ) +{ + if ( pHori ) pHori->ScaleMetrics( nMult, nDiv ); + if ( pVert ) pVert->ScaleMetrics( nMult, nDiv ); + nDefDist = (sal_uInt16)Scale( nDefDist, nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxBoxInfoItem::HasMetrics() const +{ + return 1; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBoxInfoItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 cFlags; + sal_uInt16 _nDefDist; + rStrm >> cFlags >> _nDefDist; + + SvxBoxInfoItem* pAttr = new SvxBoxInfoItem( Which() ); + + pAttr->SetTable ( ( cFlags & 0x01 ) != 0 ); + pAttr->SetDist ( ( cFlags & 0x02 ) != 0 ); + pAttr->SetMinDist( ( cFlags & 0x04 ) != 0 ); + pAttr->SetDefDist( _nDefDist ); + + while( sal_True ) + { + sal_Int8 cLine; + rStrm >> cLine; + + if( cLine > 1 ) + break; + short nOutline, nInline, nDistance; + Color aColor; + rStrm >> aColor >> nOutline >> nInline >> nDistance; + SvxBorderLine aBorder( &aColor, nOutline, nInline, nDistance ); + + switch( cLine ) + { + case 0: pAttr->SetLine( &aBorder, BOXINFO_LINE_HORI ); break; + case 1: pAttr->SetLine( &aBorder, BOXINFO_LINE_VERT ); break; + } + } + return pAttr; +} + +// ----------------------------------------------------------------------- + +void SvxBoxInfoItem::ResetFlags() +{ + nValidFlags = 0x7F; // alles g"ultig au/ser Disable +} + +sal_Bool SvxBoxInfoItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + table::BorderLine aRetLine; + sal_Int16 nVal=0; + sal_Bool bIntMember = sal_False; + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bSerialize = sal_False; + switch(nMemberId) + { + case 0: + { + // 2 BorderLines, flags, valid flags and distance + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aSeq( 5 ); + aSeq[0] = ::com::sun::star::uno::makeAny( SvxBoxItem::SvxLineToLine( pHori, bConvert) ); + aSeq[1] = ::com::sun::star::uno::makeAny( SvxBoxItem::SvxLineToLine( pVert, bConvert) ); + if ( IsTable() ) + nVal |= 0x01; + if ( IsDist() ) + nVal |= 0x02; + if ( IsMinDist() ) + nVal |= 0x04; + aSeq[2] = ::com::sun::star::uno::makeAny( nVal ); + nVal = nValidFlags; + aSeq[3] = ::com::sun::star::uno::makeAny( nVal ); + aSeq[4] = ::com::sun::star::uno::makeAny( (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED(GetDefDist()) : GetDefDist()) ); + rVal = ::com::sun::star::uno::makeAny( aSeq ); + return sal_True; + } + + case MID_HORIZONTAL: + bSerialize = sal_True; + aRetLine = SvxBoxItem::SvxLineToLine( pHori, bConvert); + break; + case MID_VERTICAL: + bSerialize = sal_True; + aRetLine = SvxBoxItem::SvxLineToLine( pVert, bConvert); + break; + case MID_FLAGS: + bIntMember = sal_True; + if ( IsTable() ) + nVal |= 0x01; + if ( IsDist() ) + nVal |= 0x02; + if ( IsMinDist() ) + nVal |= 0x04; + rVal <<= nVal; + break; + case MID_VALIDFLAGS: + bIntMember = sal_True; + nVal = nValidFlags; + rVal <<= nVal; + break; + case MID_DISTANCE: + bIntMember = sal_True; + rVal <<= (sal_Int32)(bConvert ? TWIP_TO_MM100_UNSIGNED(GetDefDist()) : GetDefDist()); + break; + default: DBG_ERROR("Wrong MemberId!"); return sal_False; + } + + if( !bIntMember ) + { +/* + if ( bSerialize ) + { + ::com::sun::star::uno::Sequence < ::com::sun::star::uno::Any > aSeq(4); + aSeq[0] <<= aRetLine.Color; + aSeq[1] <<= aRetLine.InnerLineWidth; + aSeq[2] <<= aRetLine.OuterLineWidth; + aSeq[3] <<= aRetLine.LineDistance; + rVal <<= aSeq; + } + else + */ + rVal <<= aRetLine; + } + + return sal_True; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxBoxInfoItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); +// sal_uInt16 nLine = BOX_LINE_TOP; +// sal_Bool bDistMember = sal_False; + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet; + switch(nMemberId) + { + case 0: + { + ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aSeq; + if (( rVal >>= aSeq ) && ( aSeq.getLength() == 5 )) + { + // 2 BorderLines, flags, valid flags and distance + table::BorderLine aBorderLine; + SvxBorderLine aLine; + sal_Int16 nFlags( 0 ); + sal_Int32 nVal( 0 ); + if ( aSeq[0] >>= aBorderLine ) + { + sal_Bool bSet = SvxBoxItem::LineToSvxLine(aBorderLine, aLine, bConvert); + if ( bSet ) + SetLine( &aLine, BOXINFO_LINE_HORI ); + } + else + return sal_False; + if ( aSeq[1] >>= aBorderLine ) + { + sal_Bool bSet = SvxBoxItem::LineToSvxLine(aBorderLine, aLine, bConvert); + if ( bSet ) + SetLine( &aLine, BOXINFO_LINE_VERT ); + } + else + return sal_False; + if ( aSeq[2] >>= nFlags ) + { + SetTable ( ( nFlags & 0x01 ) != 0 ); + SetDist ( ( nFlags & 0x02 ) != 0 ); + SetMinDist( ( nFlags & 0x04 ) != 0 ); + } + else + return sal_False; + if ( aSeq[3] >>= nFlags ) + nValidFlags = (BYTE)nFlags; + else + return sal_False; + if (( aSeq[4] >>= nVal ) && ( nVal >= 0 )) + { + if( bConvert ) + nVal = MM100_TO_TWIP(nVal); + SetDefDist( (USHORT)nVal ); + } + } + return sal_True; + } + + case MID_HORIZONTAL: + case MID_VERTICAL: + { + if( !rVal.hasValue() ) + return sal_False; + + table::BorderLine aBorderLine; + if( rVal >>= aBorderLine ) + { + // usual struct + } + else if (rVal.getValueTypeClass() == uno::TypeClass_SEQUENCE ) + { + // serialization for basic macro recording + uno::Reference < script::XTypeConverter > xConverter + ( ::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.script.Converter")), + uno::UNO_QUERY ); + uno::Any aNew; + uno::Sequence < uno::Any > aSeq; + try { aNew = xConverter->convertTo( rVal, ::getCppuType((const uno::Sequence < uno::Any >*)0) ); } + catch (uno::Exception&) {} + + if( (aNew >>= aSeq) && aSeq.getLength() == 4 ) + { + sal_Int32 nVal = 0; + if ( aSeq[0] >>= nVal ) + aBorderLine.Color = nVal; + if ( aSeq[1] >>= nVal ) + aBorderLine.InnerLineWidth = (sal_Int16) nVal; + if ( aSeq[2] >>= nVal ) + aBorderLine.OuterLineWidth = (sal_Int16) nVal; + if ( aSeq[3] >>= nVal ) + aBorderLine.LineDistance = (sal_Int16) nVal; + } + else + return sal_False; + } + else if (rVal.getValueType() == ::getCppuType((const ::com::sun::star::uno::Sequence < sal_Int16 >*)0) ) + { + // serialization for basic macro recording + ::com::sun::star::uno::Sequence < sal_Int16 > aSeq; + rVal >>= aSeq; + if ( aSeq.getLength() == 4 ) + { + aBorderLine.Color = aSeq[0]; + aBorderLine.InnerLineWidth = aSeq[1]; + aBorderLine.OuterLineWidth = aSeq[2]; + aBorderLine.LineDistance = aSeq[3]; + } + else + return sal_False; + } + else + return sal_False; + + SvxBorderLine aLine; + sal_Bool bSet = SvxBoxItem::LineToSvxLine(aBorderLine, aLine, bConvert); + if ( bSet ) + SetLine( &aLine, nMemberId == MID_HORIZONTAL ? BOXINFO_LINE_HORI : BOXINFO_LINE_VERT ); + break; + } + case MID_FLAGS: + { + sal_Int16 nFlags = sal_Int16(); + bRet = (rVal >>= nFlags); + if ( bRet ) + { + SetTable ( ( nFlags & 0x01 ) != 0 ); + SetDist ( ( nFlags & 0x02 ) != 0 ); + SetMinDist( ( nFlags & 0x04 ) != 0 ); + } + + break; + } + case MID_VALIDFLAGS: + { + sal_Int16 nFlags = sal_Int16(); + bRet = (rVal >>= nFlags); + if ( bRet ) + nValidFlags = (BYTE)nFlags; + break; + } + case MID_DISTANCE: + { + sal_Int32 nVal = 0; + bRet = (rVal >>= nVal); + if ( bRet && nVal>=0 ) + { + if( bConvert ) + nVal = MM100_TO_TWIP(nVal); + SetDefDist( (USHORT)nVal ); + } + break; + } + default: DBG_ERROR("Wrong MemberId!"); return sal_False; + } + + return sal_True; +} + +// class SvxFmtBreakItem ------------------------------------------------- + +int SvxFmtBreakItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rAttr ), "unequal types" ); + + return GetValue() == ( (SvxFmtBreakItem&)rAttr ).GetValue(); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxFmtBreakItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetValueTextByPos( GetValue() ); + return ePres; + default: ;//prevent warning + } +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +XubString SvxFmtBreakItem::GetValueTextByPos( sal_uInt16 nPos ) const +{ + DBG_ASSERT( nPos < SVX_BREAK_END, "enum overflow!" ); + XubString aStr( EditResId( RID_SVXITEMS_BREAK_BEGIN + nPos ) ); + return aStr; +} + +// ----------------------------------------------------------------------- +sal_Bool SvxFmtBreakItem::QueryValue( uno::Any& rVal, BYTE /*nMemberId*/ ) const +{ + style::BreakType eBreak = style::BreakType_NONE; + switch ( (SvxBreak)GetValue() ) + { + case SVX_BREAK_COLUMN_BEFORE: eBreak = style::BreakType_COLUMN_BEFORE; break; + case SVX_BREAK_COLUMN_AFTER: eBreak = style::BreakType_COLUMN_AFTER ; break; + case SVX_BREAK_COLUMN_BOTH: eBreak = style::BreakType_COLUMN_BOTH ; break; + case SVX_BREAK_PAGE_BEFORE: eBreak = style::BreakType_PAGE_BEFORE ; break; + case SVX_BREAK_PAGE_AFTER: eBreak = style::BreakType_PAGE_AFTER ; break; + case SVX_BREAK_PAGE_BOTH: eBreak = style::BreakType_PAGE_BOTH ; break; + default: ;//prevent warning + } + rVal <<= eBreak; + return sal_True; +} +// ----------------------------------------------------------------------- +sal_Bool SvxFmtBreakItem::PutValue( const uno::Any& rVal, BYTE /*nMemberId*/ ) +{ + style::BreakType nBreak; + + if(!(rVal >>= nBreak)) + { + sal_Int32 nValue = 0; + if(!(rVal >>= nValue)) + return sal_False; + + nBreak = (style::BreakType) nValue; + } + + SvxBreak eBreak = SVX_BREAK_NONE; + switch( nBreak ) + { + case style::BreakType_COLUMN_BEFORE: eBreak = SVX_BREAK_COLUMN_BEFORE; break; + case style::BreakType_COLUMN_AFTER: eBreak = SVX_BREAK_COLUMN_AFTER; break; + case style::BreakType_COLUMN_BOTH: eBreak = SVX_BREAK_COLUMN_BOTH; break; + case style::BreakType_PAGE_BEFORE: eBreak = SVX_BREAK_PAGE_BEFORE; break; + case style::BreakType_PAGE_AFTER: eBreak = SVX_BREAK_PAGE_AFTER; break; + case style::BreakType_PAGE_BOTH: eBreak = SVX_BREAK_PAGE_BOTH; break; + default: ;//prevent warning + } + SetValue((sal_uInt16) eBreak); + + return sal_True; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFmtBreakItem::Clone( SfxItemPool* ) const +{ + return new SvxFmtBreakItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxFmtBreakItem::Store( SvStream& rStrm , sal_uInt16 nItemVersion ) const +{ + rStrm << (sal_Int8)GetValue(); + if( FMTBREAK_NOAUTO > nItemVersion ) + rStrm << (sal_Int8)0x01; + return rStrm; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxFmtBreakItem::GetVersion( sal_uInt16 nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxFmtBreakItem: Gibt es ein neues Fileformat?" ); + return SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer ? 0 : FMTBREAK_NOAUTO; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFmtBreakItem::Create( SvStream& rStrm, sal_uInt16 nVersion ) const +{ + sal_Int8 eBreak, bDummy; + rStrm >> eBreak; + if( FMTBREAK_NOAUTO > nVersion ) + rStrm >> bDummy; + return new SvxFmtBreakItem( (const SvxBreak)eBreak, Which() ); +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxFmtBreakItem::GetValueCount() const +{ + return SVX_BREAK_END; // SVX_BREAK_PAGE_BOTH + 1 +} + +// class SvxFmtKeepItem ------------------------------------------------- + +SfxPoolItem* SvxFmtKeepItem::Clone( SfxItemPool* ) const +{ + return new SvxFmtKeepItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxFmtKeepItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFmtKeepItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 bIsKeep; + rStrm >> bIsKeep; + return new SvxFmtKeepItem( sal_Bool( bIsKeep != 0 ), Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxFmtKeepItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * + ) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + sal_uInt16 nId = RID_SVXITEMS_FMTKEEP_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_FMTKEEP_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ;//prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxLineItem ------------------------------------------------------ + +SvxLineItem::SvxLineItem( const sal_uInt16 nId ) : + + SfxPoolItem ( nId ), + + pLine( NULL ) +{ +} + +// ----------------------------------------------------------------------- + +SvxLineItem::SvxLineItem( const SvxLineItem& rCpy ) : + + SfxPoolItem ( rCpy ) +{ + pLine = rCpy.GetLine() ? new SvxBorderLine( *rCpy.GetLine() ) : 0; +} + + +// ----------------------------------------------------------------------- + +SvxLineItem::~SvxLineItem() +{ + delete pLine; +} + +// ----------------------------------------------------------------------- + +SvxLineItem& SvxLineItem::operator=( const SvxLineItem& rLine ) +{ + SetLine( rLine.GetLine() ); + + return *this; +} + +// ----------------------------------------------------------------------- + +int SvxLineItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return CmpBrdLn( pLine, ((SvxLineItem&)rAttr).GetLine() ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxLineItem::Clone( SfxItemPool* ) const +{ + return new SvxLineItem( *this ); +} + +sal_Bool SvxLineItem::QueryValue( uno::Any& rVal, BYTE nMemId ) const +{ + sal_Bool bConvert = 0!=(nMemId&CONVERT_TWIPS); + nMemId &= ~CONVERT_TWIPS; + if ( nMemId == 0 ) + { + rVal <<= uno::makeAny( SvxBoxItem::SvxLineToLine(pLine, bConvert) ); + return sal_True; + } + else if ( pLine ) + { + switch ( nMemId ) + { + case MID_FG_COLOR: rVal <<= sal_Int32(pLine->GetColor().GetColor()); break; + case MID_OUTER_WIDTH: rVal <<= sal_Int32(pLine->GetOutWidth()); break; + case MID_INNER_WIDTH: rVal <<= sal_Int32(pLine->GetInWidth( )); break; + case MID_DISTANCE: rVal <<= sal_Int32(pLine->GetDistance()); break; + default: + DBG_ERROR( "Wrong MemberId" ); + return sal_False; + } + } + + return TRUE; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxLineItem::PutValue( const uno::Any& rVal, BYTE nMemId ) +{ + sal_Bool bConvert = 0!=(nMemId&CONVERT_TWIPS); + nMemId &= ~CONVERT_TWIPS; + sal_Int32 nVal = 0; + if ( nMemId == 0 ) + { + table::BorderLine aLine; + if ( rVal >>= aLine ) + { + if ( !pLine ) + pLine = new SvxBorderLine; + if( !SvxBoxItem::LineToSvxLine(aLine, *pLine, bConvert) ) + DELETEZ( pLine ); + return sal_True; + } + return sal_False; + } + else if ( rVal >>= nVal ) + { + if ( !pLine ) + pLine = new SvxBorderLine; + + switch ( nMemId ) + { + case MID_FG_COLOR: pLine->SetColor( Color(nVal) ); break; + case MID_OUTER_WIDTH: pLine->SetOutWidth((USHORT)nVal); break; + case MID_INNER_WIDTH: pLine->SetInWidth((USHORT)nVal); break; + case MID_DISTANCE: pLine->SetDistance((USHORT)nVal); break; + default: + DBG_ERROR( "Wrong MemberId" ); + return sal_False; + } + + return sal_True; + } + + return sal_False; +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxLineItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, const IntlWrapper *pIntl +) const +{ +#ifndef SVX_LIGHT + rText.Erase(); + + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + return SFX_ITEM_PRESENTATION_NONE; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + if ( pLine ) + rText = pLine->GetValueString( eCoreUnit, ePresUnit, pIntl, + (SFX_ITEM_PRESENTATION_COMPLETE == ePres) ); + return ePres; + } + default: ;//prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxLineItem::Store( SvStream& rStrm , sal_uInt16 /*nItemVersion*/ ) const +{ + if( pLine ) + { + rStrm << pLine->GetColor() + << (short)pLine->GetOutWidth() + << (short)pLine->GetInWidth() + << (short)pLine->GetDistance(); + } + else + rStrm << Color() << (short)0 << (short)0 << (short)0; + return rStrm; +} + +// ----------------------------------------------------------------------- + +int SvxLineItem::ScaleMetrics( long nMult, long nDiv ) +{ + if ( pLine ) pLine->ScaleMetrics( nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxLineItem::HasMetrics() const +{ + return 1; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxLineItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + SvxLineItem* _pLine = new SvxLineItem( Which() ); + short nOutline, nInline, nDistance; + Color aColor; + + rStrm >> aColor >> nOutline >> nInline >> nDistance; + if( nOutline ) + { + SvxBorderLine aLine( &aColor, nOutline, nInline, nDistance ); + _pLine->SetLine( &aLine ); + } + return _pLine; +} + +// ----------------------------------------------------------------------- + +void SvxLineItem::SetLine( const SvxBorderLine* pNew ) +{ + delete pLine; + pLine = pNew ? new SvxBorderLine( *pNew ) : 0; +} + +#ifdef _MSC_VER +#pragma optimize ( "", off ) +#endif + +// class SvxBrushItem ---------------------------------------------------- + +#define LOAD_GRAPHIC ((sal_uInt16)0x0001) +#define LOAD_LINK ((sal_uInt16)0x0002) +#define LOAD_FILTER ((sal_uInt16)0x0004) + +// class SvxBrushItem_Impl ----------------------------------------------- + +class SvxBrushItem_Impl +{ +public: + GraphicObject* pGraphicObject; + sal_Int8 nGraphicTransparency; //contains a percentage value which is + //copied to the GraphicObject when necessary + Link aDoneLink; + SvStream* pStream; + + SvxBrushItem_Impl( GraphicObject* p ) : pGraphicObject( p ), nGraphicTransparency(0), pStream(0) {} +}; + +// ----------------------------------------------------------------------- + +void SvxBrushItem::SetDoneLink( const Link& rLink ) +{ + pImpl->aDoneLink = rLink; +} + +// ----------------------------------------------------------------------- + +SvxBrushItem::SvxBrushItem( sal_uInt16 _nWhich ) : + + SfxPoolItem( _nWhich ), + + aColor ( COL_TRANSPARENT ), + pImpl ( new SvxBrushItem_Impl( 0 ) ), + pStrLink ( NULL ), + pStrFilter ( NULL ), + eGraphicPos ( GPOS_NONE ), + bLoadAgain ( sal_True ) + +{ +} + +// ----------------------------------------------------------------------- + +SvxBrushItem::SvxBrushItem( const Color& rColor, sal_uInt16 _nWhich) : + + SfxPoolItem( _nWhich ), + + aColor ( rColor ), + pImpl ( new SvxBrushItem_Impl( 0 ) ), + pStrLink ( NULL ), + pStrFilter ( NULL ), + eGraphicPos ( GPOS_NONE ), + bLoadAgain ( sal_True ) + +{ +} + +// ----------------------------------------------------------------------- + +SvxBrushItem::SvxBrushItem( const Graphic& rGraphic, SvxGraphicPosition ePos, + sal_uInt16 _nWhich ) : + + SfxPoolItem( _nWhich ), + + aColor ( COL_TRANSPARENT ), + pImpl ( new SvxBrushItem_Impl( new GraphicObject( rGraphic ) ) ), + pStrLink ( NULL ), + pStrFilter ( NULL ), + eGraphicPos ( ( GPOS_NONE != ePos ) ? ePos : GPOS_MM ), + bLoadAgain ( sal_True ) + +{ + DBG_ASSERT( GPOS_NONE != ePos, "SvxBrushItem-Ctor with GPOS_NONE == ePos" ); +} + +// ----------------------------------------------------------------------- + +SvxBrushItem::SvxBrushItem( const GraphicObject& rGraphicObj, + SvxGraphicPosition ePos, sal_uInt16 _nWhich ) : + + SfxPoolItem( _nWhich ), + + aColor ( COL_TRANSPARENT ), + pImpl ( new SvxBrushItem_Impl( new GraphicObject( rGraphicObj ) ) ), + pStrLink ( NULL ), + pStrFilter ( NULL ), + eGraphicPos ( ( GPOS_NONE != ePos ) ? ePos : GPOS_MM ), + bLoadAgain ( sal_True ) + +{ + DBG_ASSERT( GPOS_NONE != ePos, "SvxBrushItem-Ctor with GPOS_NONE == ePos" ); +} + +// ----------------------------------------------------------------------- + +SvxBrushItem::SvxBrushItem( + const String& rLink, const String& rFilter, + SvxGraphicPosition ePos, sal_uInt16 _nWhich ) : + + SfxPoolItem( _nWhich ), + + aColor ( COL_TRANSPARENT ), + pImpl ( new SvxBrushItem_Impl( NULL ) ), + pStrLink ( new String( rLink ) ), + pStrFilter ( new String( rFilter ) ), + eGraphicPos ( ( GPOS_NONE != ePos ) ? ePos : GPOS_MM ), + bLoadAgain ( sal_True ) + +{ + DBG_ASSERT( GPOS_NONE != ePos, "SvxBrushItem-Ctor with GPOS_NONE == ePos" ); +} + +// ----------------------------------------------------------------------- + +SvxBrushItem::SvxBrushItem( SvStream& rStream, sal_uInt16 nVersion, + sal_uInt16 _nWhich ) : + + SfxPoolItem( _nWhich ), + + aColor ( COL_TRANSPARENT ), + pImpl ( new SvxBrushItem_Impl( NULL ) ), + pStrLink ( NULL ), + pStrFilter ( NULL ), + eGraphicPos ( GPOS_NONE ) + +{ + sal_Bool bTrans; + Color aTempColor; + Color aTempFillColor; + sal_Int8 nStyle; + + rStream >> bTrans; + rStream >> aTempColor; + rStream >> aTempFillColor; + rStream >> nStyle; + + switch ( nStyle ) + { + case 8://BRUSH_25: + { + sal_uInt32 nRed = aTempColor.GetRed(); + sal_uInt32 nGreen = aTempColor.GetGreen(); + sal_uInt32 nBlue = aTempColor.GetBlue(); + nRed += (sal_uInt32)(aTempFillColor.GetRed())*2; + nGreen += (sal_uInt32)(aTempFillColor.GetGreen())*2; + nBlue += (sal_uInt32)(aTempFillColor.GetBlue())*2; + aColor = Color( (sal_Int8)(nRed/3), (sal_Int8)(nGreen/3), (sal_Int8)(nBlue/3) ); + } + break; + + case 9://BRUSH_50: + { + sal_uInt32 nRed = aTempColor.GetRed(); + sal_uInt32 nGreen = aTempColor.GetGreen(); + sal_uInt32 nBlue = aTempColor.GetBlue(); + nRed += (sal_uInt32)(aTempFillColor.GetRed()); + nGreen += (sal_uInt32)(aTempFillColor.GetGreen()); + nBlue += (sal_uInt32)(aTempFillColor.GetBlue()); + aColor = Color( (sal_Int8)(nRed/2), (sal_Int8)(nGreen/2), (sal_Int8)(nBlue/2) ); + } + break; + + case 10://BRUSH_75: + { + sal_uInt32 nRed = aTempColor.GetRed()*2; + sal_uInt32 nGreen = aTempColor.GetGreen()*2; + sal_uInt32 nBlue = aTempColor.GetBlue()*2; + nRed += (sal_uInt32)(aTempFillColor.GetRed()); + nGreen += (sal_uInt32)(aTempFillColor.GetGreen()); + nBlue += (sal_uInt32)(aTempFillColor.GetBlue()); + aColor = Color( (sal_Int8)(nRed/3), (sal_Int8)(nGreen/3), (sal_Int8)(nBlue/3) ); + } + break; + + case 0://BRUSH_NULL: + aColor = Color( COL_TRANSPARENT ); + break; + + default: + aColor = aTempColor; + } + + if ( nVersion >= BRUSH_GRAPHIC_VERSION ) + { + sal_uInt16 nDoLoad = 0; + sal_Int8 nPos; + + rStream >> nDoLoad; + + if ( nDoLoad & LOAD_GRAPHIC ) + { + Graphic aGraphic; + + rStream >> aGraphic; + pImpl->pGraphicObject = new GraphicObject( aGraphic ); + + if( SVSTREAM_FILEFORMAT_ERROR == rStream.GetError() ) + { + rStream.ResetError(); + rStream.SetError( ERRCODE_SVX_GRAPHIC_WRONG_FILEFORMAT| + ERRCODE_WARNING_MASK ); + } + } + + if ( nDoLoad & LOAD_LINK ) + { + String aRel; + // UNICODE: rStream >> aRel; + rStream.ReadByteString(aRel); + + // TODO/MBA: how can we get a BaseURL here?! + DBG_ERROR("No BaseURL!"); + String aAbs = INetURLObject::GetAbsURL( String(), aRel ); + DBG_ASSERT( aAbs.Len(), "Invalid URL!" ); + pStrLink = new String( aAbs ); + } + + if ( nDoLoad & LOAD_FILTER ) + { + pStrFilter = new String; + // UNICODE: rStream >> *pStrFilter; + rStream.ReadByteString(*pStrFilter); + } + + rStream >> nPos; + + eGraphicPos = (SvxGraphicPosition)nPos; + } +} + +// ----------------------------------------------------------------------- + +SvxBrushItem::SvxBrushItem( const SvxBrushItem& rItem ) : + + SfxPoolItem( rItem.Which() ), + + pImpl ( new SvxBrushItem_Impl( NULL ) ), + pStrLink ( NULL ), + pStrFilter ( NULL ), + eGraphicPos ( GPOS_NONE ), + bLoadAgain ( sal_True ) + +{ + *this = rItem; +} + +// ----------------------------------------------------------------------- + +SvxBrushItem::~SvxBrushItem() +{ + delete pImpl->pGraphicObject; + delete pImpl; + delete pStrLink; + delete pStrFilter; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxBrushItem::GetVersion( sal_uInt16 /*nFileVersion*/ ) const +{ + return BRUSH_GRAPHIC_VERSION; +} + +// ----------------------------------------------------------------------- +inline sal_Int8 lcl_PercentToTransparency(long nPercent) +{ + //0xff must not be returned! + return sal_Int8(nPercent ? (50 + 0xfe * nPercent) / 100 : 0); +} +inline sal_Int8 lcl_TransparencyToPercent(sal_Int32 nTrans) +{ + return (sal_Int8)((nTrans * 100 + 127) / 254); +} + +sal_Bool SvxBrushItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId) + { + case MID_BACK_COLOR: + rVal <<= (sal_Int32)( aColor.GetColor() ); + break; + case MID_BACK_COLOR_R_G_B: + rVal <<= (sal_Int32)( aColor.GetRGBColor() ); + break; + case MID_BACK_COLOR_TRANSPARENCY: + rVal <<= lcl_TransparencyToPercent(aColor.GetTransparency()); + break; + case MID_GRAPHIC_POSITION: + rVal <<= (style::GraphicLocation)(sal_Int16)eGraphicPos; + break; + + case MID_GRAPHIC: + DBG_ERRORFILE( "not implemented" ); + break; + + case MID_GRAPHIC_TRANSPARENT: + rVal = Bool2Any( aColor.GetTransparency() == 0xff ); + break; + + case MID_GRAPHIC_URL: + { + OUString sLink; + if ( pStrLink ) + sLink = *pStrLink; + else if( pImpl->pGraphicObject ) + { + OUString sPrefix(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_GRAPHOBJ_URLPREFIX)); + String sId( pImpl->pGraphicObject->GetUniqueID(), + RTL_TEXTENCODING_ASCII_US ); + sLink = sPrefix; + sLink += OUString(sId); + } + rVal <<= sLink; + } + break; + + case MID_GRAPHIC_FILTER: + { + OUString sFilter; + if ( pStrFilter ) + sFilter = *pStrFilter; + rVal <<= sFilter; + } + break; + case MID_GRAPHIC_TRANSPARENCY : + rVal <<= pImpl->nGraphicTransparency; + break; + } + + return sal_True; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxBrushItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId) + { + case MID_BACK_COLOR: + case MID_BACK_COLOR_R_G_B: + { + sal_Int32 nCol = 0; + if ( !( rVal >>= nCol ) ) + return sal_False; + if(MID_BACK_COLOR_R_G_B == nMemberId) + { + nCol = COLORDATA_RGB( nCol ); + nCol += aColor.GetColor() & 0xff000000; + } + aColor = Color( nCol ); + } + break; + case MID_BACK_COLOR_TRANSPARENCY: + { + sal_Int32 nTrans = 0; + if ( !( rVal >>= nTrans ) || nTrans < 0 || nTrans > 100 ) + return sal_False; + aColor.SetTransparency(lcl_PercentToTransparency(nTrans)); + } + break; + + case MID_GRAPHIC_POSITION: + { + style::GraphicLocation eLocation; + if ( !( rVal>>=eLocation ) ) + { + sal_Int32 nValue = 0; + if ( !( rVal >>= nValue ) ) + return sal_False; + eLocation = (style::GraphicLocation)nValue; + } + SetGraphicPos( (SvxGraphicPosition)(sal_uInt16)eLocation ); + } + break; + + case MID_GRAPHIC: + DBG_ERRORFILE( "not implemented" ); + break; + + case MID_GRAPHIC_TRANSPARENT: + aColor.SetTransparency( Any2Bool( rVal ) ? 0xff : 0 ); + break; + + case MID_GRAPHIC_URL: + { + if ( rVal.getValueType() == ::getCppuType( (OUString*)0 ) ) + { + OUString sLink; + rVal >>= sLink; + if( 0 == sLink.compareToAscii( UNO_NAME_GRAPHOBJ_URLPKGPREFIX, + sizeof(UNO_NAME_GRAPHOBJ_URLPKGPREFIX)-1 ) ) + { + DBG_ERROR( "package urls aren't implemented" ); + } + else if( 0 == sLink.compareToAscii( UNO_NAME_GRAPHOBJ_URLPREFIX, + sizeof(UNO_NAME_GRAPHOBJ_URLPREFIX)-1 ) ) + { + DELETEZ( pStrLink ); + String sTmp( sLink ); + ByteString sId( sTmp.Copy( + sizeof(UNO_NAME_GRAPHOBJ_URLPREFIX)-1), + RTL_TEXTENCODING_ASCII_US ); + GraphicObject *pOldGrfObj = pImpl->pGraphicObject; + pImpl->pGraphicObject = new GraphicObject( sId ); + ApplyGraphicTransparency_Impl(); + delete pOldGrfObj; + } + else + { + SetGraphicLink(sLink); + } + if ( sLink.getLength() && eGraphicPos == GPOS_NONE ) + eGraphicPos = GPOS_MM; + else if( !sLink.getLength() ) + eGraphicPos = GPOS_NONE; + } + } + break; + + case MID_GRAPHIC_FILTER: + { + if( rVal.getValueType() == ::getCppuType( (OUString*)0 ) ) + { + OUString sLink; + rVal >>= sLink; + SetGraphicFilter( sLink ); + } + } + break; + case MID_GRAPHIC_TRANSPARENCY : + { + sal_Int32 nTmp = 0; + rVal >>= nTmp; + if(nTmp >= 0 && nTmp <= 100) + { + pImpl->nGraphicTransparency = sal_Int8(nTmp); + if(pImpl->pGraphicObject) + ApplyGraphicTransparency_Impl(); + } + } + break; + } + + return sal_True; +} + +// ----------------------------------------------------------------------- + +SfxItemPresentation SvxBrushItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * + ) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + if ( GPOS_NONE == eGraphicPos ) + { + rText = ::GetColorString( aColor ); + rText += cpDelim; + sal_uInt16 nId = RID_SVXITEMS_TRANSPARENT_FALSE; + + if ( aColor.GetTransparency() ) + nId = RID_SVXITEMS_TRANSPARENT_TRUE; + rText += EE_RESSTR(nId); + } + else + { + rText = EE_RESSTR(RID_SVXITEMS_GRAPHIC); + } + + return ePres; + } + default: ;//prevent warning + } + + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SvxBrushItem& SvxBrushItem::operator=( const SvxBrushItem& rItem ) +{ + aColor = rItem.aColor; + eGraphicPos = rItem.eGraphicPos; + + DELETEZ( pImpl->pGraphicObject ); + DELETEZ( pStrLink ); + DELETEZ( pStrFilter ); + + if ( GPOS_NONE != eGraphicPos ) + { + if ( rItem.pStrLink ) + pStrLink = new String( *rItem.pStrLink ); + if ( rItem.pStrFilter ) + pStrFilter = new String( *rItem.pStrFilter ); + if ( rItem.pImpl->pGraphicObject ) + { + pImpl->pGraphicObject = new GraphicObject( *rItem.pImpl->pGraphicObject ); + } + } + pImpl->nGraphicTransparency = rItem.pImpl->nGraphicTransparency; + return *this; +} + +// ----------------------------------------------------------------------- + +int SvxBrushItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + SvxBrushItem& rCmp = (SvxBrushItem&)rAttr; + sal_Bool bEqual = ( aColor == rCmp.aColor && eGraphicPos == rCmp.eGraphicPos && + pImpl->nGraphicTransparency == rCmp.pImpl->nGraphicTransparency); + + if ( bEqual ) + { + if ( GPOS_NONE != eGraphicPos ) + { + if ( !rCmp.pStrLink ) + bEqual = !pStrLink; + else + bEqual = pStrLink && ( *pStrLink == *rCmp.pStrLink ); + + if ( bEqual ) + { + if ( !rCmp.pStrFilter ) + bEqual = !pStrFilter; + else + bEqual = pStrFilter && ( *pStrFilter == *rCmp.pStrFilter ); + } + + if ( bEqual && !rCmp.pStrLink ) + { + if ( !rCmp.pImpl->pGraphicObject ) + bEqual = !pImpl->pGraphicObject; + else + bEqual = pImpl->pGraphicObject && + ( *pImpl->pGraphicObject == *rCmp.pImpl->pGraphicObject ); + } + } + } + + return bEqual; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBrushItem::Clone( SfxItemPool* ) const +{ + return new SvxBrushItem( *this ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBrushItem::Create( SvStream& rStream, sal_uInt16 nVersion ) const +{ + return new SvxBrushItem( rStream, nVersion, Which() ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxBrushItem::Store( SvStream& rStream , sal_uInt16 /*nItemVersion*/ ) const +{ + rStream << (sal_Bool)sal_False; + rStream << aColor; + rStream << aColor; + rStream << (sal_Int8)(aColor.GetTransparency() > 0 ? 0 : 1); //BRUSH_NULL : BRUSH_SOLID + + sal_uInt16 nDoLoad = 0; + + if ( pImpl->pGraphicObject && !pStrLink ) + nDoLoad |= LOAD_GRAPHIC; + if ( pStrLink ) + nDoLoad |= LOAD_LINK; + if ( pStrFilter ) + nDoLoad |= LOAD_FILTER; + rStream << nDoLoad; + + if ( pImpl->pGraphicObject && !pStrLink ) + rStream << pImpl->pGraphicObject->GetGraphic(); + if ( pStrLink ) + { + DBG_ERROR("No BaseURL!"); + // TODO/MBA: how to get a BaseURL?! + String aRel = INetURLObject::GetRelURL( String(), *pStrLink ); + // UNICODE: rStream << aRel; + rStream.WriteByteString(aRel); + } + if ( pStrFilter ) + { + // UNICODE: rStream << *pStrFilter; + rStream.WriteByteString(*pStrFilter); + } + rStream << (sal_Int8)eGraphicPos; + return rStream; +} + +// ----------------------------------------------------------------------- +// const wegcasten, da const als logisches const zu verstehen ist +// wenn GetGraphic() gerufen wird, soll sich das Item darum kuemmern, +// eine gelinkte Grafik zu holen. +// ----------------------------------------------------------------------- + +void SvxBrushItem::PurgeGraphic() const +{ + PurgeMedium(); + DELETEZ( pImpl->pGraphicObject ); + ((SvxBrushItem*)this)->bLoadAgain = sal_True; +} + +// ----------------------------------------------------------------------- + +void SvxBrushItem::PurgeMedium() const +{ + DELETEZ( pImpl->pStream ); +} + +// ----------------------------------------------------------------------- +const GraphicObject* SvxBrushItem::GetGraphicObject() const +{ + if ( bLoadAgain && pStrLink && !pImpl->pGraphicObject ) + // wenn Grafik schon geladen, als Cache benutzen + { + //JP 29.6.2001: only with "valid" names - empty names now allowed + if( pStrLink->Len() ) + { + // currently we don't have asynchronous processing +/* if( pImpl->aDoneLink.IsSet() ) + { + // Auf besonderen Wunsch des Writers wird der synchrone und der + // asynchrone Fall was die Benachrichtigung angeht unterschiedlich + // behandelt. Der Callback erfolgt nur bei asynchronem Eintreffen + // der Daten + + Link aTmp = pImpl->aDoneLink; + pImpl->aDoneLink = Link(); + pImpl->xMedium->DownLoad( + STATIC_LINK( this, SvxBrushItem, DoneHdl_Impl ) ); + pImpl->aDoneLink = aTmp; + } */ + + pImpl->pStream = utl::UcbStreamHelper::CreateStream( *pStrLink, STREAM_STD_READ ); + if( pImpl->pStream && !pImpl->pStream->GetError() ) + { + Graphic aGraphic; + int nRes; + pImpl->pStream->Seek( STREAM_SEEK_TO_BEGIN ); + nRes = GraphicFilter::GetGraphicFilter()-> + ImportGraphic( aGraphic, *pStrLink, *pImpl->pStream, + GRFILTER_FORMAT_DONTKNOW, NULL, GRFILTER_I_FLAGS_DONT_SET_LOGSIZE_FOR_JPEG ); + + if( nRes != GRFILTER_OK ) + { + const_cast < SvxBrushItem*> (this)->bLoadAgain = sal_False; + } + else + { + pImpl->pGraphicObject = new GraphicObject; + pImpl->pGraphicObject->SetGraphic( aGraphic ); + const_cast < SvxBrushItem*> (this)->ApplyGraphicTransparency_Impl(); + } + } + else + { + const_cast < SvxBrushItem*> (this)->bLoadAgain = sal_False; + } + + // currently we don't have asynchronous processing +// pThis->pImpl->aDoneLink.Call( pThis ); + } + } + + return pImpl->pGraphicObject; +} + +// ----------------------------------------------------------------------- + +const Graphic* SvxBrushItem::GetGraphic() const +{ + const GraphicObject* pGrafObj = GetGraphicObject(); + return( pGrafObj ? &( pGrafObj->GetGraphic() ) : NULL ); +} + +// ----------------------------------------------------------------------- + +void SvxBrushItem::SetGraphicPos( SvxGraphicPosition eNew ) +{ + eGraphicPos = eNew; + + if ( GPOS_NONE == eGraphicPos ) + { + DELETEZ( pImpl->pGraphicObject ); + DELETEZ( pStrLink ); + DELETEZ( pStrFilter ); + } + else + { + if ( !pImpl->pGraphicObject && !pStrLink ) + { + pImpl->pGraphicObject = new GraphicObject; // dummy anlegen + } + } +} + +// ----------------------------------------------------------------------- + +void SvxBrushItem::SetGraphic( const Graphic& rNew ) +{ + if ( !pStrLink ) + { + if ( pImpl->pGraphicObject ) + pImpl->pGraphicObject->SetGraphic( rNew ); + else + pImpl->pGraphicObject = new GraphicObject( rNew ); + + ApplyGraphicTransparency_Impl(); + + if ( GPOS_NONE == eGraphicPos ) + eGraphicPos = GPOS_MM; // None waere Brush, also Default: Mitte + } + else + { + DBG_ERROR( "SetGraphic() on linked graphic! :-/" ); + } +} + +// ----------------------------------------------------------------------- + +void SvxBrushItem::SetGraphicObject( const GraphicObject& rNewObj ) +{ + if ( !pStrLink ) + { + if ( pImpl->pGraphicObject ) + *pImpl->pGraphicObject = rNewObj; + else + pImpl->pGraphicObject = new GraphicObject( rNewObj ); + + ApplyGraphicTransparency_Impl(); + + if ( GPOS_NONE == eGraphicPos ) + eGraphicPos = GPOS_MM; // None waere Brush, also Default: Mitte + } + else + { + DBG_ERROR( "SetGraphic() on linked graphic! :-/" ); + } +} + +// ----------------------------------------------------------------------- + +void SvxBrushItem::SetGraphicLink( const String& rNew ) +{ + if ( !rNew.Len() ) + DELETEZ( pStrLink ); + else + { + if ( pStrLink ) + *pStrLink = rNew; + else + pStrLink = new String( rNew ); + + DELETEZ( pImpl->pGraphicObject ); + } +} + +// ----------------------------------------------------------------------- + +void SvxBrushItem::SetGraphicFilter( const String& rNew ) +{ + if ( !rNew.Len() ) + DELETEZ( pStrFilter ); + else + { + if ( pStrFilter ) + *pStrFilter = rNew; + else + pStrFilter = new String( rNew ); + } +} + +//static +SvxGraphicPosition SvxBrushItem::WallpaperStyle2GraphicPos( WallpaperStyle eStyle ) +{ + SvxGraphicPosition eResult; + // der Switch ist nicht der schnellste, dafuer aber am sichersten + switch( eStyle ) + { + case WALLPAPER_NULL: eResult = GPOS_NONE; break; + case WALLPAPER_TILE: eResult = GPOS_TILED; break; + case WALLPAPER_CENTER: eResult = GPOS_MM; break; + case WALLPAPER_SCALE: eResult = GPOS_AREA; break; + case WALLPAPER_TOPLEFT: eResult = GPOS_LT; break; + case WALLPAPER_TOP: eResult = GPOS_MT; break; + case WALLPAPER_TOPRIGHT: eResult = GPOS_RT; break; + case WALLPAPER_LEFT: eResult = GPOS_LM; break; + case WALLPAPER_RIGHT: eResult = GPOS_RM; break; + case WALLPAPER_BOTTOMLEFT: eResult = GPOS_LB; break; + case WALLPAPER_BOTTOM: eResult = GPOS_MB; break; + case WALLPAPER_BOTTOMRIGHT: eResult = GPOS_RB; break; + default: eResult = GPOS_NONE; + } + return eResult; +}; + +//static +WallpaperStyle SvxBrushItem::GraphicPos2WallpaperStyle( SvxGraphicPosition ePos ) +{ + WallpaperStyle eResult; + switch( ePos ) + { + case GPOS_NONE: eResult = WALLPAPER_NULL; break; + case GPOS_TILED: eResult = WALLPAPER_TILE; break; + case GPOS_MM: eResult = WALLPAPER_CENTER; break; + case GPOS_AREA: eResult = WALLPAPER_SCALE; break; + case GPOS_LT: eResult = WALLPAPER_TOPLEFT; break; + case GPOS_MT: eResult = WALLPAPER_TOP; break; + case GPOS_RT: eResult = WALLPAPER_TOPRIGHT; break; + case GPOS_LM: eResult = WALLPAPER_LEFT; break; + case GPOS_RM: eResult = WALLPAPER_RIGHT; break; + case GPOS_LB: eResult = WALLPAPER_BOTTOMLEFT; break; + case GPOS_MB: eResult = WALLPAPER_BOTTOM; break; + case GPOS_RB: eResult = WALLPAPER_BOTTOMRIGHT; break; + default: eResult = WALLPAPER_NULL; + } + return eResult; +} + + +SvxBrushItem::SvxBrushItem( const CntWallpaperItem& rItem, sal_uInt16 _nWhich ) : + SfxPoolItem( _nWhich ), + pImpl( new SvxBrushItem_Impl( 0 ) ), + pStrLink(0), + pStrFilter(0), + bLoadAgain( sal_True ) +{ + aColor = rItem.GetColor(); + + if( rItem.GetBitmapURL().Len() ) + { + pStrLink = new String( rItem.GetBitmapURL() ); + SetGraphicPos( WallpaperStyle2GraphicPos((WallpaperStyle)rItem.GetStyle() ) ); + } +} + +CntWallpaperItem* SvxBrushItem::CreateCntWallpaperItem() const +{ + CntWallpaperItem* pItem = new CntWallpaperItem( 0 ); + pItem->SetColor( aColor.GetColor() ); + pItem->SetStyle( (USHORT)GraphicPos2WallpaperStyle( GetGraphicPos() ) ); + sal_Bool bLink = (pStrLink != 0); + if( bLink ) + { + String aURL = *pStrLink; + pItem->SetBitmapURL( aURL ); + } + if( pImpl->pGraphicObject ) + { + DBG_ERRORFILE( "Don't know what to do with a graphic" ); + } +// pItem->SetGraphic( *pImpl->pGraphic, bLink ); + + return pItem; +} + +#ifdef _MSC_VER +#pragma optimize ( "", on ) +#endif +/* -----------------------------16.08.2002 09:18------------------------------ + + ---------------------------------------------------------------------------*/ +void SvxBrushItem::ApplyGraphicTransparency_Impl() +{ + DBG_ASSERT(pImpl->pGraphicObject, "no GraphicObject available" ); + if(pImpl->pGraphicObject) + { + GraphicAttr aAttr(pImpl->pGraphicObject->GetAttr()); + aAttr.SetTransparency(lcl_PercentToTransparency( + pImpl->nGraphicTransparency)); + pImpl->pGraphicObject->SetAttr(aAttr); + } +} +// class SvxFrameDirectionItem ---------------------------------------------- + +SvxFrameDirectionItem::SvxFrameDirectionItem( USHORT _nWhich ) + : SfxUInt16Item( _nWhich, (UINT16)FRMDIR_HORI_LEFT_TOP ) +{ +} + +SvxFrameDirectionItem::SvxFrameDirectionItem( SvxFrameDirection nValue , + USHORT _nWhich ) + : SfxUInt16Item( _nWhich, (UINT16)nValue ) +{ +} + +SvxFrameDirectionItem::~SvxFrameDirectionItem() +{ +} + +int SvxFrameDirectionItem::operator==( const SfxPoolItem& rCmp ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rCmp), "unequal types" ); + + return GetValue() == ((SvxFrameDirectionItem&)rCmp).GetValue(); +} + +SfxPoolItem* SvxFrameDirectionItem::Clone( SfxItemPool * ) const +{ + return new SvxFrameDirectionItem( *this ); +} + +SfxPoolItem* SvxFrameDirectionItem::Create( SvStream & rStrm, USHORT /*nVer*/ ) const +{ + sal_uInt16 nValue; + rStrm >> nValue; + return new SvxFrameDirectionItem( (SvxFrameDirection)nValue, Which() ); +} + +SvStream& SvxFrameDirectionItem::Store( SvStream & rStrm, USHORT /*nIVer*/ ) const +{ + sal_uInt16 nValue = GetValue(); + rStrm << nValue; + return rStrm; +} + +USHORT SvxFrameDirectionItem::GetVersion( USHORT nFVer ) const +{ + return SOFFICE_FILEFORMAT_50 > nFVer ? USHRT_MAX : 0; +} + +SfxItemPresentation SvxFrameDirectionItem::GetPresentation( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper *) const +{ + SfxItemPresentation eRet = ePres; + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = EE_RESSTR( RID_SVXITEMS_FRMDIR_BEGIN + GetValue() ); + break; + + default: + eRet = SFX_ITEM_PRESENTATION_NONE; + } + return eRet; +} + +sal_Bool SvxFrameDirectionItem::PutValue( const com::sun::star::uno::Any& rVal, + BYTE ) +{ + sal_Int16 nVal = sal_Int16(); + sal_Bool bRet = ( rVal >>= nVal ); + if( bRet ) + { + // translate WritingDirection2 constants into SvxFrameDirection + switch( nVal ) + { + case text::WritingMode2::LR_TB: + SetValue( FRMDIR_HORI_LEFT_TOP ); + break; + case text::WritingMode2::RL_TB: + SetValue( FRMDIR_HORI_RIGHT_TOP ); + break; + case text::WritingMode2::TB_RL: + SetValue( FRMDIR_VERT_TOP_RIGHT ); + break; + case text::WritingMode2::TB_LR: + SetValue( FRMDIR_VERT_TOP_LEFT ); + break; + case text::WritingMode2::PAGE: + SetValue( FRMDIR_ENVIRONMENT ); + break; + default: + bRet = sal_False; + break; + } + } + + return bRet; +} + +sal_Bool SvxFrameDirectionItem::QueryValue( com::sun::star::uno::Any& rVal, + BYTE ) const +{ + // translate SvxFrameDirection into WritingDirection2 + sal_Int16 nVal; + sal_Bool bRet = sal_True; + switch( GetValue() ) + { + case FRMDIR_HORI_LEFT_TOP: + nVal = text::WritingMode2::LR_TB; + break; + case FRMDIR_HORI_RIGHT_TOP: + nVal = text::WritingMode2::RL_TB; + break; + case FRMDIR_VERT_TOP_RIGHT: + nVal = text::WritingMode2::TB_RL; + break; + case FRMDIR_VERT_TOP_LEFT: + nVal = text::WritingMode2::TB_LR; + break; + case FRMDIR_ENVIRONMENT: + nVal = text::WritingMode2::PAGE; + break; + default: + DBG_ERROR("Unknown SvxFrameDirection value!"); + bRet = sal_False; + break; + } + + // return value + error state + if( bRet ) + { + rVal <<= nVal; + } + return bRet; +} + diff --git a/editeng/source/items/itemtype.cxx b/editeng/source/items/itemtype.cxx new file mode 100644 index 000000000000..c8b6da6dddef --- /dev/null +++ b/editeng/source/items/itemtype.cxx @@ -0,0 +1,242 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: itemtype.cxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +// include --------------------------------------------------------------- +#include <tools/list.hxx> +#include <vcl/outdev.hxx> +#include <editeng/editrids.hrc> +#include <unotools/intlwrapper.hxx> +#include <unotools/localedatawrapper.hxx> +#include <editeng/itemtype.hxx> +#include <editeng/eerdll.hxx> + +// ----------------------------------------------------------------------- + +XubString GetMetricText( long nVal, SfxMapUnit eSrcUnit, SfxMapUnit eDestUnit, const IntlWrapper* pIntl ) +{ + sal_Bool bNeg = sal_False; + long nRet = 0; + XubString sRet; + + if ( nVal < 0 ) + { + bNeg = sal_True; + nVal *= -1; + } + + switch ( eDestUnit ) + { + case SFX_MAPUNIT_100TH_MM: + case SFX_MAPUNIT_10TH_MM: + case SFX_MAPUNIT_MM: + case SFX_MAPUNIT_CM: + { + nRet = (long)OutputDevice::LogicToLogic( + nVal, (MapUnit)eSrcUnit, (MapUnit)SFX_MAPUNIT_100TH_MM ); + + switch ( eDestUnit ) + { + case SFX_MAPUNIT_100TH_MM: nRet *= 1000; break; + case SFX_MAPUNIT_10TH_MM: nRet *= 100; break; + case SFX_MAPUNIT_MM: nRet *= 10; break; + default: ;//prevent warning + } + break; + } + + case SFX_MAPUNIT_1000TH_INCH: + case SFX_MAPUNIT_100TH_INCH: + case SFX_MAPUNIT_10TH_INCH: + case SFX_MAPUNIT_INCH: + { + nRet = (long)OutputDevice::LogicToLogic( + nVal, (MapUnit)eSrcUnit, (MapUnit)SFX_MAPUNIT_1000TH_INCH ); + + switch ( eDestUnit ) + { + case SFX_MAPUNIT_1000TH_INCH: nRet *= 1000; break; + case SFX_MAPUNIT_100TH_INCH: nRet *= 100; break; + case SFX_MAPUNIT_10TH_INCH: nRet *= 10; break; + default: ;//prevent warning + } + break; + } + + case SFX_MAPUNIT_POINT: + case SFX_MAPUNIT_TWIP: + case SFX_MAPUNIT_PIXEL: + return String::CreateFromInt32( (long)OutputDevice::LogicToLogic( + nVal, (MapUnit)eSrcUnit, (MapUnit)eDestUnit )); + + default: + DBG_ERROR( "not supported mapunit" ); + return sRet; + } + + if ( SFX_MAPUNIT_CM == eDestUnit || SFX_MAPUNIT_INCH == eDestUnit ) + { + long nMod = nRet % 10; + + if ( nMod > 4 ) + nRet += 10 - nMod; + else if ( nMod > 0 ) + nRet -= nMod; + } + + if ( bNeg ) + sRet += sal_Unicode('-'); + + long nDiff = 1000; + for( int nDigits = 4; nDigits; --nDigits, nDiff /= 10 ) + { + if ( nRet < nDiff ) + sRet += sal_Unicode('0'); + else + sRet += String::CreateFromInt32( nRet / nDiff ); + nRet %= nDiff; + if( 4 == nDigits ) + { +// DBG_ASSERT(pIntl, "no IntlWrapper* set") + if(pIntl) + sRet += pIntl->getLocaleData()->getNumDecimalSep(); + else + sRet += ','; + if( !nRet ) + { + sRet += sal_Unicode('0'); + break; + } + } + else if( !nRet ) + break; + } + return sRet; +} + +// ----------------------------------------------------------------------- + +XubString GetSvxString( sal_uInt16 nId ) +{ + return EE_RESSTR( nId ); +} + +#ifndef SVX_LIGHT + +// ----------------------------------------------------------------------- + +XubString GetColorString( const Color& rCol ) +{ + XubString sStr; + + FASTBOOL bFound = sal_False; + ColorData nColData = + RGB_COLORDATA( rCol.GetRed(), rCol.GetGreen(), rCol.GetBlue() ); + sal_uInt16 nColor = 0, nColCount = 16; + + static ColorData aColAry[] = { + COL_BLACK, COL_BLUE, COL_GREEN, COL_CYAN, + COL_RED, COL_MAGENTA, COL_BROWN, COL_GRAY, + COL_LIGHTGRAY, COL_LIGHTBLUE, COL_LIGHTGREEN, COL_LIGHTCYAN, + COL_LIGHTRED, COL_LIGHTMAGENTA, COL_YELLOW, COL_WHITE }; + + while ( !bFound && nColor < nColCount ) + { + if ( aColAry[nColor] == nColData ) + bFound = sal_True; + else + nColor++; + } + + if ( nColor < nColCount ) + sStr = EE_RESSTR( RID_SVXITEMS_COLOR_BEGIN + nColor + 1 ); + + if ( !sStr.Len() ) + { + sStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "RGB" )); + sStr += sal_Unicode('('); + sStr += String::CreateFromInt32( rCol.GetRed() ); + sStr += cpDelim; + sStr += String::CreateFromInt32( rCol.GetGreen() ); + sStr += cpDelim; + sStr += String::CreateFromInt32( rCol.GetBlue() ); + sStr += sal_Unicode(')'); + } + return sStr; +} + +#endif + +// ----------------------------------------------------------------------- + +sal_uInt16 GetMetricId( SfxMapUnit eUnit ) +{ + sal_uInt16 nId = RID_SVXITEMS_METRIC_MM; + + switch ( eUnit ) + { + case SFX_MAPUNIT_100TH_MM: + case SFX_MAPUNIT_10TH_MM: + case SFX_MAPUNIT_MM: + nId = RID_SVXITEMS_METRIC_MM; + break; + + case SFX_MAPUNIT_CM: + nId = RID_SVXITEMS_METRIC_CM; + break; + + case SFX_MAPUNIT_1000TH_INCH: + case SFX_MAPUNIT_100TH_INCH: + case SFX_MAPUNIT_10TH_INCH: + case SFX_MAPUNIT_INCH: + nId = RID_SVXITEMS_METRIC_INCH; + break; + + case SFX_MAPUNIT_POINT: + nId = RID_SVXITEMS_METRIC_POINT; + break; + + case SFX_MAPUNIT_TWIP: + nId = RID_SVXITEMS_METRIC_TWIP; + break; + + case SFX_MAPUNIT_PIXEL: + nId = RID_SVXITEMS_METRIC_PIXEL; + break; + + default: + DBG_ERROR( "not supported mapunit" ); + } + return nId; +} + + diff --git a/editeng/source/items/makefile.mk b/editeng/source/items/makefile.mk new file mode 100644 index 000000000000..512db7cc34bd --- /dev/null +++ b/editeng/source/items/makefile.mk @@ -0,0 +1,79 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.19 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +#PROJECTPCH4DLL=TRUE +#PROJECTPCH=svxpch +#PROJECTPCHSOURCE=$(PRJ)$/util$/svxpch +#ENABLE_EXCEPTIONS=TRUE + +PRJNAME=editeng +TARGET=items + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SRS1NAME=items +SRC1FILES = \ + page.src \ + svxitems.src + +SLOFILES= \ + $(SLO)$/optitems.obj \ + $(SLO)$/svdfield.obj \ + $(SLO)$/writingmodeitem.obj \ + $(SLO)$/frmitems.obj \ + $(SLO)$/paraitem.obj \ + $(SLO)$/textitem.obj \ + $(SLO)$/flditem.obj \ + $(SLO)$/svxfont.obj \ + $(SLO)$/paperinf.obj \ + $(SLO)$/itemtype.obj \ + $(SLO)$/bulitem.obj \ + $(SLO)$/numitem.obj \ + $(SLO)$/xmlcnitm.obj \ + $(SLO)$/charhiddenitem.obj + +EXCEPTIONSFILES= \ + $(SLO)$/svdfield.obj \ + $(SLO)$/paraitem.obj \ + $(SLO)$/frmitems.obj \ + $(SLO)$/numitem.obj\ + $(SLO)$/xmlcnitm.obj\ + $(SLO)$/flditem.obj + +.INCLUDE : target.mk + diff --git a/editeng/source/items/numitem.cxx b/editeng/source/items/numitem.cxx new file mode 100644 index 000000000000..dc1113ada05a --- /dev/null +++ b/editeng/source/items/numitem.cxx @@ -0,0 +1,1276 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: numitem.cxx,v $ + * $Revision: 1.30 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/numitem.hxx> + +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/text/VertOrientation.hpp> +#include <com/sun/star/text/RelOrientation.hpp> +#include <editeng/brshitem.hxx> +#include <vcl/font.hxx> +#include <editeng/editids.hrc> +#include <editeng/editrids.hrc> +#include <editeng/numdef.hxx> +#include <vcl/graph.hxx> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <editeng/unolingu.hxx> +#include <com/sun/star/text/XNumberingFormatter.hpp> +#include <com/sun/star/text/XDefaultNumberingProvider.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <comphelper/processfactory.hxx> + +#include <editeng/unonrule.hxx> + +#define MM100_TO_TWIP(MM100) ((MM100*72L+63L)/127L) + +#define DEF_WRITER_LSPACE 500 //Standardeinrueckung +#define DEF_DRAW_LSPACE 800 //Standardeinrueckung + +#define NUMITEM_VERSION_01 0x01 +#define NUMITEM_VERSION_02 0x02 +#define NUMITEM_VERSION_03 0x03 +#define NUMITEM_VERSION_04 0x04 + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::style; + +sal_Int32 SvxNumberType::nRefCount = 0; +com::sun::star::uno::Reference<com::sun::star::text::XNumberingFormatter> SvxNumberType::xFormatter = 0; +void lcl_getFormatter(com::sun::star::uno::Reference<com::sun::star::text::XNumberingFormatter>& _xFormatter) +{ + if(!_xFormatter.is()) + { + try + { + Reference< XMultiServiceFactory > xMSF = ::comphelper::getProcessServiceFactory(); + Reference < XInterface > xI = xMSF->createInstance( + ::rtl::OUString::createFromAscii( "com.sun.star.text.DefaultNumberingProvider" ) ); + Reference<XDefaultNumberingProvider> xRet(xI, UNO_QUERY); + DBG_ASSERT(xRet.is(), "service missing: \"com.sun.star.text.DefaultNumberingProvider\""); + _xFormatter = Reference<XNumberingFormatter> (xRet, UNO_QUERY); + } + catch(Exception& ) + { + } + } +} +/* -----------------------------22.02.01 14:24-------------------------------- + + ---------------------------------------------------------------------------*/ +SvxNumberType::SvxNumberType(sal_Int16 nType) : + nNumType(nType), + bShowSymbol(sal_True) +{ + nRefCount++; +} +/* -----------------------------22.02.01 14:31-------------------------------- + + ---------------------------------------------------------------------------*/ +SvxNumberType::SvxNumberType(const SvxNumberType& rType) : + nNumType(rType.nNumType), + bShowSymbol(rType.bShowSymbol) +{ + nRefCount++; +} +/* -----------------------------22.02.01 14:24-------------------------------- + + ---------------------------------------------------------------------------*/ +SvxNumberType::~SvxNumberType() +{ + if(!--nRefCount) + xFormatter = 0; +} +/* -----------------------------22.02.01 11:09-------------------------------- + + ---------------------------------------------------------------------------*/ +String SvxNumberType::GetNumStr( ULONG nNo ) const +{ + LanguageType eLang = Application::GetSettings().GetLanguage(); + Locale aLocale = SvxCreateLocale(eLang); + return GetNumStr( nNo, aLocale ); +} +/* -----------------28.10.98 15:56------------------- + * + * --------------------------------------------------*/ +String SvxNumberType::GetNumStr( ULONG nNo, const Locale& rLocale ) const +{ + lcl_getFormatter(xFormatter); + String aTmpStr; + if(!xFormatter.is()) + return aTmpStr; + + if(bShowSymbol) + { + switch(nNumType) + { + case NumberingType::CHAR_SPECIAL: + case NumberingType::BITMAP: + break; + default: + { + //#95525# '0' allowed for ARABIC numberings + if(NumberingType::ARABIC == nNumType && 0 == nNo ) + aTmpStr = '0'; + else + { + Sequence< PropertyValue > aProperties(2); + PropertyValue* pValues = aProperties.getArray(); + pValues[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("NumberingType")); + pValues[0].Value <<= nNumType; + pValues[1].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Value")); + pValues[1].Value <<= (sal_Int32)nNo; + + try + { + aTmpStr = xFormatter->makeNumberingString( aProperties, rLocale ); + } + catch(Exception&) + { + } + } + } + } + } + return aTmpStr; +} +/* -----------------27.10.98 10:33------------------- + * + * --------------------------------------------------*/ +// --> OD 2008-01-09 #newlistlevelattrs# +SvxNumberFormat::SvxNumberFormat( sal_Int16 eType, + SvxNumPositionAndSpaceMode ePositionAndSpaceMode ) +// <-- + : SvxNumberType(eType), + eNumAdjust(SVX_ADJUST_LEFT), + nInclUpperLevels(0), + nStart(1), + cBullet(SVX_DEF_BULLET), + nBulletRelSize(100), + nBulletColor(COL_BLACK), + // --> OD 2008-01-09 #newlistlevelattrs# + mePositionAndSpaceMode( ePositionAndSpaceMode ), + // <-- + nFirstLineOffset(0), + nAbsLSpace(0), + nLSpace(0), + nCharTextDistance(0), + // --> OD 2008-01-09 #newlistlevelattrs# + meLabelFollowedBy( LISTTAB ), + mnListtabPos( 0 ), + mnFirstLineIndent( 0 ), + mnIndentAt( 0 ), + // <-- + pGraphicBrush(0), + eVertOrient(text::VertOrientation::NONE), + pBulletFont(0) +{ +} +/* -----------------27.10.98 10:56------------------- + * + * --------------------------------------------------*/ +SvxNumberFormat::SvxNumberFormat(const SvxNumberFormat& rFormat) : + SvxNumberType(rFormat), + // --> OD 2008-01-09 #newlistlevelattrs# + mePositionAndSpaceMode( rFormat.mePositionAndSpaceMode ), + // <-- + pGraphicBrush(0), + pBulletFont(0) +{ + *this = rFormat; +} +/* -----------------27.10.98 10:56------------------- + * + * --------------------------------------------------*/ +SvxNumberFormat::~SvxNumberFormat() +{ + delete pGraphicBrush; + delete pBulletFont; +} +/* -----------------08.12.98 11:14------------------- + * + * --------------------------------------------------*/ +SvxNumberFormat::SvxNumberFormat(SvStream &rStream) +: mePositionAndSpaceMode( LABEL_WIDTH_AND_POSITION ), + meLabelFollowedBy( LISTTAB ), + mnListtabPos( 0 ), + mnFirstLineIndent( 0 ), + mnIndentAt( 0 ) +{ + + USHORT nVersion; + rStream >> nVersion; + + USHORT nUSHORT; + rStream >> nUSHORT; + SetNumberingType((sal_Int16)nUSHORT); + rStream >> nUSHORT; + eNumAdjust = (SvxAdjust)nUSHORT; + rStream >> nUSHORT; + nInclUpperLevels = (BYTE)nUSHORT; + rStream >> nUSHORT; + nStart = nUSHORT; + rStream >> nUSHORT; + cBullet = nUSHORT; + + short nShort; + rStream >> nShort; + nFirstLineOffset = nShort; + rStream >> nShort; + nAbsLSpace = nShort; + rStream >> nShort; + nLSpace = nShort; + + rStream >> nShort; + nCharTextDistance = nShort; + rtl_TextEncoding eEnc = gsl_getSystemTextEncoding(); + rStream.ReadByteString(sPrefix, eEnc); + rStream.ReadByteString(sSuffix, eEnc); + rStream.ReadByteString(sCharStyleName, eEnc); + rStream >> nUSHORT; + if(nUSHORT) + { + SvxBrushItem aHelper(0); + pGraphicBrush = (SvxBrushItem*) aHelper.Create( rStream, BRUSH_GRAPHIC_VERSION ); + } + else + pGraphicBrush = 0; + + rStream >> nUSHORT; + eVertOrient = (sal_Int16)nUSHORT; + + rStream >> nUSHORT; + if(nUSHORT) + { + pBulletFont = new Font; + rStream >> *pBulletFont; + if(!pBulletFont->GetCharSet()) + pBulletFont->SetCharSet(rStream.GetStreamCharSet()); + } + else + pBulletFont = 0; + rStream >> aGraphicSize; + + rStream >> nBulletColor; + rStream >> nUSHORT; + nBulletRelSize = nUSHORT; + rStream >> nUSHORT; + SetShowSymbol((BOOL)nUSHORT); + + if( nVersion < NUMITEM_VERSION_03 ) + cBullet = ByteString::ConvertToUnicode( (sal_Char)cBullet, + (pBulletFont&&pBulletFont->GetCharSet()) ? pBulletFont->GetCharSet() + : RTL_TEXTENCODING_SYMBOL ); + if(pBulletFont) + { + BOOL bConvertBulletFont = rStream.GetVersion() <= SOFFICE_FILEFORMAT_50; + if(bConvertBulletFont) + { + + FontToSubsFontConverter pConverter = + CreateFontToSubsFontConverter(pBulletFont->GetName(), + FONTTOSUBSFONT_IMPORT|FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS); + if(pConverter) + { + cBullet = ConvertFontToSubsFontChar(pConverter, cBullet); + String sFontName = GetFontToSubsFontName(pConverter); + pBulletFont->SetName(sFontName); + DestroyFontToSubsFontConverter(pConverter); + } + } + } + + if( NUMITEM_VERSION_04 <= nVersion ) + { + rStream >> nUSHORT; + mePositionAndSpaceMode = (SvxNumPositionAndSpaceMode) nUSHORT; + rStream >> nUSHORT; + meLabelFollowedBy = ( SvxNumLabelFollowedBy ) nUSHORT; + long nLong; + rStream >> nLong; + mnListtabPos = nLong; + rStream >> nLong; + mnFirstLineIndent = nLong; + rStream >> nLong; + mnIndentAt = nLong; + } +} +/* -----------------08.12.98 11:14------------------- + * + * --------------------------------------------------*/ +SvStream& SvxNumberFormat::Store(SvStream &rStream, FontToSubsFontConverter pConverter) +{ + if(pConverter && pBulletFont) + { + cBullet = ConvertFontToSubsFontChar(pConverter, cBullet); + String sFontName = GetFontToSubsFontName(pConverter); + pBulletFont->SetName(sFontName); + } + + rStream << (USHORT)NUMITEM_VERSION_04; + + rStream << (USHORT)GetNumberingType(); + rStream << (USHORT)eNumAdjust; + rStream << (USHORT)nInclUpperLevels; + rStream << nStart; + rStream << (USHORT)cBullet; + + rStream << nFirstLineOffset; + rStream << nAbsLSpace; + rStream << nLSpace; + + rStream << nCharTextDistance; + rtl_TextEncoding eEnc = gsl_getSystemTextEncoding(); + rStream.WriteByteString(sPrefix, eEnc); + rStream.WriteByteString(sSuffix, eEnc); + rStream.WriteByteString(sCharStyleName, eEnc); + if(pGraphicBrush) + { + rStream << (USHORT)1; + + // #75113# in SD or SI force bullet itself to be stored, + // for that purpose throw away link when link and graphic + // are present, so Brush save is forced + if(pGraphicBrush->GetGraphicLink() && pGraphicBrush->GetGraphic()) + { + String aEmpty; + pGraphicBrush->SetGraphicLink(aEmpty); + } + + pGraphicBrush->Store(rStream, BRUSH_GRAPHIC_VERSION); + } + else + rStream << (USHORT)0; + + rStream << (USHORT)eVertOrient; + if(pBulletFont) + { + rStream << (USHORT)1; + rStream << *pBulletFont; + } + else + rStream << (USHORT)0; + rStream << aGraphicSize; + + Color nTempColor = nBulletColor; + if(COL_AUTO == nBulletColor.GetColor()) + nTempColor = COL_BLACK; + rStream << nTempColor; + rStream << nBulletRelSize; + rStream << (USHORT)IsShowSymbol(); + + rStream << ( USHORT ) mePositionAndSpaceMode; + rStream << ( USHORT ) meLabelFollowedBy; + rStream << ( long ) mnListtabPos; + rStream << ( long ) mnFirstLineIndent; + rStream << ( long ) mnIndentAt; + + return rStream; +} + +/* -----------------------------23.02.01 11:10-------------------------------- + + ---------------------------------------------------------------------------*/ +SvxNumberFormat& SvxNumberFormat::operator=( const SvxNumberFormat& rFormat ) +{ + SetNumberingType(rFormat.GetNumberingType()); + eNumAdjust = rFormat.eNumAdjust ; + nInclUpperLevels = rFormat.nInclUpperLevels ; + nStart = rFormat.nStart ; + cBullet = rFormat.cBullet ; + // --> OD 2008-01-09 #newlistlevelattrs# + mePositionAndSpaceMode = rFormat.mePositionAndSpaceMode; + // <-- + nFirstLineOffset = rFormat.nFirstLineOffset; + nAbsLSpace = rFormat.nAbsLSpace ; + nLSpace = rFormat.nLSpace ; + nCharTextDistance = rFormat.nCharTextDistance ; + // --> OD 2008-01-09 #newlistlevelattrs# + meLabelFollowedBy = rFormat.meLabelFollowedBy; + mnListtabPos = rFormat.mnListtabPos; + mnFirstLineIndent = rFormat.mnFirstLineIndent; + mnIndentAt = rFormat.mnIndentAt; + // <-- + eVertOrient = rFormat.eVertOrient ; + sPrefix = rFormat.sPrefix ; + sSuffix = rFormat.sSuffix ; + aGraphicSize = rFormat.aGraphicSize ; + nBulletColor = rFormat.nBulletColor ; + nBulletRelSize = rFormat.nBulletRelSize; + SetShowSymbol(rFormat.IsShowSymbol()); + sCharStyleName = rFormat.sCharStyleName; + DELETEZ(pGraphicBrush); + if(rFormat.pGraphicBrush) + { + pGraphicBrush = new SvxBrushItem(*rFormat.pGraphicBrush); + pGraphicBrush->SetDoneLink( STATIC_LINK( this, SvxNumberFormat, GraphicArrived) ); + } + DELETEZ(pBulletFont); + if(rFormat.pBulletFont) + pBulletFont = new Font(*rFormat.pBulletFont); + return *this; +} +/* -----------------27.10.98 10:56------------------- + * + * --------------------------------------------------*/ +BOOL SvxNumberFormat::operator==( const SvxNumberFormat& rFormat) const +{ + if( GetNumberingType() != rFormat.GetNumberingType() || + eNumAdjust != rFormat.eNumAdjust || + nInclUpperLevels != rFormat.nInclUpperLevels || + nStart != rFormat.nStart || + cBullet != rFormat.cBullet || + // --> OD 2008-01-09 #newlistlevelattrs# + mePositionAndSpaceMode != rFormat.mePositionAndSpaceMode || + // <-- + nFirstLineOffset != rFormat.nFirstLineOffset || + nAbsLSpace != rFormat.nAbsLSpace || + nLSpace != rFormat.nLSpace || + nCharTextDistance != rFormat.nCharTextDistance || + // --> OD 2008-01-09 #newlistlevelattrs# + meLabelFollowedBy != rFormat.meLabelFollowedBy || + mnListtabPos != rFormat.mnListtabPos || + mnFirstLineIndent != rFormat.mnFirstLineIndent || + mnIndentAt != rFormat.mnIndentAt || + // <-- + eVertOrient != rFormat.eVertOrient || + sPrefix != rFormat.sPrefix || + sSuffix != rFormat.sSuffix || + aGraphicSize != rFormat.aGraphicSize || + nBulletColor != rFormat.nBulletColor || + nBulletRelSize != rFormat.nBulletRelSize || + IsShowSymbol() != rFormat.IsShowSymbol() || + sCharStyleName != rFormat.sCharStyleName + ) + return FALSE; + if ( + (pGraphicBrush && !rFormat.pGraphicBrush) || + (!pGraphicBrush && rFormat.pGraphicBrush) || + (pGraphicBrush && *pGraphicBrush != *rFormat.pGraphicBrush) + ) + { + return FALSE; + } + if ( + (pBulletFont && !rFormat.pBulletFont) || + (!pBulletFont && rFormat.pBulletFont) || + (pBulletFont && *pBulletFont != *rFormat.pBulletFont) + ) + { + return FALSE; + } + return TRUE; +} +/* -----------------28.10.98 09:53------------------- + * + * --------------------------------------------------*/ +void SvxNumberFormat::SetGraphicBrush( const SvxBrushItem* pBrushItem, + const Size* pSize, const sal_Int16* pOrient) +{ + if(!pBrushItem) + { + delete pGraphicBrush; + pGraphicBrush = 0; + } + else if ( !pGraphicBrush || (pGraphicBrush && !(*pBrushItem == *pGraphicBrush)) ) + { + delete pGraphicBrush; + pGraphicBrush = (SvxBrushItem*)pBrushItem->Clone(); + pGraphicBrush->SetDoneLink( STATIC_LINK( this, SvxNumberFormat, GraphicArrived) ); + } + + if(pOrient) + eVertOrient = *pOrient; + else + eVertOrient = text::VertOrientation::NONE; + if(pSize) + aGraphicSize = *pSize; + else + aGraphicSize.Width() = aGraphicSize.Height() = 0; +} +/* -----------------28.10.98 09:59------------------- + * + * --------------------------------------------------*/ +void SvxNumberFormat::SetGraphic( const String& rName ) +{ + const String* pName; + if( pGraphicBrush && + 0 != (pName = pGraphicBrush->GetGraphicLink()) + && *pName == rName ) + return ; + + delete pGraphicBrush; + String sTmp; + pGraphicBrush = new SvxBrushItem( rName, sTmp, GPOS_AREA, 0 ); + pGraphicBrush->SetDoneLink( STATIC_LINK( this, SvxNumberFormat, GraphicArrived) ); + if( eVertOrient == text::VertOrientation::NONE ) + eVertOrient = text::VertOrientation::TOP; + + aGraphicSize.Width() = aGraphicSize.Height() = 0; +} +/* -----------------------------22.02.01 15:55-------------------------------- + + ---------------------------------------------------------------------------*/ +void SvxNumberFormat::SetVertOrient(sal_Int16 eSet) +{ + eVertOrient = eSet; +} +/* -----------------------------22.02.01 15:55-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Int16 SvxNumberFormat::GetVertOrient() const +{ + return eVertOrient; +} +/* -----------------28.10.98 09:59------------------- + * + * --------------------------------------------------*/ +void SvxNumberFormat::SetBulletFont(const Font* pFont) +{ + delete pBulletFont; + pBulletFont = pFont ? new Font(*pFont): 0; +} + +// --> OD 2008-01-09 #newlistlevelattrs# +SvxNumberFormat::SvxNumPositionAndSpaceMode SvxNumberFormat::GetPositionAndSpaceMode() const +{ + return mePositionAndSpaceMode; +} +void SvxNumberFormat::SetPositionAndSpaceMode( SvxNumPositionAndSpaceMode ePositionAndSpaceMode ) +{ + mePositionAndSpaceMode = ePositionAndSpaceMode; +} + +short SvxNumberFormat::GetLSpace() const +{ +//#if OSL_DEBUG_LEVEL > 1 +// DBG_ASSERT( mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION, +// "<SvxNumberFormat::GetLSpace()> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION"); +//#endif + return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION ? nLSpace : 0; +} +short SvxNumberFormat::GetAbsLSpace() const +{ +//#if OSL_DEBUG_LEVEL > 1 +// DBG_ASSERT( mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION, +// "<SvxNumberFormat::GetAbsLSpace()> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION"); +//#endif + return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION + ? nAbsLSpace + : static_cast<short>( GetFirstLineIndent() + GetIndentAt() ); +} +short SvxNumberFormat::GetFirstLineOffset() const +{ +//#if OSL_DEBUG_LEVEL > 1 +// DBG_ASSERT( mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION, +// "<SvxNumberFormat::GetFirstLineOffset()> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION"); +//#endif + return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION + ? nFirstLineOffset + : static_cast<short>( GetFirstLineIndent() ); +} +short SvxNumberFormat::GetCharTextDistance() const +{ +//#if OSL_DEBUG_LEVEL > 1 +// DBG_ASSERT( mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION, +// "<SvxNumberFormat::GetCharTextDistance()> - misusage: position-and-space-mode does not equal LABEL_WIDTH_AND_POSITION"); +//#endif + return mePositionAndSpaceMode == LABEL_WIDTH_AND_POSITION ? nCharTextDistance : 0; +} + +void SvxNumberFormat::SetLabelFollowedBy( const SvxNumLabelFollowedBy eLabelFollowedBy ) +{ + meLabelFollowedBy = eLabelFollowedBy; +} +SvxNumberFormat::SvxNumLabelFollowedBy SvxNumberFormat::GetLabelFollowedBy() const +{ + return meLabelFollowedBy; +} +void SvxNumberFormat::SetListtabPos( const long nListtabPos ) +{ + mnListtabPos = nListtabPos; +} +long SvxNumberFormat::GetListtabPos() const +{ + return mnListtabPos; +} +void SvxNumberFormat::SetFirstLineIndent( const long nFirstLineIndent ) +{ + mnFirstLineIndent = nFirstLineIndent; +} +long SvxNumberFormat::GetFirstLineIndent() const +{ + return mnFirstLineIndent; +} +void SvxNumberFormat::SetIndentAt( const long nIndentAt ) +{ + mnIndentAt = nIndentAt; +} +long SvxNumberFormat::GetIndentAt() const +{ + return mnIndentAt; +} +// <-- + +/* -----------------28.10.98 10:03------------------- + * + * --------------------------------------------------*/ +IMPL_STATIC_LINK( SvxNumberFormat, GraphicArrived, void *, EMPTYARG ) +{ + // ggfs. die GrfSize setzen: + if( !pThis->aGraphicSize.Width() || !pThis->aGraphicSize.Height() ) + { + const Graphic* pGrf = pThis->pGraphicBrush->GetGraphic(); + if( pGrf ) + pThis->aGraphicSize = SvxNumberFormat::GetGraphicSizeMM100( pGrf ); + } + pThis->NotifyGraphicArrived(); + return 0; +} +/* -----------------------------02.07.01 15:36-------------------------------- + + ---------------------------------------------------------------------------*/ +void SvxNumberFormat::NotifyGraphicArrived() +{ +} + +/* -----------------28.10.98 10:38------------------- + * + * --------------------------------------------------*/ +Size SvxNumberFormat::GetGraphicSizeMM100(const Graphic* pGraphic) +{ + const MapMode aMapMM100( MAP_100TH_MM ); + const Size& rSize = pGraphic->GetPrefSize(); + Size aRetSize; + if ( pGraphic->GetPrefMapMode().GetMapUnit() == MAP_PIXEL ) + { + OutputDevice* pOutDev = Application::GetDefaultDevice(); + MapMode aOldMap( pOutDev->GetMapMode() ); + pOutDev->SetMapMode( aMapMM100 ); + aRetSize = pOutDev->PixelToLogic( rSize ); + pOutDev->SetMapMode( aOldMap ); + } + else + aRetSize = OutputDevice::LogicToLogic( rSize, pGraphic->GetPrefMapMode(), aMapMM100 ); + return aRetSize; +} +/* -----------------28.10.98 15:57------------------- + * + * --------------------------------------------------*/ +String SvxNumberFormat::CreateRomanString( ULONG nNo, BOOL bUpper ) +{ + nNo %= 4000; // mehr kann nicht dargestellt werden +// i, ii, iii, iv, v, vi, vii, vii, viii, ix +// (Dummy),1000,500,100,50,10,5,1 + const char *cRomanArr = bUpper + ? "MDCLXVI--" // +2 Dummy-Eintraege !! + : "mdclxvi--"; // +2 Dummy-Eintraege !! + + String sRet; + USHORT nMask = 1000; + while( nMask ) + { + BYTE nZahl = BYTE(nNo / nMask); + BYTE nDiff = 1; + nNo %= nMask; + + if( 5 < nZahl ) + { + if( nZahl < 9 ) + sRet += sal_Unicode(*(cRomanArr-1)); + ++nDiff; + nZahl -= 5; + } + switch( nZahl ) + { + case 3: { sRet += sal_Unicode(*cRomanArr); } + case 2: { sRet += sal_Unicode(*cRomanArr); } + case 1: { sRet += sal_Unicode(*cRomanArr); } + break; + + case 4: { + sRet += sal_Unicode(*cRomanArr); + sRet += sal_Unicode(*(cRomanArr-nDiff)); + } + break; + case 5: { sRet += sal_Unicode(*(cRomanArr-nDiff)); } + break; + } + + nMask /= 10; // zur naechsten Dekade + cRomanArr += 2; + } + return sRet; +} +#ifdef OLD_NUMBER_FORMATTING +void SvxNumberFormat::GetCharStr( ULONG nNo, String& rStr ) const +{ + DBG_ASSERT( nNo, "0 ist eine ungueltige Nummer !!" ); + + const ULONG coDiff = 'Z' - 'A' +1; + char cAdd = (SVX_NUM_CHARS_UPPER_LETTER == eNumType ? 'A' : 'a') - 1; + ULONG nCalc; + + do { + nCalc = nNo % coDiff; + if( !nCalc ) + nCalc = coDiff; + rStr.Insert( sal_Unicode(cAdd + nCalc ), 0 ); + nNo -= nCalc; + if( nNo ) + nNo /= coDiff; + } while( nNo ); +} + +void SvxNumberFormat::GetCharStrN( ULONG nNo, String& rStr ) const +{ + DBG_ASSERT( nNo, "0 ist eine ungueltige Nummer !!" ); + + const ULONG coDiff = 'Z' - 'A' +1; + char cChar = (char)(--nNo % coDiff); + if( SVX_NUM_CHARS_UPPER_LETTER_N == eNumType ) + cChar += 'A'; + else + cChar += 'a'; + + rStr.Fill( (USHORT)(nNo / coDiff) + 1, sal_Unicode(cChar) ); +} +#endif //OLD_NUMBER_FORMATTING +/* -----------------------------22.02.01 13:31-------------------------------- + + ---------------------------------------------------------------------------*/ +const String& SvxNumberFormat::GetCharFmtName()const +{ + return sCharStyleName; +} +/* -----------------27.10.98 10:38------------------- + * + * --------------------------------------------------*/ +sal_Int32 SvxNumRule::nRefCount = 0; +static SvxNumberFormat* pStdNumFmt = 0; +static SvxNumberFormat* pStdOutlineNumFmt = 0; +// --> OD 2008-02-11 #newlistlevelattrs# +SvxNumRule::SvxNumRule( ULONG nFeatures, + USHORT nLevels, + BOOL bCont, + SvxNumRuleType eType, + SvxNumberFormat::SvxNumPositionAndSpaceMode + eDefaultNumberFormatPositionAndSpaceMode ) + : nLevelCount(nLevels), + nFeatureFlags(nFeatures), + eNumberingType(eType), + bContinuousNumbering(bCont) +{ + ++nRefCount; + LanguageType eLang = Application::GetSettings().GetLanguage(); + aLocale = SvxCreateLocale(eLang); + for(USHORT i = 0; i < SVX_MAX_NUM; i++) + { + if(i < nLevels) + { + aFmts[i] = new SvxNumberFormat(SVX_NUM_CHARS_UPPER_LETTER); + //daran wird zwischen writer und draw unterschieden + if(nFeatures & NUM_CONTINUOUS) + { + // --> OD 2008-02-11 #newlistlevelattrs# + if ( eDefaultNumberFormatPositionAndSpaceMode == + SvxNumberFormat::LABEL_WIDTH_AND_POSITION ) + { + aFmts[i]->SetLSpace( MM100_TO_TWIP(DEF_WRITER_LSPACE) ); + aFmts[i]->SetAbsLSpace( MM100_TO_TWIP(DEF_WRITER_LSPACE * (i+1)) ); + aFmts[i]->SetFirstLineOffset(MM100_TO_TWIP(-DEF_WRITER_LSPACE)); + } + else if ( eDefaultNumberFormatPositionAndSpaceMode == + SvxNumberFormat::LABEL_ALIGNMENT ) + { + // first line indent of general numbering in inch: -0,25 inch + const long cFirstLineIndent = -1440/4; + // indent values of general numbering in inch: + // 0,5 0,75 1,0 1,25 1,5 + // 1,75 2,0 2,25 2,5 2,75 + const long cIndentAt = 1440/4; + aFmts[i]->SetPositionAndSpaceMode( SvxNumberFormat::LABEL_ALIGNMENT ); + aFmts[i]->SetLabelFollowedBy( SvxNumberFormat::LISTTAB ); + aFmts[i]->SetListtabPos( cIndentAt * (i+2) ); + aFmts[i]->SetFirstLineIndent( cFirstLineIndent ); + aFmts[i]->SetIndentAt( cIndentAt * (i+2) ); + } + // <-- + } + else + { + aFmts[i]->SetLSpace( DEF_DRAW_LSPACE ); + aFmts[i]->SetAbsLSpace( DEF_DRAW_LSPACE * (i) ); + } + } + else + aFmts[i] = 0; + aFmtsSet[i] = FALSE; + } +} +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +SvxNumRule::SvxNumRule(const SvxNumRule& rCopy) +{ + ++nRefCount; + aLocale = rCopy.aLocale; + nLevelCount = rCopy.nLevelCount ; + nFeatureFlags = rCopy.nFeatureFlags ; + bContinuousNumbering = rCopy.bContinuousNumbering; + eNumberingType = rCopy.eNumberingType; + memset( aFmts, 0, sizeof( aFmts )); + for(USHORT i = 0; i < SVX_MAX_NUM; i++) + { + if(rCopy.aFmts[i]) + aFmts[i] = new SvxNumberFormat(*rCopy.aFmts[i]); + else + aFmts[i] = 0; + aFmtsSet[i] = rCopy.aFmtsSet[i]; + } +} +/* -----------------08.12.98 11:07------------------- + * + * --------------------------------------------------*/ +SvxNumRule::SvxNumRule(SvStream &rStream) +{ + ++nRefCount; + LanguageType eLang = Application::GetSettings().GetLanguage(); + aLocale = SvxCreateLocale(eLang); + USHORT nVersion; + USHORT nTemp; + rStream >> nVersion; + rStream >> nLevelCount; + rStream >> nTemp; + nFeatureFlags = nTemp; + rStream >> nTemp; + bContinuousNumbering = (BOOL)nTemp; + rStream >> nTemp; + eNumberingType = (SvxNumRuleType)nTemp; + memset( aFmts, 0, sizeof( aFmts )); + + for(USHORT i = 0; i < SVX_MAX_NUM; i++) + { + USHORT nSet; + rStream >> nSet; + if(nSet) + aFmts[i] = new SvxNumberFormat(rStream); + else + aFmts[i] = 0; + aFmtsSet[i] = aFmts[i] ? TRUE : FALSE; + } + if(NUMITEM_VERSION_02 <= nVersion) + { + USHORT nShort; + rStream >> nShort; + nFeatureFlags = nShort; + } +} + +/* -----------------08.12.98 11:07------------------- + * + * --------------------------------------------------*/ +SvStream& SvxNumRule::Store(SvStream &rStream) +{ + rStream<<(USHORT)NUMITEM_VERSION_03; + rStream<<nLevelCount; + //first save of nFeatureFlags for old versions + rStream<<(USHORT)nFeatureFlags; + rStream<<(USHORT)bContinuousNumbering; + rStream<<(USHORT)eNumberingType; + + FontToSubsFontConverter pConverter = 0; + BOOL bConvertBulletFont = rStream.GetVersion() <= SOFFICE_FILEFORMAT_50; + for(USHORT i = 0; i < SVX_MAX_NUM; i++) + { + if(aFmts[i]) + { + rStream << USHORT(1); + if(bConvertBulletFont && aFmts[i]->GetBulletFont()) + { + if(!pConverter) + pConverter = + CreateFontToSubsFontConverter(aFmts[i]->GetBulletFont()->GetName(), + FONTTOSUBSFONT_EXPORT|FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS); + } + aFmts[i]->Store(rStream, pConverter); + } + else + rStream << USHORT(0); + } + //second save of nFeatureFlags for new versions + rStream<<(USHORT)nFeatureFlags; + if(pConverter) + DestroyFontToSubsFontConverter(pConverter); + + return rStream; +} + +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +SvxNumRule::~SvxNumRule() +{ + for(USHORT i = 0; i < SVX_MAX_NUM; i++) + delete aFmts[i]; + if(!--nRefCount) + { + DELETEZ(pStdNumFmt); + DELETEZ(pStdOutlineNumFmt); + } +} +/* -----------------29.10.98 16:07------------------- + * + * --------------------------------------------------*/ +SvxNumRule& SvxNumRule::operator=( const SvxNumRule& rCopy ) +{ + nLevelCount = rCopy.nLevelCount; + nFeatureFlags = rCopy.nFeatureFlags; + bContinuousNumbering = rCopy.bContinuousNumbering; + eNumberingType = rCopy.eNumberingType; + for(USHORT i = 0; i < SVX_MAX_NUM; i++) + { + delete aFmts[i]; + if(rCopy.aFmts[i]) + aFmts[i] = new SvxNumberFormat(*rCopy.aFmts[i]); + else + aFmts[i] = 0; + aFmtsSet[i] = rCopy.aFmtsSet[i]; + } + return *this; +} +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +int SvxNumRule::operator==( const SvxNumRule& rCopy) const +{ + if(nLevelCount != rCopy.nLevelCount || + nFeatureFlags != rCopy.nFeatureFlags || + bContinuousNumbering != rCopy.bContinuousNumbering || + eNumberingType != rCopy.eNumberingType) + return FALSE; + for(USHORT i = 0; i < nLevelCount; i++) + { + if ( + (aFmtsSet[i] != rCopy.aFmtsSet[i]) || + (!aFmts[i] && rCopy.aFmts[i]) || + (aFmts[i] && !rCopy.aFmts[i]) || + (aFmts[i] && *aFmts[i] != *rCopy.aFmts[i]) + ) + { + return FALSE; + } + } + return TRUE; +} +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +const SvxNumberFormat* SvxNumRule::Get(USHORT nLevel)const +{ + DBG_ASSERT(nLevel < SVX_MAX_NUM, "falsches Level" ); + if( nLevel < SVX_MAX_NUM ) + return aFmtsSet[nLevel] ? aFmts[nLevel] : 0; + else + return 0; +} +/* -----------------02.11.98 09:10------------------- + * + * --------------------------------------------------*/ +const SvxNumberFormat& SvxNumRule::GetLevel(USHORT nLevel)const +{ + if(!pStdNumFmt) + { + pStdNumFmt = new SvxNumberFormat(SVX_NUM_ARABIC); + pStdOutlineNumFmt = new SvxNumberFormat(SVX_NUM_NUMBER_NONE); + } + + DBG_ASSERT(nLevel < SVX_MAX_NUM, "falsches Level" ); + + return ( ( nLevel < SVX_MAX_NUM ) && aFmts[nLevel] ) ? + *aFmts[nLevel] : eNumberingType == SVX_RULETYPE_NUMBERING ? + *pStdNumFmt : *pStdOutlineNumFmt; +} + +/* -----------------29.10.98 09:08------------------- + * + * --------------------------------------------------*/ +void SvxNumRule::SetLevel( USHORT i, const SvxNumberFormat& rNumFmt, BOOL bIsValid ) +{ + DBG_ASSERT(i < SVX_MAX_NUM, "falsches Level" ); + + if( (i < SVX_MAX_NUM) && (!aFmtsSet[i] || !(rNumFmt == *Get( i ))) ) + { + delete aFmts[ i ]; + aFmts[ i ] = new SvxNumberFormat( rNumFmt ); + aFmtsSet[i] = bIsValid; +// bInvalidRuleFlag = TRUE; + } +} +/* -----------------30.10.98 12:44------------------- + * + * --------------------------------------------------*/ +void SvxNumRule::SetLevel(USHORT nLevel, const SvxNumberFormat* pFmt) +{ + DBG_ASSERT(nLevel < SVX_MAX_NUM, "falsches Level" ); + + if( nLevel < SVX_MAX_NUM ) + { + aFmtsSet[nLevel] = 0 != pFmt; + if(pFmt) + SetLevel(nLevel, *pFmt); + else + { + delete aFmts[nLevel]; + aFmts[nLevel] = 0; + } + } +} +/* -----------------28.10.98 15:38------------------- + * + * --------------------------------------------------*/ +String SvxNumRule::MakeNumString( const SvxNodeNum& rNum, BOOL bInclStrings ) const +{ + String aStr; + if( SVX_NO_NUM > rNum.GetLevel() && !( SVX_NO_NUMLEVEL & rNum.GetLevel() ) ) + { + const SvxNumberFormat& rMyNFmt = GetLevel( rNum.GetLevel() ); + if( SVX_NUM_NUMBER_NONE != rMyNFmt.GetNumberingType() ) + { + BYTE i = rNum.GetLevel(); + + if( !IsContinuousNumbering() && + 1 < rMyNFmt.GetIncludeUpperLevels() ) // nur der eigene Level ? + { + BYTE n = rMyNFmt.GetIncludeUpperLevels(); + if( 1 < n ) + { + if( i+1 >= n ) + i -= n - 1; + else + i = 0; + } + } + + for( ; i <= rNum.GetLevel(); ++i ) + { + const SvxNumberFormat& rNFmt = GetLevel( i ); + if( SVX_NUM_NUMBER_NONE == rNFmt.GetNumberingType() ) + { + // Soll aus 1.1.1 --> 2. NoNum --> 1..1 oder 1.1 ?? + // if( i != rNum.nMyLevel ) + // aStr += aDotStr; + continue; + } + + sal_Bool bDot = sal_True; + if( rNum.GetLevelVal()[ i ] ) + { + if(SVX_NUM_BITMAP != rNFmt.GetNumberingType()) + aStr += rNFmt.GetNumStr( rNum.GetLevelVal()[ i ], aLocale ); + else + bDot = sal_False; + } + else + aStr += sal_Unicode('0'); // alle 0-Level sind eine 0 + if( i != rNum.GetLevel() && bDot) + aStr += sal_Unicode('.'); + } + } + + if( bInclStrings ) + { + aStr.Insert( rMyNFmt.GetPrefix(), 0 ); + aStr += rMyNFmt.GetSuffix(); + } + } + return aStr; +} +/* -----------------18.08.99 10:18------------------- + Description: changes linked to embedded bitmaps + --------------------------------------------------*/ +BOOL SvxNumRule::UnLinkGraphics() +{ + BOOL bRet = FALSE; + for(USHORT i = 0; i < GetLevelCount(); i++) + { + SvxNumberFormat aFmt(GetLevel(i)); + const SvxBrushItem* pBrush = aFmt.GetBrush(); + const String* pLinkStr; + const Graphic* pGraphic; + if(SVX_NUM_BITMAP == aFmt.GetNumberingType()) + { + if(pBrush && + 0 != (pLinkStr = pBrush->GetGraphicLink()) && + pLinkStr->Len() && + 0 !=(pGraphic = pBrush->GetGraphic())) + { + SvxBrushItem aTempItem(*pBrush); + aTempItem.SetGraphicLink( String()); + aTempItem.SetGraphic(*pGraphic); + sal_Int16 eOrient = aFmt.GetVertOrient(); + aFmt.SetGraphicBrush( &aTempItem, &aFmt.GetGraphicSize(), &eOrient ); + bRet = TRUE; + } + } + else if((SVX_NUM_BITMAP|LINK_TOKEN) == aFmt.GetNumberingType()) + aFmt.SetNumberingType(SVX_NUM_BITMAP); + SetLevel(i, aFmt); + } + return bRet; +} + +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +SvxNumBulletItem::SvxNumBulletItem(SvxNumRule& rRule) : + SfxPoolItem(SID_ATTR_NUMBERING_RULE), + pNumRule(new SvxNumRule(rRule)) +{ +} + +/*-----------------23.11.98 10:36------------------- + MT: Das sind ja sehr sinnige Kommentare... +--------------------------------------------------*/ +SvxNumBulletItem::SvxNumBulletItem(SvxNumRule& rRule, USHORT _nWhich ) : + SfxPoolItem(_nWhich), + pNumRule(new SvxNumRule(rRule)) +{ +} + +SfxPoolItem* SvxNumBulletItem::Create(SvStream &s, USHORT n) const +{ + return SfxPoolItem::Create(s, n ); +} + +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +SvxNumBulletItem::SvxNumBulletItem(const SvxNumBulletItem& rCopy) : + SfxPoolItem(rCopy.Which()) +{ + pNumRule = new SvxNumRule(*rCopy.pNumRule); +} +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +SvxNumBulletItem::~SvxNumBulletItem() +{ + delete pNumRule; +} + +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +int SvxNumBulletItem::operator==( const SfxPoolItem& rCopy) const +{ + return *pNumRule == *((SvxNumBulletItem&)rCopy).pNumRule; +} +/* -----------------27.10.98 10:41------------------- + * + * --------------------------------------------------*/ +SfxPoolItem* SvxNumBulletItem::Clone( SfxItemPool * ) const +{ + return new SvxNumBulletItem(*this); +} +/* -----------------08.12.98 10:43------------------- + * + * --------------------------------------------------*/ +USHORT SvxNumBulletItem::GetVersion( USHORT /*nFileVersion*/ ) const +{ + return NUMITEM_VERSION_03; +} +/* -----------------08.12.98 10:43------------------- + * + * --------------------------------------------------*/ +SvStream& SvxNumBulletItem::Store(SvStream &rStream, USHORT /*nItemVersion*/ )const +{ + pNumRule->Store(rStream); + return rStream; +} + +/* -----------------08.12.98 10:43------------------- + * + * --------------------------------------------------*/ + +sal_Bool SvxNumBulletItem::QueryValue( com::sun::star::uno::Any& rVal, BYTE /*nMemberId*/ ) const +{ + rVal <<= SvxCreateNumRule( pNumRule ); + return sal_True; +} + +sal_Bool SvxNumBulletItem::PutValue( const com::sun::star::uno::Any& rVal, BYTE /*nMemberId*/ ) +{ + uno::Reference< container::XIndexReplace > xRule; + if( rVal >>= xRule ) + { + try + { + SvxNumRule* pNewRule = new SvxNumRule( SvxGetNumRule( xRule ) ); + if( pNewRule->GetLevelCount() != pNumRule->GetLevelCount() || + pNewRule->GetNumRuleType() != pNumRule->GetNumRuleType() ) + { + SvxNumRule* pConverted = SvxConvertNumRule( pNewRule, pNumRule->GetLevelCount(), pNumRule->GetNumRuleType() ); + delete pNewRule; + pNewRule = pConverted; + } + delete pNumRule; + pNumRule = pNewRule; + return sal_True; + } + catch(lang::IllegalArgumentException&) + { + } + } + return sal_False; +} + +/* -----------------08.12.98 10:43------------------- + * + * --------------------------------------------------*/ +SvxNumRule* SvxConvertNumRule( const SvxNumRule* pRule, USHORT nLevels, SvxNumRuleType eType ) +{ + const USHORT nSrcLevels = pRule->GetLevelCount(); + SvxNumRule* pNewRule = new SvxNumRule( pRule->GetFeatureFlags(), nLevels, pRule->IsContinuousNumbering(), eType ); + + for( USHORT nLevel = 0; (nLevel < nLevels) && (nLevel < nSrcLevels); nLevel++ ) + pNewRule->SetLevel( nLevel, pRule->GetLevel( nLevel ) ); + + return pNewRule; +} diff --git a/editeng/source/items/optitems.cxx b/editeng/source/items/optitems.cxx new file mode 100644 index 000000000000..9ddbdbe8ea43 --- /dev/null +++ b/editeng/source/items/optitems.cxx @@ -0,0 +1,206 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: optitems.cxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <tools/shl.hxx> +#include <tools/resid.hxx> +#include <tools/stream.hxx> +#include <com/sun/star/linguistic2/XSpellChecker1.hpp> + +#include <editeng/optitems.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/editrids.hrc> +#include <editeng/eerdll.hxx> +#include <editeng/editrids.hrc> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; + +// STATIC DATA ----------------------------------------------------------- + +TYPEINIT1(SfxSpellCheckItem, SfxPoolItem); +TYPEINIT1(SfxHyphenRegionItem, SfxPoolItem); + +// class SfxSpellCheckItem ----------------------------------------------- + +SfxSpellCheckItem::SfxSpellCheckItem +( + Reference< XSpellChecker1 > &xChecker, + sal_uInt16 _nWhich +) : + + SfxPoolItem( _nWhich ) +{ + xSpellCheck = xChecker; +} + +// ----------------------------------------------------------------------- + +SfxSpellCheckItem::SfxSpellCheckItem( const SfxSpellCheckItem& rItem ) : + + SfxPoolItem( rItem ), + xSpellCheck( rItem.GetXSpellChecker() ) +{ +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SfxSpellCheckItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit , + SfxMapUnit , + String& rText, + const IntlWrapper* +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + return ePres; + } + default: + return SFX_ITEM_PRESENTATION_NONE; + } +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SfxSpellCheckItem::Clone( SfxItemPool* ) const +{ + return new SfxSpellCheckItem( *this ); +} + +// ----------------------------------------------------------------------- + +int SfxSpellCheckItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rItem), "unequal types" ); + return ( xSpellCheck == ( (const SfxSpellCheckItem& )rItem ).GetXSpellChecker() ); +} + +// class SfxHyphenRegionItem ----------------------------------------------- + +SfxHyphenRegionItem::SfxHyphenRegionItem( const sal_uInt16 nId ) : + + SfxPoolItem( nId ) +{ + nMinLead = nMinTrail = 0; +} + +// ----------------------------------------------------------------------- + +SfxHyphenRegionItem::SfxHyphenRegionItem( const SfxHyphenRegionItem& rItem ) : + + SfxPoolItem ( rItem ), + + nMinLead ( rItem.GetMinLead() ), + nMinTrail ( rItem.GetMinTrail() ) +{ +} + +// ----------------------------------------------------------------------- + +int SfxHyphenRegionItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( ( ( (SfxHyphenRegionItem&)rAttr ).nMinLead == nMinLead ) && + ( ( (SfxHyphenRegionItem&)rAttr ).nMinTrail == nMinTrail ) ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SfxHyphenRegionItem::Clone( SfxItemPool* ) const +{ + return new SfxHyphenRegionItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SfxHyphenRegionItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit , + SfxMapUnit , + String& rText, + const IntlWrapper* +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText += String::CreateFromInt32( nMinLead ); + rText += String( EditResId( RID_SVXITEMS_HYPHEN_MINLEAD ) ); + rText += ','; + rText += String::CreateFromInt32( nMinTrail ); + rText += String( EditResId( RID_SVXITEMS_HYPHEN_MINTRAIL ) ); + return ePres; + } + default: + return SFX_ITEM_PRESENTATION_NONE; + } +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SfxHyphenRegionItem::Create(SvStream& rStrm, sal_uInt16 ) const +{ + sal_uInt8 _nMinLead, _nMinTrail; + rStrm >> _nMinLead >> _nMinTrail; + SfxHyphenRegionItem* pAttr = new SfxHyphenRegionItem( Which() ); + pAttr->GetMinLead() = _nMinLead; + pAttr->GetMinTrail() = _nMinTrail; + return pAttr; +} + +// ----------------------------------------------------------------------- + +SvStream& SfxHyphenRegionItem::Store( SvStream& rStrm, sal_uInt16 ) const +{ + rStrm << (sal_uInt8) GetMinLead() + << (sal_uInt8) GetMinTrail(); + return rStrm; +} + + diff --git a/editeng/source/items/page.src b/editeng/source/items/page.src new file mode 100644 index 000000000000..6579c60fff4d --- /dev/null +++ b/editeng/source/items/page.src @@ -0,0 +1,258 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: page.src,v $ + * $Revision: 1.71 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + // include --------------------------------------------------------------- + +#include <editeng/editrids.hrc> + +String RID_SVXSTR_PAPER_A0 +{ + Text = "A0" ; +}; +String RID_SVXSTR_PAPER_A1 +{ + Text = "A1" ; +}; +String RID_SVXSTR_PAPER_A2 +{ + Text = "A2" ; +}; +String RID_SVXSTR_PAPER_A3 +{ + Text = "A3" ; +}; +String RID_SVXSTR_PAPER_A4 +{ + Text = "A4" ; +}; +String RID_SVXSTR_PAPER_A5 +{ + Text = "A5" ; +}; +String RID_SVXSTR_PAPER_B4_ISO +{ + Text = "B4 (ISO)" ; +}; +String RID_SVXSTR_PAPER_B5_ISO +{ + Text = "B5 (ISO)" ; +}; +String RID_SVXSTR_PAPER_LETTER +{ + Text = "Letter" ; +}; +String RID_SVXSTR_PAPER_LEGAL +{ + Text = "Legal" ; +}; +String RID_SVXSTR_PAPER_TABLOID +{ + Text = "Tabloid" ; +}; +String RID_SVXSTR_PAPER_USER +{ + Text [ en-US ] = "User Defined" ; +}; +String RID_SVXSTR_PAPER_B6_ISO +{ + Text = "B6 (ISO)" ; +}; +String RID_SVXSTR_PAPER_C4 +{ + Text = "C4 Envelope" ; +}; +String RID_SVXSTR_PAPER_C5 +{ + Text = "C5 Envelope" ; +}; +String RID_SVXSTR_PAPER_C6 +{ + Text = "C6 Envelope" ; +}; +String RID_SVXSTR_PAPER_C65 +{ + Text = "C6/5 Envelope" ; +}; +String RID_SVXSTR_PAPER_DL +{ + Text = "DL Envelope" ; +}; +String RID_SVXSTR_PAPER_DIA +{ + Text = "Dia Slide" ; +}; +String RID_SVXSTR_PAPER_SCREEN +{ + Text [ en-US ] = "Screen" ; +}; +String RID_SVXSTR_PAPER_C +{ + Text = "C" ; +}; +String RID_SVXSTR_PAPER_D +{ + Text = "D" ; +}; +String RID_SVXSTR_PAPER_E +{ + Text = "E" ; +}; +String RID_SVXSTR_PAPER_EXECUTIVE +{ + Text = "Executive" ; +}; +String RID_SVXSTR_PAPER_LEGAL2 +{ + Text = "Long Bond" ; +}; +String RID_SVXSTR_PAPER_MONARCH +{ + Text = "#8 (Monarch) Envelope" ; +}; +String RID_SVXSTR_PAPER_COM675 +{ + Text = "#6 3/4 (Personal) Envelope" ; +}; +String RID_SVXSTR_PAPER_COM9 +{ + Text = "#9 Envelope" ; +}; +String RID_SVXSTR_PAPER_COM10 +{ + Text = "#10 Envelope" ; +}; +String RID_SVXSTR_PAPER_COM11 +{ + Text = "#11 Envelope" ; +}; +String RID_SVXSTR_PAPER_COM12 +{ + Text = "#12 Envelope" ; +}; +String RID_SVXSTR_PAPER_KAI16 +{ + Text = "16 Kai" ; +}; +String RID_SVXSTR_PAPER_KAI32 +{ + Text = "32 Kai" ; +}; +String RID_SVXSTR_PAPER_KAI32BIG +{ + Text = "Big 32 Kai" ; +}; +String RID_SVXSTR_PAPER_B4_JIS +{ + Text = "B4 (JIS)" ; +}; +String RID_SVXSTR_PAPER_B5_JIS +{ + Text = "B5 (JIS)" ; +}; +String RID_SVXSTR_PAPER_B6_JIS +{ + Text = "B6 (JIS)" ; +}; +String RID_SVXSTR_PAPERBIN +{ + Text [ en-US ] = "Paper tray" ; +}; +String RID_SVXSTR_PAPERBIN_SETTINGS +{ + Text [ en-US ] = "[From printer settings]" ; +}; + // ********************************************************************** EOF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/editeng/source/items/paperinf.cxx b/editeng/source/items/paperinf.cxx new file mode 100644 index 000000000000..55ed7a030f84 --- /dev/null +++ b/editeng/source/items/paperinf.cxx @@ -0,0 +1,188 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: paperinf.cxx,v $ + * $Revision: 1.12 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +// include --------------------------------------------------------------- + +#include <limits.h> +#include <tools/shl.hxx> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <editeng/editrids.hrc> +#include <editeng/paperinf.hxx> +#include <editeng/eerdll.hxx> + +/*-------------------------------------------------------------------- + Beschreibung: Ist der Printer gueltig + --------------------------------------------------------------------*/ + +inline BOOL IsValidPrinter( const Printer* pPtr ) +{ + return pPtr->GetName().Len() ? TRUE : FALSE; +} + +//------------------------------------------------------------------------ + +Size SvxPaperInfo::GetPaperSize( Paper ePaper, MapUnit eUnit ) +{ + PaperInfo aInfo(ePaper); + Size aRet(aInfo.getWidth(), aInfo.getHeight()); // in 100thMM + return eUnit == MAP_100TH_MM ? aRet : OutputDevice::LogicToLogic(aRet, MAP_100TH_MM, eUnit); +} + +/*------------------------------------------------------------------------ + Beschreibung: Papiergroesse der Druckers liefern, aligned auf + die eigenen Groessen. + Falls kein Printer im System eingestellt ist, + wird DIN A4 Portrait als Defaultpapiergroesse geliefert. +------------------------------------------------------------------------*/ + +//Is this method may be confused about the units it returns ? +//Always returns TWIPS for known paper sizes or on failure. +//But in the case of PAPER_USER paper and with a Printer with a mapmode set +//will return in those printer units ? +Size SvxPaperInfo::GetPaperSize( const Printer* pPrinter ) +{ + if ( !IsValidPrinter(pPrinter) ) + return GetPaperSize( PAPER_A4 ); + const Paper ePaper = pPrinter->GetPaper(); + + if ( ePaper == PAPER_USER ) + { + // Orientation nicht beruecksichtigen, da durch SV bereits + // die richtigen Masze eingestellt worden sind. + Size aPaperSize = pPrinter->GetPaperSize(); + const Size aInvalidSize; + + if ( aPaperSize == aInvalidSize ) + return GetPaperSize(PAPER_A4); + MapMode aMap1 = pPrinter->GetMapMode(); + MapMode aMap2; + + if ( aMap1 == aMap2 ) + aPaperSize = + pPrinter->PixelToLogic( aPaperSize, MapMode( MAP_TWIP ) ); + return aPaperSize; + } + + const Orientation eOrient = pPrinter->GetOrientation(); + Size aSize( GetPaperSize( ePaper ) ); + // bei Landscape die Seiten tauschen, ist bei SV schon geschehen + if ( eOrient == ORIENTATION_LANDSCAPE ) + Swap( aSize ); + return aSize; +} + +// ----------------------------------------------------------------------- + +Paper SvxPaperInfo::GetSvxPaper( const Size &rSize, MapUnit eUnit, bool bSloppy ) +{ + Size aSize(eUnit == MAP_100TH_MM ? rSize : OutputDevice::LogicToLogic(rSize, eUnit, MAP_100TH_MM)); + PaperInfo aInfo(aSize.Width(), aSize.Height()); + if (bSloppy) + aInfo.doSloppyFit(); + return aInfo.getPaper(); +} + +// ----------------------------------------------------------------------- + +long SvxPaperInfo::GetSloppyPaperDimension( long nSize, MapUnit eUnit ) +{ + nSize = eUnit == MAP_100TH_MM ? nSize : OutputDevice::LogicToLogic(nSize, eUnit, MAP_100TH_MM); + nSize = PaperInfo::sloppyFitPageDimension(nSize); + return eUnit == MAP_100TH_MM ? nSize : OutputDevice::LogicToLogic(nSize, MAP_100TH_MM, eUnit); +} + +// ----------------------------------------------------------------------- + +Size SvxPaperInfo::GetDefaultPaperSize( MapUnit eUnit ) +{ + PaperInfo aInfo(PaperInfo::getSystemDefaultPaper()); + Size aRet(aInfo.getWidth(), aInfo.getHeight()); + return eUnit == MAP_100TH_MM ? aRet : OutputDevice::LogicToLogic(aRet, MAP_100TH_MM, eUnit); +} + +/*------------------------------------------------------------------------ + Beschreibung: String Repr"asentation f"ur die SV-Defines f"ur + Papiergroessen. +------------------------------------------------------------------------*/ + +String SvxPaperInfo::GetName( Paper ePaper ) +{ + USHORT nResId = 0; + + switch ( ePaper ) + { + case PAPER_A0: nResId = RID_SVXSTR_PAPER_A0; break; + case PAPER_A1: nResId = RID_SVXSTR_PAPER_A1; break; + case PAPER_A2: nResId = RID_SVXSTR_PAPER_A2; break; + case PAPER_A3: nResId = RID_SVXSTR_PAPER_A3; break; + case PAPER_A4: nResId = RID_SVXSTR_PAPER_A4; break; + case PAPER_A5: nResId = RID_SVXSTR_PAPER_A5; break; + case PAPER_B4_ISO: nResId = RID_SVXSTR_PAPER_B4_ISO; break; + case PAPER_B5_ISO: nResId = RID_SVXSTR_PAPER_B5_ISO; break; + case PAPER_LETTER: nResId = RID_SVXSTR_PAPER_LETTER; break; + case PAPER_LEGAL: nResId = RID_SVXSTR_PAPER_LEGAL; break; + case PAPER_TABLOID: nResId = RID_SVXSTR_PAPER_TABLOID; break; + case PAPER_USER: nResId = RID_SVXSTR_PAPER_USER; break; + case PAPER_B6_ISO: nResId = RID_SVXSTR_PAPER_B6_ISO; break; + case PAPER_ENV_C4: nResId = RID_SVXSTR_PAPER_C4; break; + case PAPER_ENV_C5: nResId = RID_SVXSTR_PAPER_C5; break; + case PAPER_ENV_C6: nResId = RID_SVXSTR_PAPER_C6; break; + case PAPER_ENV_C65: nResId = RID_SVXSTR_PAPER_C65; break; + case PAPER_ENV_DL: nResId = RID_SVXSTR_PAPER_DL; break; + case PAPER_SLIDE_DIA: nResId = RID_SVXSTR_PAPER_DIA; break; + case PAPER_SCREEN: nResId = RID_SVXSTR_PAPER_SCREEN; break; + case PAPER_C: nResId = RID_SVXSTR_PAPER_C; break; + case PAPER_D: nResId = RID_SVXSTR_PAPER_D; break; + case PAPER_E: nResId = RID_SVXSTR_PAPER_E; break; + case PAPER_EXECUTIVE: nResId = RID_SVXSTR_PAPER_EXECUTIVE;break; + case PAPER_FANFOLD_LEGAL_DE: nResId = RID_SVXSTR_PAPER_LEGAL2; break; + case PAPER_ENV_MONARCH: nResId = RID_SVXSTR_PAPER_MONARCH; break; + case PAPER_ENV_PERSONAL: nResId = RID_SVXSTR_PAPER_COM675; break; + case PAPER_ENV_9: nResId = RID_SVXSTR_PAPER_COM9; break; + case PAPER_ENV_10: nResId = RID_SVXSTR_PAPER_COM10; break; + case PAPER_ENV_11: nResId = RID_SVXSTR_PAPER_COM11; break; + case PAPER_ENV_12: nResId = RID_SVXSTR_PAPER_COM12; break; + case PAPER_KAI16: nResId = RID_SVXSTR_PAPER_KAI16; break; + case PAPER_KAI32: nResId = RID_SVXSTR_PAPER_KAI32; break; + case PAPER_KAI32BIG: nResId = RID_SVXSTR_PAPER_KAI32BIG; break; + case PAPER_B4_JIS: nResId = RID_SVXSTR_PAPER_B4_JIS; break; + case PAPER_B5_JIS: nResId = RID_SVXSTR_PAPER_B5_JIS; break; + case PAPER_B6_JIS: nResId = RID_SVXSTR_PAPER_B6_JIS; break; + default: DBG_ERRORFILE( "unknown papersize" ); + } + + return ( nResId > 0 ) ? String( EditResId( nResId ) ) : String(); +} + + diff --git a/editeng/source/items/paraitem.cxx b/editeng/source/items/paraitem.cxx new file mode 100644 index 000000000000..8cb43c6c65ad --- /dev/null +++ b/editeng/source/items/paraitem.cxx @@ -0,0 +1,1760 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: paraitem.cxx,v $ + * $Revision: 1.40 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +// include --------------------------------------------------------------- +#include <com/sun/star/style/TabStop.hpp> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/style/LineSpacingMode.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/syslocale.hxx> +#include <comphelper/types.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star; + +#include <tools/rtti.hxx> +#define GLOBALOVERFLOW3 + +#define _SVX_PARAITEM_CXX +#include <svl/itempool.hxx> + +#include <svl/memberid.hrc> +#include <editeng/editrids.hrc> + +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/orphitem.hxx> +#include <editeng/widwitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/pmdlitem.hxx> +#include <editeng/spltitem.hxx> +#include <editeng/hyznitem.hxx> +#include <editeng/scriptspaceitem.hxx> +#include <editeng/hngpnctitem.hxx> +#include <editeng/forbiddenruleitem.hxx> +#include <editeng/paravertalignitem.hxx> +#include <editeng/pgrditem.hxx> +#include <rtl/ustring.hxx> +#include <editeng/memberids.hrc> +#include <editeng/editids.hrc> +#include <editeng/itemtype.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/paperinf.hxx> +#include <vcl/svapp.hxx> +#include <algorithm> + +using namespace ::rtl; +using namespace ::com::sun::star; + +// Konvertierung fuer UNO +#define TWIP_TO_MM100(TWIP) ((TWIP) >= 0 ? (((TWIP)*127L+36L)/72L) : (((TWIP)*127L-36L)/72L)) +#define TWIP_TO_MM100_UNSIGNED(TWIP) ((((TWIP)*127L+36L)/72L)) +#define MM100_TO_TWIP(MM100) ((MM100) >= 0 ? (((MM100)*72L+63L)/127L) : (((MM100)*72L-63L)/127L)) +#define MM100_TO_TWIP_UNSIGNED(MM100) ((((MM100)*72L+63L)/127L)) + + +// STATIC DATA ----------------------------------------------------------- + + +// ----------------------------------------------------------------------- + + +TYPEINIT1_FACTORY(SvxLineSpacingItem, SfxPoolItem , new SvxLineSpacingItem(LINE_SPACE_DEFAULT_HEIGHT, 0)); +TYPEINIT1_FACTORY(SvxAdjustItem, SfxPoolItem, new SvxAdjustItem(SVX_ADJUST_LEFT, 0)); +TYPEINIT1_FACTORY(SvxWidowsItem, SfxByteItem, new SvxWidowsItem(0, 0)); +TYPEINIT1_FACTORY(SvxOrphansItem, SfxByteItem, new SvxOrphansItem(0, 0)); +TYPEINIT1_FACTORY(SvxHyphenZoneItem, SfxPoolItem, new SvxHyphenZoneItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxTabStopItem, SfxPoolItem, new SvxTabStopItem(0)); +TYPEINIT1_FACTORY(SvxFmtSplitItem, SfxBoolItem, new SvxFmtSplitItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxPageModelItem, SfxStringItem, new SvxPageModelItem(0)); +TYPEINIT1_FACTORY(SvxScriptSpaceItem, SfxBoolItem, new SvxScriptSpaceItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxHangingPunctuationItem, SfxBoolItem, new SvxHangingPunctuationItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxForbiddenRuleItem, SfxBoolItem, new SvxForbiddenRuleItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxParaVertAlignItem, SfxUInt16Item, new SvxParaVertAlignItem(0, 0)); +TYPEINIT1_FACTORY(SvxParaGridItem, SfxBoolItem, new SvxParaGridItem(sal_True, 0)); + +SV_IMPL_VARARR_SORT( SvxTabStopArr, SvxTabStop ) + +// ----------------------------------------------------------------------- + +SvxLineSpacingItem::SvxLineSpacingItem( sal_uInt16 nHeight, const sal_uInt16 nId ) + : SfxEnumItemInterface( nId ) +{ + nPropLineSpace = 100; + nInterLineSpace = 0; + nLineHeight = nHeight; + eLineSpace = SVX_LINE_SPACE_AUTO; + eInterLineSpace = SVX_INTER_LINE_SPACE_OFF; +} + +// ----------------------------------------------------------------------- + +int SvxLineSpacingItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + const SvxLineSpacingItem& rLineSpace = (const SvxLineSpacingItem&)rAttr; + return ( + // Gleiche Linespacing Rule? + (eLineSpace == rLineSpace.eLineSpace) + // Bei maximalem und minimalem Linespacing muss das Mass + // uebereinstimmen. + && (eLineSpace == SVX_LINE_SPACE_AUTO || + nLineHeight == rLineSpace.nLineHeight) + // Gleiche Interlinespacing Rule? + && ( eInterLineSpace == rLineSpace.eInterLineSpace ) + // Entweder proportional oder draufaddieren eingestellt. + && (( eInterLineSpace == SVX_INTER_LINE_SPACE_OFF) + || (eInterLineSpace == SVX_INTER_LINE_SPACE_PROP + && nPropLineSpace == rLineSpace.nPropLineSpace) + || (eInterLineSpace == SVX_INTER_LINE_SPACE_FIX + && (nInterLineSpace == rLineSpace.nInterLineSpace)))) ? + 1 : 0; +} + +/*-----------------18.03.98 16:32------------------- + os: wer weiss noch, wieso das LineSpacingItem so + kompliziert ist? Fuer UNO koennen wir das nicht + gebrauchen. Da gibt es nur zwei Werte: + - ein sal_uInt16 fuer den Modus + - ein sal_uInt32 fuer alle Werte (Abstand, Hoehe, rel. Angaben) + +--------------------------------------------------*/ +sal_Bool SvxLineSpacingItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + + style::LineSpacing aLSp; + switch( eLineSpace ) + { + case SVX_LINE_SPACE_AUTO: + if(eInterLineSpace == SVX_INTER_LINE_SPACE_FIX) + { + aLSp.Mode = style::LineSpacingMode::LEADING; + aLSp.Height = ( bConvert ? (short)TWIP_TO_MM100(nInterLineSpace) : nInterLineSpace); + } + else if(eInterLineSpace == SVX_INTER_LINE_SPACE_OFF) + { + aLSp.Mode = style::LineSpacingMode::PROP; + aLSp.Height = 100; + } + else + { + aLSp.Mode = style::LineSpacingMode::PROP; + aLSp.Height = nPropLineSpace; + } + break; + case SVX_LINE_SPACE_FIX : + case SVX_LINE_SPACE_MIN : + aLSp.Mode = eLineSpace == SVX_LINE_SPACE_FIX ? style::LineSpacingMode::FIX : style::LineSpacingMode::MINIMUM; + aLSp.Height = ( bConvert ? (short)TWIP_TO_MM100_UNSIGNED(nLineHeight) : nLineHeight ); + break; + default: + ;//prevent warning about SVX_LINE_SPACE_END + } + + switch ( nMemberId ) + { + case 0 : rVal <<= aLSp; break; + case MID_LINESPACE : rVal <<= aLSp.Mode; break; + case MID_HEIGHT : rVal <<= aLSp.Height; break; + default: DBG_ERROR("Wrong MemberId!"); break; + } + + return sal_True; +} +/*-----------------18.03.98 16:32------------------- + +--------------------------------------------------*/ +sal_Bool SvxLineSpacingItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + + // fill with current data + style::LineSpacing aLSp; + uno::Any aAny; + sal_Bool bRet = QueryValue( aAny, bConvert ? CONVERT_TWIPS : 0 ) && ( aAny >>= aLSp ); + + // get new data + switch ( nMemberId ) + { + case 0 : bRet = (rVal >>= aLSp); break; + case MID_LINESPACE : bRet = (rVal >>= aLSp.Mode); break; + case MID_HEIGHT : bRet = (rVal >>= aLSp.Height); break; + default: DBG_ERROR("Wrong MemberId!"); break; + } + + if( bRet ) + { + nLineHeight = aLSp.Height; + switch( aLSp.Mode ) + { + case style::LineSpacingMode::LEADING: + { + eInterLineSpace = SVX_INTER_LINE_SPACE_FIX; + eLineSpace = SVX_LINE_SPACE_AUTO; + nInterLineSpace = aLSp.Height; + if(bConvert) + nInterLineSpace = (short)MM100_TO_TWIP(nInterLineSpace); + + } + break; + case style::LineSpacingMode::PROP: + { + eLineSpace = SVX_LINE_SPACE_AUTO; + nPropLineSpace = (sal_Int8)std::min(aLSp.Height, (short)0xFF); + if(100 == aLSp.Height) + eInterLineSpace = SVX_INTER_LINE_SPACE_OFF; + else + eInterLineSpace = SVX_INTER_LINE_SPACE_PROP; + } + break; + case style::LineSpacingMode::FIX: + case style::LineSpacingMode::MINIMUM: + { + eInterLineSpace = SVX_INTER_LINE_SPACE_OFF; + eLineSpace = aLSp.Mode == style::LineSpacingMode::FIX ? SVX_LINE_SPACE_FIX : SVX_LINE_SPACE_MIN; + nLineHeight = aLSp.Height; + if(bConvert) + nLineHeight = (USHORT)MM100_TO_TWIP_UNSIGNED(nLineHeight); + } + break; + } + } + + return bRet; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxLineSpacingItem::Clone( SfxItemPool * ) const +{ + return new SvxLineSpacingItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxLineSpacingItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ +#ifdef DBG_UTIL + rText.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "SvxLineSpacingItem" )); +#else + rText.Erase(); +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxLineSpacingItem::Create(SvStream& rStrm, sal_uInt16) const +{ + sal_Int8 nPropSpace; + short nInterSpace; + sal_uInt16 nHeight; + sal_Int8 nRule, nInterRule; + + rStrm >> nPropSpace + >> nInterSpace + >> nHeight + >> nRule + >> nInterRule; + + SvxLineSpacingItem* pAttr = new SvxLineSpacingItem( nHeight, Which() ); + pAttr->SetInterLineSpace( nInterSpace ); + pAttr->SetPropLineSpace( nPropSpace ); + pAttr->GetLineSpaceRule() = (SvxLineSpace)nRule; + pAttr->GetInterLineSpaceRule() = (SvxInterLineSpace)nInterRule; + return pAttr; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxLineSpacingItem::Store( SvStream& rStrm, sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8) GetPropLineSpace() + << (short) GetInterLineSpace() + << (sal_uInt16) GetLineHeight() + << (sal_Int8) GetLineSpaceRule() + << (sal_Int8) GetInterLineSpaceRule(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxLineSpacingItem::GetValueCount() const +{ + return SVX_LINESPACE_END; // SVX_LINESPACE_TWO_LINES + 1 +} + +// ----------------------------------------------------------------------- + +XubString SvxLineSpacingItem::GetValueTextByPos( sal_uInt16 nPos ) const +{ + //! Strings demnaechst aus Resource laden + XubString aText; + switch ( nPos ) + { + case SVX_LINESPACE_USER : aText.AppendAscii( "Benutzer" ); break; + case SVX_LINESPACE_ONE_LINE : aText.AppendAscii( "Einzeilig" ); break; + case SVX_LINESPACE_ONE_POINT_FIVE_LINES : aText.AppendAscii( "1,5zeilig" ); break; + case SVX_LINESPACE_TWO_LINES : aText.AppendAscii( "Zweizeilig" ); break; + } + return aText; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxLineSpacingItem::GetEnumValue() const +{ + sal_uInt16 nVal; + switch ( nPropLineSpace ) + { + case 100: nVal = SVX_LINESPACE_ONE_LINE; break; + case 150: nVal = SVX_LINESPACE_ONE_POINT_FIVE_LINES; break; + case 200: nVal = SVX_LINESPACE_TWO_LINES; break; + default: nVal = SVX_LINESPACE_USER; break; + } + return nVal; +} + +// ----------------------------------------------------------------------- + +void SvxLineSpacingItem::SetEnumValue( sal_uInt16 nVal ) +{ + switch ( nVal ) + { + case SVX_LINESPACE_ONE_LINE: nPropLineSpace = 100; break; + case SVX_LINESPACE_ONE_POINT_FIVE_LINES: nPropLineSpace = 150; break; + case SVX_LINESPACE_TWO_LINES: nPropLineSpace = 200; break; + } +} + +// class SvxAdjustItem --------------------------------------------------- + +SvxAdjustItem::SvxAdjustItem(const SvxAdjust eAdjst, const sal_uInt16 nId ) + : SfxEnumItemInterface( nId ), + bOneBlock( sal_False ), bLastCenter( sal_False ), bLastBlock( sal_False ) +{ + SetAdjust( eAdjst ); +} + +// ----------------------------------------------------------------------- + +int SvxAdjustItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return( ( GetAdjust() == ((SvxAdjustItem&)rAttr).GetAdjust() && + bOneBlock == ((SvxAdjustItem&)rAttr).bOneBlock && + bLastCenter == ((SvxAdjustItem&)rAttr).bLastCenter && + bLastBlock == ((SvxAdjustItem&)rAttr).bLastBlock ) + ? 1 : 0 ); +} + +/*-----------------18.03.98 16:15------------------- + +--------------------------------------------------*/ +sal_Bool SvxAdjustItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case MID_PARA_ADJUST : rVal <<= (sal_Int16)GetAdjust(); break; + case MID_LAST_LINE_ADJUST : rVal <<= (sal_Int16)GetLastBlock(); break; + case MID_EXPAND_SINGLE : + { + sal_Bool bValue = bOneBlock; + rVal.setValue( &bValue, ::getCppuBooleanType() ); + break; + } + default: ;//prevent warning + } + return sal_True; +} +/*-----------------18.03.98 16:15------------------- + +--------------------------------------------------*/ + +sal_Bool SvxAdjustItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case MID_PARA_ADJUST : + case MID_LAST_LINE_ADJUST : + { + sal_Int32 eVal = - 1; + try + { + eVal = ::comphelper::getEnumAsINT32(rVal); + } + catch(...) {} + if(eVal >= 0 && eVal <= 4) + { + if(MID_LAST_LINE_ADJUST == nMemberId && + eVal != SVX_ADJUST_LEFT && + eVal != SVX_ADJUST_BLOCK && + eVal != SVX_ADJUST_CENTER) + return FALSE; + if(eVal < (sal_uInt16)SVX_ADJUST_END) + nMemberId == MID_PARA_ADJUST ? + SetAdjust((SvxAdjust)eVal) : + SetLastBlock((SvxAdjust)eVal); + } + } + break; + case MID_EXPAND_SINGLE : + bOneBlock = Any2Bool(rVal); + break; + } + return sal_True; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxAdjustItem::Clone( SfxItemPool * ) const +{ + return new SvxAdjustItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxAdjustItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetValueTextByPos( (sal_uInt16)GetAdjust() ); + return ePres; + default: ;//prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxAdjustItem::GetValueCount() const +{ + return SVX_ADJUST_END; // SVX_ADJUST_BLOCKLINE + 1 +} + +// ----------------------------------------------------------------------- + +XubString SvxAdjustItem::GetValueTextByPos( sal_uInt16 nPos ) const +{ + DBG_ASSERT( nPos <= (sal_uInt16)SVX_ADJUST_BLOCKLINE, "enum overflow!" ); + return EE_RESSTR(RID_SVXITEMS_ADJUST_BEGIN + nPos); +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxAdjustItem::GetEnumValue() const +{ + return (sal_uInt16)GetAdjust(); +} + +// ----------------------------------------------------------------------- + +void SvxAdjustItem::SetEnumValue( sal_uInt16 nVal ) +{ + SetAdjust( (const SvxAdjust)nVal ); +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxAdjustItem::GetVersion( sal_uInt16 nFileVersion ) const +{ + return (nFileVersion == SOFFICE_FILEFORMAT_31) + ? 0 : ADJUST_LASTBLOCK_VERSION; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxAdjustItem::Create(SvStream& rStrm, sal_uInt16 nVersion) const +{ + char eAdjustment; + rStrm >> eAdjustment; + SvxAdjustItem *pRet = new SvxAdjustItem( (SvxAdjust)eAdjustment, Which() ); + if( nVersion >= ADJUST_LASTBLOCK_VERSION ) + { + sal_Int8 nFlags; + rStrm >> nFlags; + pRet->bOneBlock = 0 != (nFlags & 0x0001); + pRet->bLastCenter = 0 != (nFlags & 0x0002); + pRet->bLastBlock = 0 != (nFlags & 0x0004); + } + return pRet; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxAdjustItem::Store( SvStream& rStrm, sal_uInt16 nItemVersion ) const +{ + rStrm << (char)GetAdjust(); + if ( nItemVersion >= ADJUST_LASTBLOCK_VERSION ) + { + sal_Int8 nFlags = 0; + if ( bOneBlock ) + nFlags |= 0x0001; + if ( bLastCenter ) + nFlags |= 0x0002; + if ( bLastBlock ) + nFlags |= 0x0004; + rStrm << (sal_Int8) nFlags; + } + return rStrm; +} + +// class SvxWidowsItem --------------------------------------------------- + +SvxWidowsItem::SvxWidowsItem(const BYTE nL, const USHORT nId ) : + SfxByteItem( nId, nL ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxWidowsItem::Clone( SfxItemPool * ) const +{ + return new SvxWidowsItem( *this ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxWidowsItem::Create(SvStream& rStrm, sal_uInt16) const +{ + sal_Int8 nLines; + rStrm >> nLines; + return new SvxWidowsItem( nLines, Which() ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxWidowsItem::Store( SvStream& rStrm, sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8)GetValue(); + return rStrm; +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxWidowsItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + { + rText.Erase(); + break; + } + + case SFX_ITEM_PRESENTATION_NAMELESS: + { + rText = EE_RESSTR(RID_SVXITEMS_LINES); + break; + } + + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR(RID_SVXITEMS_WIDOWS_COMPLETE); + rText += ' '; + rText += EE_RESSTR(RID_SVXITEMS_LINES); + } + + default: + { + DBG_ERRORFILE( "SvxWidowsItem::GetPresentation(): unknown SfxItemPresentation" ); + } + } + + rText.SearchAndReplace( String::CreateFromAscii( "%1" ), String::CreateFromInt32( GetValue() ) ); + return ePres; +} + +// class SvxOrphansItem -------------------------------------------------- + +SvxOrphansItem::SvxOrphansItem(const BYTE nL, const USHORT nId ) : + SfxByteItem( nId, nL ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxOrphansItem::Clone( SfxItemPool * ) const +{ + return new SvxOrphansItem( *this ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxOrphansItem::Create(SvStream& rStrm, sal_uInt16) const +{ + sal_Int8 nLines; + rStrm >> nLines; + return new SvxOrphansItem( nLines, Which() ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxOrphansItem::Store( SvStream& rStrm, sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8) GetValue(); + return rStrm; +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxOrphansItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + { + rText.Erase(); + break; + } + + case SFX_ITEM_PRESENTATION_NAMELESS: + { + rText = EE_RESSTR(RID_SVXITEMS_LINES); + break; + } + + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR(RID_SVXITEMS_ORPHANS_COMPLETE); + rText += ' '; + rText += EE_RESSTR(RID_SVXITEMS_LINES); + } + + default: + { + DBG_ERRORFILE( "SvxOrphansItem::GetPresentation(): unknown SfxItemPresentation" ); + } + } + + rText.SearchAndReplace( String::CreateFromAscii( "%1" ), String::CreateFromInt32( GetValue() ) ); + return ePres; +} + +// class SvxHyphenZoneItem ----------------------------------------------- + +SvxHyphenZoneItem::SvxHyphenZoneItem( const sal_Bool bHyph, const sal_uInt16 nId ) : + SfxPoolItem( nId ) +{ + bHyphen = bHyph; + bPageEnd = sal_True; + nMinLead = nMinTrail = 0; + nMaxHyphens = 255; +} + +// ----------------------------------------------------------------------- +sal_Bool SvxHyphenZoneItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_IS_HYPHEN: + rVal = Bool2Any(bHyphen); + break; + case MID_HYPHEN_MIN_LEAD: + rVal <<= (sal_Int16)nMinLead; + break; + case MID_HYPHEN_MIN_TRAIL: + rVal <<= (sal_Int16)nMinTrail; + break; + case MID_HYPHEN_MAX_HYPHENS: + rVal <<= (sal_Int16)nMaxHyphens; + break; + } + return sal_True; +} +// ----------------------------------------------------------------------- +sal_Bool SvxHyphenZoneItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Int16 nNewVal = 0; + + if( nMemberId != MID_IS_HYPHEN ) + if(!(rVal >>= nNewVal)) + return sal_False; + + switch(nMemberId) + { + case MID_IS_HYPHEN: + bHyphen = Any2Bool(rVal); + break; + case MID_HYPHEN_MIN_LEAD: + nMinLead = (BYTE)nNewVal; + break; + case MID_HYPHEN_MIN_TRAIL: + nMinTrail = (BYTE)nNewVal; + break; + case MID_HYPHEN_MAX_HYPHENS: + nMaxHyphens = (BYTE)nNewVal; + break; + } + return sal_True; +} + +// ----------------------------------------------------------------------- + +int SvxHyphenZoneItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return ( (((SvxHyphenZoneItem&)rAttr).bHyphen == bHyphen) + && (((SvxHyphenZoneItem&)rAttr).bPageEnd == bPageEnd) + && (((SvxHyphenZoneItem&)rAttr).nMinLead == nMinLead) + && (((SvxHyphenZoneItem&)rAttr).nMinTrail == nMinTrail) + && (((SvxHyphenZoneItem&)rAttr).nMaxHyphens == nMaxHyphens) ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxHyphenZoneItem::Clone( SfxItemPool * ) const +{ + return new SvxHyphenZoneItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxHyphenZoneItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + case SFX_ITEM_PRESENTATION_NAMELESS: + { + sal_uInt16 nId = RID_SVXITEMS_HYPHEN_FALSE; + + if ( bHyphen ) + nId = RID_SVXITEMS_HYPHEN_TRUE; + rText = EE_RESSTR(nId); + rText += cpDelim; + nId = RID_SVXITEMS_PAGE_END_FALSE; + + if ( bPageEnd ) + nId = RID_SVXITEMS_PAGE_END_TRUE; + rText += EE_RESSTR(nId); + rText += cpDelim; + rText += String::CreateFromInt32( nMinLead ); + rText += cpDelim; + rText += String::CreateFromInt32( nMinTrail ); + rText += cpDelim; + rText += String::CreateFromInt32( nMaxHyphens ); + return SFX_ITEM_PRESENTATION_COMPLETE; + } + case SFX_ITEM_PRESENTATION_COMPLETE: + { + sal_uInt16 nId = RID_SVXITEMS_HYPHEN_FALSE; + + if ( bHyphen ) + nId = RID_SVXITEMS_HYPHEN_TRUE; + rText = EE_RESSTR(nId); + rText += cpDelim; + nId = RID_SVXITEMS_PAGE_END_FALSE; + + if ( bPageEnd ) + nId = RID_SVXITEMS_PAGE_END_TRUE; + rText += EE_RESSTR(nId); + rText += cpDelim; + rText += String::CreateFromInt32(nMinLead); + rText += EE_RESSTR(RID_SVXITEMS_HYPHEN_MINLEAD); + rText += cpDelim; + rText += String::CreateFromInt32(nMinTrail); + rText += EE_RESSTR(RID_SVXITEMS_HYPHEN_MINTRAIL); + rText += cpDelim; + rText += String::CreateFromInt32(nMaxHyphens); + rText += EE_RESSTR(RID_SVXITEMS_HYPHEN_MAX); + return SFX_ITEM_PRESENTATION_COMPLETE; + } + default: ;//prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxHyphenZoneItem::Create(SvStream& rStrm, sal_uInt16) const +{ + sal_Int8 _bHyphen, _bHyphenPageEnd; + sal_Int8 _nMinLead, _nMinTrail, _nMaxHyphens; + rStrm >> _bHyphen >> _bHyphenPageEnd >> _nMinLead >> _nMinTrail >> _nMaxHyphens; + SvxHyphenZoneItem* pAttr = new SvxHyphenZoneItem( sal_False, Which() ); + pAttr->SetHyphen( sal_Bool( _bHyphen != 0 ) ); + pAttr->SetPageEnd( sal_Bool( _bHyphenPageEnd != 0 ) ); + pAttr->GetMinLead() = _nMinLead; + pAttr->GetMinTrail() = _nMinTrail; + pAttr->GetMaxHyphens() = _nMaxHyphens; + return pAttr; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxHyphenZoneItem::Store( SvStream& rStrm, sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8) IsHyphen() + << (sal_Int8) IsPageEnd() + << (sal_Int8) GetMinLead() + << (sal_Int8) GetMinTrail() + << (sal_Int8) GetMaxHyphens(); + return rStrm; +} + +// class SvxTabStop ------------------------------------------------------ + +SvxTabStop::SvxTabStop() +{ + nTabPos = 0; + eAdjustment = SVX_TAB_ADJUST_LEFT; + m_cDecimal = cDfltDecimalChar; + cFill = cDfltFillChar; +} + +// ----------------------------------------------------------------------- + +SvxTabStop::SvxTabStop( const long nPos, const SvxTabAdjust eAdjst, + const sal_Unicode cDec, const sal_Unicode cFil ) +{ + nTabPos = nPos; + eAdjustment = eAdjst; + m_cDecimal = cDec; + cFill = cFil; +} +// ----------------------------------------------------------------------------- +void SvxTabStop::fillDecimal() const +{ + if ( cDfltDecimalChar == m_cDecimal ) + m_cDecimal = SvtSysLocale().GetLocaleData().getNumDecimalSep().GetChar(0); +} +// ----------------------------------------------------------------------- + +XubString SvxTabStop::GetValueString() const +{ + XubString aStr; + + aStr += sal_Unicode( '(' ); + aStr += UniString::CreateFromInt32(nTabPos); + aStr += cpDelim; + aStr += XubString( EditResId( RID_SVXITEMS_TAB_ADJUST_BEGIN + (sal_uInt16)eAdjustment ) ); + + aStr += cpDelim; + aStr += sal_Unicode('['); + aStr += XubString( EditResId( RID_SVXITEMS_TAB_DECIMAL_CHAR ) ); + aStr += GetDecimal(); + aStr += sal_Unicode(']'); + aStr += cpDelim; + aStr += cpDelim; + aStr += sal_Unicode('['); + aStr += XubString( EditResId( RID_SVXITEMS_TAB_FILL_CHAR ) ); + aStr += cFill; + aStr += sal_Unicode(']'); + aStr += sal_Unicode(')'); + + return aStr; +} + +// class SvxTabStopItem -------------------------------------------------- + +SvxTabStopItem::SvxTabStopItem( sal_uInt16 _nWhich ) : + SfxPoolItem( _nWhich ), + SvxTabStopArr( sal_Int8(SVX_TAB_DEFCOUNT) ) +{ + const sal_uInt16 nTabs = SVX_TAB_DEFCOUNT, nDist = SVX_TAB_DEFDIST; + const SvxTabAdjust eAdjst= SVX_TAB_ADJUST_DEFAULT; + + for (sal_uInt16 i = 0; i < nTabs; ++i) + { + SvxTabStop aTab( (i + 1) * nDist, eAdjst ); + SvxTabStopArr::Insert( aTab ); + } +} + +// ----------------------------------------------------------------------- + +SvxTabStopItem::SvxTabStopItem( const sal_uInt16 nTabs, + const sal_uInt16 nDist, + const SvxTabAdjust eAdjst, + sal_uInt16 _nWhich ) : + SfxPoolItem( _nWhich ), + SvxTabStopArr( sal_Int8(nTabs) ) +{ + for ( sal_uInt16 i = 0; i < nTabs; ++i ) + { + SvxTabStop aTab( (i + 1) * nDist, eAdjst ); + SvxTabStopArr::Insert( aTab ); + } +} + +// ----------------------------------------------------------------------- + +SvxTabStopItem::SvxTabStopItem( const SvxTabStopItem& rTSI ) : + SfxPoolItem( rTSI.Which() ), + SvxTabStopArr( (sal_Int8)rTSI.Count() ) +{ + SvxTabStopArr::Insert( &rTSI ); +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxTabStopItem::GetPos( const SvxTabStop& rTab ) const +{ + sal_uInt16 nFound; + return Seek_Entry( rTab, &nFound ) ? nFound : SVX_TAB_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +sal_uInt16 SvxTabStopItem::GetPos( const long nPos ) const +{ + sal_uInt16 nFound; + return Seek_Entry( SvxTabStop( nPos ), &nFound ) ? nFound : SVX_TAB_NOTFOUND; +} + +// ----------------------------------------------------------------------- + +SvxTabStopItem& SvxTabStopItem::operator=( const SvxTabStopItem& rTSI ) +{ + Remove( 0, Count() ); + SvxTabStopArr::Insert( &rTSI ); + return *this; +} + + +/* + enum ::com::sun::star::style::TabAlign +{ + TABALIGN_LEFT, + TABALIGN_CENTER, + TABALIGN_RIGHT, + TABALIGN_DECIMAL +}; + +struct ::com::sun::star::style::TabStop +{ + long Position; + ::com::sun::star::style::TabAlign ::com::sun::star::drawing::Alignment; + unsigned short DecimalChar; + unsigned short FillChar; +}; +typedef sequence ::com::sun::star::style::TabStop> TabSTopSequence; + + */ +/*-----------------19.03.98 08:50------------------- + +--------------------------------------------------*/ + +sal_Bool SvxTabStopItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch ( nMemberId ) + { + case MID_TABSTOPS: + { + sal_uInt16 nCount = Count(); + uno::Sequence< style::TabStop> aSeq(nCount); + style::TabStop* pArr = aSeq.getArray(); + for(sal_uInt16 i = 0; i < nCount; i++) + { + const SvxTabStop& rTab = *(GetStart() + i); + pArr[i].Position = bConvert ? TWIP_TO_MM100(rTab.GetTabPos()) : rTab.GetTabPos(); + switch(rTab.GetAdjustment()) + { + case SVX_TAB_ADJUST_LEFT : pArr[i].Alignment = style::TabAlign_LEFT; break; + case SVX_TAB_ADJUST_RIGHT : pArr[i].Alignment = style::TabAlign_RIGHT; break; + case SVX_TAB_ADJUST_DECIMAL: pArr[i].Alignment = style::TabAlign_DECIMAL; break; + case SVX_TAB_ADJUST_CENTER : pArr[i].Alignment = style::TabAlign_CENTER; break; + default: //SVX_TAB_ADJUST_DEFAULT + pArr[i].Alignment = style::TabAlign_DEFAULT; + + } + pArr[i].DecimalChar = rTab.GetDecimal(); + pArr[i].FillChar = rTab.GetFill(); + } + rVal <<= aSeq; + break; + } + case MID_STD_TAB: + { + const SvxTabStop &rTab = *(GetStart()); + rVal <<= static_cast<sal_Int32>(bConvert ? TWIP_TO_MM100(rTab.GetTabPos()) : rTab.GetTabPos()); + break; + } + } + return sal_True; +} +/*-----------------19.03.98 08:50------------------- + +--------------------------------------------------*/ + +sal_Bool SvxTabStopItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch ( nMemberId ) + { + case MID_TABSTOPS: + { + uno::Sequence< style::TabStop> aSeq; + if(!(rVal >>= aSeq)) + { + uno::Sequence < uno::Sequence < uno::Any > > aAnySeq; + if (!(rVal >>= aAnySeq)) + return sal_False; + sal_Int32 nLength = aAnySeq.getLength(); + aSeq.realloc( nLength ); + for ( sal_Int32 n=0; n<nLength; n++ ) + { + uno::Sequence < uno::Any >& rAnySeq = aAnySeq[n]; + if ( rAnySeq.getLength() == 4 ) + { + if (!(rAnySeq[0] >>= aSeq[n].Position)) return sal_False; + if (!(rAnySeq[1] >>= aSeq[n].Alignment)) + { + sal_Int32 nVal = 0; + if (rAnySeq[1] >>= nVal) + aSeq[n].Alignment = (com::sun::star::style::TabAlign) nVal; + else + return sal_False; + } + if (!(rAnySeq[2] >>= aSeq[n].DecimalChar)) + { + ::rtl::OUString aVal; + if ( (rAnySeq[2] >>= aVal) && aVal.getLength() == 1 ) + aSeq[n].DecimalChar = aVal.toChar(); + else + return sal_False; + } + if (!(rAnySeq[3] >>= aSeq[n].FillChar)) + { + ::rtl::OUString aVal; + if ( (rAnySeq[3] >>= aVal) && aVal.getLength() == 1 ) + aSeq[n].FillChar = aVal.toChar(); + else + return sal_False; + } + } + else + return sal_False; + } + } + + SvxTabStopArr::Remove( 0, Count() ); + const style::TabStop* pArr = aSeq.getConstArray(); + const sal_uInt16 nCount = (sal_uInt16)aSeq.getLength(); + for(sal_uInt16 i = 0; i < nCount ; i++) + { + SvxTabAdjust eAdjust = SVX_TAB_ADJUST_DEFAULT; + switch(pArr[i].Alignment) + { + case style::TabAlign_LEFT : eAdjust = SVX_TAB_ADJUST_LEFT; break; + case style::TabAlign_CENTER : eAdjust = SVX_TAB_ADJUST_CENTER; break; + case style::TabAlign_RIGHT : eAdjust = SVX_TAB_ADJUST_RIGHT; break; + case style::TabAlign_DECIMAL: eAdjust = SVX_TAB_ADJUST_DECIMAL; break; + default: ;//prevent warning + } + sal_Unicode cFill = pArr[i].FillChar; + sal_Unicode cDecimal = pArr[i].DecimalChar; + SvxTabStop aTab( bConvert ? MM100_TO_TWIP(pArr[i].Position) : pArr[i].Position, + eAdjust, + cDecimal, + cFill ); + Insert(aTab); + } + break; + } + case MID_STD_TAB: + { + sal_Int32 nNewPos = 0; + if (!(rVal >>= nNewPos) ) + return sal_False; + const SvxTabStop& rTab = *(GetStart()); + SvxTabStop aNewTab ( bConvert ? MM100_TO_TWIP ( nNewPos ) : nNewPos, + rTab.GetAdjustment(), rTab.GetDecimal(), rTab.GetFill() ); + Remove ( 0 ); + Insert( aNewTab ); + break; + } + } + return sal_True; +} +// ----------------------------------------------------------------------- + +int SvxTabStopItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + const SvxTabStopItem& rTSI = (SvxTabStopItem&)rAttr; + + if ( Count() != rTSI.Count() ) + return 0; + + for ( sal_uInt16 i = 0; i < Count(); ++i ) + if( !(*this)[i].IsEqual( rTSI[i] ) ) + return 0; + return 1; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxTabStopItem::Clone( SfxItemPool * ) const +{ + return new SvxTabStopItem( *this ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxTabStopItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, const IntlWrapper *pIntl +) const +{ + rText.Erase(); + + if ( ePres > SFX_ITEM_PRESENTATION_NONE ) + { +#ifndef SVX_LIGHT + sal_Bool bComma = sal_False; + + for ( sal_uInt16 i = 0; i < Count(); ++i ) + { + if ( SVX_TAB_ADJUST_DEFAULT != ((*this)[i]).GetAdjustment() ) + { + if ( bComma ) + rText += sal_Unicode(','); + rText += GetMetricText( + (long)((*this)[i]).GetTabPos(), eCoreUnit, ePresUnit, pIntl ); + if ( SFX_ITEM_PRESENTATION_COMPLETE == ePres ) + rText += EE_RESSTR(GetMetricId(ePresUnit)); + bComma = sal_True; + } + } +#endif + } + return ePres; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxTabStopItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 nTabs; + rStrm >> nTabs; + SvxTabStopItem* pAttr = + new SvxTabStopItem( 0, 0, SVX_TAB_ADJUST_DEFAULT, Which() ); + + for ( sal_Int8 i = 0; i < nTabs; i++ ) + { + long nPos; + sal_Int8 eAdjust; + unsigned char cDecimal, cFill; + rStrm >> nPos >> eAdjust >> cDecimal >> cFill; + if( !i || SVX_TAB_ADJUST_DEFAULT != eAdjust ) + pAttr->Insert( SvxTabStop + ( nPos, (SvxTabAdjust)eAdjust, sal_Unicode(cDecimal), sal_Unicode(cFill) ) ); + } + return pAttr; +} + +// ----------------------------------------------------------------------- + +SvStream& SvxTabStopItem::Store( SvStream& rStrm, sal_uInt16 /*nItemVersion*/ ) const +{ + //MA 05. Sep. 96: Default-Tabs werden nur noch fuer das default-Attr + //expandiert. Fuer vollstaendige Rueckwaertskompatibilitaet (<=304) + //muessten alle Tabs expandiert werden, dass blaeht aber das File u.U. + //enorm auf. + //Alles nur SWG! + + const SfxItemPool *pPool = SfxItemPool::GetStoringPool(); + const FASTBOOL bStoreDefTabs = pPool + && pPool->GetName().EqualsAscii("SWG") + && ::IsDefaultItem( this ); + + const short nTabs = Count(); + sal_uInt16 nCount = 0, nDefDist = 0; + long nNew = 0; + + if( bStoreDefTabs ) + { + const SvxTabStopItem& rDefTab = (const SvxTabStopItem &) + pPool->GetDefaultItem( pPool->GetWhich( SID_ATTR_TABSTOP, sal_False ) ); + nDefDist = sal_uInt16( rDefTab.GetStart()->GetTabPos() ); + const long nPos = nTabs > 0 ? (*this)[nTabs-1].GetTabPos() : 0; + nCount = (sal_uInt16)(nPos / nDefDist); + nNew = (nCount + 1) * nDefDist; + + if( nNew <= nPos + 50 ) + nNew += nDefDist; + + long lA3Width = SvxPaperInfo::GetPaperSize(PAPER_A3).Width(); + nCount = (sal_uInt16)(nNew < lA3Width ? ( lA3Width - nNew ) / nDefDist + 1 : 0); + } + + rStrm << (sal_Int8) ( nTabs + nCount ); + for ( short i = 0; i < nTabs; i++ ) + { + const SvxTabStop& rTab = (*this)[ i ]; + rStrm << (long) rTab.GetTabPos() + << (sal_Int8) rTab.GetAdjustment() + << (unsigned char) rTab.GetDecimal() + << (unsigned char) rTab.GetFill(); + } + + if ( bStoreDefTabs ) + for( ; nCount; --nCount ) + { + SvxTabStop aSwTabStop(nNew, SVX_TAB_ADJUST_DEFAULT); + rStrm << (long) aSwTabStop.GetTabPos() + << (sal_Int8) aSwTabStop.GetAdjustment() + << (unsigned char) aSwTabStop.GetDecimal() + << (unsigned char) aSwTabStop.GetFill(); + nNew += nDefDist; + } + + return rStrm; +} + +// ----------------------------------------------------------------------- +sal_Bool SvxTabStopItem::Insert( const SvxTabStop& rTab ) +{ + sal_uInt16 nTabPos = GetPos(rTab); + if(SVX_TAB_NOTFOUND != nTabPos ) + Remove(nTabPos); + return SvxTabStopArr::Insert( rTab ); +} +// ----------------------------------------------------------------------- +void SvxTabStopItem::Insert( const SvxTabStopItem* pTabs, sal_uInt16 nStart, + sal_uInt16 nEnd ) +{ + for( sal_uInt16 i = nStart; i < nEnd && i < pTabs->Count(); i++ ) + { + const SvxTabStop& rTab = (*pTabs)[i]; + sal_uInt16 nTabPos = GetPos(rTab); + if(SVX_TAB_NOTFOUND != nTabPos) + Remove(nTabPos); + } + SvxTabStopArr::Insert( pTabs, nStart, nEnd ); +} + + + +// class SvxFmtSplitItem ------------------------------------------------- +SvxFmtSplitItem::~SvxFmtSplitItem() +{ +} +// ----------------------------------------------------------------------- +SfxPoolItem* SvxFmtSplitItem::Clone( SfxItemPool * ) const +{ + return new SvxFmtSplitItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxFmtSplitItem::Store( SvStream& rStrm, sal_uInt16 /*nItemVersion*/ ) const +{ + rStrm << (sal_Int8)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFmtSplitItem::Create( SvStream& rStrm, sal_uInt16 ) const +{ + sal_Int8 bIsSplit; + rStrm >> bIsSplit; + return new SvxFmtSplitItem( sal_Bool( bIsSplit != 0 ), Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxFmtSplitItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + sal_uInt16 nId = RID_SVXITEMS_FMTSPLIT_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_FMTSPLIT_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ;//prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// -------------------------------------------------------------------- + +SfxPoolItem* SvxPageModelItem::Clone( SfxItemPool* ) const +{ + return new SvxPageModelItem( *this ); +} + +//------------------------------------------------------------------------ + +sal_Bool SvxPageModelItem::QueryValue( com::sun::star::uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + + switch ( nMemberId ) + { + case MID_AUTO: rVal <<= (sal_Bool) bAuto; break; + case MID_NAME: rVal <<= ::rtl::OUString( GetValue() ); break; + default: DBG_ERROR("Wrong MemberId!"); return sal_False; + } + + return sal_True; +} + +sal_Bool SvxPageModelItem::PutValue( const com::sun::star::uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet; + ::rtl::OUString aStr; + switch ( nMemberId ) + { + case MID_AUTO: bRet = ( rVal >>= bAuto ); break; + case MID_NAME: bRet = ( rVal >>= aStr ); if ( bRet ) SetValue(aStr); break; + default: DBG_ERROR("Wrong MemberId!"); return sal_False; + } + + return bRet; +} + +SfxItemPresentation SvxPageModelItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * +) const +{ + rText.Erase(); + FASTBOOL bSet = ( GetValue().Len() > 0 ); + + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + return SFX_ITEM_PRESENTATION_NONE; + + case SFX_ITEM_PRESENTATION_NAMELESS: + if ( bSet ) + rText = GetValue(); + return SFX_ITEM_PRESENTATION_NAMELESS; + + case SFX_ITEM_PRESENTATION_COMPLETE: + if ( bSet ) + { + rText = EE_RESSTR(RID_SVXITEMS_PAGEMODEL_COMPLETE); + rText += GetValue(); + } + return SFX_ITEM_PRESENTATION_COMPLETE; + default: ;//prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +//------------------------------------------------------------------------ + +SvxScriptSpaceItem::SvxScriptSpaceItem( sal_Bool bOn, const sal_uInt16 nId ) + : SfxBoolItem( nId, bOn ) +{ +} + +SfxPoolItem* SvxScriptSpaceItem::Clone( SfxItemPool * ) const +{ + return new SvxScriptSpaceItem( GetValue(), Which() ); +} + +SfxPoolItem* SvxScriptSpaceItem::Create(SvStream & rStrm, USHORT) const +{ + sal_Bool bFlag; + rStrm >> bFlag; + return new SvxScriptSpaceItem( bFlag, Which() ); +} + +USHORT SvxScriptSpaceItem::GetVersion( USHORT nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxTwoLinesItem: Gibt es ein neues Fileformat?" ); + + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + +SfxItemPresentation SvxScriptSpaceItem::GetPresentation( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, SfxMapUnit /*ePresMetric*/, + String &rText, const IntlWrapper* /*pIntl*/ ) const +{ + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR( !GetValue() + ? RID_SVXITEMS_SCRPTSPC_OFF + : RID_SVXITEMS_SCRPTSPC_ON ); + return ePres; + } + default: ;//prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +//------------------------------------------------------------------------ + +SvxHangingPunctuationItem::SvxHangingPunctuationItem( + sal_Bool bOn, const sal_uInt16 nId ) + : SfxBoolItem( nId, bOn ) +{ +} + +SfxPoolItem* SvxHangingPunctuationItem::Clone( SfxItemPool * ) const +{ + return new SvxHangingPunctuationItem( GetValue(), Which() ); +} + +SfxPoolItem* SvxHangingPunctuationItem::Create(SvStream & rStrm, USHORT) const +{ + sal_Bool nValue; + rStrm >> nValue; + return new SvxHangingPunctuationItem( nValue, Which() ); +} + +USHORT SvxHangingPunctuationItem::GetVersion( USHORT nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxHangingPunctuationItem: Gibt es ein neues Fileformat?" ); + + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + +SfxItemPresentation SvxHangingPunctuationItem::GetPresentation( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, SfxMapUnit /*ePresMetric*/, + String &rText, const IntlWrapper* /*pIntl*/ ) const +{ + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR( !GetValue() + ? RID_SVXITEMS_HNGPNCT_OFF + : RID_SVXITEMS_HNGPNCT_ON ); + return ePres; + } + default: ;//prevent warning + break; + } + return SFX_ITEM_PRESENTATION_NONE; +} +//------------------------------------------------------------------------ + +SvxForbiddenRuleItem::SvxForbiddenRuleItem( + sal_Bool bOn, const sal_uInt16 nId ) + : SfxBoolItem( nId, bOn ) +{ +} +/* -----------------------------29.11.00 11:23-------------------------------- + + ---------------------------------------------------------------------------*/ +SfxPoolItem* SvxForbiddenRuleItem::Clone( SfxItemPool * ) const +{ + return new SvxForbiddenRuleItem( GetValue(), Which() ); +} +/* -----------------------------29.11.00 11:23-------------------------------- + + ---------------------------------------------------------------------------*/ +SfxPoolItem* SvxForbiddenRuleItem::Create(SvStream & rStrm, USHORT) const +{ + sal_Bool nValue; + rStrm >> nValue; + return new SvxForbiddenRuleItem( nValue, Which() ); +} +/* -----------------------------29.11.00 11:23-------------------------------- + + ---------------------------------------------------------------------------*/ +USHORT SvxForbiddenRuleItem::GetVersion( USHORT nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxForbiddenRuleItem: Gibt es ein neues Fileformat?" ); + + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} +/* -----------------------------29.11.00 11:23-------------------------------- + + ---------------------------------------------------------------------------*/ +SfxItemPresentation SvxForbiddenRuleItem::GetPresentation( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, SfxMapUnit /*ePresMetric*/, + String &rText, const IntlWrapper* /*pIntl*/ ) const +{ + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR( !GetValue() + ? RID_SVXITEMS_FORBIDDEN_RULE_OFF + : RID_SVXITEMS_FORBIDDEN_RULE_ON ); + return ePres; + } + default: ;//prevent warning + break; + } + return SFX_ITEM_PRESENTATION_NONE; +} + +/************************************************************************* +|* class SvxParaVertAlignItem +*************************************************************************/ + +SvxParaVertAlignItem::SvxParaVertAlignItem( sal_uInt16 nValue, + const sal_uInt16 nW ) + : SfxUInt16Item( nW, nValue ) +{ +} + +SfxPoolItem* SvxParaVertAlignItem::Clone( SfxItemPool* ) const +{ + return new SvxParaVertAlignItem( GetValue(), Which() ); +} + +SfxPoolItem* SvxParaVertAlignItem::Create( SvStream& rStrm, USHORT ) const +{ + sal_uInt16 nVal; + rStrm >> nVal; + return new SvxParaVertAlignItem( nVal, Which() ); +} + +SvStream& SvxParaVertAlignItem::Store( SvStream & rStrm, USHORT ) const +{ + rStrm << GetValue(); + return rStrm; +} + +USHORT SvxParaVertAlignItem::GetVersion( USHORT nFFVer ) const +{ + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + +SfxItemPresentation SvxParaVertAlignItem::GetPresentation( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, SfxMapUnit /*ePresMetric*/, + String &rText, const IntlWrapper* ) const +{ + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + USHORT nTmp; + switch( GetValue() ) + { + case AUTOMATIC: nTmp = RID_SVXITEMS_PARAVERTALIGN_AUTO; break; + case TOP: nTmp = RID_SVXITEMS_PARAVERTALIGN_TOP; break; + case CENTER: nTmp = RID_SVXITEMS_PARAVERTALIGN_CENTER; break; + case BOTTOM: nTmp = RID_SVXITEMS_PARAVERTALIGN_BOTTOM; break; + default: nTmp = RID_SVXITEMS_PARAVERTALIGN_BASELINE; break; + } + rText = EE_RESSTR( nTmp ); + return ePres; + } + default: ;//prevent warning + break; + } + return SFX_ITEM_PRESENTATION_NONE; +} + +sal_Bool SvxParaVertAlignItem::QueryValue( com::sun::star::uno::Any& rVal, + BYTE /*nMemberId*/ ) const +{ + rVal <<= (sal_Int16)GetValue(); + return sal_True; +} + +sal_Bool SvxParaVertAlignItem::PutValue( const com::sun::star::uno::Any& rVal, + BYTE /*nMemberId*/ ) +{ + sal_Int16 nVal = sal_Int16(); + if((rVal >>= nVal) && nVal >=0 && nVal <= BOTTOM ) + { + SetValue( (USHORT)nVal ); + return sal_True; + } + else + return sal_False; +} + +int SvxParaVertAlignItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" ); + return SfxUInt16Item::operator==( rItem ); +} + + +SvxParaGridItem::SvxParaGridItem( sal_Bool bOn, const sal_uInt16 nId ) + : SfxBoolItem( nId, bOn ) +{ +} + +SfxPoolItem* SvxParaGridItem::Clone( SfxItemPool * ) const +{ + return new SvxParaGridItem( GetValue(), Which() ); +} + +SfxPoolItem* SvxParaGridItem::Create(SvStream & rStrm, USHORT) const +{ + sal_Bool bFlag; + rStrm >> bFlag; + return new SvxParaGridItem( bFlag, Which() ); +} + +USHORT SvxParaGridItem::GetVersion( USHORT nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxParaGridItem: Gibt es ein neues Fileformat?" ); + + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + +SfxItemPresentation SvxParaGridItem::GetPresentation( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, SfxMapUnit /*ePresMetric*/, + String &rText, const IntlWrapper* /*pIntl*/ ) const +{ + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = GetValue() ? + EE_RESSTR( RID_SVXITEMS_PARASNAPTOGRID_ON ) : + EE_RESSTR( RID_SVXITEMS_PARASNAPTOGRID_OFF ); + + return ePres; + } + default: ;//prevent warning + break; + } + return SFX_ITEM_PRESENTATION_NONE; +} + + diff --git a/editeng/source/items/svdfield.cxx b/editeng/source/items/svdfield.cxx new file mode 100644 index 000000000000..22befecdaba3 --- /dev/null +++ b/editeng/source/items/svdfield.cxx @@ -0,0 +1,65 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: svdomeas.cxx,v $ + * $Revision: 1.35.18.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/measfld.hxx> + +SV_IMPL_PERSIST1(SdrMeasureField,SvxFieldData); + +__EXPORT SdrMeasureField::~SdrMeasureField() +{ +} + +SvxFieldData* __EXPORT SdrMeasureField::Clone() const +{ + return new SdrMeasureField(*this); +} + +int __EXPORT SdrMeasureField::operator==(const SvxFieldData& rSrc) const +{ + return eMeasureFieldKind==((SdrMeasureField&)rSrc).GetMeasureFieldKind(); +} + +void __EXPORT SdrMeasureField::Load(SvPersistStream& rIn) +{ + UINT16 nFieldKind; + rIn>>nFieldKind; + eMeasureFieldKind=(SdrMeasureFieldKind)nFieldKind; +} + +void __EXPORT SdrMeasureField::Save(SvPersistStream& rOut) +{ + rOut<<(UINT16)eMeasureFieldKind; +} + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/editeng/source/items/svxfont.cxx b/editeng/source/items/svxfont.cxx new file mode 100644 index 000000000000..7cab2fbb1d1d --- /dev/null +++ b/editeng/source/items/svxfont.cxx @@ -0,0 +1,860 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: svxfont.cxx,v $ + * $Revision: 1.15.216.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +// include ---------------------------------------------------------------- + +#include <vcl/outdev.hxx> +#include <vcl/print.hxx> +#include <tools/poly.hxx> +#include <unotools/charclass.hxx> +#include <editeng/unolingu.hxx> +#include <com/sun/star/i18n/KCharacterType.hpp> + +#define _SVX_SVXFONT_CXX + +#include <editeng/svxfont.hxx> +#include <editeng/escpitem.hxx> + +// Minimum: Prozentwert fuers kernen +#define MINKERNPERCENT 5 + +// prop. Groesse der Kleinbuchstaben bei Kapitaelchen +#define KAPITAELCHENPROP 66 + +#ifndef REDUCEDSVXFONT + const sal_Unicode CH_BLANK = sal_Unicode(' '); // ' ' Leerzeichen + static sal_Char __READONLY_DATA sDoubleSpace[] = " "; +#endif + +/************************************************************************* + * class SvxFont + *************************************************************************/ + +SvxFont::SvxFont() +{ + nKern = nEsc = 0; + nPropr = 100; + eCaseMap = SVX_CASEMAP_NOT_MAPPED; + eLang = LANGUAGE_SYSTEM; +} + +SvxFont::SvxFont( const Font &rFont ) + : Font( rFont ) +{ + nKern = nEsc = 0; + nPropr = 100; + eCaseMap = SVX_CASEMAP_NOT_MAPPED; + eLang = LANGUAGE_SYSTEM; +} + +/************************************************************************* + * class SvxFont: Copy-Ctor + *************************************************************************/ + +SvxFont::SvxFont( const SvxFont &rFont ) + : Font( rFont ) +{ + nKern = rFont.GetFixKerning(); + nEsc = rFont.GetEscapement(); + nPropr = rFont.GetPropr(); + eCaseMap = rFont.GetCaseMap(); + eLang = rFont.GetLanguage(); +} + +/************************************************************************* + * static SvxFont::DrawArrow + *************************************************************************/ + +void SvxFont::DrawArrow( OutputDevice &rOut, const Rectangle& rRect, + const Size& rSize, const Color& rCol, BOOL bLeft ) +{ + long nLeft = ( rRect.Left() + rRect.Right() - rSize.Width() )/ 2; + long nRight = nLeft + rSize.Width(); + long nMid = ( rRect.Top() + rRect.Bottom() ) / 2; + long nTop = nMid - rSize.Height() / 2; + long nBottom = nTop + rSize.Height(); + if( nLeft < rRect.Left() ) + { + nLeft = rRect.Left(); + nRight = rRect.Right(); + } + if( nTop < rRect.Top() ) + { + nTop = rRect.Top(); + nBottom = rRect.Bottom(); + } + Polygon aPoly; + Point aTmp( bLeft ? nLeft : nRight, nMid ); + Point aNxt( bLeft ? nRight : nLeft, nTop ); + aPoly.Insert( 0, aTmp ); + aPoly.Insert( 0, aNxt ); + aNxt.Y() = nBottom; + aPoly.Insert( 0, aNxt ); + aPoly.Insert( 0, aTmp ); + Color aOldLineColor = rOut.GetLineColor(); + Color aOldFillColor = rOut.GetFillColor(); + rOut.SetFillColor( rCol ); + rOut.SetLineColor( Color( COL_BLACK ) ); + rOut.DrawPolygon( aPoly ); + rOut.DrawLine( aTmp, aNxt ); + rOut.SetLineColor( aOldLineColor ); + rOut.SetFillColor( aOldFillColor ); +} + +/************************************************************************* + * SvxFont::CalcCaseMap + *************************************************************************/ + +XubString SvxFont::CalcCaseMap( const XubString &rTxt ) const +{ + if( !IsCaseMap() || !rTxt.Len() ) return rTxt; + XubString aTxt( rTxt ); + // Ich muss mir noch die Sprache besorgen + const LanguageType eLng = LANGUAGE_DONTKNOW == eLang + ? LANGUAGE_SYSTEM : eLang; + + CharClass aCharClass( SvxCreateLocale( eLng ) ); + + switch( eCaseMap ) + { + case SVX_CASEMAP_KAPITAELCHEN: + case SVX_CASEMAP_VERSALIEN: + { + aCharClass.toUpper( aTxt ); + break; + } + + case SVX_CASEMAP_GEMEINE: + { + aCharClass.toLower( aTxt ); + break; + } + case SVX_CASEMAP_TITEL: + { + // Jeder Wortbeginn wird gross geschrieben, + // der Rest des Wortes wird unbesehen uebernommen. + // Bug: wenn das Attribut mitten im Wort beginnt. + BOOL bBlank = TRUE; + + for( USHORT i = 0; i < aTxt.Len(); ++i ) + { + if( sal_Unicode(' ') == aTxt.GetChar(i) || sal_Unicode('\t') == aTxt.GetChar(i) ) + bBlank = TRUE; + else + { + if( bBlank ) + { + String aTemp( aTxt.GetChar( i ) ); + aCharClass.toUpper( aTemp ); + aTxt.Replace( i, 1, aTemp ); + } + bBlank = FALSE; + } + } + break; + } + default: + { + DBG_ASSERT(!this, "SvxFont::CaseMapTxt: unknown casemap"); + break; + } + } + return aTxt; +} + +/************************************************************************* + * Hier beginnen die Methoden, die im Writer nicht benutzt werden koennen, + * deshalb kann man diesen Bereich durch setzen von REDUCEDSVXFONT ausklammern. + *************************************************************************/ +#ifndef REDUCEDSVXFONT + +/************************************************************************* + * class SvxDoCapitals + * die virtuelle Methode Do wird von SvxFont::DoOnCapitals abwechselnd mit + * den "Gross-" und "Kleinbuchstaben"-Teilen aufgerufen. + * Die Ableitungen von SvxDoCapitals erfuellen diese Methode mit Leben. + *************************************************************************/ + +class SvxDoCapitals +{ +protected: + OutputDevice *pOut; + const XubString &rTxt; + const xub_StrLen nIdx; + const xub_StrLen nLen; + +public: + SvxDoCapitals( OutputDevice *_pOut, const XubString &_rTxt, + const xub_StrLen _nIdx, const xub_StrLen _nLen ) + : pOut(_pOut), rTxt(_rTxt), nIdx(_nIdx), nLen(_nLen) + { } + + virtual void DoSpace( const BOOL bDraw ); + virtual void SetSpace(); + virtual void Do( const XubString &rTxt, + const xub_StrLen nIdx, const xub_StrLen nLen, + const BOOL bUpper ) = 0; + + inline OutputDevice *GetOut() { return pOut; } + inline const XubString &GetTxt() const { return rTxt; } + xub_StrLen GetIdx() const { return nIdx; } + xub_StrLen GetLen() const { return nLen; } +}; + +void SvxDoCapitals::DoSpace( const BOOL /*bDraw*/ ) { } + +void SvxDoCapitals::SetSpace() { } + +void SvxDoCapitals::Do( const XubString &/*_rTxt*/, const xub_StrLen /*_nIdx*/, + const xub_StrLen /*_nLen*/, const BOOL /*bUpper*/ ) { } + +/************************************************************************* + * SvxFont::DoOnCapitals() const + * zerlegt den String in Gross- und Kleinbuchstaben und ruft jeweils die + * Methode SvxDoCapitals::Do( ) auf. + *************************************************************************/ + +void SvxFont::DoOnCapitals(SvxDoCapitals &rDo, const xub_StrLen nPartLen) const +{ + const XubString &rTxt = rDo.GetTxt(); + const xub_StrLen nIdx = rDo.GetIdx(); + const xub_StrLen nLen = STRING_LEN == nPartLen ? rDo.GetLen() : nPartLen; + + const XubString aTxt( CalcCaseMap( rTxt ) ); + const USHORT nTxtLen = Min( rTxt.Len(), nLen ); + USHORT nPos = 0; + USHORT nOldPos = nPos; + + // #108210# + // Test if string length differ between original and CaseMapped + sal_Bool bCaseMapLengthDiffers(aTxt.Len() != rTxt.Len()); + + const LanguageType eLng = LANGUAGE_DONTKNOW == eLang + ? LANGUAGE_SYSTEM : eLang; + + CharClass aCharClass( SvxCreateLocale( eLng ) ); + String aCharString; + + while( nPos < nTxtLen ) + { + // Erst kommen die Upper-Chars dran + + // 4251: Es gibt Zeichen, die Upper _und_ Lower sind (z.B. das Blank). + // Solche Zweideutigkeiten fuehren ins Chaos, deswegen werden diese + // Zeichen der Menge Lower zugeordnet ! + + while( nPos < nTxtLen ) + { + aCharString = rTxt.GetChar( nPos + nIdx ); + sal_Int32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 ); + if ( nCharacterType & ::com::sun::star::i18n::KCharacterType::LOWER ) + break; + if ( ! ( nCharacterType & ::com::sun::star::i18n::KCharacterType::UPPER ) ) + break; + ++nPos; + } + if( nOldPos != nPos ) + { + if(bCaseMapLengthDiffers) + { + // #108210# + // If strings differ work preparing the necessary snippet to address that + // potential difference + const XubString aSnippet(rTxt, nIdx + nOldPos, nPos-nOldPos); + XubString aNewText = CalcCaseMap(aSnippet); + + rDo.Do( aNewText, 0, aNewText.Len(), TRUE ); + } + else + { + rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, TRUE ); + } + + nOldPos = nPos; + } + // Nun werden die Lower-Chars verarbeitet (ohne Blanks) + while( nPos < nTxtLen ) + { + sal_uInt32 nCharacterType = aCharClass.getCharacterType( aCharString, 0 ); + if ( ( nCharacterType & ::com::sun::star::i18n::KCharacterType::UPPER ) ) + break; + if ( CH_BLANK == aCharString ) + break; + if( ++nPos < nTxtLen ) + aCharString = rTxt.GetChar( nPos + nIdx ); + } + if( nOldPos != nPos ) + { + if(bCaseMapLengthDiffers) + { + // #108210# + // If strings differ work preparing the necessary snippet to address that + // potential difference + const XubString aSnippet(rTxt, nIdx + nOldPos, nPos - nOldPos); + XubString aNewText = CalcCaseMap(aSnippet); + + rDo.Do( aNewText, 0, aNewText.Len(), FALSE ); + } + else + { + rDo.Do( aTxt, nIdx + nOldPos, nPos-nOldPos, FALSE ); + } + + nOldPos = nPos; + } + // Nun werden die Blanks verarbeitet + while( nPos < nTxtLen && CH_BLANK == aCharString && ++nPos < nTxtLen ) + aCharString = rTxt.GetChar( nPos + nIdx ); + + if( nOldPos != nPos ) + { + rDo.DoSpace( FALSE ); + + if(bCaseMapLengthDiffers) + { + // #108210# + // If strings differ work preparing the necessary snippet to address that + // potential difference + const XubString aSnippet(rTxt, nIdx + nOldPos, nPos - nOldPos); + XubString aNewText = CalcCaseMap(aSnippet); + + rDo.Do( aNewText, 0, aNewText.Len(), FALSE ); + } + else + { + rDo.Do( aTxt, nIdx + nOldPos, nPos - nOldPos, FALSE ); + } + + nOldPos = nPos; + rDo.SetSpace(); + } + } + rDo.DoSpace( TRUE ); +} + +/************************************************************************** + * SvxFont::SetPhysFont() + *************************************************************************/ + +void SvxFont::SetPhysFont( OutputDevice *pOut ) const +{ + const Font& rCurrentFont = pOut->GetFont(); + if ( nPropr == 100 ) + { + if ( !rCurrentFont.IsSameInstance( *this ) ) + pOut->SetFont( *this ); + } + else + { + Font aNewFont( *this ); + Size aSize( aNewFont.GetSize() ); + aNewFont.SetSize( Size( aSize.Width() * nPropr / 100L, + aSize.Height() * nPropr / 100L ) ); + if ( !rCurrentFont.IsSameInstance( aNewFont ) ) + pOut->SetFont( aNewFont ); + } +} + +/************************************************************************* + * SvxFont::ChgPhysFont() + *************************************************************************/ + +Font SvxFont::ChgPhysFont( OutputDevice *pOut ) const +{ + Font aOldFont( pOut->GetFont() ); + SetPhysFont( pOut ); + return aOldFont; +} + +/************************************************************************* + * SvxFont::GetPhysTxtSize() + *************************************************************************/ + +Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const XubString &rTxt, + const xub_StrLen nIdx, const xub_StrLen nLen ) const +{ + if ( !IsCaseMap() && !IsKern() ) + return Size( pOut->GetTextWidth( rTxt, nIdx, nLen ), + pOut->GetTextHeight() ); + + Size aTxtSize; + aTxtSize.setHeight( pOut->GetTextHeight() ); + if ( !IsCaseMap() ) + aTxtSize.setWidth( pOut->GetTextWidth( rTxt, nIdx, nLen ) ); + else + { + // #108210# + const XubString aNewText = CalcCaseMap(rTxt); + sal_Bool bCaseMapLengthDiffers(aNewText.Len() != rTxt.Len()); + sal_Int32 nWidth(0L); + + if(bCaseMapLengthDiffers) + { + // If strings differ work preparing the necessary snippet to address that + // potential difference + const XubString aSnippet(rTxt, nIdx, nLen); + XubString _aNewText = CalcCaseMap(aSnippet); + nWidth = pOut->GetTextWidth( _aNewText, 0, _aNewText.Len() ); + } + else + { + nWidth = pOut->GetTextWidth( aNewText, nIdx, nLen ); + } + + aTxtSize.setWidth(nWidth); + } + + if( IsKern() && ( nLen > 1 ) ) + aTxtSize.Width() += ( ( nLen-1 ) * long( nKern ) ); + + return aTxtSize; +} + +Size SvxFont::GetPhysTxtSize( const OutputDevice *pOut, const XubString &rTxt ) +{ + if ( !IsCaseMap() && !IsKern() ) + return Size( pOut->GetTextWidth( rTxt ), pOut->GetTextHeight() ); + + Size aTxtSize; + aTxtSize.setHeight( pOut->GetTextHeight() ); + if ( !IsCaseMap() ) + aTxtSize.setWidth( pOut->GetTextWidth( rTxt ) ); + else + aTxtSize.setWidth( pOut->GetTextWidth( CalcCaseMap( rTxt ) ) ); + + if( IsKern() && ( rTxt.Len() > 1 ) ) + aTxtSize.Width() += ( ( rTxt.Len()-1 ) * long( nKern ) ); + + return aTxtSize; +} + +Size SvxFont::QuickGetTextSize( const OutputDevice *pOut, const XubString &rTxt, + const USHORT nIdx, const USHORT nLen, sal_Int32* pDXArray ) const +{ + if ( !IsCaseMap() && !IsKern() ) + return Size( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ), + pOut->GetTextHeight() ); + + Size aTxtSize; + aTxtSize.setHeight( pOut->GetTextHeight() ); + if ( !IsCaseMap() ) + aTxtSize.setWidth( pOut->GetTextArray( rTxt, pDXArray, nIdx, nLen ) ); + else + aTxtSize.setWidth( pOut->GetTextArray( CalcCaseMap( rTxt ), + pDXArray, nIdx, nLen ) ); + + if( IsKern() && ( nLen > 1 ) ) + { + aTxtSize.Width() += ( ( nLen-1 ) * long( nKern ) ); + + if ( pDXArray ) + { + for ( xub_StrLen i = 0; i < nLen; i++ ) + pDXArray[i] += ( (i+1) * long( nKern ) ); + // Der letzte ist um ein nKern zu gross: + pDXArray[nLen-1] -= nKern; + } + } + return aTxtSize; +} + +/************************************************************************* + * SvxFont::GetTxtSize() + *************************************************************************/ + +Size SvxFont::GetTxtSize( const OutputDevice *pOut, const XubString &rTxt, + const xub_StrLen nIdx, const xub_StrLen nLen ) +{ + xub_StrLen nTmp = nLen; + if ( nTmp == STRING_LEN ) // schon initialisiert? + nTmp = rTxt.Len(); + Font aOldFont( ChgPhysFont((OutputDevice *)pOut) ); + Size aTxtSize; + if( IsCapital() && rTxt.Len() ) + { + aTxtSize = GetCapitalSize( pOut, rTxt, nIdx, nTmp ); + } + else aTxtSize = GetPhysTxtSize(pOut,rTxt,nIdx,nTmp); + ((OutputDevice *)pOut)->SetFont( aOldFont ); + return aTxtSize; +} + +/************************************************************************* + * SvxFont::DrawText() + *************************************************************************/ + +void SvxFont::DrawText( OutputDevice *pOut, + const Point &rPos, const XubString &rTxt, + const xub_StrLen nIdx, const xub_StrLen nLen ) const +{ + if( !nLen || !rTxt.Len() ) return; + xub_StrLen nTmp = nLen; + if ( nTmp == STRING_LEN ) // schon initialisiert? + nTmp = rTxt.Len(); + Point aPos( rPos ); + if ( nEsc ) + { + Size aSize = (this->GetSize()); + aPos.Y() -= ((nEsc*long(aSize.Height()))/ 100L); + } + Font aOldFont( ChgPhysFont( pOut ) ); + + if ( IsCapital() ) + DrawCapital( pOut, aPos, rTxt, nIdx, nTmp ); + else + { + Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nTmp ); + + if ( !IsCaseMap() ) + pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp ); + else + pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), + nIdx, nTmp ); + } + pOut->SetFont(aOldFont); +} + +void SvxFont::QuickDrawText( OutputDevice *pOut, + const Point &rPos, const XubString &rTxt, + const xub_StrLen nIdx, const xub_StrLen nLen, const sal_Int32* pDXArray ) const +{ + // Font muss ins OutputDevice selektiert sein... + if ( !IsCaseMap() && !IsCapital() && !IsKern() && !IsEsc() ) + { + pOut->DrawTextArray( rPos, rTxt, pDXArray, nIdx, nLen ); + return; + } + + Point aPos( rPos ); + + if ( nEsc ) + { + long nDiff = GetSize().Height(); + nDiff *= nEsc; + nDiff /= 100; + + if ( !IsVertical() ) + aPos.Y() -= nDiff; + else + aPos.X() += nDiff; + } + + if( IsCapital() ) + { + DBG_ASSERT( !pDXArray, "DrawCapital nicht fuer TextArray!" ); + DrawCapital( pOut, aPos, rTxt, nIdx, nLen ); + } + else + { + if ( IsKern() && !pDXArray ) + { + Size aSize = GetPhysTxtSize( pOut, rTxt, nIdx, nLen ); + + if ( !IsCaseMap() ) + pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nLen ); + else + pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nLen ); + } + else + { + if ( !IsCaseMap() ) + pOut->DrawTextArray( aPos, rTxt, pDXArray, nIdx, nLen ); + else + pOut->DrawTextArray( aPos, CalcCaseMap( rTxt ), pDXArray, nIdx, nLen ); + } + } +} + +// ----------------------------------------------------------------------- + +void SvxFont::DrawPrev( OutputDevice *pOut, Printer* pPrinter, + const Point &rPos, const XubString &rTxt, + const xub_StrLen nIdx, const xub_StrLen nLen ) const +{ + if ( !nLen || !rTxt.Len() ) + return; + xub_StrLen nTmp = nLen; + + if ( nTmp == STRING_LEN ) // schon initialisiert? + nTmp = rTxt.Len(); + Point aPos( rPos ); + + if ( nEsc ) + { + short nTmpEsc; + if( DFLT_ESC_AUTO_SUPER == nEsc ) + nTmpEsc = 33; + else if( DFLT_ESC_AUTO_SUB == nEsc ) + nTmpEsc = -20; + else + nTmpEsc = nEsc; + Size aSize = ( this->GetSize() ); + aPos.Y() -= ( ( nTmpEsc * long( aSize.Height() ) ) / 100L ); + } + Font aOldFont( ChgPhysFont( pOut ) ); + Font aOldPrnFont( ChgPhysFont( pPrinter ) ); + + if ( IsCapital() ) + DrawCapital( pOut, aPos, rTxt, nIdx, nTmp ); + else + { + Size aSize = GetPhysTxtSize( pPrinter, rTxt, nIdx, nTmp ); + + if ( !IsCaseMap() ) + pOut->DrawStretchText( aPos, aSize.Width(), rTxt, nIdx, nTmp ); + else + { + // #108210# + const XubString aNewText = CalcCaseMap(rTxt); + sal_Bool bCaseMapLengthDiffers(aNewText.Len() != rTxt.Len()); + + if(bCaseMapLengthDiffers) + { + // If strings differ work preparing the necessary snippet to address that + // potential difference + const XubString aSnippet(rTxt, nIdx, nTmp); + XubString _aNewText = CalcCaseMap(aSnippet); + + pOut->DrawStretchText( aPos, aSize.Width(), _aNewText, 0, _aNewText.Len() ); + } + else + { + pOut->DrawStretchText( aPos, aSize.Width(), CalcCaseMap( rTxt ), nIdx, nTmp ); + } + } + } + pOut->SetFont(aOldFont); + pPrinter->SetFont( aOldPrnFont ); +} + +// ----------------------------------------------------------------------- + +SvxFont& SvxFont::operator=( const Font& rFont ) +{ + Font::operator=( rFont ); + return *this; +} + +SvxFont& SvxFont::operator=( const SvxFont& rFont ) +{ + Font::operator=( rFont ); + eLang = rFont.eLang; + eCaseMap = rFont.eCaseMap; + nEsc = rFont.nEsc; + nPropr = rFont.nPropr; + nKern = rFont.nKern; + return *this; +} + + +/************************************************************************* + * class SvxDoGetCapitalSize + * wird von SvxFont::GetCapitalSize() zur Berechnung der TxtSize bei + * eingestellten Kapitaelchen benutzt. + *************************************************************************/ + +class SvxDoGetCapitalSize : public SvxDoCapitals +{ +protected: + SvxFont* pFont; + Size aTxtSize; + short nKern; +public: + SvxDoGetCapitalSize( SvxFont *_pFnt, const OutputDevice *_pOut, + const XubString &_rTxt, const xub_StrLen _nIdx, + const xub_StrLen _nLen, const short _nKrn ) + : SvxDoCapitals( (OutputDevice*)_pOut, _rTxt, _nIdx, _nLen ), + pFont( _pFnt ), + nKern( _nKrn ) + { } + + virtual void Do( const XubString &rTxt, const xub_StrLen nIdx, + const xub_StrLen nLen, const BOOL bUpper ); + + inline const Size &GetSize() const { return aTxtSize; }; +}; + +void SvxDoGetCapitalSize::Do( const XubString &_rTxt, const xub_StrLen _nIdx, + const xub_StrLen _nLen, const BOOL bUpper ) +{ + Size aPartSize; + if ( !bUpper ) + { + BYTE nProp = pFont->GetPropr(); + pFont->SetProprRel( KAPITAELCHENPROP ); + pFont->SetPhysFont( pOut ); + aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) ); + aPartSize.setHeight( pOut->GetTextHeight() ); + aTxtSize.Height() = aPartSize.Height(); + pFont->SetPropr( nProp ); + pFont->SetPhysFont( pOut ); + } + else + { + aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) ); + aPartSize.setHeight( pOut->GetTextHeight() ); + } + aTxtSize.Width() += aPartSize.Width(); + aTxtSize.Width() += ( _nLen * long( nKern ) ); +} + +/************************************************************************* + * SvxFont::GetCapitalSize() + * berechnet TxtSize, wenn Kapitaelchen eingestellt sind. + *************************************************************************/ + +Size SvxFont::GetCapitalSize( const OutputDevice *pOut, const XubString &rTxt, + const xub_StrLen nIdx, const xub_StrLen nLen) const +{ + // Start: + SvxDoGetCapitalSize aDo( (SvxFont *)this, pOut, rTxt, nIdx, nLen, nKern ); + DoOnCapitals( aDo ); + Size aTxtSize( aDo.GetSize() ); + + // End: + if( !aTxtSize.Height() ) + { + aTxtSize.setWidth( 0 ); + aTxtSize.setHeight( pOut->GetTextHeight() ); + } + return aTxtSize; +} + +/************************************************************************* + * class SvxDoDrawCapital + * wird von SvxFont::DrawCapital zur Ausgabe von Kapitaelchen benutzt. + *************************************************************************/ + +class SvxDoDrawCapital : public SvxDoCapitals +{ +protected: + SvxFont *pFont; + Point aPos; + Point aSpacePos; + short nKern; +public: + SvxDoDrawCapital( SvxFont *pFnt, OutputDevice *_pOut, const XubString &_rTxt, + const xub_StrLen _nIdx, const xub_StrLen _nLen, + const Point &rPos, const short nKrn ) + : SvxDoCapitals( _pOut, _rTxt, _nIdx, _nLen ), + pFont( pFnt ), + aPos( rPos ), + aSpacePos( rPos ), + nKern( nKrn ) + { } + virtual void DoSpace( const BOOL bDraw ); + virtual void SetSpace(); + virtual void Do( const XubString &rTxt, const xub_StrLen nIdx, + const xub_StrLen nLen, const BOOL bUpper ); +}; + +void SvxDoDrawCapital::DoSpace( const BOOL bDraw ) +{ + if ( bDraw || pFont->IsWordLineMode() ) + { + USHORT nDiff = (USHORT)(aPos.X() - aSpacePos.X()); + if ( nDiff ) + { + BOOL bWordWise = pFont->IsWordLineMode(); + BOOL bTrans = pFont->IsTransparent(); + pFont->SetWordLineMode( FALSE ); + pFont->SetTransparent( TRUE ); + pFont->SetPhysFont( pOut ); + pOut->DrawStretchText( aSpacePos, nDiff, XubString( sDoubleSpace, + RTL_TEXTENCODING_MS_1252 ), 0, 2 ); + pFont->SetWordLineMode( bWordWise ); + pFont->SetTransparent( bTrans ); + pFont->SetPhysFont( pOut ); + } + } +} + +void SvxDoDrawCapital::SetSpace() +{ + if ( pFont->IsWordLineMode() ) + aSpacePos.X() = aPos.X(); +} + +void SvxDoDrawCapital::Do( const XubString &_rTxt, const xub_StrLen _nIdx, + const xub_StrLen _nLen, const BOOL bUpper) +{ + BYTE nProp = 0; + Size aPartSize; + + // Einstellen der gewuenschten Fonts + FontUnderline eUnder = pFont->GetUnderline(); + FontStrikeout eStrike = pFont->GetStrikeout(); + pFont->SetUnderline( UNDERLINE_NONE ); + pFont->SetStrikeout( STRIKEOUT_NONE ); + if ( !bUpper ) + { + nProp = pFont->GetPropr(); + pFont->SetProprRel( KAPITAELCHENPROP ); + } + pFont->SetPhysFont( pOut ); + + aPartSize.setWidth( pOut->GetTextWidth( _rTxt, _nIdx, _nLen ) ); + aPartSize.setHeight( pOut->GetTextHeight() ); + long nWidth = aPartSize.Width(); + if ( nKern ) + { + aPos.X() += (nKern/2); + if ( _nLen ) nWidth += (_nLen*long(nKern)); + } + pOut->DrawStretchText(aPos,nWidth-nKern,_rTxt,_nIdx,_nLen); + + // Font restaurieren + pFont->SetUnderline( eUnder ); + pFont->SetStrikeout( eStrike ); + if ( !bUpper ) + pFont->SetPropr( nProp ); + pFont->SetPhysFont( pOut ); + + aPos.X() += nWidth-(nKern/2); +} + +/************************************************************************* + * SvxFont::DrawCapital() gibt Kapitaelchen aus. + *************************************************************************/ + +void SvxFont::DrawCapital( OutputDevice *pOut, + const Point &rPos, const XubString &rTxt, + const xub_StrLen nIdx, const xub_StrLen nLen ) const +{ + SvxDoDrawCapital aDo( (SvxFont *)this,pOut,rTxt,nIdx,nLen,rPos,nKern ); + DoOnCapitals( aDo ); +} + +#endif // !REDUCEDSVXFONT + + diff --git a/editeng/source/items/svxitems.src b/editeng/source/items/svxitems.src new file mode 100644 index 000000000000..d738a10a1ede --- /dev/null +++ b/editeng/source/items/svxitems.src @@ -0,0 +1,1027 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: svxitems.src,v $ + * $Revision: 1.83.212.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + // include ------------------------------------------------------------------ +#include <editeng/editrids.hrc> + // pragma ------------------------------------------------------------------- + + // Value-Strings ------------------------------------------------------------ +String RID_SVXITEMS_TRUE +{ + Text [ en-US ] = "True" ; +}; +String RID_SVXITEMS_FALSE +{ + Text [ en-US ] = "False" ; +}; + // enum SvxBreak ------------------------------------------------------------ +String RID_SVXITEMS_BREAK_NONE +{ + Text [ en-US ] = "No break" ; +}; +String RID_SVXITEMS_BREAK_COLUMN_BEFORE +{ + Text [ en-US ] = "Break before new column" ; +}; +String RID_SVXITEMS_BREAK_COLUMN_AFTER +{ + Text [ en-US ] = "Break after new column" ; +}; +String RID_SVXITEMS_BREAK_COLUMN_BOTH +{ + Text [ en-US ] = "Break before and after new column" ; +}; +String RID_SVXITEMS_BREAK_PAGE_BEFORE +{ + Text [ en-US ] = "Break before new page" ; +}; +String RID_SVXITEMS_BREAK_PAGE_AFTER +{ + Text [ en-US ] = "Break after new page" ; +}; +String RID_SVXITEMS_BREAK_PAGE_BOTH +{ + Text [ en-US ] = "Break before and after new page" ; +}; + // enum SvxShadowLocation --------------------------------------------------- +String RID_SVXITEMS_SHADOW_NONE +{ + Text [ en-US ] = "No Shadow" ; +}; +String RID_SVXITEMS_SHADOW_TOPLEFT +{ + Text [ en-US ] = "Shadow top left" ; +}; +String RID_SVXITEMS_SHADOW_TOPRIGHT +{ + Text [ en-US ] = "Shadow top right" ; +}; +String RID_SVXITEMS_SHADOW_BOTTOMLEFT +{ + Text [ en-US ] = "Shadow bottom left" ; +}; +String RID_SVXITEMS_SHADOW_BOTTOMRIGHT +{ + Text [ en-US ] = "Shadow bottom right" ; +}; + // enum ColorName ----------------------------------------------------------- +String RID_SVXITEMS_COLOR +{ + Text [ en-US ] = "Color " ; +}; +String RID_SVXITEMS_COLOR_BLACK +{ + Text [ en-US ] = "Black" ; +}; +String RID_SVXITEMS_COLOR_BLUE +{ + Text [ en-US ] = "Blue" ; +}; +String RID_SVXITEMS_COLOR_GREEN +{ + Text [ en-US ] = "Green" ; +}; +String RID_SVXITEMS_COLOR_CYAN +{ + Text [ en-US ] = "Cyan" ; +}; +String RID_SVXITEMS_COLOR_RED +{ + Text [ en-US ] = "Red" ; +}; +String RID_SVXITEMS_COLOR_MAGENTA +{ + Text [ en-US ] = "Magenta" ; +}; +String RID_SVXITEMS_COLOR_BROWN +{ + Text [ en-US ] = "Brown" ; +}; +String RID_SVXITEMS_COLOR_GRAY +{ + Text [ en-US ] = "Gray" ; +}; +String RID_SVXITEMS_COLOR_LIGHTGRAY +{ + Text [ en-US ] = "Light Gray" ; +}; +String RID_SVXITEMS_COLOR_LIGHTBLUE +{ + Text [ en-US ] = "Light Blue" ; +}; +String RID_SVXITEMS_COLOR_LIGHTGREEN +{ + Text [ en-US ] = "Light Green" ; +}; +String RID_SVXITEMS_COLOR_LIGHTCYAN +{ + Text [ en-US ] = "Light Cyan" ; +}; +String RID_SVXITEMS_COLOR_LIGHTRED +{ + Text [ en-US ] = "Light Red" ; +}; +String RID_SVXITEMS_COLOR_LIGHTMAGENTA +{ + Text [ en-US ] = "Light Magenta" ; +}; +String RID_SVXITEMS_COLOR_YELLOW +{ + Text [ en-US ] = "Yellow" ; +}; +String RID_SVXITEMS_COLOR_WHITE +{ + Text [ en-US ] = "White" ; +}; +String RID_SVXITEMS_COLOR_MENUBAR +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_MENUBARTEXT +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_POPUPMENU +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_POPUPMENUTEXT +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_WINDOWTEXT +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_WINDOWWORKSPACE +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_HIGHLIGHT +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_HIGHLIGHTTEXT +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_3DTEXT +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_3DFACE +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_3DLIGHT +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_3DSHADOW +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_SCROLLBAR +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_FIELD +{ + Text = "?" ; +}; +String RID_SVXITEMS_COLOR_FIELDTEXT +{ + Text = "?" ; +}; + // enum FontItalic ------------------------------------------------------- +String RID_SVXITEMS_ITALIC_NONE +{ + Text [ en-US ] = "Not Italic" ; +}; +String RID_SVXITEMS_ITALIC_OBLIQUE +{ + Text [ en-US ] = "Oblique italic" ; +}; +String RID_SVXITEMS_ITALIC_NORMAL +{ + Text [ en-US ] = "Italic" ; +}; + // enum FontWeight ------------------------------------------------------- +String RID_SVXITEMS_WEIGHT_DONTKNOW +{ + Text = "?" ; +}; +String RID_SVXITEMS_WEIGHT_THIN +{ + Text [ en-US ] = "thin" ; +}; +String RID_SVXITEMS_WEIGHT_ULTRALIGHT +{ + Text [ en-US ] = "ultra thin" ; +}; +String RID_SVXITEMS_WEIGHT_LIGHT +{ + Text [ en-US ] = "light" ; +}; +String RID_SVXITEMS_WEIGHT_SEMILIGHT +{ + Text [ en-US ] = "semi light" ; +}; +String RID_SVXITEMS_WEIGHT_NORMAL +{ + Text [ en-US ] = "normal" ; +}; +String RID_SVXITEMS_WEIGHT_MEDIUM +{ + Text [ en-US ] = "medium" ; +}; +String RID_SVXITEMS_WEIGHT_SEMIBOLD +{ + Text [ en-US ] = "semi bold" ; +}; +String RID_SVXITEMS_WEIGHT_BOLD +{ + Text [ en-US ] = "bold" ; +}; +String RID_SVXITEMS_WEIGHT_ULTRABOLD +{ + Text [ en-US ] = "ultra bold" ; +}; +String RID_SVXITEMS_WEIGHT_BLACK +{ + Text [ en-US ] = "black" ; +}; + // enum FontUnderline - used for underline ------------------------------ +String RID_SVXITEMS_UL_NONE +{ + Text [ en-US ] = "No underline" ; +}; +String RID_SVXITEMS_UL_SINGLE +{ + Text [ en-US ] = "Single underline" ; +}; +String RID_SVXITEMS_UL_DOUBLE +{ + Text [ en-US ] = "Double underline" ; +}; +String RID_SVXITEMS_UL_DOTTED +{ + Text [ en-US ] = "Dotted underline" ; +}; +String RID_SVXITEMS_UL_DONTKNOW +{ + Text [ en-US ] = "Underline"; +}; +String RID_SVXITEMS_UL_DASH +{ + Text [ en-US ] = "Underline (dashes)"; +}; +String RID_SVXITEMS_UL_LONGDASH +{ + Text [ en-US ] = "Underline (long dashes)"; +}; +String RID_SVXITEMS_UL_DASHDOT +{ + Text [ en-US ] = "Underline (dot dash)"; +}; +String RID_SVXITEMS_UL_DASHDOTDOT +{ + Text [ en-US ] = "Underline (dot dot dash)"; +}; +String RID_SVXITEMS_UL_SMALLWAVE +{ + Text [ en-US ] = "Underline (small wave)"; +}; +String RID_SVXITEMS_UL_WAVE +{ + Text [ en-US ] = "Underline (Wave)"; +}; +String RID_SVXITEMS_UL_DOUBLEWAVE +{ + Text [ en-US ] = "Underline (Double wave)"; +}; +String RID_SVXITEMS_UL_BOLD +{ + Text [ en-US ] = "Underlined (Bold)"; +}; +String RID_SVXITEMS_UL_BOLDDOTTED +{ + Text [ en-US ] = "Dotted underline (Bold)"; +}; +String RID_SVXITEMS_UL_BOLDDASH +{ + Text [ en-US ] = "Underline (Dash bold)"; +}; +String RID_SVXITEMS_UL_BOLDLONGDASH +{ + Text [ en-US ] = "Underline (long dash, bold)"; +}; +String RID_SVXITEMS_UL_BOLDDASHDOT +{ + Text [ en-US ] = "Underline (dot dash, bold)"; +}; +String RID_SVXITEMS_UL_BOLDDASHDOTDOT +{ + Text [ en-US ] = "Underline (dot dot dash, bold)"; +}; +String RID_SVXITEMS_UL_BOLDWAVE +{ + Text [ en-US ] = "Underline (wave, bold)"; +}; + // enum FontUnderline - used for overline ------------------------------- +String RID_SVXITEMS_OL_NONE +{ + Text [ en-US ] = "No overline" ; +}; +String RID_SVXITEMS_OL_SINGLE +{ + Text [ en-US ] = "Single overline" ; +}; +String RID_SVXITEMS_OL_DOUBLE +{ + Text [ en-US ] = "Double overline" ; +}; +String RID_SVXITEMS_OL_DOTTED +{ + Text [ en-US ] = "Dotted overline" ; +}; +String RID_SVXITEMS_OL_DONTKNOW +{ + Text [ en-US ] = "Overline"; +}; +String RID_SVXITEMS_OL_DASH +{ + Text [ en-US ] = "Overline (dashes)"; +}; +String RID_SVXITEMS_OL_LONGDASH +{ + Text [ en-US ] = "Overline (long dashes)"; +}; +String RID_SVXITEMS_OL_DASHDOT +{ + Text [ en-US ] = "Overline (dot dash)"; +}; +String RID_SVXITEMS_OL_DASHDOTDOT +{ + Text [ en-US ] = "Overline (dot dot dash)"; +}; +String RID_SVXITEMS_OL_SMALLWAVE +{ + Text [ en-US ] = "Overline (small wave)"; +}; +String RID_SVXITEMS_OL_WAVE +{ + Text [ en-US ] = "Overline (Wave)"; +}; +String RID_SVXITEMS_OL_DOUBLEWAVE +{ + Text [ en-US ] = "Overline (Double wave)"; +}; +String RID_SVXITEMS_OL_BOLD +{ + Text [ en-US ] = "Overlined (Bold)"; +}; +String RID_SVXITEMS_OL_BOLDDOTTED +{ + Text [ en-US ] = "Dotted overline (Bold)"; +}; +String RID_SVXITEMS_OL_BOLDDASH +{ + Text [ en-US ] = "Overline (Dash bold)"; +}; +String RID_SVXITEMS_OL_BOLDLONGDASH +{ + Text [ en-US ] = "Overline (long dash, bold)"; +}; +String RID_SVXITEMS_OL_BOLDDASHDOT +{ + Text [ en-US ] = "Overline (dot dash, bold)"; +}; +String RID_SVXITEMS_OL_BOLDDASHDOTDOT +{ + Text [ en-US ] = "Overline (dot dot dash, bold)"; +}; +String RID_SVXITEMS_OL_BOLDWAVE +{ + Text [ en-US ] = "Overline (wave, bold)"; +}; + // enum FontStrikeout ---------------------------------------------------- +String RID_SVXITEMS_STRIKEOUT_NONE +{ + Text [ en-US ] = "No strikethrough" ; +}; +String RID_SVXITEMS_STRIKEOUT_SINGLE +{ + Text [ en-US ] = "Single strikethrough" ; +}; +String RID_SVXITEMS_STRIKEOUT_DOUBLE +{ + Text [ en-US ] = "Double strikethrough" ; +}; +String RID_SVXITEMS_STRIKEOUT_BOLD +{ + Text [ en-US ] = "Bold strikethrough"; +}; +String RID_SVXITEMS_STRIKEOUT_SLASH +{ + Text [ en-US ] = "Strike through with slash"; +}; +String RID_SVXITEMS_STRIKEOUT_X +{ + Text [ en-US ] = "Strike through with Xes"; +}; + // enum CASEMAP ---------------------------------------------------------- +String RID_SVXITEMS_CASEMAP_NONE +{ + Text [ en-US ] = "None" ; +}; +String RID_SVXITEMS_CASEMAP_VERSALIEN +{ + Text [ en-US ] = "Caps" ; +}; +String RID_SVXITEMS_CASEMAP_GEMEINE +{ + Text [ en-US ] = "Lowercase" ; +}; +String RID_SVXITEMS_CASEMAP_TITEL +{ + Text [ en-US ] = "Title" ; +}; +String RID_SVXITEMS_CASEMAP_KAPITAELCHEN +{ + Text [ en-US ] = "Small caps" ; +}; + // enum ESCAPEMENT ------------------------------------------------------- +String RID_SVXITEMS_ESCAPEMENT_OFF +{ + Text [ en-US ] = "Normal position" ; +}; +String RID_SVXITEMS_ESCAPEMENT_SUPER +{ + Text [ en-US ] = "Superscript " ; +}; +String RID_SVXITEMS_ESCAPEMENT_SUB +{ + Text [ en-US ] = "Subscript " ; +}; +String RID_SVXITEMS_ESCAPEMENT_AUTO +{ + Text [ en-US ] = "automatic" ; +}; + // enum SvxAdjust ----------------------------------------------------------- +String RID_SVXITEMS_ADJUST_LEFT +{ + Text [ en-US ] = "Align left" ; +}; +String RID_SVXITEMS_ADJUST_RIGHT +{ + Text [ en-US ] = "Align right" ; +}; +String RID_SVXITEMS_ADJUST_BLOCK +{ + Text [ en-US ] = "Justify" ; +}; +String RID_SVXITEMS_ADJUST_CENTER +{ + Text [ en-US ] = "Centered" ; +}; +String RID_SVXITEMS_ADJUST_BLOCKLINE +{ + Text [ en-US ] = "Justify" ; +}; + // enum SvxTabAdjust -------------------------------------------------------- +String RID_SVXITEMS_TAB_DECIMAL_CHAR +{ + Text [ en-US ] = "Decimal Symbol:" ; +}; +String RID_SVXITEMS_TAB_FILL_CHAR +{ + Text [ en-US ] = "Fill character:" ; +}; +String RID_SVXITEMS_TAB_ADJUST_LEFT +{ + Text [ en-US ] = "Left" ; +}; +String RID_SVXITEMS_TAB_ADJUST_RIGHT +{ + Text [ en-US ] = "Right" ; +}; +String RID_SVXITEMS_TAB_ADJUST_DECIMAL +{ + Text [ en-US ] = "Decimal" ; +}; +String RID_SVXITEMS_TAB_ADJUST_CENTER +{ + Text [ en-US ] = "Centered" ; +}; +String RID_SVXITEMS_TAB_ADJUST_DEFAULT +{ + Text [ en-US ] = "Default" ; +}; +String RID_SINGLE_LINE0 +{ + Text [ en-US ] = "Single, fine lines" ; +}; +String RID_SINGLE_LINE1 +{ + Text [ en-US ] = "Single, thin" ; +}; +String RID_SINGLE_LINE2 +{ + Text [ en-US ] = "Single, thick" ; +}; +String RID_SINGLE_LINE3 +{ + Text [ en-US ] = "Single, very thick" ; +}; +String RID_SINGLE_LINE4 +{ + Text [ en-US ] = "Single, bold" ; +}; +String RID_DOUBLE_LINE0 +{ + Text [ en-US ] = "Double, fine lines, spacing: small" ; +}; +String RID_DOUBLE_LINE1 +{ + Text [ en-US ] = "Double, fine line, spacing: large" ; +}; +String RID_DOUBLE_LINE2 +{ + Text [ en-US ] = "Double, thin, spacing: small" ; +}; +String RID_DOUBLE_LINE3 +{ + Text [ en-US ] = "Double, thick, spacing: large" ; +}; +String RID_DOUBLE_LINE4 +{ + Text [ en-US ] = "Double, inside: fine lines, outside: thin, spacing: large" ; +}; +String RID_DOUBLE_LINE5 +{ + Text [ en-US ] = "Double, inside: fine lines, outside: thick, spacing: large" ; +}; +String RID_DOUBLE_LINE6 +{ + Text [ en-US ] = "Double, inside: fine lines, outside: very thick, spacing: large" ; +}; +String RID_DOUBLE_LINE7 +{ + Text [ en-US ] = "Double, inside: thin, outside: thick, spacing: large" ; +}; +String RID_DOUBLE_LINE8 +{ + Text [ en-US ] = "Double, inside: thick, outside: thin, spacing: small" ; +}; +String RID_DOUBLE_LINE9 +{ + Text [ en-US ] = "Double, inside: thick, outside: very thick, spacing: large" ; +}; +String RID_DOUBLE_LINE10 +{ + Text [ en-US ] = "Double, inside: very thick, outside: thick, Spacing: large" ; +}; +String RID_SVXITEMS_METRIC_MM +{ + Text = "mm" ; +}; +String RID_SVXITEMS_METRIC_CM +{ + Text = "cm" ; +}; +String RID_SVXITEMS_METRIC_INCH +{ + Text = "inch" ; +}; +String RID_SVXITEMS_METRIC_POINT +{ + Text = "pt" ; +}; +String RID_SVXITEMS_METRIC_TWIP +{ + Text = "twip" ; +}; +String RID_SVXITEMS_METRIC_PIXEL +{ + Text = "pixel" ; +}; + // GetValueText von BoolItems +String RID_SVXITEMS_SHADOWED_TRUE +{ + Text [ en-US ] = "Shadowed" ; +}; +String RID_SVXITEMS_SHADOWED_FALSE +{ + Text [ en-US ] = "Not Shadowed" ; +}; +String RID_SVXITEMS_BLINK_TRUE +{ + Text [ en-US ] = "Blinking" ; +}; +String RID_SVXITEMS_BLINK_FALSE +{ + Text [ en-US ] = "Not Blinking" ; +}; +String RID_SVXITEMS_AUTOKERN_TRUE +{ + Text [ en-US ] = "Pair Kerning" ; +}; +String RID_SVXITEMS_AUTOKERN_FALSE +{ + Text [ en-US ] = "No pair kerning" ; +}; +String RID_SVXITEMS_WORDLINE_TRUE +{ + Text [ en-US ] = "Individual words" ; +}; +String RID_SVXITEMS_WORDLINE_FALSE +{ + Text [ en-US ] = "Not Words Only" ; +}; +String RID_SVXITEMS_CONTOUR_TRUE +{ + Text [ en-US ] = "Outline" ; +}; +String RID_SVXITEMS_CONTOUR_FALSE +{ + Text [ en-US ] = "No Outline" ; +}; +String RID_SVXITEMS_NOLINEBREAK_TRUE +{ + Text = "?" ; +}; +String RID_SVXITEMS_NOLINEBREAK_FALSE +{ + Text = "?" ; +}; +String RID_SVXITEMS_NOHYPHEN_TRUE +{ + Text = "?" ; +}; +String RID_SVXITEMS_NOHYPHEN_FALSE +{ + Text = "?" ; +}; +String RID_SVXITEMS_PRINT_TRUE +{ + Text [ en-US ] = "Print" ; +}; +String RID_SVXITEMS_PRINT_FALSE +{ + Text [ en-US ] = "Don't print" ; +}; +String RID_SVXITEMS_OPAQUE_TRUE +{ + Text [ en-US ] = "Opaque" ; +}; +String RID_SVXITEMS_OPAQUE_FALSE +{ + Text [ en-US ] = "Not Opaque" ; +}; +String RID_SVXITEMS_FMTKEEP_TRUE +{ + Text [ en-US ] = "Keep with next paragraph" ; +}; +String RID_SVXITEMS_FMTKEEP_FALSE +{ + Text [ en-US ] = "Don't Keep Paragraphs Together" ; +}; +String RID_SVXITEMS_FMTSPLIT_TRUE +{ + Text [ en-US ] = "Split paragraph" ; +}; +String RID_SVXITEMS_FMTSPLIT_FALSE +{ + Text [ en-US ] = "Don't split paragraph" ; +}; +String RID_SVXITEMS_PROT_CONTENT_TRUE +{ + Text [ en-US ] = "Contents protected" ; +}; +String RID_SVXITEMS_PROT_CONTENT_FALSE +{ + Text [ en-US ] = "Contents not protected" ; +}; +String RID_SVXITEMS_PROT_SIZE_TRUE +{ + Text [ en-US ] = "Size protected" ; +}; +String RID_SVXITEMS_PROT_SIZE_FALSE +{ + Text [ en-US ] = "Size not protected" ; +}; +String RID_SVXITEMS_PROT_POS_TRUE +{ + Text [ en-US ] = "Position protected" ; +}; +String RID_SVXITEMS_PROT_POS_FALSE +{ + Text [ en-US ] = "Position not protected" ; +}; +String RID_SVXITEMS_TRANSPARENT_TRUE +{ + Text [ en-US ] = "Transparent" ; +}; +String RID_SVXITEMS_TRANSPARENT_FALSE +{ + Text [ en-US ] = "Not Transparent" ; +}; +String RID_SVXITEMS_HYPHEN_TRUE +{ + Text [ en-US ] = "Hyphenation" ; +}; +String RID_SVXITEMS_HYPHEN_FALSE +{ + Text [ en-US ] = "No hyphenation" ; +}; +String RID_SVXITEMS_PAGE_END_TRUE +{ + Text [ en-US ] = "Page End" ; +}; +String RID_SVXITEMS_PAGE_END_FALSE +{ + Text [ en-US ] = "No Page End" ; +}; +String RID_SVXITEMS_SIZE_WIDTH +{ + Text [ en-US ] = "Width: " ; +}; +String RID_SVXITEMS_SIZE_HEIGHT +{ + Text [ en-US ] = "Height: " ; +}; +String RID_SVXITEMS_LRSPACE_LEFT +{ + Text [ en-US ] = "Indent left " ; +}; +String RID_SVXITEMS_LRSPACE_FLINE +{ + Text [ en-US ] = "First Line " ; +}; +String RID_SVXITEMS_LRSPACE_RIGHT +{ + Text [ en-US ] = "Indent right " ; +}; +String RID_SVXITEMS_SHADOW_COMPLETE +{ + Text [ en-US ] = "Shadow: " ; +}; +String RID_SVXITEMS_BORDER_COMPLETE +{ + Text [ en-US ] = "Borders " ; +}; +String RID_SVXITEMS_BORDER_NONE +{ + Text [ en-US ] = "No border"; +}; +String RID_SVXITEMS_BORDER_TOP +{ + Text [ en-US ] = "top " ; +}; +String RID_SVXITEMS_BORDER_BOTTOM +{ + Text [ en-US ] = "bottom " ; +}; +String RID_SVXITEMS_BORDER_LEFT +{ + Text [ en-US ] = "left " ; +}; +String RID_SVXITEMS_BORDER_RIGHT +{ + Text [ en-US ] = "right " ; +}; +String RID_SVXITEMS_BORDER_DISTANCE +{ + Text [ en-US ] = "Spacing " ; +}; +String RID_SVXITEMS_ULSPACE_UPPER +{ + Text [ en-US ] = "From top " ; +}; +String RID_SVXITEMS_ULSPACE_LOWER +{ + Text [ en-US ] = "From bottom " ; +}; +String RID_SVXITEMS_LINES +{ + Text [ en-US ] = "%1 Lines" ; + Text [ x-comment ] = "pb: %1 == will be replaced by the number of lines"; +}; +String RID_SVXITEMS_WIDOWS_COMPLETE +{ + Text [ en-US ] = "Widow control" ; +}; +String RID_SVXITEMS_ORPHANS_COMPLETE +{ + Text [ en-US ] = "Orphan control" ; +}; +String RID_SVXITEMS_HYPHEN_MINLEAD +{ + Text [ en-US ] = "Characters at end of line" ; +}; +String RID_SVXITEMS_HYPHEN_MINTRAIL +{ + Text [ en-US ] = "Characters at beginning of line" ; +}; +String RID_SVXITEMS_HYPHEN_MAX +{ + Text [ en-US ] = "Hyphens" ; +}; +String RID_SVXITEMS_PAGEMODEL_COMPLETE +{ + Text [ en-US ] = "Page Style: " ; +}; +String RID_SVXITEMS_KERNING_COMPLETE +{ + Text [ en-US ] = "Kerning " ; +}; +String RID_SVXITEMS_KERNING_EXPANDED +{ + Text [ en-US ] = "locked " ; +}; +String RID_SVXITEMS_KERNING_CONDENSED +{ + Text [ en-US ] = "Condensed " ; +}; +String RID_SVXITEMS_GRAPHIC +{ + Text [ en-US ] = "Graphic" ; +}; +String RID_SVXITEMS_EMPHASIS_NONE_STYLE +{ + Text [ en-US ] = "none"; +}; +String RID_SVXITEMS_EMPHASIS_DOT_STYLE +{ + Text [ en-US ] = "Dots "; +}; +String RID_SVXITEMS_EMPHASIS_CIRCLE_STYLE +{ + Text [ en-US ] = "Circle "; +}; +String RID_SVXITEMS_EMPHASIS_DISC_STYLE +{ +// ??? disc == filled ring + Text [ en-US ] = "Filled circle "; +}; +String RID_SVXITEMS_EMPHASIS_ACCENT_STYLE +{ + Text [ en-US ] = "Accent "; +}; +String RID_SVXITEMS_EMPHASIS_ABOVE_POS +{ + Text [ en-US ] = "Above"; +}; +String RID_SVXITEMS_EMPHASIS_BELOW_POS +{ + Text [ en-US ] = "Below"; +}; +String RID_SVXITEMS_TWOLINES_OFF +{ + Text [ en-US ] = "Double-lined off"; +}; +String RID_SVXITEMS_TWOLINES +{ + Text [ en-US ] = "Double-lined"; +}; +String RID_SVXITEMS_SCRPTSPC_OFF +{ + Text [ en-US ] = "No automatic character spacing"; +}; +String RID_SVXITEMS_SCRPTSPC_ON +{ + Text [ en-US ] = "No automatic character spacing"; +}; +String RID_SVXITEMS_HNGPNCT_OFF +{ + Text [ en-US ] = "No hanging punctuation at line end"; +}; +String RID_SVXITEMS_HNGPNCT_ON +{ + Text [ en-US ] = "Hanging punctuation at line end"; +}; +String RID_SVXITEMS_FORBIDDEN_RULE_OFF +{ + Text [ en-US ] = "Apply list of forbidden characters to beginning and end of lines"; +}; +String RID_SVXITEMS_FORBIDDEN_RULE_ON +{ + Text [ en-US ] = "Don't apply list of forbidden characters to beginning and end of lines"; +}; +String RID_SVXITEMS_CHARROTATE_OFF +{ + Text [ en-US ] = "No rotated characters"; +}; +String RID_SVXITEMS_CHARROTATE +{ + Text [ en-US ] = "Character rotated by $(ARG1)°"; +}; +String RID_SVXITEMS_CHARROTATE_FITLINE +{ + Text [ en-US ] = "Fit to line"; +}; +String RID_SVXITEMS_CHARSCALE +{ + Text [ en-US ] = "Characters scaled $(ARG1)%"; +}; +String RID_SVXITEMS_CHARSCALE_OFF +{ + Text [ en-US ] = "No scaled characters"; +}; +String RID_SVXITEMS_RELIEF_NONE +{ + Text [ en-US ] = "No relief"; +}; +String RID_SVXITEMS_RELIEF_EMBOSSED +{ + Text [ en-US ] = "Relief"; +}; +String RID_SVXITEMS_RELIEF_ENGRAVED +{ + Text [ en-US ] = "Engraved"; +}; +String RID_SVXITEMS_PARAVERTALIGN_AUTO +{ + Text [ en-US ] = "Automatic text alignment"; +}; +String RID_SVXITEMS_PARAVERTALIGN_BASELINE +{ + Text [ en-US ] = "Text aligned to base line"; +}; +String RID_SVXITEMS_PARAVERTALIGN_TOP +{ + Text [ en-US ] = "Text aligned top"; +}; +String RID_SVXITEMS_PARAVERTALIGN_CENTER +{ + Text [ en-US ] = "Text aligned middle"; +}; +String RID_SVXITEMS_PARAVERTALIGN_BOTTOM +{ + Text [ en-US ] = "Text aligned bottom"; +}; +String RID_SVXITEMS_FRMDIR_HORI_LEFT_TOP +{ + Text [ en-US ] = "Text direction left-to-right (horizontal)"; +}; +String RID_SVXITEMS_FRMDIR_HORI_RIGHT_TOP +{ + Text [ en-US ] = "Text direction right-to-left (horizontal)"; +}; +String RID_SVXITEMS_FRMDIR_VERT_TOP_RIGHT +{ + Text [ en-US ] = "Text direction right-to-left (vertical)"; +}; +String RID_SVXITEMS_FRMDIR_VERT_TOP_LEFT +{ + Text [ en-US ] = "Text direction left-to-right (vertical)"; +}; +String RID_SVXITEMS_FRMDIR_ENVIRONMENT +{ + Text [ en-US ] = "Use superordinate object text direction setting"; +}; +String RID_SVXITEMS_PARASNAPTOGRID_ON +{ + Text[ en-US ] = "Paragraph snaps to text grid (if active)"; +}; +String RID_SVXITEMS_PARASNAPTOGRID_OFF +{ + Text[ en-US ] = "Paragraph does not snap to text grid"; +}; +String RID_SVXITEMS_CHARHIDDEN_FALSE +{ + Text [ en-US ] = "Not hidden"; +}; +String RID_SVXITEMS_CHARHIDDEN_TRUE +{ + Text [ en-US ] = "Hidden"; +}; +// ********************************************************************** EOF + diff --git a/editeng/source/items/textitem.cxx b/editeng/source/items/textitem.cxx new file mode 100644 index 000000000000..a8dec28d69cd --- /dev/null +++ b/editeng/source/items/textitem.cxx @@ -0,0 +1,3846 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: textitem.cxx,v $ + * $Revision: 1.74.86.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +// include --------------------------------------------------------------- +#include <com/sun/star/style/CaseMap.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/frame/status/FontHeight.hpp> +#include <vcl/bitmapex.hxx> +#include <tools/stream.hxx> +#include <toolkit/unohlp.hxx> +#include <math.h> +#include <rtl/math.hxx> +#include <unotools/fontdefs.hxx> +#include <vcl/outdev.hxx> +#include <editeng/eeitem.hxx> +#include <svtools/unitconv.hxx> + +#define GLOBALOVERFLOW3 + +#include <svl/memberid.hrc> +#include <editeng/editids.hrc> +#include <editeng/editrids.hrc> +#include <vcl/vclenum.hxx> +#include <tools/bigint.hxx> +#include <tools/tenccvt.hxx> + +#include <rtl/ustring.hxx> +#include <i18npool/mslangid.hxx> +#include <svl/itemset.hxx> + +#include <svtools/langtab.hxx> +#include <svl/itempool.hxx> +#include <svtools/ctrltool.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/style/CaseMap.hpp> +#include <com/sun/star/awt/SimpleFontMetric.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/awt/CharSet.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/awt/FontWidth.hpp> +#include <com/sun/star/awt/XFont.hpp> +#include <com/sun/star/awt/FontType.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/awt/FontStrikeout.hpp> +#include <com/sun/star/awt/FontFamily.hpp> +#include <com/sun/star/awt/FontPitch.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/text/FontEmphasis.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <editeng/memberids.hrc> +#include <editeng/flstitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fwdtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/prszitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/nlbkitem.hxx> +#include <editeng/nhypitem.hxx> +#include <editeng/lcolitem.hxx> +#include <editeng/blnkitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/twolinesitem.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/charrotateitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/itemtype.hxx> +#include <editeng/eerdll.hxx> + +// #90477# +#include <tools/tenccvt.hxx> + +#define STORE_UNICODE_MAGIC_MARKER 0xFE331188 + +using namespace ::rtl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; + +// Konvertierung fuer UNO +#define TWIP_TO_MM100(TWIP) ((TWIP) >= 0 ? (((TWIP)*127L+36L)/72L) : (((TWIP)*127L-36L)/72L)) +#define MM100_TO_TWIP(MM100) ((MM100) >= 0 ? (((MM100)*72L+63L)/127L) : (((MM100)*72L-63L)/127L)) +#define TWIP_TO_MM100_UNSIGNED(TWIP) ((((TWIP)*127L+36L)/72L)) +#define MM100_TO_TWIP_UNSIGNED(MM100) ((((MM100)*72L+63L)/127L)) + +BOOL SvxFontItem::bEnableStoreUnicodeNames = FALSE; + +// STATIC DATA ----------------------------------------------------------- + +// ----------------------------------------------------------------------- + +TYPEINIT1(SvxFontListItem, SfxPoolItem); +TYPEINIT1_FACTORY(SvxFontItem, SfxPoolItem, new SvxFontItem(0)); +TYPEINIT1_FACTORY(SvxPostureItem, SfxEnumItem, new SvxPostureItem(ITALIC_NONE, 0)); +TYPEINIT1_FACTORY(SvxWeightItem, SfxEnumItem, new SvxWeightItem(WEIGHT_NORMAL, 0)); +TYPEINIT1_FACTORY(SvxFontHeightItem, SfxPoolItem, new SvxFontHeightItem(240, 100, 0)); +TYPEINIT1_FACTORY(SvxFontWidthItem, SfxPoolItem, new SvxFontWidthItem(0, 100, 0)); +TYPEINIT1_FACTORY(SvxTextLineItem, SfxEnumItem, new SvxTextLineItem(UNDERLINE_NONE, 0)); +TYPEINIT1_FACTORY(SvxUnderlineItem, SfxEnumItem, new SvxUnderlineItem(UNDERLINE_NONE, 0)); +TYPEINIT1_FACTORY(SvxOverlineItem, SfxEnumItem, new SvxOverlineItem(UNDERLINE_NONE, 0)); +TYPEINIT1_FACTORY(SvxCrossedOutItem, SfxEnumItem, new SvxCrossedOutItem(STRIKEOUT_NONE, 0)); +TYPEINIT1_FACTORY(SvxShadowedItem, SfxBoolItem, new SvxShadowedItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxAutoKernItem, SfxBoolItem, new SvxAutoKernItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxWordLineModeItem, SfxBoolItem, new SvxWordLineModeItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxContourItem, SfxBoolItem, new SvxContourItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxPropSizeItem, SfxUInt16Item, new SvxPropSizeItem(100, 0)); +TYPEINIT1_FACTORY(SvxColorItem, SfxPoolItem, new SvxColorItem(0)); +TYPEINIT1_FACTORY(SvxCharSetColorItem, SvxColorItem, new SvxCharSetColorItem(0)); +TYPEINIT1_FACTORY(SvxKerningItem, SfxInt16Item, new SvxKerningItem(0, 0)); +TYPEINIT1_FACTORY(SvxCaseMapItem, SfxEnumItem, new SvxCaseMapItem(SVX_CASEMAP_NOT_MAPPED, 0)); +TYPEINIT1_FACTORY(SvxEscapementItem, SfxPoolItem, new SvxEscapementItem(0)); +TYPEINIT1_FACTORY(SvxLanguageItem, SfxEnumItem, new SvxLanguageItem(LANGUAGE_GERMAN, 0)); +TYPEINIT1_FACTORY(SvxNoLinebreakItem, SfxBoolItem, new SvxNoLinebreakItem(sal_True, 0)); +TYPEINIT1_FACTORY(SvxNoHyphenItem, SfxBoolItem, new SvxNoHyphenItem(sal_True, 0)); +TYPEINIT1_FACTORY(SvxLineColorItem, SvxColorItem, new SvxLineColorItem(0)); +TYPEINIT1_FACTORY(SvxBlinkItem, SfxBoolItem, new SvxBlinkItem(sal_False, 0)); +TYPEINIT1_FACTORY(SvxEmphasisMarkItem, SfxUInt16Item, new SvxEmphasisMarkItem(EMPHASISMARK_NONE, 0)); +TYPEINIT1_FACTORY(SvxTwoLinesItem, SfxPoolItem, new SvxTwoLinesItem(sal_True, 0, 0, 0)); +TYPEINIT1_FACTORY(SvxScriptTypeItem, SfxUInt16Item, new SvxScriptTypeItem); +TYPEINIT1_FACTORY(SvxCharRotateItem, SfxUInt16Item, new SvxCharRotateItem(0, sal_False, 0)); +TYPEINIT1_FACTORY(SvxCharScaleWidthItem, SfxUInt16Item, new SvxCharScaleWidthItem(100, 0)); +TYPEINIT1_FACTORY(SvxCharReliefItem, SfxEnumItem, new SvxCharReliefItem(RELIEF_NONE, 0)); + + +TYPEINIT1(SvxScriptSetItem, SfxSetItem ); + + +// class SvxFontListItem ------------------------------------------------- + +SvxFontListItem::SvxFontListItem( const FontList* pFontLst, + const USHORT nId ) : + SfxPoolItem( nId ), + pFontList( pFontLst ) +{ + if ( pFontList ) + { + sal_Int32 nCount = pFontList->GetFontNameCount(); + aFontNameSeq.realloc( nCount ); + + for ( USHORT i = 0; i < nCount; i++ ) + aFontNameSeq[i] = pFontList->GetFontName(i).GetName(); + } +} + +// ----------------------------------------------------------------------- + +SvxFontListItem::SvxFontListItem( const SvxFontListItem& rItem ) : + + SfxPoolItem( rItem ), + pFontList( rItem.GetFontList() ), + aFontNameSeq( rItem.aFontNameSeq ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFontListItem::Clone( SfxItemPool* ) const +{ + return new SvxFontListItem( *this ); +} + +// ----------------------------------------------------------------------- + +int SvxFontListItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return( pFontList == ((SvxFontListItem&)rAttr).pFontList ); +} + +sal_Bool SvxFontListItem::QueryValue( com::sun::star::uno::Any& rVal, BYTE /*nMemberId*/ ) const +{ + rVal <<= aFontNameSeq; + return sal_True; +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxFontListItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxFontItem ----------------------------------------------------- + +SvxFontItem::SvxFontItem( const USHORT nId ) : + SfxPoolItem( nId ) +{ + eFamily = FAMILY_SWISS; + ePitch = PITCH_VARIABLE; + eTextEncoding = RTL_TEXTENCODING_DONTKNOW; +} + +// ----------------------------------------------------------------------- + +SvxFontItem::SvxFontItem( const FontFamily eFam, const XubString& aName, + const XubString& aStName, const FontPitch eFontPitch, + const rtl_TextEncoding eFontTextEncoding, const USHORT nId ) : + + SfxPoolItem( nId ), + + aFamilyName(aName), + aStyleName(aStName) +{ + eFamily = eFam; + ePitch = eFontPitch; + eTextEncoding = eFontTextEncoding; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxFontItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case 0: + { + com::sun::star::awt::FontDescriptor aFontDescriptor; + aFontDescriptor.Name = aFamilyName.GetBuffer(); + aFontDescriptor.StyleName = aStyleName.GetBuffer(); + aFontDescriptor.Family = (sal_Int16)(eFamily); + aFontDescriptor.CharSet = (sal_Int16)(eTextEncoding); + aFontDescriptor.Pitch = (sal_Int16)(ePitch); + rVal <<= aFontDescriptor; + } + break; + case MID_FONT_FAMILY_NAME : + rVal <<= OUString(aFamilyName.GetBuffer()); + break; + case MID_FONT_STYLE_NAME: + rVal <<= OUString(aStyleName.GetBuffer()); + break; + case MID_FONT_FAMILY : rVal <<= (sal_Int16)(eFamily); break; + case MID_FONT_CHAR_SET : rVal <<= (sal_Int16)(eTextEncoding); break; + case MID_FONT_PITCH : rVal <<= (sal_Int16)(ePitch); break; + } + return sal_True; +} +// ----------------------------------------------------------------------- +sal_Bool SvxFontItem::PutValue( const uno::Any& rVal, BYTE nMemberId) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case 0: + { + com::sun::star::awt::FontDescriptor aFontDescriptor; + if ( !( rVal >>= aFontDescriptor )) + return sal_False; + + aFamilyName = aFontDescriptor.Name; + aStyleName = aFontDescriptor.StyleName; + eFamily = (FontFamily)aFontDescriptor.Family; + eTextEncoding = (rtl_TextEncoding)aFontDescriptor.CharSet; + ePitch = (FontPitch)aFontDescriptor.Pitch; + } + break; + case MID_FONT_FAMILY_NAME : + { + OUString aStr; + if(!(rVal >>= aStr)) + return sal_False; + aFamilyName = aStr.getStr(); + } + break; + case MID_FONT_STYLE_NAME: + { + OUString aStr; + if(!(rVal >>= aStr)) + return sal_False; + aStyleName = aStr.getStr(); + } + break; + case MID_FONT_FAMILY : + { + sal_Int16 nFamily = sal_Int16(); + if(!(rVal >>= nFamily)) + return sal_False; + eFamily = (FontFamily)nFamily; + } + break; + case MID_FONT_CHAR_SET : + { + sal_Int16 nSet = sal_Int16(); + if(!(rVal >>= nSet)) + return sal_False; + eTextEncoding = (rtl_TextEncoding)nSet; + } + break; + case MID_FONT_PITCH : + { + sal_Int16 nPitch = sal_Int16(); + if(!(rVal >>= nPitch)) + return sal_False; + ePitch = (FontPitch)nPitch; + } + break; + } + return sal_True; +} + +// ----------------------------------------------------------------------- + +int SvxFontItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + const SvxFontItem& rItem = (const SvxFontItem&)rAttr; + + int bRet = ( eFamily == rItem.eFamily && + aFamilyName == rItem.aFamilyName && + aStyleName == rItem.aStyleName ); + + if ( bRet ) + { + if ( ePitch != rItem.ePitch || eTextEncoding != rItem.eTextEncoding ) + { + bRet = sal_False; + DBG_WARNING( "FontItem::operator==(): nur Pitch oder rtl_TextEncoding unterschiedlich" ); + } + } + return bRet; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFontItem::Clone( SfxItemPool * ) const +{ + return new SvxFontItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxFontItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + BOOL bToBats = + GetFamilyName().EqualsAscii( "StarSymbol", 0, sizeof("StarSymbol")-1 ) || + GetFamilyName().EqualsAscii( "OpenSymbol", 0, sizeof("OpenSymbol")-1 ); + + // #90477# rStrm << (BYTE) GetFamily() + // << (BYTE) GetPitch() + // << (BYTE)(bToBats ? RTL_TEXTENCODING_SYMBOL : GetStoreCharSet( GetCharSet(), (USHORT)rStrm.GetVersion() ) ); + rStrm << (BYTE) GetFamily() << (BYTE) GetPitch() + << (BYTE)(bToBats ? RTL_TEXTENCODING_SYMBOL : GetSOStoreTextEncoding(GetCharSet(), (sal_uInt16)rStrm.GetVersion())); + + String aStoreFamilyName( GetFamilyName() ); + if( bToBats ) + aStoreFamilyName = String( "StarBats", sizeof("StarBats")-1, RTL_TEXTENCODING_ASCII_US ); + rStrm.WriteByteString(aStoreFamilyName); + rStrm.WriteByteString(GetStyleName()); + + // #96441# Kach for EditEngine, only set while creating clipboard stream. + if ( bEnableStoreUnicodeNames ) + { + sal_uInt32 nMagic = STORE_UNICODE_MAGIC_MARKER; + rStrm << nMagic; + rStrm.WriteByteString( aStoreFamilyName, RTL_TEXTENCODING_UNICODE ); + rStrm.WriteByteString( GetStyleName(), RTL_TEXTENCODING_UNICODE ); + } + + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFontItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE _eFamily, eFontPitch, eFontTextEncoding; + String aName, aStyle; + rStrm >> _eFamily; + rStrm >> eFontPitch; + rStrm >> eFontTextEncoding; + + // UNICODE: rStrm >> aName; + rStrm.ReadByteString(aName); + + // UNICODE: rStrm >> aStyle; + rStrm.ReadByteString(aStyle); + + // Task 91008/90471: set the "correct" textencoding + eFontTextEncoding = (BYTE)GetSOLoadTextEncoding( eFontTextEncoding, (USHORT)rStrm.GetVersion() ); + + // irgendwann wandelte sich der StarBats vom ANSI- zum SYMBOL-Font + if ( RTL_TEXTENCODING_SYMBOL != eFontTextEncoding && aName.EqualsAscii("StarBats") ) + eFontTextEncoding = RTL_TEXTENCODING_SYMBOL; + + // Check if we have stored unicode + sal_Size nStreamPos = rStrm.Tell(); + sal_uInt32 nMagic = STORE_UNICODE_MAGIC_MARKER; + rStrm >> nMagic; + if ( nMagic == STORE_UNICODE_MAGIC_MARKER ) + { + rStrm.ReadByteString( aName, RTL_TEXTENCODING_UNICODE ); + rStrm.ReadByteString( aStyle, RTL_TEXTENCODING_UNICODE ); + } + else + { + rStrm.Seek( nStreamPos ); + } + + + + return new SvxFontItem( (FontFamily)_eFamily, aName, aStyle, + (FontPitch)eFontPitch, (rtl_TextEncoding)eFontTextEncoding, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxFontItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = aFamilyName; + return ePres; + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +//------------------------------------------------------------------------ + +void SvxFontItem::EnableStoreUnicodeNames( BOOL bEnable ) +{ + bEnableStoreUnicodeNames = bEnable; +} + +// class SvxPostureItem -------------------------------------------------- + +SvxPostureItem::SvxPostureItem( const FontItalic ePosture, const USHORT nId ) : + SfxEnumItem( nId, (USHORT)ePosture ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxPostureItem::Clone( SfxItemPool * ) const +{ + return new SvxPostureItem( *this ); +} + +// ----------------------------------------------------------------------- + +USHORT SvxPostureItem::GetValueCount() const +{ + return ITALIC_NORMAL + 1; // auch ITALIC_NONE geh"ort dazu +} + +// ----------------------------------------------------------------------- + +SvStream& SvxPostureItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (BYTE)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxPostureItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE nPosture; + rStrm >> nPosture; + return new SvxPostureItem( (const FontItalic)nPosture, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxPostureItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetValueTextByPos( GetValue() ); + return ePres; + default: ;//prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +XubString SvxPostureItem::GetValueTextByPos( USHORT nPos ) const +{ + DBG_ASSERT( nPos <= (USHORT)ITALIC_NORMAL, "enum overflow!" ); + + XubString sTxt; + FontItalic eItalic = (FontItalic)nPos; + USHORT nId = 0; + + switch ( eItalic ) + { + case ITALIC_NONE: nId = RID_SVXITEMS_ITALIC_NONE; break; + case ITALIC_OBLIQUE: nId = RID_SVXITEMS_ITALIC_OBLIQUE; break; + case ITALIC_NORMAL: nId = RID_SVXITEMS_ITALIC_NORMAL; break; + default: ;//prevent warning + } + + if ( nId ) + sTxt = EditResId( nId ); + return sTxt; +} + + +/*-----------------13.03.98 14:28------------------- + +--------------------------------------------------*/ +sal_Bool SvxPostureItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case MID_ITALIC: + rVal = Bool2Any(GetBoolValue()); + break; + case MID_POSTURE: + rVal <<= (awt::FontSlant)GetValue(); // Werte von awt::FontSlant und FontItalic sind gleich + break; + } + return sal_True; +} +/*-----------------13.03.98 14:28------------------- + +--------------------------------------------------*/ +sal_Bool SvxPostureItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case MID_ITALIC: + SetBoolValue(Any2Bool(rVal)); + break; + case MID_POSTURE: + { + awt::FontSlant eSlant; + if(!(rVal >>= eSlant)) + { + sal_Int32 nValue = 0; + if(!(rVal >>= nValue)) + return sal_False; + + eSlant = (awt::FontSlant)nValue; + } + SetValue((USHORT)eSlant); + } + } + return sal_True; +} +// ----------------------------------------------------------------------- + +int SvxPostureItem::HasBoolValue() const +{ + return sal_True; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxPostureItem::GetBoolValue() const +{ + return ( (FontItalic)GetValue() >= ITALIC_OBLIQUE ); +} + +// ----------------------------------------------------------------------- + +void SvxPostureItem::SetBoolValue( sal_Bool bVal ) +{ + SetValue( (USHORT)(bVal ? ITALIC_NORMAL : ITALIC_NONE) ); +} + +// class SvxWeightItem --------------------------------------------------- + +SvxWeightItem::SvxWeightItem( const FontWeight eWght, const USHORT nId ) : + SfxEnumItem( nId, (USHORT)eWght ) +{ +} + + + +// ----------------------------------------------------------------------- + +int SvxWeightItem::HasBoolValue() const +{ + return sal_True; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxWeightItem::GetBoolValue() const +{ + return (FontWeight)GetValue() >= WEIGHT_BOLD; +} + +// ----------------------------------------------------------------------- + +void SvxWeightItem::SetBoolValue( sal_Bool bVal ) +{ + SetValue( (USHORT)(bVal ? WEIGHT_BOLD : WEIGHT_NORMAL) ); +} + +// ----------------------------------------------------------------------- + +USHORT SvxWeightItem::GetValueCount() const +{ + return WEIGHT_BLACK; // WEIGHT_DONTKNOW geh"ort nicht dazu +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxWeightItem::Clone( SfxItemPool * ) const +{ + return new SvxWeightItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxWeightItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (BYTE)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxWeightItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE nWeight; + rStrm >> nWeight; + return new SvxWeightItem( (FontWeight)nWeight, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxWeightItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetValueTextByPos( GetValue() ); + return ePres; + default: ;//prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +XubString SvxWeightItem::GetValueTextByPos( USHORT nPos ) const +{ + DBG_ASSERT( nPos <= (USHORT)WEIGHT_BLACK, "enum overflow!" ); + return EE_RESSTR( RID_SVXITEMS_WEIGHT_BEGIN + nPos ); +} + +/*-----------------13.03.98 14:18------------------- + +--------------------------------------------------*/ +sal_Bool SvxWeightItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case MID_BOLD : + rVal = Bool2Any(GetBoolValue()); + break; + case MID_WEIGHT: + { + rVal <<= (float)( VCLUnoHelper::ConvertFontWeight( (FontWeight)GetValue() ) ); + } + break; + } + return sal_True; +} +/*-----------------13.03.98 14:18------------------- + +--------------------------------------------------*/ +sal_Bool SvxWeightItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case MID_BOLD : + SetBoolValue(Any2Bool(rVal)); + break; + case MID_WEIGHT: + { + double fValue = 0; + if(!(rVal >>= fValue)) + { + sal_Int32 nValue = 0; + if(!(rVal >>= nValue)) + return sal_False; + fValue = (float)nValue; + } + SetValue( (USHORT)VCLUnoHelper::ConvertFontWeight((float)fValue) ); + } + break; + } + return sal_True; +} + +// class SvxFontHeightItem ----------------------------------------------- + +SvxFontHeightItem::SvxFontHeightItem( const ULONG nSz, + const USHORT nPrp, + const USHORT nId ) : + SfxPoolItem( nId ) +{ + SetHeight( nSz,nPrp ); // mit den Prozenten rechnen +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFontHeightItem::Clone( SfxItemPool * ) const +{ + return new SvxFontHeightItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxFontHeightItem::Store( SvStream& rStrm , USHORT nItemVersion ) const +{ + rStrm << (USHORT)GetHeight(); + + if( FONTHEIGHT_UNIT_VERSION <= nItemVersion ) + rStrm << GetProp() << (USHORT)GetPropUnit(); + else + { + // JP 30.06.98: beim Export in alte Versionen geht die relative + // Angabe verloren, wenn es keine Prozentuale ist + USHORT _nProp = GetProp(); + if( SFX_MAPUNIT_RELATIVE != GetPropUnit() ) + _nProp = 100; + rStrm << _nProp; + } + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFontHeightItem::Create( SvStream& rStrm, + USHORT nVersion ) const +{ + USHORT nsize, nprop = 0, nPropUnit = SFX_MAPUNIT_RELATIVE; + + rStrm >> nsize; + + if( FONTHEIGHT_16_VERSION <= nVersion ) + rStrm >> nprop; + else + { + BYTE nP; + rStrm >> nP; + nprop = (USHORT)nP; + } + + if( FONTHEIGHT_UNIT_VERSION <= nVersion ) + rStrm >> nPropUnit; + + SvxFontHeightItem* pItem = new SvxFontHeightItem( nsize, 100, Which() ); + pItem->SetProp( nprop, (SfxMapUnit)nPropUnit ); + return pItem; +} + +// ----------------------------------------------------------------------- + +int SvxFontHeightItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" ); + return GetHeight() == ((SvxFontHeightItem&)rItem).GetHeight() && + GetProp() == ((SvxFontHeightItem&)rItem).GetProp() && + GetPropUnit() == ((SvxFontHeightItem&)rItem).GetPropUnit(); +} + +/*-----------------13.03.98 14:53------------------- + +--------------------------------------------------*/ +sal_Bool SvxFontHeightItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + // In StarOne sind im uno::Any immer 1/100mm. Ueber die MemberId wird + // gesteuert, ob der Wert im Item 1/100mm oder Twips sind. + + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case 0: + { + ::com::sun::star::frame::status::FontHeight aFontHeight; + + // Point (also Twips) sind gefragt, + // also umrechnen, wenn CONVERT_TWIPS nicht gesetzt ist + if( bConvert ) + { + long nTwips = bConvert ? nHeight : MM100_TO_TWIP_UNSIGNED(nHeight); + aFontHeight.Height = (float)( nTwips / 20.0 ); + } + else + { + double fPoints = MM100_TO_TWIP_UNSIGNED(nHeight) / 20.0; + float fRoundPoints = + static_cast<float>(::rtl::math::round(fPoints, 1)); + aFontHeight.Height = fRoundPoints; + } + + aFontHeight.Prop = (sal_Int16)(SFX_MAPUNIT_RELATIVE == ePropUnit ? nProp : 100); + + float fRet = (float)(short)nProp; + switch( ePropUnit ) + { + case SFX_MAPUNIT_RELATIVE: + fRet = 0.; + break; + case SFX_MAPUNIT_100TH_MM: + fRet = MM100_TO_TWIP(fRet); + fRet /= 20.; + break; + case SFX_MAPUNIT_POINT: + + break; + case SFX_MAPUNIT_TWIP: + fRet /= 20.; + break; + default: ;//prevent warning + } + aFontHeight.Diff = fRet; + rVal <<= aFontHeight; + } + break; + case MID_FONTHEIGHT: + { + // Point (also Twips) sind gefragt, + // also umrechnen, wenn CONVERT_TWIPS nicht gesetzt ist + if( bConvert ) + { + long nTwips = bConvert ? nHeight : MM100_TO_TWIP_UNSIGNED(nHeight); + rVal <<= (float)( nTwips / 20.0 ); + } + else + { + double fPoints = MM100_TO_TWIP_UNSIGNED(nHeight) / 20.0; + float fRoundPoints = + static_cast<float>(::rtl::math::round(fPoints, 1)); + rVal <<= fRoundPoints; + } + } + break; + case MID_FONTHEIGHT_PROP: + rVal <<= (sal_Int16)(SFX_MAPUNIT_RELATIVE == ePropUnit ? nProp : 100); + break; + case MID_FONTHEIGHT_DIFF: + { + float fRet = (float)(short)nProp; + switch( ePropUnit ) + { + case SFX_MAPUNIT_RELATIVE: + fRet = 0.; + break; + case SFX_MAPUNIT_100TH_MM: + fRet = MM100_TO_TWIP(fRet); + fRet /= 20.; + break; + case SFX_MAPUNIT_POINT: + + break; + case SFX_MAPUNIT_TWIP: + fRet /= 20.; + break; + default: ;//prevent warning + } + rVal <<= fRet; + } + break; + } + return sal_True; +} +/* -----------------01.07.98 13:43------------------- + * Relative Abweichung aus der Hoehe herausrechnen + * --------------------------------------------------*/ +sal_uInt32 lcl_GetRealHeight_Impl(sal_uInt32 nHeight, sal_uInt16 nProp, SfxMapUnit eProp, sal_Bool bCoreInTwip) +{ + sal_uInt32 nRet = nHeight; + short nDiff = 0; + switch( eProp ) + { + case SFX_MAPUNIT_RELATIVE: + nRet *= 100; + nRet /= nProp; + break; + case SFX_MAPUNIT_POINT: + { + short nTemp = (short)nProp; + nDiff = nTemp * 20; + if(!bCoreInTwip) + nDiff = (short)TWIP_TO_MM100((long)(nDiff)); + } + break; + case SFX_MAPUNIT_100TH_MM: + //dann ist die Core doch wohl auch in 1/100 mm + nDiff = (short)nProp; + break; + case SFX_MAPUNIT_TWIP: + // hier doch sicher TWIP + nDiff = ((short)nProp); + break; + default: ;//prevent warning + } + nRet -= nDiff; + + return nRet; +} + +/*-----------------13.03.98 14:53------------------- + +--------------------------------------------------*/ +sal_Bool SvxFontHeightItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ + sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case 0: + { + ::com::sun::star::frame::status::FontHeight aFontHeight; + if ( rVal >>= aFontHeight ) + { + // Height + ePropUnit = SFX_MAPUNIT_RELATIVE; + nProp = 100; + double fPoint = aFontHeight.Height; + if( fPoint < 0. || fPoint > 10000. ) + return sal_False; + + nHeight = (long)( fPoint * 20.0 + 0.5 ); // Twips + if (!bConvert) + nHeight = TWIP_TO_MM100_UNSIGNED(nHeight); // umrechnen, wenn das Item 1/100mm enthaelt + + nProp = aFontHeight.Prop; + } + else + return sal_False; + } + break; + case MID_FONTHEIGHT: + { + ePropUnit = SFX_MAPUNIT_RELATIVE; + nProp = 100; + double fPoint = 0; + if(!(rVal >>= fPoint)) + { + sal_Int32 nValue = 0; + if(!(rVal >>= nValue)) + return sal_False; + fPoint = (float)nValue; + } + if(fPoint < 0. || fPoint > 10000.) + return sal_False; + + nHeight = (long)( fPoint * 20.0 + 0.5 ); // Twips + if (!bConvert) + nHeight = TWIP_TO_MM100_UNSIGNED(nHeight); // umrechnen, wenn das Item 1/100mm enthaelt + } + break; + case MID_FONTHEIGHT_PROP: + { + sal_Int16 nNew = sal_Int16(); + if(!(rVal >>= nNew)) + return sal_True; + + nHeight = lcl_GetRealHeight_Impl(nHeight, nProp, ePropUnit, bConvert); + + nHeight *= nNew; + nHeight /= 100; + nProp = nNew; + ePropUnit = SFX_MAPUNIT_RELATIVE; + } + break; + case MID_FONTHEIGHT_DIFF: + { + nHeight = lcl_GetRealHeight_Impl(nHeight, nProp, ePropUnit, bConvert); + float fValue = 0; + if(!(rVal >>= fValue)) + { + sal_Int32 nValue = 0; + if(!(rVal >>= nValue)) + return sal_False; + fValue = (float)nValue; + } + sal_Int16 nCoreDiffValue = (sal_Int16)(fValue * 20.); + nHeight += bConvert ? nCoreDiffValue : TWIP_TO_MM100(nCoreDiffValue); + nProp = (sal_uInt16)((sal_Int16)fValue); + ePropUnit = SFX_MAPUNIT_POINT; + } + break; + } + return sal_True; +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxFontHeightItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper *pIntl +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + if( SFX_MAPUNIT_RELATIVE != ePropUnit ) + { + ( rText = String::CreateFromInt32( (short)nProp ) ) += + EE_RESSTR( GetMetricId( ePropUnit ) ); + if( 0 <= (short)nProp ) + rText.Insert( sal_Unicode('+'), 0 ); + } + else if( 100 == nProp ) + { + rText = GetMetricText( (long)nHeight, + eCoreUnit, SFX_MAPUNIT_POINT, pIntl ); + rText += EE_RESSTR(GetMetricId(SFX_MAPUNIT_POINT)); + } + else + ( rText = String::CreateFromInt32( nProp )) += sal_Unicode('%'); + return ePres; + } + default: ; //prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +USHORT SvxFontHeightItem::GetVersion(USHORT nFileVersion) const +{ + return (nFileVersion <= SOFFICE_FILEFORMAT_40) + ? FONTHEIGHT_16_VERSION + : FONTHEIGHT_UNIT_VERSION; +} + +// ----------------------------------------------------------------------- + +int SvxFontHeightItem::ScaleMetrics( long nMult, long nDiv ) +{ + nHeight = (sal_uInt32)Scale( nHeight, nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxFontHeightItem::HasMetrics() const +{ + return 1; +} + +void SvxFontHeightItem::SetHeight( sal_uInt32 nNewHeight, const USHORT nNewProp, + SfxMapUnit eUnit ) +{ + DBG_ASSERT( GetRefCount() == 0, "SetValue() with pooled item" ); + +#ifndef SVX_LIGHT + if( SFX_MAPUNIT_RELATIVE != eUnit ) + nHeight = nNewHeight + ::ItemToControl( (short)nNewProp, eUnit, + SFX_FUNIT_TWIP ); + else +#endif // !SVX_LIGHT + if( 100 != nNewProp ) + nHeight = sal_uInt32(( nNewHeight * nNewProp ) / 100 ); + else + nHeight = nNewHeight; + + nProp = nNewProp; + ePropUnit = eUnit; +} + +void SvxFontHeightItem::SetHeight( sal_uInt32 nNewHeight, USHORT nNewProp, + SfxMapUnit eMetric, SfxMapUnit eCoreMetric ) +{ + DBG_ASSERT( GetRefCount() == 0, "SetValue() with pooled item" ); + +#ifndef SVX_LIGHT + if( SFX_MAPUNIT_RELATIVE != eMetric ) + nHeight = nNewHeight + + ::ControlToItem( ::ItemToControl((short)nNewProp, eMetric, + SFX_FUNIT_TWIP ), SFX_FUNIT_TWIP, + eCoreMetric ); + else +#endif // !SVX_LIGHT + if( 100 != nNewProp ) + nHeight = sal_uInt32(( nNewHeight * nNewProp ) / 100 ); + else + nHeight = nNewHeight; + + nProp = nNewProp; + ePropUnit = eMetric; +} + +// class SvxFontWidthItem ----------------------------------------------- + +SvxFontWidthItem::SvxFontWidthItem( const USHORT nSz, const USHORT nPrp, const USHORT nId ) : + SfxPoolItem( nId ) +{ + nWidth = nSz; + nProp = nPrp; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFontWidthItem::Clone( SfxItemPool * ) const +{ + return new SvxFontWidthItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxFontWidthItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << GetWidth() << GetProp(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +int SvxFontWidthItem::ScaleMetrics( long nMult, long nDiv ) +{ + nWidth = (USHORT)Scale( nWidth, nMult, nDiv ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxFontWidthItem::HasMetrics() const +{ + return 1; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxFontWidthItem::Create( SvStream& rStrm, + USHORT /*nVersion*/ ) const +{ + USHORT nS; + USHORT nP; + + rStrm >> nS; + rStrm >> nP; + SvxFontWidthItem* pItem = new SvxFontWidthItem( 0, nP, Which() ); + pItem->SetWidthValue( nS ); + return pItem; +} + +// ----------------------------------------------------------------------- + +int SvxFontWidthItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" ); + return GetWidth() == ((SvxFontWidthItem&)rItem).GetWidth() && + GetProp() == ((SvxFontWidthItem&)rItem).GetProp(); +} + +/*-----------------13.03.98 16:03------------------- + +--------------------------------------------------*/ +sal_Bool SvxFontWidthItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_FONTWIDTH: + rVal <<= (sal_Int16)(nWidth); + break; + case MID_FONTWIDTH_PROP: + rVal <<= (sal_Int16)(nProp); + break; + } + return sal_True; +} +/*-----------------13.03.98 16:03------------------- + +--------------------------------------------------*/ +sal_Bool SvxFontWidthItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Int16 nVal = sal_Int16(); + if(!(rVal >>= nVal)) + return sal_False; + + switch(nMemberId) + { + case MID_FONTWIDTH: + nProp = nVal; + break; + case MID_FONTWIDTH_PROP: + nWidth = nVal; + break; + } + return sal_True; +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxFontWidthItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper *pIntl +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + if ( 100 == nProp ) + { + rText = GetMetricText( (long)nWidth, + eCoreUnit, SFX_MAPUNIT_POINT, pIntl ); + rText += EE_RESSTR(GetMetricId(SFX_MAPUNIT_POINT)); + } + else + ( rText = String::CreateFromInt32( nProp )) += sal_Unicode('%'); + return ePres; + } + default: ; //prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxTextLineItem ------------------------------------------------ + +SvxTextLineItem::SvxTextLineItem( const FontUnderline eSt, const USHORT nId ) + : SfxEnumItem( nId, (USHORT)eSt ), mColor( COL_TRANSPARENT ) +{ +} + +// ----------------------------------------------------------------------- + +int SvxTextLineItem::HasBoolValue() const +{ + return sal_True; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxTextLineItem::GetBoolValue() const +{ + return (FontUnderline)GetValue() != UNDERLINE_NONE; +} + +// ----------------------------------------------------------------------- + +void SvxTextLineItem::SetBoolValue( sal_Bool bVal ) +{ + SetValue( (USHORT)(bVal ? UNDERLINE_SINGLE : UNDERLINE_NONE) ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxTextLineItem::Clone( SfxItemPool * ) const +{ + SvxTextLineItem* pNew = new SvxTextLineItem( *this ); + pNew->SetColor( GetColor() ); + return pNew; +} + +// ----------------------------------------------------------------------- + +USHORT SvxTextLineItem::GetValueCount() const +{ + return UNDERLINE_DOTTED + 1; // auch UNDERLINE_NONE geh"ort dazu +} + +// ----------------------------------------------------------------------- + +SvStream& SvxTextLineItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (BYTE)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxTextLineItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE nState; + rStrm >> nState; + return new SvxTextLineItem( (FontUnderline)nState, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxTextLineItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetValueTextByPos( GetValue() ); + if( !mColor.GetTransparency() ) + ( rText += cpDelim ) += ::GetColorString( mColor ); + return ePres; + default: ; //prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +XubString SvxTextLineItem::GetValueTextByPos( USHORT /*nPos*/ ) const +{ + DBG_ERROR("SvxTextLineItem::GetValueTextByPos: Pure virtual method"); + return XubString(); +} + +/*-----------------13.03.98 16:25------------------- + +--------------------------------------------------*/ +sal_Bool SvxTextLineItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_TEXTLINED: + rVal = Bool2Any(GetBoolValue()); + break; + case MID_TL_STYLE: + rVal <<= (sal_Int16)(GetValue()); + break; + case MID_TL_COLOR: + rVal <<= (sal_Int32)( mColor.GetColor() ); + break; + case MID_TL_HASCOLOR: + rVal = Bool2Any( !mColor.GetTransparency() ); + break; + } + return sal_True; + +} +/*-----------------13.03.98 16:28------------------- + +--------------------------------------------------*/ +sal_Bool SvxTextLineItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_True; + switch(nMemberId) + { + case MID_TEXTLINED: + SetBoolValue(Any2Bool(rVal)); + break; + case MID_TL_STYLE: + { + sal_Int32 nValue = 0; + if(!(rVal >>= nValue)) + bRet = sal_False; + else + SetValue((sal_Int16)nValue); + } + break; + case MID_TL_COLOR: + { + sal_Int32 nCol = 0; + if( !( rVal >>= nCol ) ) + bRet = sal_False; + else + { + // Keep transparence, because it contains the information + // whether the font color or the stored color should be used + sal_uInt8 nTrans = mColor.GetTransparency(); + mColor = Color( nCol ); + mColor.SetTransparency( nTrans ); + } + } + break; + case MID_TL_HASCOLOR: + mColor.SetTransparency( Any2Bool( rVal ) ? 0 : 0xff ); + break; + } + return bRet; +} + +int SvxTextLineItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" ); + return SfxEnumItem::operator==( rItem ) && + GetColor() == ((SvxTextLineItem&)rItem).GetColor(); +} + +// class SvxUnderlineItem ------------------------------------------------ + +SvxUnderlineItem::SvxUnderlineItem( const FontUnderline eSt, const USHORT nId ) + : SvxTextLineItem( eSt, nId ) +{ +} + +//------------------------------------------------------------------------ + +SfxPoolItem* SvxUnderlineItem::Clone( SfxItemPool * ) const +{ + SvxUnderlineItem* pNew = new SvxUnderlineItem( *this ); + pNew->SetColor( GetColor() ); + return pNew; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxUnderlineItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE nState; + rStrm >> nState; + return new SvxUnderlineItem( (FontUnderline)nState, Which() ); +} + +// ----------------------------------------------------------------------- + +XubString SvxUnderlineItem::GetValueTextByPos( USHORT nPos ) const +{ + DBG_ASSERT( nPos <= (USHORT)UNDERLINE_BOLDWAVE, "enum overflow!" ); + return EE_RESSTR( RID_SVXITEMS_UL_BEGIN + nPos ); +} + +// class SvxOverlineItem ------------------------------------------------ + +SvxOverlineItem::SvxOverlineItem( const FontUnderline eSt, const USHORT nId ) + : SvxTextLineItem( eSt, nId ) +{ +} + +//------------------------------------------------------------------------ + +SfxPoolItem* SvxOverlineItem::Clone( SfxItemPool * ) const +{ + SvxOverlineItem* pNew = new SvxOverlineItem( *this ); + pNew->SetColor( GetColor() ); + return pNew; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxOverlineItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE nState; + rStrm >> nState; + return new SvxOverlineItem( (FontUnderline)nState, Which() ); +} + +// ----------------------------------------------------------------------- + +XubString SvxOverlineItem::GetValueTextByPos( USHORT nPos ) const +{ + DBG_ASSERT( nPos <= (USHORT)UNDERLINE_BOLDWAVE, "enum overflow!" ); + return EE_RESSTR( RID_SVXITEMS_OL_BEGIN + nPos ); +} + +// class SvxCrossedOutItem ----------------------------------------------- + +SvxCrossedOutItem::SvxCrossedOutItem( const FontStrikeout eSt, const USHORT nId ) + : SfxEnumItem( nId, (USHORT)eSt ) +{ +} + +// ----------------------------------------------------------------------- + +int SvxCrossedOutItem::HasBoolValue() const +{ + return sal_True; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxCrossedOutItem::GetBoolValue() const +{ + return (FontStrikeout)GetValue() != STRIKEOUT_NONE; +} + +// ----------------------------------------------------------------------- + +void SvxCrossedOutItem::SetBoolValue( sal_Bool bVal ) +{ + SetValue( (USHORT)(bVal ? STRIKEOUT_SINGLE : STRIKEOUT_NONE) ); +} + +// ----------------------------------------------------------------------- + +USHORT SvxCrossedOutItem::GetValueCount() const +{ + return STRIKEOUT_DOUBLE + 1; // auch STRIKEOUT_NONE geh"ort dazu +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxCrossedOutItem::Clone( SfxItemPool * ) const +{ + return new SvxCrossedOutItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxCrossedOutItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (BYTE)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxCrossedOutItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE eCross; + rStrm >> eCross; + return new SvxCrossedOutItem( (FontStrikeout)eCross, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxCrossedOutItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetValueTextByPos( GetValue() ); + return ePres; + default: ;//prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +XubString SvxCrossedOutItem::GetValueTextByPos( USHORT nPos ) const +{ + DBG_ASSERT( nPos <= (USHORT)STRIKEOUT_X, "enum overflow!" ); + return EE_RESSTR( RID_SVXITEMS_STRIKEOUT_BEGIN + nPos ); +} + +/*-----------------13.03.98 16:28------------------- + +--------------------------------------------------*/ +sal_Bool SvxCrossedOutItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_CROSSED_OUT: + rVal = Bool2Any(GetBoolValue()); + break; + case MID_CROSS_OUT: + rVal <<= (sal_Int16)(GetValue()); + break; + } + return sal_True; +} +/*-----------------13.03.98 16:29------------------- + +--------------------------------------------------*/ +sal_Bool SvxCrossedOutItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_CROSSED_OUT: + SetBoolValue(Any2Bool(rVal)); + break; + case MID_CROSS_OUT: + { + sal_Int32 nValue = 0; + if(!(rVal >>= nValue)) + return sal_False; + SetValue((sal_Int16)nValue); + } + break; + } + return sal_True; +} +// class SvxShadowedItem ------------------------------------------------- + +SvxShadowedItem::SvxShadowedItem( const sal_Bool bShadowed, const USHORT nId ) : + SfxBoolItem( nId, bShadowed ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxShadowedItem::Clone( SfxItemPool * ) const +{ + return new SvxShadowedItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxShadowedItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (BYTE) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxShadowedItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE nState; + rStrm >> nState; + return new SvxShadowedItem( nState, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxShadowedItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + USHORT nId = RID_SVXITEMS_SHADOWED_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_SHADOWED_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxAutoKernItem ------------------------------------------------- + +SvxAutoKernItem::SvxAutoKernItem( const sal_Bool bAutoKern, const USHORT nId ) : + SfxBoolItem( nId, bAutoKern ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxAutoKernItem::Clone( SfxItemPool * ) const +{ + return new SvxAutoKernItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxAutoKernItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (BYTE) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxAutoKernItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE nState; + rStrm >> nState; + return new SvxAutoKernItem( nState, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxAutoKernItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + USHORT nId = RID_SVXITEMS_AUTOKERN_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_AUTOKERN_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxWordLineModeItem --------------------------------------------- + +SvxWordLineModeItem::SvxWordLineModeItem( const sal_Bool bWordLineMode, + const USHORT nId ) : + SfxBoolItem( nId, bWordLineMode ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxWordLineModeItem::Clone( SfxItemPool * ) const +{ + return new SvxWordLineModeItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxWordLineModeItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (sal_Bool) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxWordLineModeItem::Create(SvStream& rStrm, USHORT) const +{ + sal_Bool bValue; + rStrm >> bValue; + return new SvxWordLineModeItem( bValue, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxWordLineModeItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + USHORT nId = RID_SVXITEMS_WORDLINE_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_WORDLINE_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxContourItem -------------------------------------------------- + +SvxContourItem::SvxContourItem( const sal_Bool bContoured, const USHORT nId ) : + SfxBoolItem( nId, bContoured ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxContourItem::Clone( SfxItemPool * ) const +{ + return new SvxContourItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxContourItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (sal_Bool) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxContourItem::Create(SvStream& rStrm, USHORT) const +{ + sal_Bool bValue; + rStrm >> bValue; + return new SvxContourItem( bValue, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxContourItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + USHORT nId = RID_SVXITEMS_CONTOUR_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_CONTOUR_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxPropSizeItem ------------------------------------------------- + +SvxPropSizeItem::SvxPropSizeItem( const USHORT nPercent, const USHORT nId ) : + SfxUInt16Item( nId, nPercent ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxPropSizeItem::Clone( SfxItemPool * ) const +{ + return new SvxPropSizeItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxPropSizeItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (USHORT) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxPropSizeItem::Create(SvStream& rStrm, USHORT) const +{ + USHORT nSize; + rStrm >> nSize; + return new SvxPropSizeItem( nSize, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxPropSizeItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxColorItem ---------------------------------------------------- + +SvxColorItem::SvxColorItem( const USHORT nId ) : + SfxPoolItem( nId ), + mColor( COL_BLACK ) +{ +} + +// ----------------------------------------------------------------------- + +SvxColorItem::SvxColorItem( const Color& rCol, const USHORT nId ) : + SfxPoolItem( nId ), + mColor( rCol ) +{ +} + +// ----------------------------------------------------------------------- + +SvxColorItem::SvxColorItem( SvStream &rStrm, const USHORT nId ) : + SfxPoolItem( nId ) +{ + Color aColor; + rStrm >> aColor; + mColor = aColor; +} + +// ----------------------------------------------------------------------- + +SvxColorItem::SvxColorItem( const SvxColorItem &rCopy ) : + SfxPoolItem( rCopy ), + mColor( rCopy.mColor ) +{ +} + +// ----------------------------------------------------------------------- + +SvxColorItem::~SvxColorItem() +{ +} + +// ----------------------------------------------------------------------- +USHORT SvxColorItem::GetVersion( USHORT nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxColorItem: Gibt es ein neues Fileformat?" ); + return SOFFICE_FILEFORMAT_50 >= nFFVer ? VERSION_USEAUTOCOLOR : 0; +} + +// ----------------------------------------------------------------------- + +int SvxColorItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return mColor == ( (const SvxColorItem&)rAttr ).mColor; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxColorItem::QueryValue( uno::Any& rVal, BYTE /*nMemberId*/ ) const +{ + rVal <<= (sal_Int32)(mColor.GetColor()); + return sal_True; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxColorItem::PutValue( const uno::Any& rVal, BYTE /*nMemberId*/ ) +{ + sal_Int32 nColor = 0; + if(!(rVal >>= nColor)) + return sal_False; + + mColor.SetColor( nColor ); + return sal_True; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxColorItem::Clone( SfxItemPool * ) const +{ + return new SvxColorItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxColorItem::Store( SvStream& rStrm , USHORT nItemVersion ) const +{ + if( VERSION_USEAUTOCOLOR == nItemVersion && + COL_AUTO == mColor.GetColor() ) + rStrm << Color( COL_BLACK ); + else + rStrm << mColor; + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxColorItem::Create(SvStream& rStrm, USHORT /*nVer*/ ) const +{ + return new SvxColorItem( rStrm, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxColorItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = ::GetColorString( mColor ); + return ePres; + default: ; //prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +void SvxColorItem::SetValue( const Color& rNewCol ) +{ + mColor = rNewCol; +} + +// class SvxCharSetColorItem --------------------------------------------- + +SvxCharSetColorItem::SvxCharSetColorItem( const USHORT nId ) : + SvxColorItem( nId ), + + eFrom( RTL_TEXTENCODING_DONTKNOW ) +{ +} + +// ----------------------------------------------------------------------- + +SvxCharSetColorItem::SvxCharSetColorItem( const Color& rCol, + const rtl_TextEncoding _eFrom, + const USHORT nId ) : + SvxColorItem( rCol, nId ), + + eFrom( _eFrom ) +{ +} + + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxCharSetColorItem::Clone( SfxItemPool * ) const +{ + return new SvxCharSetColorItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxCharSetColorItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + // #90477# rStrm << (BYTE) GetStoreCharSet( GetCharSet(), (USHORT)rStrm.GetVersion() ) + // << GetValue(); + rStrm << (BYTE)GetSOStoreTextEncoding(GetCharSet(), (sal_uInt16)rStrm.GetVersion()) + << GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxCharSetColorItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE cSet; + Color aColor; + rStrm >> cSet >> aColor; + return new SvxCharSetColorItem( aColor, (rtl_TextEncoding)cSet, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxCharSetColorItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxKerningItem -------------------------------------------------- + +SvxKerningItem::SvxKerningItem( const short nKern, const USHORT nId ) : + SfxInt16Item( nId, nKern ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxKerningItem::Clone( SfxItemPool * ) const +{ + return new SvxKerningItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxKerningItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (short) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +int SvxKerningItem::ScaleMetrics( long nMult, long nDiv ) +{ + SetValue( (sal_Int16)Scale( GetValue(), nMult, nDiv ) ); + return 1; +} + +// ----------------------------------------------------------------------- + +int SvxKerningItem::HasMetrics() const +{ + return 1; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxKerningItem::Create(SvStream& rStrm, USHORT) const +{ + short nValue; + rStrm >> nValue; + return new SvxKerningItem( nValue, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxKerningItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper *pIntl +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + rText = GetMetricText( (long)GetValue(), eCoreUnit, SFX_MAPUNIT_POINT, pIntl ); + rText += EE_RESSTR(GetMetricId(SFX_MAPUNIT_POINT)); + return ePres; + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = EE_RESSTR(RID_SVXITEMS_KERNING_COMPLETE); + USHORT nId = 0; + + if ( GetValue() > 0 ) + nId = RID_SVXITEMS_KERNING_EXPANDED; + else if ( GetValue() < 0 ) + nId = RID_SVXITEMS_KERNING_CONDENSED; + + if ( nId ) + rText += EE_RESSTR(nId); + rText += GetMetricText( (long)GetValue(), eCoreUnit, SFX_MAPUNIT_POINT, pIntl ); + rText += EE_RESSTR(GetMetricId(SFX_MAPUNIT_POINT)); + return ePres; + } + default: ; //prevent warning + } +#endif + return SFX_ITEM_PRESENTATION_NONE; +} +/* -----------------------------19.02.01 12:21-------------------------------- + + ---------------------------------------------------------------------------*/ +sal_Bool SvxKerningItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ + sal_Int16 nVal = GetValue(); + if(nMemberId & CONVERT_TWIPS) + nVal = (sal_Int16)TWIP_TO_MM100(nVal); + rVal <<= nVal; + return sal_True; +} +// ----------------------------------------------------------------------- +sal_Bool SvxKerningItem::PutValue( const uno::Any& rVal, BYTE nMemberId) +{ + sal_Int16 nVal = sal_Int16(); + if(!(rVal >>= nVal)) + return sal_False; + if(nMemberId & CONVERT_TWIPS) + nVal = (sal_Int16)MM100_TO_TWIP(nVal); + SetValue(nVal); + return sal_True; +} + +// class SvxCaseMapItem -------------------------------------------------- + +SvxCaseMapItem::SvxCaseMapItem( const SvxCaseMap eMap, const USHORT nId ) : + SfxEnumItem( nId, (USHORT)eMap ) +{ +} + +// ----------------------------------------------------------------------- + +USHORT SvxCaseMapItem::GetValueCount() const +{ + return SVX_CASEMAP_END; // SVX_CASEMAP_KAPITAELCHEN + 1 +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxCaseMapItem::Clone( SfxItemPool * ) const +{ + return new SvxCaseMapItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxCaseMapItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (BYTE) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxCaseMapItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE cMap; + rStrm >> cMap; + return new SvxCaseMapItem( (const SvxCaseMap)cMap, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxCaseMapItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetValueTextByPos( GetValue() ); + return ePres; + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +XubString SvxCaseMapItem::GetValueTextByPos( USHORT nPos ) const +{ + DBG_ASSERT( nPos < (USHORT)SVX_CASEMAP_END, "enum overflow!" ); + return EE_RESSTR( RID_SVXITEMS_CASEMAP_BEGIN + nPos ); +} + +/*-----------------13.03.98 16:29------------------- + +--------------------------------------------------*/ +sal_Bool SvxCaseMapItem::QueryValue( uno::Any& rVal, BYTE /*nMemberId*/ ) const +{ + sal_Int16 nRet = style::CaseMap::NONE; + switch( GetValue() ) + { +// case SVX_CASEMAP_NOT_MAPPED : nRet = style::CaseMap::NONE ; break; + case SVX_CASEMAP_VERSALIEN : nRet = style::CaseMap::UPPERCASE; break; + case SVX_CASEMAP_GEMEINE : nRet = style::CaseMap::LOWERCASE; break; + case SVX_CASEMAP_TITEL : nRet = style::CaseMap::TITLE ; break; + case SVX_CASEMAP_KAPITAELCHEN: nRet = style::CaseMap::SMALLCAPS; break; + } + rVal <<= (sal_Int16)(nRet); + return sal_True; +} +/*-----------------13.03.98 16:29------------------- + +--------------------------------------------------*/ +sal_Bool SvxCaseMapItem::PutValue( const uno::Any& rVal, BYTE /*nMemberId*/ ) +{ + sal_uInt16 nVal = sal_uInt16(); + if(!(rVal >>= nVal)) + return sal_False; + + switch( nVal ) + { + case style::CaseMap::NONE : nVal = SVX_CASEMAP_NOT_MAPPED ; break; + case style::CaseMap::UPPERCASE: nVal = SVX_CASEMAP_VERSALIEN ; break; + case style::CaseMap::LOWERCASE: nVal = SVX_CASEMAP_GEMEINE ; break; + case style::CaseMap::TITLE : nVal = SVX_CASEMAP_TITEL ; break; + case style::CaseMap::SMALLCAPS: nVal = SVX_CASEMAP_KAPITAELCHEN; break; + } + SetValue(nVal); + return sal_True; +} + +// class SvxEscapementItem ----------------------------------------------- + +SvxEscapementItem::SvxEscapementItem( const USHORT nId ) : + SfxEnumItemInterface( nId ), + + nEsc ( 0 ), + nProp ( 100 ) +{ +} + +// ----------------------------------------------------------------------- + +SvxEscapementItem::SvxEscapementItem( const SvxEscapement eEscape, + const USHORT nId ) : + SfxEnumItemInterface( nId ), + nProp( 100 ) +{ + SetEscapement( eEscape ); + if( nEsc ) + nProp = 58; +} + +// ----------------------------------------------------------------------- + +SvxEscapementItem::SvxEscapementItem( const short _nEsc, + const BYTE _nProp, + const USHORT nId ) : + SfxEnumItemInterface( nId ), + nEsc ( _nEsc ), + nProp ( _nProp ) +{ +} + +// ----------------------------------------------------------------------- + +int SvxEscapementItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" ); + + return( nEsc == ((SvxEscapementItem&)rAttr).nEsc && + nProp == ((SvxEscapementItem&)rAttr).nProp ); +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxEscapementItem::Clone( SfxItemPool * ) const +{ + return new SvxEscapementItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxEscapementItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + short _nEsc = GetEsc(); + if( SOFFICE_FILEFORMAT_31 == rStrm.GetVersion() ) + { + if( DFLT_ESC_AUTO_SUPER == _nEsc ) + _nEsc = DFLT_ESC_SUPER; + else if( DFLT_ESC_AUTO_SUB == _nEsc ) + _nEsc = DFLT_ESC_SUB; + } + rStrm << (BYTE) GetProp() + << (short) _nEsc; + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxEscapementItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE _nProp; + short _nEsc; + rStrm >> _nProp >> _nEsc; + return new SvxEscapementItem( _nEsc, _nProp, Which() ); +} + +// ----------------------------------------------------------------------- + +USHORT SvxEscapementItem::GetValueCount() const +{ + return SVX_ESCAPEMENT_END; // SVX_ESCAPEMENT_SUBSCRIPT + 1 +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxEscapementItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + rText = GetValueTextByPos( GetEnumValue() ); + + if ( nEsc != 0 ) + { + if( DFLT_ESC_AUTO_SUPER == nEsc || DFLT_ESC_AUTO_SUB == nEsc ) + rText += String( EE_RESSTR(RID_SVXITEMS_ESCAPEMENT_AUTO) ); + else + ( rText += String::CreateFromInt32( nEsc )) += sal_Unicode('%'); + } + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +XubString SvxEscapementItem::GetValueTextByPos( USHORT nPos ) const +{ + DBG_ASSERT( nPos < (USHORT)SVX_ESCAPEMENT_END, "enum overflow!" ); + return EE_RESSTR(RID_SVXITEMS_ESCAPEMENT_BEGIN + nPos); +} + +// ----------------------------------------------------------------------- + +USHORT SvxEscapementItem::GetEnumValue() const +{ + if ( nEsc < 0 ) + return SVX_ESCAPEMENT_SUBSCRIPT; + else if ( nEsc > 0 ) + return SVX_ESCAPEMENT_SUPERSCRIPT; + return SVX_ESCAPEMENT_OFF; +} + +// ----------------------------------------------------------------------- + +void SvxEscapementItem::SetEnumValue( USHORT nVal ) +{ + SetEscapement( (const SvxEscapement)nVal ); +} + +/*-----------------13.03.98 17:05------------------- + +--------------------------------------------------*/ +sal_Bool SvxEscapementItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_ESC: + rVal <<= (sal_Int16)(nEsc); + break; + case MID_ESC_HEIGHT: + rVal <<= (sal_Int8)(nProp); + break; + case MID_AUTO_ESC: + rVal = Bool2Any(DFLT_ESC_AUTO_SUB == nEsc || DFLT_ESC_AUTO_SUPER == nEsc); + break; + } + return sal_True; +} +/*-----------------13.03.98 17:05------------------- + +--------------------------------------------------*/ +sal_Bool SvxEscapementItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_ESC: + { + sal_Int16 nVal = sal_Int16(); + if( (rVal >>= nVal) && (Abs(nVal) <= 101)) + nEsc = nVal; + else + return sal_False; + } + break; + case MID_ESC_HEIGHT: + { + sal_Int8 nVal = sal_Int8(); + if( (rVal >>= nVal) && (nVal <= 100)) + nProp = nVal; + else + return sal_False; + } + break; + case MID_AUTO_ESC: + { + BOOL bVal = Any2Bool(rVal); + if(bVal) + { + if(nEsc < 0) + nEsc = DFLT_ESC_AUTO_SUB; + else + nEsc = DFLT_ESC_AUTO_SUPER; + } + else + if(DFLT_ESC_AUTO_SUPER == nEsc ) + --nEsc; + else if(DFLT_ESC_AUTO_SUB == nEsc) + ++nEsc; + } + break; + } + return sal_True; +} + +// class SvxLanguageItem ------------------------------------------------- + +SvxLanguageItem::SvxLanguageItem( const LanguageType eLang, const USHORT nId ) + : SfxEnumItem( nId , eLang ) +{ +} + +// ----------------------------------------------------------------------- + +USHORT SvxLanguageItem::GetValueCount() const +{ + // #i50205# got rid of class International + DBG_ERRORFILE("SvxLanguageItem::GetValueCount: supposed to return a count of what?"); + // FIXME: previously returned LANGUAGE_COUNT from tools/intn.hxx which was wrong anyway. + // Could be SvtLanguageTable::GetEntryCount() (all locales with resource string)? + // Could be LocaleDataWrapper::getInstalledLanguageTypes() (all locales with locale data)? + return 0; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxLanguageItem::Clone( SfxItemPool * ) const +{ + return new SvxLanguageItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxLanguageItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (USHORT) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxLanguageItem::Create(SvStream& rStrm, USHORT) const +{ + USHORT nValue; + rStrm >> nValue; + return new SvxLanguageItem( (LanguageType)nValue, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxLanguageItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ +#ifndef SVX_LIGHT + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + SvtLanguageTable aLangTable; + rText = aLangTable.GetString( (LanguageType)GetValue() ); + return ePres; + } + default: ; //prevent warning + } +#endif // !SVX_LIGHT + return SFX_ITEM_PRESENTATION_NONE; +} + +/*-----------------14.03.98 14:13------------------- + +--------------------------------------------------*/ +sal_Bool SvxLanguageItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_LANG_INT: // for basic conversions! + rVal <<= (sal_Int16)(GetValue()); + break; + case MID_LANG_LOCALE: + lang::Locale aRet( MsLangId::convertLanguageToLocale( GetValue(), false)); + rVal <<= aRet; + break; + } + return sal_True; +} +/*-----------------14.03.98 14:13------------------- + +--------------------------------------------------*/ +sal_Bool SvxLanguageItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch(nMemberId) + { + case MID_LANG_INT: // for basic conversions! + { + sal_Int32 nValue = 0; + if(!(rVal >>= nValue)) + return sal_False; + + SetValue((sal_Int16)nValue); + } + break; + case MID_LANG_LOCALE: + { + lang::Locale aLocale; + if(!(rVal >>= aLocale)) + return sal_False; + + if (aLocale.Language.getLength() || aLocale.Country.getLength()) + SetValue(MsLangId::convertLocaleToLanguage( aLocale )); + else + SetValue(LANGUAGE_NONE); + } + break; + } + return sal_True; +} + +// class SvxNoLinebreakItem ---------------------------------------------- +SvxNoLinebreakItem::SvxNoLinebreakItem( const sal_Bool bBreak, const USHORT nId ) : + SfxBoolItem( nId, bBreak ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxNoLinebreakItem::Clone( SfxItemPool* ) const +{ + return new SvxNoLinebreakItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxNoLinebreakItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (sal_Bool)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxNoLinebreakItem::Create(SvStream& rStrm, USHORT) const +{ + sal_Bool bValue; + rStrm >> bValue; + return new SvxNoLinebreakItem( bValue, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxNoLinebreakItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxNoHyphenItem ------------------------------------------------- + +SvxNoHyphenItem::SvxNoHyphenItem( const sal_Bool bHyphen, const USHORT nId ) : + SfxBoolItem( nId , bHyphen ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxNoHyphenItem::Clone( SfxItemPool* ) const +{ + return new SvxNoHyphenItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxNoHyphenItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (sal_Bool) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxNoHyphenItem::Create( SvStream& rStrm, USHORT ) const +{ + sal_Bool bValue; + rStrm >> bValue; + return new SvxNoHyphenItem( bValue, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxNoHyphenItem::GetPresentation +( + SfxItemPresentation /*ePres*/, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + rText.Erase(); + return SFX_ITEM_PRESENTATION_NONE; +} + +/* + * Dummy-Item fuer ToolBox-Controls: + * + */ + +// ----------------------------------------------------------------------- +// class SvxLineColorItem (== SvxColorItem) +// ----------------------------------------------------------------------- + +SvxLineColorItem::SvxLineColorItem( const USHORT nId ) : + SvxColorItem( nId ) +{ +} + +// ----------------------------------------------------------------------- + +SvxLineColorItem::SvxLineColorItem( const Color& rCol, const USHORT nId ) : + SvxColorItem( rCol, nId ) +{ +} + +// ----------------------------------------------------------------------- + +SvxLineColorItem::SvxLineColorItem( SvStream &rStrm, const USHORT nId ) : + SvxColorItem( rStrm, nId ) +{ +} + +// ----------------------------------------------------------------------- + +SvxLineColorItem::SvxLineColorItem( const SvxLineColorItem &rCopy ) : + SvxColorItem( rCopy ) +{ +} + +// ----------------------------------------------------------------------- + +SvxLineColorItem::~SvxLineColorItem() +{ +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxLineColorItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit eCoreUnit, + SfxMapUnit ePresUnit, + XubString& rText, + const IntlWrapper * pIntlWrapper +) const +{ + return SvxColorItem::GetPresentation( ePres, eCoreUnit, ePresUnit, + rText, pIntlWrapper ); +} + +// class SvxBlinkItem ------------------------------------------------- + + +SvxBlinkItem::SvxBlinkItem( const sal_Bool bBlink, const USHORT nId ) : + SfxBoolItem( nId, bBlink ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBlinkItem::Clone( SfxItemPool * ) const +{ + return new SvxBlinkItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxBlinkItem::Store( SvStream& rStrm , USHORT /*nItemVersion*/ ) const +{ + rStrm << (BYTE) GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxBlinkItem::Create(SvStream& rStrm, USHORT) const +{ + BYTE nState; + rStrm >> nState; + return new SvxBlinkItem( nState, Which() ); +} + +// ----------------------------------------------------------------------- + +SfxItemPresentation SvxBlinkItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + USHORT nId = RID_SVXITEMS_BLINK_FALSE; + + if ( GetValue() ) + nId = RID_SVXITEMS_BLINK_TRUE; + rText = EE_RESSTR(nId); + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// class SvxEmphaisMarkItem --------------------------------------------------- + +SvxEmphasisMarkItem::SvxEmphasisMarkItem( const FontEmphasisMark nValue, + const USHORT nId ) + : SfxUInt16Item( nId, nValue ) +{ +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxEmphasisMarkItem::Clone( SfxItemPool * ) const +{ + return new SvxEmphasisMarkItem( *this ); +} + +// ----------------------------------------------------------------------- + +SvStream& SvxEmphasisMarkItem::Store( SvStream& rStrm, + USHORT /*nItemVersion*/ ) const +{ + rStrm << (sal_uInt16)GetValue(); + return rStrm; +} + +// ----------------------------------------------------------------------- + +SfxPoolItem* SvxEmphasisMarkItem::Create( SvStream& rStrm, USHORT ) const +{ + sal_uInt16 nValue; + rStrm >> nValue; + return new SvxEmphasisMarkItem( (FontEmphasisMark)nValue, Which() ); +} + +//------------------------------------------------------------------------ + +SfxItemPresentation SvxEmphasisMarkItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, + const IntlWrapper * /*pIntl*/ +) const +{ + switch ( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + return ePres; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + sal_uInt16 nVal = GetValue(); + rText = EE_RESSTR( RID_SVXITEMS_EMPHASIS_BEGIN_STYLE + + ( EMPHASISMARK_STYLE & nVal )); + USHORT nId = ( EMPHASISMARK_POS_ABOVE & nVal ) + ? RID_SVXITEMS_EMPHASIS_ABOVE_POS + : ( EMPHASISMARK_POS_BELOW & nVal ) + ? RID_SVXITEMS_EMPHASIS_BELOW_POS + : 0; + if( nId ) + rText += EE_RESSTR( nId ); + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxEmphasisMarkItem::QueryValue( uno::Any& rVal, BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + switch( nMemberId ) + { + case MID_EMPHASIS: + { + sal_Int16 nValue = GetValue(); + sal_Int16 nRet = 0; + switch(nValue & EMPHASISMARK_STYLE) + { + case EMPHASISMARK_NONE : nRet = FontEmphasis::NONE; break; + case EMPHASISMARK_DOT : nRet = FontEmphasis::DOT_ABOVE; break; + case EMPHASISMARK_CIRCLE : nRet = FontEmphasis::CIRCLE_ABOVE; break; + case EMPHASISMARK_DISC : nRet = FontEmphasis::DISK_ABOVE; break; + case EMPHASISMARK_ACCENT : nRet = FontEmphasis::ACCENT_ABOVE; break; + } + if(nRet && nValue & EMPHASISMARK_POS_BELOW) + nRet += 10; + rVal <<= nRet; + } + break; + } + return sal_True; +} + +sal_Bool SvxEmphasisMarkItem::PutValue( const uno::Any& rVal, BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_True; + switch( nMemberId ) + { + case MID_EMPHASIS: + { + sal_Int32 nValue = -1; + rVal >>= nValue; + switch(nValue) + { + case FontEmphasis::NONE : nValue = EMPHASISMARK_NONE; break; + case FontEmphasis::DOT_ABOVE : nValue = EMPHASISMARK_DOT|EMPHASISMARK_POS_ABOVE; break; + case FontEmphasis::CIRCLE_ABOVE: nValue = EMPHASISMARK_CIRCLE|EMPHASISMARK_POS_ABOVE; break; + case FontEmphasis::DISK_ABOVE : nValue = EMPHASISMARK_DISC|EMPHASISMARK_POS_ABOVE; break; + case FontEmphasis::ACCENT_ABOVE: nValue = EMPHASISMARK_ACCENT|EMPHASISMARK_POS_ABOVE; break; + case FontEmphasis::DOT_BELOW : nValue = EMPHASISMARK_DOT|EMPHASISMARK_POS_BELOW; break; + case FontEmphasis::CIRCLE_BELOW: nValue = EMPHASISMARK_CIRCLE|EMPHASISMARK_POS_BELOW; break; + case FontEmphasis::DISK_BELOW : nValue = EMPHASISMARK_DISC|EMPHASISMARK_POS_BELOW; break; + case FontEmphasis::ACCENT_BELOW: nValue = EMPHASISMARK_ACCENT|EMPHASISMARK_POS_BELOW; break; + default: return sal_False; + } + SetValue( (sal_Int16)nValue ); + } + break; + } + return bRet; +} + +USHORT SvxEmphasisMarkItem::GetVersion( USHORT nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxEmphasisMarkItem: Gibt es ein neues Fileformat?" ); + + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + + +/************************************************************************* +|* class SvxTwoLinesItem +*************************************************************************/ + +SvxTwoLinesItem::SvxTwoLinesItem( sal_Bool bFlag, sal_Unicode nStartBracket, + sal_Unicode nEndBracket, sal_uInt16 nW ) + : SfxPoolItem( nW ), + cStartBracket( nStartBracket ), cEndBracket( nEndBracket ), bOn( bFlag ) +{ +} + +SvxTwoLinesItem::SvxTwoLinesItem( const SvxTwoLinesItem& rAttr ) + : SfxPoolItem( rAttr.Which() ), + cStartBracket( rAttr.cStartBracket ), + cEndBracket( rAttr.cEndBracket ), + bOn( rAttr.bOn ) +{ +} + +SvxTwoLinesItem::~SvxTwoLinesItem() +{ +} + +int SvxTwoLinesItem::operator==( const SfxPoolItem& rAttr ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rAttr ), "not equal attribute types" ); + return bOn == ((SvxTwoLinesItem&)rAttr).bOn && + cStartBracket == ((SvxTwoLinesItem&)rAttr).cStartBracket && + cEndBracket == ((SvxTwoLinesItem&)rAttr).cEndBracket; +} + +SfxPoolItem* SvxTwoLinesItem::Clone( SfxItemPool* ) const +{ + return new SvxTwoLinesItem( *this ); +} + +sal_Bool SvxTwoLinesItem::QueryValue( com::sun::star::uno::Any& rVal, + BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_True; + switch( nMemberId ) + { + case MID_TWOLINES: + rVal = Bool2Any( bOn ); + break; + case MID_START_BRACKET: + { + OUString s; + if( cStartBracket ) + s = OUString( cStartBracket ); + rVal <<= s; + } + break; + case MID_END_BRACKET: + { + OUString s; + if( cEndBracket ) + s = OUString( cEndBracket ); + rVal <<= s; + } + break; + default: + bRet = sal_False; + break; + } + return bRet; +} + +sal_Bool SvxTwoLinesItem::PutValue( const com::sun::star::uno::Any& rVal, + BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_False; + OUString s; + switch( nMemberId ) + { + case MID_TWOLINES: + bOn = Any2Bool( rVal ); + bRet = sal_True; + break; + case MID_START_BRACKET: + if( rVal >>= s ) + { + cStartBracket = s.getLength() ? s[ 0 ] : 0; + bRet = sal_True; + } + break; + case MID_END_BRACKET: + if( rVal >>= s ) + { + cEndBracket = s.getLength() ? s[ 0 ] : 0; + bRet = sal_True; + } + break; + } + return bRet; +} + +SfxItemPresentation SvxTwoLinesItem::GetPresentation( SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, SfxMapUnit /*ePresMetric*/, + String &rText, const IntlWrapper* /*pIntl*/ ) const +{ + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + if( !GetValue() ) + rText = EE_RESSTR( RID_SVXITEMS_TWOLINES_OFF ); + else + { + rText = EE_RESSTR( RID_SVXITEMS_TWOLINES ); + if( GetStartBracket() ) + rText.Insert( GetStartBracket(), 0 ); + if( GetEndBracket() ) + rText += GetEndBracket(); + } + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + + +SfxPoolItem* SvxTwoLinesItem::Create( SvStream & rStrm, USHORT /*nVer*/) const +{ + sal_Bool _bOn; + sal_Unicode cStart, cEnd; + rStrm >> _bOn >> cStart >> cEnd; + return new SvxTwoLinesItem( _bOn, cStart, cEnd, Which() ); +} + +SvStream& SvxTwoLinesItem::Store(SvStream & rStrm, USHORT /*nIVer*/) const +{ + rStrm << GetValue() << GetStartBracket() << GetEndBracket(); + return rStrm; +} + +USHORT SvxTwoLinesItem::GetVersion( USHORT nFFVer ) const +{ + DBG_ASSERT( SOFFICE_FILEFORMAT_31==nFFVer || + SOFFICE_FILEFORMAT_40==nFFVer || + SOFFICE_FILEFORMAT_50==nFFVer, + "SvxTwoLinesItem: Gibt es ein neues Fileformat?" ); + + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + + +/************************************************************************* +|* class SvxCharRotateItem +*************************************************************************/ + +SvxCharRotateItem::SvxCharRotateItem( sal_uInt16 nValue, + sal_Bool bFitIntoLine, + const sal_uInt16 nW ) + : SfxUInt16Item( nW, nValue ), bFitToLine( bFitIntoLine ) +{ +} + +SfxPoolItem* SvxCharRotateItem::Clone( SfxItemPool* ) const +{ + return new SvxCharRotateItem( GetValue(), IsFitToLine(), Which() ); +} + +SfxPoolItem* SvxCharRotateItem::Create( SvStream& rStrm, USHORT ) const +{ + sal_uInt16 nVal; + sal_Bool b; + rStrm >> nVal >> b; + return new SvxCharRotateItem( nVal, b, Which() ); +} + +SvStream& SvxCharRotateItem::Store( SvStream & rStrm, USHORT ) const +{ + sal_Bool bFlag = IsFitToLine(); + rStrm << GetValue() << bFlag; + return rStrm; +} + +USHORT SvxCharRotateItem::GetVersion( USHORT nFFVer ) const +{ + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + +SfxItemPresentation SvxCharRotateItem::GetPresentation( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, SfxMapUnit /*ePresMetric*/, + String &rText, const IntlWrapper* ) const +{ + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + if( !GetValue() ) + rText = EE_RESSTR( RID_SVXITEMS_CHARROTATE_OFF ); + else + { + rText = EE_RESSTR( RID_SVXITEMS_CHARROTATE ); + rText.SearchAndReplaceAscii( "$(ARG1)", + String::CreateFromInt32( GetValue() / 10 )); + if( IsFitToLine() ) + rText += EE_RESSTR( RID_SVXITEMS_CHARROTATE_FITLINE ); + } + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +sal_Bool SvxCharRotateItem::QueryValue( com::sun::star::uno::Any& rVal, + BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_True; + switch( nMemberId ) + { + case MID_ROTATE: + rVal <<= (sal_Int16)GetValue(); + break; + case MID_FITTOLINE: + rVal = Bool2Any( IsFitToLine() ); + break; + default: + bRet = sal_False; + break; + } + return bRet; +} + +sal_Bool SvxCharRotateItem::PutValue( const com::sun::star::uno::Any& rVal, + BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_True; + switch( nMemberId ) + { + case MID_ROTATE: + { + sal_Int16 nVal = 0; + if((rVal >>= nVal) && (0 == nVal || 900 == nVal || 2700 == nVal)) + SetValue( (USHORT)nVal ); + else + bRet = sal_False; + break; + } + + case MID_FITTOLINE: + SetFitToLine( Any2Bool( rVal ) ); + break; + default: + bRet = sal_False; + } + return bRet; +} + +int SvxCharRotateItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal type" ); + return SfxUInt16Item::operator==( rItem ) && + IsFitToLine() == ((const SvxCharRotateItem&)rItem).IsFitToLine(); +} + + +/************************************************************************* +|* class SvxCharScaleItem +*************************************************************************/ + +SvxCharScaleWidthItem::SvxCharScaleWidthItem( sal_uInt16 nValue, + const sal_uInt16 nW ) + : SfxUInt16Item( nW, nValue ) +{ +} + +SfxPoolItem* SvxCharScaleWidthItem::Clone( SfxItemPool* ) const +{ + return new SvxCharScaleWidthItem( GetValue(), Which() ); +} + +SfxPoolItem* SvxCharScaleWidthItem::Create( SvStream& rStrm, USHORT ) const +{ + sal_uInt16 nVal; + rStrm >> nVal; + SvxCharScaleWidthItem* pItem = new SvxCharScaleWidthItem( nVal, Which() ); + + if ( Which() == EE_CHAR_FONTWIDTH ) + { + // #87271#: Was a SvxFontWidthItem in 5.2 + // USHORT nFixWidth, USHORT nPropWidth. + // nFixWidth has never been used... + rStrm >> nVal; + USHORT nTest; + rStrm >> nTest; + if ( nTest == 0x1234 ) + pItem->SetValue( nVal ); + else + rStrm.SeekRel( -2*(long)sizeof(sal_uInt16) ); + } + + return pItem; +} + +SvStream& SvxCharScaleWidthItem::Store( SvStream& rStream, USHORT nVer ) const +{ + SvStream& rRet = SfxUInt16Item::Store( rStream, nVer ); + if ( Which() == EE_CHAR_FONTWIDTH ) + { + // see comment in Create().... + rRet.SeekRel( -1*(long)sizeof(USHORT) ); + rRet << (USHORT)0; + rRet << GetValue(); + // Really ugly, but not a problem for reading the doc in 5.2 + rRet << (USHORT)0x1234; + } + return rRet; +} + + +USHORT SvxCharScaleWidthItem::GetVersion( USHORT nFFVer ) const +{ + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + +SfxItemPresentation SvxCharScaleWidthItem::GetPresentation( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, SfxMapUnit /*ePresMetric*/, + String &rText, const IntlWrapper* ) const +{ + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + { + if( !GetValue() ) + rText = EE_RESSTR( RID_SVXITEMS_CHARSCALE_OFF ); + else + { + rText = EE_RESSTR( RID_SVXITEMS_CHARSCALE ); + rText.SearchAndReplaceAscii( "$(ARG1)", + String::CreateFromInt32( GetValue() )); + } + return ePres; + } + default: ; //prevent warning + } + return SFX_ITEM_PRESENTATION_NONE; +} + +sal_Bool SvxCharScaleWidthItem::PutValue( const uno::Any& rVal, BYTE /*nMemberId*/ ) +{ + // SfxUInt16Item::QueryValue returns sal_Int32 in Any now... (srx642w) + // where we still want this to be a sal_Int16 + sal_Int16 nValue = sal_Int16(); + if (rVal >>= nValue) + { + SetValue( (UINT16) nValue ); + return TRUE; + } + + DBG_ERROR( "SvxCharScaleWidthItem::PutValue - Wrong type!" ); + return FALSE; +} + +sal_Bool SvxCharScaleWidthItem::QueryValue( uno::Any& rVal, BYTE /*nMemberId*/ ) const +{ + // SfxUInt16Item::QueryValue returns sal_Int32 in Any now... (srx642w) + // where we still want this to be a sal_Int16 + rVal <<= (sal_Int16)GetValue(); + return TRUE; +} + +/************************************************************************* +|* class SvxCharReliefItem +*************************************************************************/ + +SvxCharReliefItem::SvxCharReliefItem( FontRelief eValue, + const sal_uInt16 nId ) + : SfxEnumItem( nId, (USHORT)eValue ) +{ +} + +SfxPoolItem* SvxCharReliefItem::Clone( SfxItemPool * ) const +{ + return new SvxCharReliefItem( *this ); +} + +SfxPoolItem* SvxCharReliefItem::Create(SvStream & rStrm, USHORT) const +{ + sal_uInt16 nVal; + rStrm >> nVal; + return new SvxCharReliefItem( (FontRelief)nVal, Which() ); +} + +SvStream& SvxCharReliefItem::Store(SvStream & rStrm, USHORT /*nIVer*/) const +{ + sal_uInt16 nVal = GetValue(); + rStrm << nVal; + return rStrm; +} + +USHORT SvxCharReliefItem::GetVersion( USHORT nFFVer ) const +{ + return SOFFICE_FILEFORMAT_50 > nFFVer ? USHRT_MAX : 0; +} + +String SvxCharReliefItem::GetValueTextByPos( USHORT nPos ) const +{ + DBG_ASSERT( RID_SVXITEMS_RELIEF_ENGRAVED - RID_SVXITEMS_RELIEF_NONE, + "enum overflow" ); + return String( EditResId( RID_SVXITEMS_RELIEF_BEGIN + nPos )); +} + +USHORT SvxCharReliefItem::GetValueCount() const +{ + return RID_SVXITEMS_RELIEF_ENGRAVED - RID_SVXITEMS_RELIEF_NONE; +} + +SfxItemPresentation SvxCharReliefItem::GetPresentation +( + SfxItemPresentation ePres, + SfxMapUnit /*eCoreUnit*/, + SfxMapUnit /*ePresUnit*/, + XubString& rText, const IntlWrapper * /*pIntl*/ +) const +{ + SfxItemPresentation eRet = ePres; + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = GetValueTextByPos( GetValue() ); + break; + + default: + eRet = SFX_ITEM_PRESENTATION_NONE; + } + return eRet; +} + +sal_Bool SvxCharReliefItem::PutValue( const com::sun::star::uno::Any& rVal, + BYTE nMemberId ) +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_True; + switch( nMemberId ) + { + case MID_RELIEF: + { + sal_Int16 nVal = -1; + rVal >>= nVal; + if(nVal >= 0 && nVal <= RELIEF_ENGRAVED) + SetValue( (USHORT)nVal ); + else + bRet = sal_False; + } + break; + default: + bRet = sal_False; + break; + } + return bRet; +} + +sal_Bool SvxCharReliefItem::QueryValue( com::sun::star::uno::Any& rVal, + BYTE nMemberId ) const +{ +// sal_Bool bConvert = 0!=(nMemberId&CONVERT_TWIPS); + nMemberId &= ~CONVERT_TWIPS; + sal_Bool bRet = sal_True; + switch( nMemberId ) + { + case MID_RELIEF: + rVal <<= (sal_Int16)GetValue(); + break; + default: + bRet = sal_False; + break; + } + return bRet; +} + +/************************************************************************* +|* class SvxScriptTypeItemItem +*************************************************************************/ + +SvxScriptTypeItem::SvxScriptTypeItem( sal_uInt16 nType ) + : SfxUInt16Item( SID_ATTR_CHAR_SCRIPTTYPE, nType ) +{ +} +SfxPoolItem* SvxScriptTypeItem::Clone( SfxItemPool * ) const +{ + return new SvxScriptTypeItem( GetValue() ); +} + +/************************************************************************* +|* class SvxScriptSetItem +*************************************************************************/ + +SvxScriptSetItem::SvxScriptSetItem( USHORT nSlotId, SfxItemPool& rPool ) + : SfxSetItem( nSlotId, new SfxItemSet( rPool, + SID_ATTR_CHAR_FONT, SID_ATTR_CHAR_FONT )) +{ + USHORT nLatin, nAsian, nComplex; + GetWhichIds( nLatin, nAsian, nComplex ); + + USHORT aIds[ 9 ] = { 0 }; + aIds[ 0 ] = aIds[ 1 ] = nLatin; + aIds[ 2 ] = aIds[ 3 ] = nAsian; + aIds[ 4 ] = aIds[ 5 ] = nComplex; + aIds[ 6 ] = aIds[ 7 ] = SID_ATTR_CHAR_SCRIPTTYPE; + aIds[ 8 ] = 0; + + GetItemSet().SetRanges( aIds ); +} + +SfxPoolItem* SvxScriptSetItem::Clone( SfxItemPool * ) const +{ + SvxScriptSetItem* p = new SvxScriptSetItem( Which(), *GetItemSet().GetPool() ); + p->GetItemSet().Put( GetItemSet(), FALSE ); + return p; +} + +SfxPoolItem* SvxScriptSetItem::Create( SvStream &, USHORT ) const +{ + return 0; +} + +const SfxPoolItem* SvxScriptSetItem::GetItemOfScriptSet( + const SfxItemSet& rSet, USHORT nId ) +{ + const SfxPoolItem* pI; + SfxItemState eSt = rSet.GetItemState( nId, FALSE, &pI ); + if( SFX_ITEM_SET != eSt ) + pI = SFX_ITEM_DEFAULT == eSt ? &rSet.Get( nId ) : 0; + return pI; +} + +const SfxPoolItem* SvxScriptSetItem::GetItemOfScript( USHORT nSlotId, const SfxItemSet& rSet, USHORT nScript ) +{ + USHORT nLatin, nAsian, nComplex; + GetWhichIds( nSlotId, rSet, nLatin, nAsian, nComplex ); + + const SfxPoolItem *pRet, *pAsn, *pCmplx; + switch( nScript ) + { + default: //no one valid -> match to latin + // case SCRIPTTYPE_LATIN: + pRet = GetItemOfScriptSet( rSet, nLatin ); + break; + case SCRIPTTYPE_ASIAN: + pRet = GetItemOfScriptSet( rSet, nAsian ); + break; + case SCRIPTTYPE_COMPLEX: + pRet = GetItemOfScriptSet( rSet, nComplex ); + break; + + case SCRIPTTYPE_LATIN|SCRIPTTYPE_ASIAN: + if( 0 == (pRet = GetItemOfScriptSet( rSet, nLatin )) || + 0 == (pAsn = GetItemOfScriptSet( rSet, nAsian )) || + *pRet != *pAsn ) + pRet = 0; + break; + + case SCRIPTTYPE_LATIN|SCRIPTTYPE_COMPLEX: + if( 0 == (pRet = GetItemOfScriptSet( rSet, nLatin )) || + 0 == (pCmplx = GetItemOfScriptSet( rSet, nComplex )) || + *pRet != *pCmplx ) + pRet = 0; + break; + + case SCRIPTTYPE_ASIAN|SCRIPTTYPE_COMPLEX: + if( 0 == (pRet = GetItemOfScriptSet( rSet, nAsian )) || + 0 == (pCmplx = GetItemOfScriptSet( rSet, nComplex )) || + *pRet != *pCmplx ) + pRet = 0; + break; + + case SCRIPTTYPE_LATIN|SCRIPTTYPE_ASIAN|SCRIPTTYPE_COMPLEX: + if( 0 == (pRet = GetItemOfScriptSet( rSet, nLatin )) || + 0 == (pAsn = GetItemOfScriptSet( rSet, nAsian )) || + 0 == (pCmplx = GetItemOfScriptSet( rSet, nComplex )) || + *pRet != *pAsn || *pRet != *pCmplx ) + pRet = 0; + break; + } + return pRet; +} + +const SfxPoolItem* SvxScriptSetItem::GetItemOfScript( USHORT nScript ) const +{ + return GetItemOfScript( Which(), GetItemSet(), nScript ); +} + +void SvxScriptSetItem::PutItemForScriptType( USHORT nScriptType, + const SfxPoolItem& rItem ) +{ + USHORT nLatin, nAsian, nComplex; + GetWhichIds( nLatin, nAsian, nComplex ); + + SfxPoolItem* pCpy = rItem.Clone(); + if( SCRIPTTYPE_LATIN & nScriptType ) + { + pCpy->SetWhich( nLatin ); + GetItemSet().Put( *pCpy ); + } + if( SCRIPTTYPE_ASIAN & nScriptType ) + { + pCpy->SetWhich( nAsian ); + GetItemSet().Put( *pCpy ); + } + if( SCRIPTTYPE_COMPLEX & nScriptType ) + { + pCpy->SetWhich( nComplex ); + GetItemSet().Put( *pCpy ); + } + delete pCpy; +} + +void SvxScriptSetItem::GetWhichIds( USHORT nSlotId, const SfxItemSet& rSet, USHORT& rLatin, USHORT& rAsian, USHORT& rComplex ) +{ + const SfxItemPool& rPool = *rSet.GetPool(); + GetSlotIds( nSlotId, rLatin, rAsian, rComplex ); + rLatin = rPool.GetWhich( rLatin ); + rAsian = rPool.GetWhich( rAsian ); + rComplex = rPool.GetWhich( rComplex ); +} + +void SvxScriptSetItem::GetWhichIds( USHORT& rLatin, USHORT& rAsian, + USHORT& rComplex ) const +{ + GetWhichIds( Which(), GetItemSet(), rLatin, rAsian, rComplex ); +} + +void SvxScriptSetItem::GetSlotIds( USHORT nSlotId, USHORT& rLatin, + USHORT& rAsian, USHORT& rComplex ) +{ + switch( nSlotId ) + { + default: + DBG_ASSERT( FALSE, "wrong SlotId for class SvxScriptSetItem" ); + // no break - default to font - Id Range !! + + case SID_ATTR_CHAR_FONT: + rLatin = SID_ATTR_CHAR_FONT; + rAsian = SID_ATTR_CHAR_CJK_FONT; + rComplex = SID_ATTR_CHAR_CTL_FONT; + break; + case SID_ATTR_CHAR_FONTHEIGHT: + rLatin = SID_ATTR_CHAR_FONTHEIGHT; + rAsian = SID_ATTR_CHAR_CJK_FONTHEIGHT; + rComplex = SID_ATTR_CHAR_CTL_FONTHEIGHT; + break; + case SID_ATTR_CHAR_WEIGHT: + rLatin = SID_ATTR_CHAR_WEIGHT; + rAsian = SID_ATTR_CHAR_CJK_WEIGHT; + rComplex = SID_ATTR_CHAR_CTL_WEIGHT; + break; + case SID_ATTR_CHAR_POSTURE: + rLatin = SID_ATTR_CHAR_POSTURE; + rAsian = SID_ATTR_CHAR_CJK_POSTURE; + rComplex = SID_ATTR_CHAR_CTL_POSTURE; + break; + case SID_ATTR_CHAR_LANGUAGE: + rLatin = SID_ATTR_CHAR_LANGUAGE; + rAsian = SID_ATTR_CHAR_CJK_LANGUAGE; + rComplex = SID_ATTR_CHAR_CTL_LANGUAGE; + break; + } +} + +void GetDefaultFonts( SvxFontItem& rLatin, SvxFontItem& rAsian, SvxFontItem& rComplex ) +{ + const USHORT nItemCnt = 3; + + static struct + { + USHORT nFontType; + USHORT nLanguage; + } + aOutTypeArr[ nItemCnt ] = + { + { DEFAULTFONT_LATIN_TEXT, LANGUAGE_ENGLISH_US }, + { DEFAULTFONT_CJK_TEXT, LANGUAGE_ENGLISH_US }, + { DEFAULTFONT_CTL_TEXT, LANGUAGE_ARABIC_SAUDI_ARABIA } + }; + + SvxFontItem* aItemArr[ nItemCnt ] = { &rLatin, &rAsian, &rComplex }; + + for ( USHORT n = 0; n < nItemCnt; ++n ) + { + Font aFont( OutputDevice::GetDefaultFont( aOutTypeArr[ n ].nFontType, + aOutTypeArr[ n ].nLanguage, + DEFAULTFONT_FLAGS_ONLYONE, 0 ) ); + SvxFontItem* pItem = aItemArr[ n ]; + pItem->GetFamily() = aFont.GetFamily(); + pItem->GetFamilyName() = aFont.GetName(); + pItem->GetStyleName().Erase(); + pItem->GetPitch() = aFont.GetPitch(); + pItem->GetCharSet() = aFont.GetCharSet(); + } +} + + +USHORT GetI18NScriptTypeOfLanguage( USHORT nLang ) +{ + return GetI18NScriptType( SvtLanguageOptions::GetScriptTypeOfLanguage( nLang ) ); +} + +USHORT GetItemScriptType( short nI18NType ) +{ + switch ( nI18NType ) + { + case i18n::ScriptType::LATIN: return SCRIPTTYPE_LATIN; + case i18n::ScriptType::ASIAN: return SCRIPTTYPE_ASIAN; + case i18n::ScriptType::COMPLEX: return SCRIPTTYPE_COMPLEX; + } + return 0; +} + +short GetI18NScriptType( USHORT nItemType ) +{ + switch ( nItemType ) + { + case SCRIPTTYPE_LATIN: return i18n::ScriptType::LATIN; + case SCRIPTTYPE_ASIAN: return i18n::ScriptType::ASIAN; + case SCRIPTTYPE_COMPLEX: return i18n::ScriptType::COMPLEX; + } + return 0; +} diff --git a/editeng/source/items/writingmodeitem.cxx b/editeng/source/items/writingmodeitem.cxx new file mode 100644 index 000000000000..585bf5da6d77 --- /dev/null +++ b/editeng/source/items/writingmodeitem.cxx @@ -0,0 +1,156 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: writingmodeitem.cxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +// include --------------------------------------------------------------- + + +#include <editeng/writingmodeitem.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/editrids.hrc> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; + +// class SvxWritingModeItem ------------------------------------------------- + +TYPEINIT1_FACTORY(SvxWritingModeItem, SfxUInt16Item, new SvxWritingModeItem(com::sun::star::text::WritingMode_LR_TB, 0)); + +SvxWritingModeItem::SvxWritingModeItem( WritingMode eValue, USHORT _nWhich ) + : SfxUInt16Item( _nWhich, (sal_uInt16)eValue ) +{ +} + +SvxWritingModeItem::~SvxWritingModeItem() +{ +} + +int SvxWritingModeItem::operator==( const SfxPoolItem& rCmp ) const +{ + DBG_ASSERT( SfxPoolItem::operator==(rCmp), "unequal types" ); + + return GetValue() == ((SvxWritingModeItem&)rCmp).GetValue(); +} + +SfxPoolItem* SvxWritingModeItem::Clone( SfxItemPool * ) const +{ + return new SvxWritingModeItem( *this ); +} + +SfxPoolItem* SvxWritingModeItem::Create( SvStream & , USHORT ) const +{ + DBG_ERROR("SvxWritingModeItem should not be streamed!"); + return NULL; +} + +SvStream& SvxWritingModeItem::Store( SvStream & rStrm, USHORT ) const +{ + DBG_ERROR("SvxWritingModeItem should not be streamed!"); + return rStrm; +} + +USHORT SvxWritingModeItem::GetVersion( USHORT /*nFVer*/ ) const +{ + return USHRT_MAX; +} + +SfxItemPresentation SvxWritingModeItem::GetPresentation( SfxItemPresentation ePres, + SfxMapUnit /*eCoreMetric*/, + SfxMapUnit /*ePresMetric*/, + String &rText, + const IntlWrapper * ) const +{ + SfxItemPresentation eRet = ePres; + switch( ePres ) + { + case SFX_ITEM_PRESENTATION_NONE: + rText.Erase(); + break; + + case SFX_ITEM_PRESENTATION_NAMELESS: + case SFX_ITEM_PRESENTATION_COMPLETE: + rText = String( EditResId( RID_SVXITEMS_FRMDIR_BEGIN + GetValue() ) ); + break; + + default: + eRet = SFX_ITEM_PRESENTATION_NONE; + } + return eRet; +} + +sal_Bool SvxWritingModeItem::PutValue( const com::sun::star::uno::Any& rVal, BYTE ) +{ + sal_Int32 nVal = 0; + sal_Bool bRet = ( rVal >>= nVal ); + + if( !bRet ) + { + WritingMode eMode; + bRet = rVal >>= eMode; + + if( bRet ) + { + nVal = (sal_Int32)eMode; + } + } + + if( bRet ) + { + switch( nVal ) + { + case WritingMode_LR_TB: + case WritingMode_RL_TB: + case WritingMode_TB_RL: + SetValue( (sal_uInt16)nVal ); + bRet = true; + break; + default: + bRet = false; + break; + } + } + + return bRet; +} + +sal_Bool SvxWritingModeItem::QueryValue( com::sun::star::uno::Any& rVal, + BYTE ) const +{ + rVal <<= (WritingMode)GetValue(); + return true; +} + +SvxWritingModeItem& SvxWritingModeItem::operator=( const SvxWritingModeItem& rItem ) +{ + SetValue( rItem.GetValue() ); + return *this; +} diff --git a/editeng/source/items/xmlcnitm.cxx b/editeng/source/items/xmlcnitm.cxx new file mode 100644 index 000000000000..0de29159c748 --- /dev/null +++ b/editeng/source/items/xmlcnitm.cxx @@ -0,0 +1,251 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xmlcnitm.cxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <com/sun/star/xml/AttributeData.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <xmloff/xmlcnimp.hxx> +#include <xmloff/unoatrcn.hxx> +#include <editeng/xmlcnitm.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::xml; + +// ------------------------------------------------------------------------ + +TYPEINIT1(SvXMLAttrContainerItem, SfxPoolItem); + +SvXMLAttrContainerItem::SvXMLAttrContainerItem( USHORT _nWhich ) : + SfxPoolItem( _nWhich ) +{ + pImpl = new SvXMLAttrContainerData; +} + +SvXMLAttrContainerItem::SvXMLAttrContainerItem( + const SvXMLAttrContainerItem& rItem ) : + SfxPoolItem( rItem ) +{ + pImpl = new SvXMLAttrContainerData( *rItem.pImpl ); +} + +SvXMLAttrContainerItem::~SvXMLAttrContainerItem() +{ + delete pImpl; +} + +int SvXMLAttrContainerItem::operator==( const SfxPoolItem& rItem ) const +{ + DBG_ASSERT( rItem.ISA(SvXMLAttrContainerItem), + "SvXMLAttrContainerItem::operator ==(): Bad type"); + return *pImpl == *((const SvXMLAttrContainerItem&)rItem).pImpl; +} + +int SvXMLAttrContainerItem::Compare( const SfxPoolItem &/*rWith*/ ) const +{ + DBG_ASSERT( !this, "not yet implemented" ); + + return 0; +} + +SfxItemPresentation SvXMLAttrContainerItem::GetPresentation( + SfxItemPresentation /*ePresentation*/, + SfxMapUnit /*eCoreMetric*/, + SfxMapUnit /*ePresentationMetric*/, + XubString &/*rText*/, + const IntlWrapper * /*pIntlWrapper*/ ) const +{ + return SFX_ITEM_PRESENTATION_NONE; +} + +USHORT SvXMLAttrContainerItem::GetVersion( USHORT /*nFileFormatVersion*/ ) const +{ + // This item should never be stored + return USHRT_MAX; +} + +BOOL SvXMLAttrContainerItem::QueryValue( com::sun::star::uno::Any& rVal, BYTE /*nMemberId*/ ) const +{ + Reference<XNameContainer> xContainer = + new SvUnoAttributeContainer( new SvXMLAttrContainerData( *pImpl ) ); + + rVal.setValue( &xContainer, ::getCppuType((Reference<XNameContainer>*)0) ); + return TRUE; +} +BOOL SvXMLAttrContainerItem::PutValue( const com::sun::star::uno::Any& rVal, BYTE /*nMemberId*/ ) +{ + Reference<XInterface> xRef; + SvUnoAttributeContainer* pContainer = NULL; + + if( rVal.getValue() != NULL && rVal.getValueType().getTypeClass() == TypeClass_INTERFACE ) + { + xRef = *(Reference<XInterface>*)rVal.getValue(); + Reference<XUnoTunnel> xTunnel(xRef, UNO_QUERY); + if( xTunnel.is() ) + pContainer = (SvUnoAttributeContainer*)(ULONG)xTunnel->getSomething(SvUnoAttributeContainer::getUnoTunnelId()); + } + + if( pContainer ) + { + delete pImpl; + pImpl = new SvXMLAttrContainerData( * pContainer->GetContainerImpl() ); + } + else + { + SvXMLAttrContainerData* pNewImpl = new SvXMLAttrContainerData; + + try + { + Reference<XNameContainer> xContainer( xRef, UNO_QUERY ); + if( !xContainer.is() ) + return FALSE; + + const Sequence< ::rtl::OUString > aNameSequence( xContainer->getElementNames() ); + const ::rtl::OUString* pNames = aNameSequence.getConstArray(); + const INT32 nCount = aNameSequence.getLength(); + Any aAny; + AttributeData* pData; + INT32 nAttr; + + for( nAttr = 0; nAttr < nCount; nAttr++ ) + { + const ::rtl::OUString aName( *pNames++ ); + + aAny = xContainer->getByName( aName ); + if( aAny.getValue() == NULL || aAny.getValueType() != ::getCppuType((AttributeData*)0) ) + return FALSE; + + pData = (AttributeData*)aAny.getValue(); + sal_Int32 pos = aName.indexOf( sal_Unicode(':') ); + if( pos != -1 ) + { + const ::rtl::OUString aPrefix( aName.copy( 0, pos )); + const ::rtl::OUString aLName( aName.copy( pos+1 )); + + if( pData->Namespace.getLength() == 0 ) + { + if( !pNewImpl->AddAttr( aPrefix, aLName, pData->Value ) ) + break; + } + else + { + if( !pNewImpl->AddAttr( aPrefix, pData->Namespace, aLName, pData->Value ) ) + break; + } + } + else + { + if( !pNewImpl->AddAttr( aName, pData->Value ) ) + break; + } + } + + if( nAttr == nCount ) + { + delete pImpl; + pImpl = pNewImpl; + } + else + { + delete pNewImpl; + return FALSE; + } + } + catch(...) + { + delete pNewImpl; + return FALSE; + } + } + return TRUE; +} + + +BOOL SvXMLAttrContainerItem::AddAttr( const ::rtl::OUString& rLName, + const ::rtl::OUString& rValue ) +{ + return pImpl->AddAttr( rLName, rValue ); +} + +BOOL SvXMLAttrContainerItem::AddAttr( const ::rtl::OUString& rPrefix, + const ::rtl::OUString& rNamespace, const ::rtl::OUString& rLName, + const ::rtl::OUString& rValue ) +{ + return pImpl->AddAttr( rPrefix, rNamespace, rLName, rValue ); +} + +USHORT SvXMLAttrContainerItem::GetAttrCount() const +{ + return (USHORT)pImpl->GetAttrCount(); +} + +::rtl::OUString SvXMLAttrContainerItem::GetAttrNamespace( USHORT i ) const +{ + return pImpl->GetAttrNamespace( i ); +} + +::rtl::OUString SvXMLAttrContainerItem::GetAttrPrefix( USHORT i ) const +{ + return pImpl->GetAttrPrefix( i ); +} + +const ::rtl::OUString& SvXMLAttrContainerItem::GetAttrLName( USHORT i ) const +{ + return pImpl->GetAttrLName( i ); +} + +const ::rtl::OUString& SvXMLAttrContainerItem::GetAttrValue( USHORT i ) const +{ + return pImpl->GetAttrValue( i ); +} + + +USHORT SvXMLAttrContainerItem::GetFirstNamespaceIndex() const +{ + return pImpl->GetFirstNamespaceIndex(); +} + +USHORT SvXMLAttrContainerItem::GetNextNamespaceIndex( USHORT nIdx ) const +{ + return pImpl->GetNextNamespaceIndex( nIdx ); +} + +const ::rtl::OUString& SvXMLAttrContainerItem::GetNamespace( USHORT i ) const +{ + return pImpl->GetNamespace( i ); +} + +const ::rtl::OUString& SvXMLAttrContainerItem::GetPrefix( USHORT i ) const +{ + return pImpl->GetPrefix( i ); +} + diff --git a/editeng/source/misc/SvXMLAutoCorrectExport.cxx b/editeng/source/misc/SvXMLAutoCorrectExport.cxx new file mode 100644 index 000000000000..fec1afcf38a1 --- /dev/null +++ b/editeng/source/misc/SvXMLAutoCorrectExport.cxx @@ -0,0 +1,120 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SvXMLAutoCorrectExport.cxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <SvXMLAutoCorrectExport.hxx> +#define _SVSTDARR_STRINGSISORTDTOR +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::rtl; + +// #110680# +SvXMLAutoCorrectExport::SvXMLAutoCorrectExport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const SvxAutocorrWordList * pNewAutocorr_List, + const rtl::OUString &rFileName, + com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler> &rHandler) +: SvXMLExport( xServiceFactory, rFileName, rHandler ), + pAutocorr_List( pNewAutocorr_List ) +{ + _GetNamespaceMap().Add( GetXMLToken ( XML_NP_BLOCK_LIST), + GetXMLToken ( XML_N_BLOCK_LIST ), + XML_NAMESPACE_BLOCKLIST ); +} + +sal_uInt32 SvXMLAutoCorrectExport::exportDoc(enum XMLTokenEnum /*eClass*/) +{ + GetDocHandler()->startDocument(); + + AddAttribute ( XML_NAMESPACE_NONE, + _GetNamespaceMap().GetAttrNameByKey ( XML_NAMESPACE_BLOCKLIST ), + _GetNamespaceMap().GetNameByKey ( XML_NAMESPACE_BLOCKLIST ) ); + { + SvXMLElementExport aRoot (*this, XML_NAMESPACE_BLOCKLIST, XML_BLOCK_LIST, sal_True, sal_True); + sal_uInt16 nBlocks= pAutocorr_List->Count(); + for ( sal_uInt16 i = 0; i < nBlocks; i++) + { + SvxAutocorrWord* p = pAutocorr_List->GetObject(i); + + AddAttribute( XML_NAMESPACE_BLOCKLIST, + XML_ABBREVIATED_NAME, + OUString(p->GetShort())); + AddAttribute( XML_NAMESPACE_BLOCKLIST, + XML_NAME, + OUString(p->IsTextOnly() ? p->GetLong() : p->GetShort())); + + SvXMLElementExport aBlock( *this, XML_NAMESPACE_BLOCKLIST, XML_BLOCK, sal_True, sal_True); + } + } + GetDocHandler()->endDocument(); + return 0; +} + +// #110680# +SvXMLExceptionListExport::SvXMLExceptionListExport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const SvStringsISortDtor &rNewList, + const rtl::OUString &rFileName, + com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler> &rHandler) +: SvXMLExport( xServiceFactory, rFileName, rHandler ), + rList( rNewList ) +{ + _GetNamespaceMap().Add( GetXMLToken ( XML_NP_BLOCK_LIST ), + GetXMLToken ( XML_N_BLOCK_LIST ), + XML_NAMESPACE_BLOCKLIST ); +} + +sal_uInt32 SvXMLExceptionListExport::exportDoc(enum XMLTokenEnum /*eClass*/) +{ + GetDocHandler()->startDocument(); + + AddAttribute ( XML_NAMESPACE_NONE, + _GetNamespaceMap().GetAttrNameByKey ( XML_NAMESPACE_BLOCKLIST ), + _GetNamespaceMap().GetNameByKey ( XML_NAMESPACE_BLOCKLIST ) ); + { + SvXMLElementExport aRoot (*this, XML_NAMESPACE_BLOCKLIST, XML_BLOCK_LIST, sal_True, sal_True); + sal_uInt16 nBlocks= rList.Count(); + for ( sal_uInt16 i = 0; i < nBlocks; i++) + { + AddAttribute( XML_NAMESPACE_BLOCKLIST, + XML_ABBREVIATED_NAME, + OUString( *rList[i] ) ); + SvXMLElementExport aBlock( *this, XML_NAMESPACE_BLOCKLIST, XML_BLOCK, sal_True, sal_True); + } + } + GetDocHandler()->endDocument(); + return 0; +} diff --git a/editeng/source/misc/SvXMLAutoCorrectExport.hxx b/editeng/source/misc/SvXMLAutoCorrectExport.hxx new file mode 100644 index 000000000000..924ca0687427 --- /dev/null +++ b/editeng/source/misc/SvXMLAutoCorrectExport.hxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SvXMLAutoCorrectExport.hxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SV_XMLAUTOCORRECTEXPORT_HXX +#define _SV_XMLAUTOCORRECTEXPORT_HXX + +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlexp.hxx> +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <editeng/svxacorr.hxx> + +class SvXMLAutoCorrectExport : public SvXMLExport +{ +private: + const SvxAutocorrWordList *pAutocorr_List; +public: + // #110680# + SvXMLAutoCorrectExport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const SvxAutocorrWordList * pNewAutocorr_List, + const rtl::OUString &rFileName, + com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler> &rHandler); + + virtual ~SvXMLAutoCorrectExport ( void ) {} + sal_uInt32 exportDoc(enum ::xmloff::token::XMLTokenEnum eClass); + void _ExportAutoStyles() {} + void _ExportMasterStyles () {} + void _ExportContent() {} +}; + +class SvStringsISortDtor; + +class SvXMLExceptionListExport : public SvXMLExport +{ +private: + const SvStringsISortDtor & rList; +public: + // #110680# + SvXMLExceptionListExport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const SvStringsISortDtor &rNewList, + const rtl::OUString &rFileName, + com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler> &rHandler); + + virtual ~SvXMLExceptionListExport ( void ) {} + sal_uInt32 exportDoc(enum ::xmloff::token::XMLTokenEnum eClass); + void _ExportAutoStyles() {} + void _ExportMasterStyles () {} + void _ExportContent() {} +}; +#endif diff --git a/editeng/source/misc/SvXMLAutoCorrectImport.cxx b/editeng/source/misc/SvXMLAutoCorrectImport.cxx new file mode 100644 index 000000000000..16929575a312 --- /dev/null +++ b/editeng/source/misc/SvXMLAutoCorrectImport.cxx @@ -0,0 +1,269 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SvXMLAutoCorrectImport.cxx,v $ + * $Revision: 1.14 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <SvXMLAutoCorrectImport.hxx> +#ifndef _APP_HXX //autogen +#include <vcl/svapp.hxx> +#endif + +#define _SVSTDARR_STRINGSISORTDTOR +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> +#include <xmloff/xmltoken.hxx> + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::rtl; + + +static OUString sBlockList ( RTL_CONSTASCII_USTRINGPARAM ( "_block-list" ) ); + +// #110680# +SvXMLAutoCorrectImport::SvXMLAutoCorrectImport( + const uno::Reference< lang::XMultiServiceFactory > xServiceFactory, + SvxAutocorrWordList *pNewAutocorr_List, + SvxAutoCorrect &rNewAutoCorrect, + const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& rNewStorage) +: SvXMLImport( xServiceFactory ), + pAutocorr_List (pNewAutocorr_List), + rAutoCorrect ( rNewAutoCorrect ), + xStorage ( rNewStorage ) +{ + GetNamespaceMap().Add( + sBlockList, + GetXMLToken ( XML_N_BLOCK_LIST), + XML_NAMESPACE_BLOCKLIST ); +} + +SvXMLAutoCorrectImport::~SvXMLAutoCorrectImport ( void ) throw () +{ +} + +SvXMLImportContext *SvXMLAutoCorrectImport::CreateContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext *pContext = 0; + + if( XML_NAMESPACE_BLOCKLIST == nPrefix && + IsXMLToken ( rLocalName, XML_BLOCK_LIST ) ) + pContext = new SvXMLWordListContext( *this, nPrefix, rLocalName, xAttrList ); + else + pContext = SvXMLImport::CreateContext( nPrefix, rLocalName, xAttrList ); + return pContext; +} + +SvXMLWordListContext::SvXMLWordListContext( + SvXMLAutoCorrectImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList > & /*xAttrList*/ ) : + SvXMLImportContext ( rImport, nPrefix, rLocalName ), + rLocalRef(rImport) +{ +} + +SvXMLImportContext *SvXMLWordListContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext *pContext = 0; + + if (nPrefix == XML_NAMESPACE_BLOCKLIST && + IsXMLToken ( rLocalName, XML_BLOCK ) ) + pContext = new SvXMLWordContext (rLocalRef, nPrefix, rLocalName, xAttrList); + else + pContext = new SvXMLImportContext( rLocalRef, nPrefix, rLocalName); + return pContext; +} +SvXMLWordListContext::~SvXMLWordListContext ( void ) +{ +} + +SvXMLWordContext::SvXMLWordContext( + SvXMLAutoCorrectImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList > & xAttrList ) : + SvXMLImportContext ( rImport, nPrefix, rLocalName ), + rLocalRef(rImport) +{ + String sRight, sWrong; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + + for (sal_Int16 i=0; i < nAttrCount; i++) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName); + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + if (XML_NAMESPACE_BLOCKLIST == nAttrPrefix) + { + if ( IsXMLToken ( aLocalName, XML_ABBREVIATED_NAME ) ) + { + sWrong = rAttrValue; + } + else if ( IsXMLToken ( aLocalName, XML_NAME ) ) + { + sRight = rAttrValue; + } + } + } + if (!sWrong.Len() || !sRight.Len() ) + return; + +// const International& rInter = Application::GetAppInternational(); +// BOOL bOnlyTxt = COMPARE_EQUAL != rInter.Compare( sRight, sWrong, INTN_COMPARE_IGNORECASE ); + BOOL bOnlyTxt = sRight != sWrong; + if( !bOnlyTxt ) + { + String sLongSave( sRight ); + if( !rLocalRef.rAutoCorrect.GetLongText( rLocalRef.xStorage, String(), sWrong, sRight ) && + sLongSave.Len() ) + { + sRight = sLongSave; + bOnlyTxt = TRUE; + } + } + SvxAutocorrWordPtr pNew = new SvxAutocorrWord( sWrong, sRight, bOnlyTxt ); + + if( !rLocalRef.pAutocorr_List->Insert( pNew ) ) + delete pNew; +} + +SvXMLWordContext::~SvXMLWordContext ( void ) +{ +} + +// #110680# +SvXMLExceptionListImport::SvXMLExceptionListImport( + const uno::Reference< lang::XMultiServiceFactory > xServiceFactory, + SvStringsISortDtor & rNewList ) +: SvXMLImport( xServiceFactory ), + rList (rNewList) +{ + GetNamespaceMap().Add( + sBlockList, + GetXMLToken ( XML_N_BLOCK_LIST), + XML_NAMESPACE_BLOCKLIST ); +} + +SvXMLExceptionListImport::~SvXMLExceptionListImport ( void ) throw () +{ +} + +SvXMLImportContext *SvXMLExceptionListImport::CreateContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext *pContext = 0; + + if( XML_NAMESPACE_BLOCKLIST==nPrefix && + IsXMLToken ( rLocalName, XML_BLOCK_LIST ) ) + pContext = new SvXMLExceptionListContext( *this, nPrefix, rLocalName, xAttrList ); + else + pContext = SvXMLImport::CreateContext( nPrefix, rLocalName, xAttrList ); + return pContext; +} + +SvXMLExceptionListContext::SvXMLExceptionListContext( + SvXMLExceptionListImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList > & /* xAttrList */ ) : + SvXMLImportContext ( rImport, nPrefix, rLocalName ), + rLocalRef(rImport) +{ +} + +SvXMLImportContext *SvXMLExceptionListContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const uno::Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLImportContext *pContext = 0; + + if (nPrefix == XML_NAMESPACE_BLOCKLIST && + IsXMLToken ( rLocalName, XML_BLOCK ) ) + pContext = new SvXMLExceptionContext (rLocalRef, nPrefix, rLocalName, xAttrList); + else + pContext = new SvXMLImportContext( rLocalRef, nPrefix, rLocalName); + return pContext; +} +SvXMLExceptionListContext::~SvXMLExceptionListContext ( void ) +{ +} + +SvXMLExceptionContext::SvXMLExceptionContext( + SvXMLExceptionListImport& rImport, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const com::sun::star::uno::Reference< + com::sun::star::xml::sax::XAttributeList > & xAttrList ) : + SvXMLImportContext ( rImport, nPrefix, rLocalName ), + rLocalRef(rImport) +{ + String sWord; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + + for (sal_Int16 i=0; i < nAttrCount; i++) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName); + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + if (XML_NAMESPACE_BLOCKLIST == nAttrPrefix) + { + if ( IsXMLToken ( aLocalName, XML_ABBREVIATED_NAME ) ) + { + sWord = rAttrValue; + } + } + } + if (!sWord.Len() ) + return; + + String * pNew = new String( sWord ); + + if( !rLocalRef.rList.Insert( pNew ) ) + delete pNew; +} + +SvXMLExceptionContext::~SvXMLExceptionContext ( void ) +{ +} diff --git a/editeng/source/misc/SvXMLAutoCorrectImport.hxx b/editeng/source/misc/SvXMLAutoCorrectImport.hxx new file mode 100644 index 000000000000..dd03bceb2158 --- /dev/null +++ b/editeng/source/misc/SvXMLAutoCorrectImport.hxx @@ -0,0 +1,151 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SvXMLAutoCorrectImport.hxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _SV_XMLAUTOCORRECTIMPORT_HXX +#define _SV_XMLAUTOCORRECTIMPORT_HXX + +#ifndef _SVSTOR_HXX +#include <sot/storage.hxx> +#endif +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <editeng/svxacorr.hxx> + +class SvXMLAutoCorrectImport : public SvXMLImport +{ +protected: + + // This method is called after the namespace map has been updated, but + // before a context for the current element has been pushed. + virtual SvXMLImportContext *CreateContext( sal_uInt16 nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); +public: + SvxAutocorrWordList *pAutocorr_List; + SvxAutoCorrect &rAutoCorrect; + com::sun::star::uno::Reference < com::sun::star::embed::XStorage > xStorage; + //SvStorageRef &rStorage; + + // #110680# + SvXMLAutoCorrectImport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + SvxAutocorrWordList *pNewAutocorr_List, + SvxAutoCorrect &rNewAutoCorrect, + const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >& rNewStorage); + + ~SvXMLAutoCorrectImport ( void ) throw (); +}; + +class SvXMLWordListContext : public SvXMLImportContext +{ +private: + SvXMLAutoCorrectImport & rLocalRef; +public: + SvXMLWordListContext ( SvXMLAutoCorrectImport& rImport, + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + ~SvXMLWordListContext ( void ); +}; + +class SvXMLWordContext : public SvXMLImportContext +{ +private: + SvXMLAutoCorrectImport & rLocalRef; +public: + SvXMLWordContext ( SvXMLAutoCorrectImport& rImport, + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + ~SvXMLWordContext ( void ); +}; + + +class SvXMLExceptionListImport : public SvXMLImport +{ +protected: + + // This method is called after the namespace map has been updated, but + // before a context for the current element has been pushed. + virtual SvXMLImportContext *CreateContext( sal_uInt16 nPrefix, + const ::rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); +public: + SvStringsISortDtor &rList; + + // #110680# + SvXMLExceptionListImport( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + SvStringsISortDtor & rNewList ); + + ~SvXMLExceptionListImport ( void ) throw (); +}; + +class SvXMLExceptionListContext : public SvXMLImportContext +{ +private: + SvXMLExceptionListImport & rLocalRef; +public: + SvXMLExceptionListContext ( SvXMLExceptionListImport& rImport, + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + ~SvXMLExceptionListContext ( void ); +}; + +class SvXMLExceptionContext : public SvXMLImportContext +{ +private: + SvXMLExceptionListImport & rLocalRef; +public: + SvXMLExceptionContext ( SvXMLExceptionListImport& rImport, + sal_uInt16 nPrefix, + const rtl::OUString& rLocalName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::xml::sax::XAttributeList > & xAttrList ); + ~SvXMLExceptionContext ( void ); +}; + + +#endif diff --git a/editeng/source/misc/acorrcfg.cxx b/editeng/source/misc/acorrcfg.cxx new file mode 100644 index 000000000000..30295c2b7094 --- /dev/null +++ b/editeng/source/misc/acorrcfg.cxx @@ -0,0 +1,681 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: acorrcfg.cxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/acorrcfg.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <unotools/pathoptions.hxx> +#include <svl/urihelper.hxx> + +#include <editeng/svxacorr.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Sequence.hxx> + +using namespace utl; +using namespace rtl; +using namespace com::sun::star::uno; + +#define C2U(cChar) OUString::createFromAscii(cChar) + +static SvxAutoCorrCfg* pAutoCorrCfg = 0; + +/*-------------------------------------------------------------------- + Beschreibung: Ctor Dtor + --------------------------------------------------------------------*/ + +SvxAutoCorrCfg::SvxAutoCorrCfg() : + aBaseConfig(*this), + aSwConfig(*this), + bFileRel(TRUE), + bNetRel(TRUE), + bAutoTextTip(TRUE), + bAutoTextPreview(FALSE), + bAutoFmtByInput(TRUE), + bSearchInAllCategories(FALSE) +{ + SvtPathOptions aPathOpt; + String sSharePath, sUserPath, sAutoPath( aPathOpt.GetAutoCorrectPath() ); + + String* pS = &sSharePath; + for( USHORT n = 0; n < 2; ++n, pS = &sUserPath ) + { + *pS = sAutoPath.GetToken( n, ';' ); + INetURLObject aPath( *pS ); + aPath.insertName( String::CreateFromAscii("acor") ); + *pS = aPath.GetMainURL(INetURLObject::DECODE_TO_IURI); + } + pAutoCorrect = new SvxAutoCorrect( sSharePath, sUserPath ); + + aBaseConfig.Load(sal_True); + aSwConfig.Load(sal_True); +} + +SvxAutoCorrCfg::~SvxAutoCorrCfg() +{ + delete pAutoCorrect; +} + +void SvxAutoCorrCfg::SetAutoCorrect( SvxAutoCorrect* pNew ) +{ + if( pNew && pNew != pAutoCorrect ) + { + if( pAutoCorrect->GetFlags() != pNew->GetFlags() ) + { + aBaseConfig.SetModified(); + aSwConfig.SetModified(); + } + delete pAutoCorrect; + pAutoCorrect = pNew; + } +} +/*-- 12.10.00 11:44:17--------------------------------------------------- + + -----------------------------------------------------------------------*/ +Sequence<OUString> SvxBaseAutoCorrCfg::GetPropertyNames() +{ + static const char* aPropNames[] = + { + "Exceptions/TwoCapitalsAtStart", // 0 + "Exceptions/CapitalAtStartSentence", // 1 + "UseReplacementTable", // 2 + "TwoCapitalsAtStart", // 3 + "CapitalAtStartSentence", // 4 + "ChangeUnderlineWeight", // 5 + "SetInetAttribute", // 6 + "ChangeOrdinalNumber", // 7 + "ChangeFraction", // 8 + "ChangeDash", // 9 + "RemoveDoubleSpaces", // 10 + "ReplaceSingleQuote", // 11 + "SingleQuoteAtStart", // 12 + "SingleQuoteAtEnd", // 13 + "ReplaceDoubleQuote", // 14 + "DoubleQuoteAtStart", // 15 + "DoubleQuoteAtEnd" // 16 + }; + const int nCount = 17; + Sequence<OUString> aNames(nCount); + OUString* pNames = aNames.getArray(); + for(int i = 0; i < nCount; i++) + pNames[i] = OUString::createFromAscii(aPropNames[i]); + return aNames; +} +/*-- 12.10.00 11:44:18--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxBaseAutoCorrCfg::Load(sal_Bool bInit) +{ + Sequence<OUString> aNames = GetPropertyNames(); + Sequence<Any> aValues = GetProperties(aNames); + if(bInit) + EnableNotification(aNames); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed"); + if(aValues.getLength() == aNames.getLength()) + { + long nFlags = 0; // default alles aus + sal_Int32 nTemp = 0; + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + if(pValues[nProp].hasValue()) + { + switch(nProp) + { + case 0: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= SaveWordCplSttLst; + break;//"Exceptions/TwoCapitalsAtStart", + case 1: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= SaveWordWrdSttLst; + break;//"Exceptions/CapitalAtStartSentence", + case 2: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= Autocorrect; + break;//"UseReplacementTable", + case 3: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= CptlSttWrd; + break;//"TwoCapitalsAtStart", + case 4: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= CptlSttSntnc; + break;//"CapitalAtStartSentence", + case 5: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgWeightUnderl; + break;//"ChangeUnderlineWeight", + case 6: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= SetINetAttr; + break;//"SetInetAttribute", + case 7: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgOrdinalNumber; + break;//"ChangeOrdinalNumber", + case 8: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgFractionSymbol; + break;//"ChangeFraction", + case 9: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgToEnEmDash; + break;//"ChangeDash", + case 10: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= IngnoreDoubleSpace; + break;//"RemoveDoubleSpaces", + case 11: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgSglQuotes; + break;//"ReplaceSingleQuote", + case 12: + pValues[nProp] >>= nTemp; + rParent.pAutoCorrect->SetStartSingleQuote( + sal::static_int_cast< sal_Unicode >( nTemp ) ); + break;//"SingleQuoteAtStart", + case 13: + pValues[nProp] >>= nTemp; + rParent.pAutoCorrect->SetEndSingleQuote( + sal::static_int_cast< sal_Unicode >( nTemp ) ); + break;//"SingleQuoteAtEnd", + case 14: + if(*(sal_Bool*)pValues[nProp].getValue()) + nFlags |= ChgQuotes; + break;//"ReplaceDoubleQuote", + case 15: + pValues[nProp] >>= nTemp; + rParent.pAutoCorrect->SetStartDoubleQuote( + sal::static_int_cast< sal_Unicode >( nTemp ) ); + break;//"DoubleQuoteAtStart", + case 16: + pValues[nProp] >>= nTemp; + rParent.pAutoCorrect->SetEndDoubleQuote( + sal::static_int_cast< sal_Unicode >( nTemp ) ); + break;//"DoubleQuoteAtEnd" + } + } + } + if( nFlags ) + rParent.pAutoCorrect->SetAutoCorrFlag( nFlags, TRUE ); + rParent.pAutoCorrect->SetAutoCorrFlag( ( 0xffff & ~nFlags ), FALSE ); + + } +} +/*-- 12.10.00 11:44:19--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxBaseAutoCorrCfg::SvxBaseAutoCorrCfg(SvxAutoCorrCfg& rPar) : + utl::ConfigItem(C2U("Office.Common/AutoCorrect")), + rParent(rPar) +{ +} +/*-- 12.10.00 11:44:19--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxBaseAutoCorrCfg::~SvxBaseAutoCorrCfg() +{ +} +/*-- 12.10.00 11:44:20--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxBaseAutoCorrCfg::Commit() +{ + Sequence<OUString> aNames( GetPropertyNames() ); + + Sequence<Any> aValues(aNames.getLength()); + Any* pValues = aValues.getArray(); + + const Type& rType = ::getBooleanCppuType(); + BOOL bVal; + const long nFlags = rParent.pAutoCorrect->GetFlags(); + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + switch(nProp) + { + case 0: + bVal = 0 != (nFlags & SaveWordCplSttLst); + pValues[nProp].setValue(&bVal, rType); + break;//"Exceptions/TwoCapitalsAtStart", + case 1: + bVal = 0 != (nFlags & SaveWordWrdSttLst); + pValues[nProp].setValue(&bVal, rType); + break;//"Exceptions/CapitalAtStartSentence", + case 2: + bVal = 0 != (nFlags & Autocorrect); + pValues[nProp].setValue(&bVal, rType); + break;//"UseReplacementTable", + case 3: + bVal = 0 != (nFlags & CptlSttWrd); + pValues[nProp].setValue(&bVal, rType); + break;//"TwoCapitalsAtStart", + case 4: + bVal = 0 != (nFlags & CptlSttSntnc); + pValues[nProp].setValue(&bVal, rType); + break;//"CapitalAtStartSentence", + case 5: + bVal = 0 != (nFlags & ChgWeightUnderl); + pValues[nProp].setValue(&bVal, rType); + break;//"ChangeUnderlineWeight", + case 6: + bVal = 0 != (nFlags & SetINetAttr); + pValues[nProp].setValue(&bVal, rType); + break;//"SetInetAttribute", + case 7: + bVal = 0 != (nFlags & ChgOrdinalNumber); + pValues[nProp].setValue(&bVal, rType); + break;//"ChangeOrdinalNumber", + case 8: + bVal = 0 != (nFlags & ChgFractionSymbol); + pValues[nProp].setValue(&bVal, rType); + break;//"ChangeFraction", + case 9: + bVal = 0 != (nFlags & ChgToEnEmDash); + pValues[nProp].setValue(&bVal, rType); + break;//"ChangeDash", + case 10: + bVal = 0 != (nFlags & IngnoreDoubleSpace); + pValues[nProp].setValue(&bVal, rType); + break;//"RemoveDoubleSpaces", + case 11: + bVal = 0 != (nFlags & ChgSglQuotes); + pValues[nProp].setValue(&bVal, rType); + break;//"ReplaceSingleQuote", + case 12: + pValues[nProp] <<= (sal_Int32)rParent.pAutoCorrect->GetStartSingleQuote(); + break;//"SingleQuoteAtStart", + case 13: + pValues[nProp] <<= (sal_Int32) rParent.pAutoCorrect->GetEndSingleQuote(); + break;//"SingleQuoteAtEnd", + case 14: + bVal = 0 != (nFlags & ChgQuotes); + pValues[nProp].setValue(&bVal, rType); + break;//"ReplaceDoubleQuote", + case 15: + pValues[nProp] <<= (sal_Int32) rParent.pAutoCorrect->GetStartDoubleQuote(); + break;//"DoubleQuoteAtStart", + case 16: + pValues[nProp] <<= (sal_Int32) rParent.pAutoCorrect->GetEndDoubleQuote(); + break;//"DoubleQuoteAtEnd" + } + } + PutProperties(aNames, aValues); +} +/*-- 12.10.00 11:44:21--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxBaseAutoCorrCfg::Notify( const Sequence<OUString>& /* aPropertyNames */) +{ + Load(sal_False); +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +Sequence<OUString> SvxSwAutoCorrCfg::GetPropertyNames() +{ + static const char* aPropNames[] = + { + "Text/FileLinks", // 0 + "Text/InternetLinks", // 1 + "Text/ShowPreview", // 2 + "Text/ShowToolTip", // 3 + "Text/SearchInAllCategories", // 4 + "Format/Option/UseReplacementTable", // 5 + "Format/Option/TwoCapitalsAtStart", // 6 + "Format/Option/CapitalAtStartSentence", // 7 + "Format/Option/ChangeUnderlineWeight", // 8 + "Format/Option/SetInetAttribute", // 9 + "Format/Option/ChangeOrdinalNumber", //10 + "Format/Option/ChangeFraction", //11 + "Format/Option/ChangeDash", //12 + "Format/Option/DelEmptyParagraphs", //13 + "Format/Option/ReplaceUserStyle", //14 + "Format/Option/ChangeToBullets/Enable", //15 + "Format/Option/ChangeToBullets/SpecialCharacter/Char", //16 + "Format/Option/ChangeToBullets/SpecialCharacter/Font", //17 + "Format/Option/ChangeToBullets/SpecialCharacter/FontFamily", //18 + "Format/Option/ChangeToBullets/SpecialCharacter/FontCharset", //19 + "Format/Option/ChangeToBullets/SpecialCharacter/FontPitch", //20 + "Format/Option/ReplaceQuote", //21 + "Format/Option/CombineParagraphs", //22 + "Format/Option/CombineValue", //23 + "Format/Option/DelSpacesAtStartEnd", //24 + "Format/Option/DelSpacesBetween", //25 + "Format/ByInput/Enable", //26 + "Format/ByInput/ChangeDash", //27 + "Format/ByInput/ApplyNumbering/Enable", //28 + "Format/ByInput/ChangeToBorders", //29 + "Format/ByInput/ChangeToTable", //30 + "Format/ByInput/ReplaceStyle", //31 + "Format/ByInput/DelSpacesAtStartEnd", //32 + "Format/ByInput/DelSpacesBetween", //33 + "Completion/Enable", //34 + "Completion/MinWordLen", //35 + "Completion/MaxListLen", //36 + "Completion/CollectWords", //37 + "Completion/EndlessList", //38 + "Completion/AppendBlank", //39 + "Completion/ShowAsTip", //40 + "Completion/AcceptKey", //41 + "Completion/KeepList", //42 + "Format/ByInput/ApplyNumbering/SpecialCharacter/Char", //43 + "Format/ByInput/ApplyNumbering/SpecialCharacter/Font", //44 + "Format/ByInput/ApplyNumbering/SpecialCharacter/FontFamily", //45 + "Format/ByInput/ApplyNumbering/SpecialCharacter/FontCharset", //46 + "Format/ByInput/ApplyNumbering/SpecialCharacter/FontPitch", //47 + }; + const int nCount = 48; + Sequence<OUString> aNames(nCount); + OUString* pNames = aNames.getArray(); + for(int i = 0; i < nCount; i++) + pNames[i] = OUString::createFromAscii(aPropNames[i]); + return aNames; +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxSwAutoCorrCfg::Load(sal_Bool bInit) +{ + Sequence<OUString> aNames = GetPropertyNames(); + Sequence<Any> aValues = GetProperties(aNames); + if(bInit) + EnableNotification(aNames); + const Any* pValues = aValues.getConstArray(); + DBG_ASSERT(aValues.getLength() == aNames.getLength(), "GetProperties failed"); + if(aValues.getLength() == aNames.getLength()) + { + SvxSwAutoFmtFlags& rSwFlags = rParent.pAutoCorrect->GetSwFlags(); + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + if(pValues[nProp].hasValue()) + { + switch(nProp) + { + case 0: rParent.bFileRel = *(sal_Bool*)pValues[nProp].getValue(); break; // "Text/FileLinks", + case 1: rParent.bNetRel = *(sal_Bool*)pValues[nProp].getValue(); break; // "Text/InternetLinks", + case 2: rParent.bAutoTextPreview = *(sal_Bool*)pValues[nProp].getValue(); break; // "Text/ShowPreview", + case 3: rParent.bAutoTextTip = *(sal_Bool*)pValues[nProp].getValue(); break; // "Text/ShowToolTip", + case 4: rParent.bSearchInAllCategories = *(sal_Bool*)pValues[nProp].getValue(); break; //"Text/SearchInAllCategories" + case 5: rSwFlags.bAutoCorrect = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/UseReplacementTable", + case 6: rSwFlags.bCptlSttSntnc = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/TwoCapitalsAtStart", + case 7: rSwFlags.bCptlSttWrd = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/CapitalAtStartSentence", + case 8: rSwFlags.bChgWeightUnderl = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeUnderlineWeight", + case 9: rSwFlags.bSetINetAttr = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/SetInetAttribute", + case 10: rSwFlags.bChgOrdinalNumber = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeOrdinalNumber", + case 11: rSwFlags.bChgFracionSymbol = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeFraction", +// it doesn't exist here - the common flags are used for that -> LM +// case 12: rSwFlags.bChgToEnEmDash = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeDash", + case 13: rSwFlags.bDelEmptyNode = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/DelEmptyParagraphs", + case 14: rSwFlags.bChgUserColl = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ReplaceUserStyle", + case 15: rSwFlags.bChgEnumNum = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ChangeToBullets/Enable", + case 16: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.cBullet = + sal::static_int_cast< sal_Unicode >(nVal); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/Char", + case 17: + { + OUString sTemp; pValues[nProp] >>= sTemp; + rSwFlags.aBulletFont.SetName(sTemp); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/Font", + case 18: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aBulletFont.SetFamily(FontFamily(nVal)); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontFamily", + case 19: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aBulletFont.SetCharSet(CharSet(nVal)); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontCharset", + case 20: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aBulletFont.SetPitch(FontPitch(nVal)); + } + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontPitch", + case 21: rSwFlags.bReplaceQuote = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/ReplaceQuote", + case 22: rSwFlags.bRightMargin = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/CombineParagraphs", + case 23: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.nRightMargin = + sal::static_int_cast< BYTE >(nVal); + } + break; // "Format/Option/CombineValue", + case 24: rSwFlags.bAFmtDelSpacesAtSttEnd = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/DelSpacesAtStartEnd", + case 25: rSwFlags.bAFmtDelSpacesBetweenLines = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/Option/DelSpacesBetween", + case 26: rParent.bAutoFmtByInput = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/Enable", + case 27: rSwFlags.bChgToEnEmDash = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ChangeDash", + case 28: rSwFlags.bSetNumRule = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ApplyNumbering/Enable", + case 29: rSwFlags.bSetBorder = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ChangeToBorders", + case 30: rSwFlags.bCreateTable = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ChangeToTable", + case 31: rSwFlags.bReplaceStyles = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/ReplaceStyle", + case 32: rSwFlags.bAFmtByInpDelSpacesAtSttEnd = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/DelSpacesAtStartEnd", + case 33: rSwFlags.bAFmtByInpDelSpacesBetweenLines = *(sal_Bool*)pValues[nProp].getValue(); break; // "Format/ByInput/DelSpacesBetween", + case 34: rSwFlags.bAutoCompleteWords = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/Enable", + case 35: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.nAutoCmpltWordLen = + sal::static_int_cast< USHORT >(nVal); + } + break; // "Completion/MinWordLen", + case 36: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.nAutoCmpltListLen = + sal::static_int_cast< USHORT >(nVal); + } + break; // "Completion/MaxListLen", + case 37: rSwFlags.bAutoCmpltCollectWords = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/CollectWords", + case 38: rSwFlags.bAutoCmpltEndless = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/EndlessList", + case 39: rSwFlags.bAutoCmpltAppendBlanc = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/AppendBlank", + case 40: rSwFlags.bAutoCmpltShowAsTip = *(sal_Bool*)pValues[nProp].getValue(); break; // "Completion/ShowAsTip", + case 41: + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.nAutoCmpltExpandKey = + sal::static_int_cast< USHORT >(nVal); + } + break; // "Completion/AcceptKey" + case 42 :rSwFlags.bAutoCmpltKeepList = *(sal_Bool*)pValues[nProp].getValue(); break;//"Completion/KeepList" + case 43 : + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.cByInputBullet = + sal::static_int_cast< sal_Unicode >(nVal); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/Char", + case 44 : + { + OUString sTemp; pValues[nProp] >>= sTemp; + rSwFlags.aByInputBulletFont.SetName(sTemp); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/Font", + case 45 : + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aByInputBulletFont.SetFamily(FontFamily(nVal)); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontFamily", + case 46 : + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aByInputBulletFont.SetCharSet(CharSet(nVal)); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontCharset", + case 47 : + { + sal_Int32 nVal = 0; pValues[nProp] >>= nVal; + rSwFlags.aByInputBulletFont.SetPitch(FontPitch(nVal)); + } + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontPitch", + } + } + } + } +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxSwAutoCorrCfg::SvxSwAutoCorrCfg(SvxAutoCorrCfg& rPar) : + utl::ConfigItem(C2U("Office.Writer/AutoFunction")), + rParent(rPar) +{ +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +SvxSwAutoCorrCfg::~SvxSwAutoCorrCfg() +{ +} +/*-- 12.10.00 11:51:48--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxSwAutoCorrCfg::Commit() +{ + Sequence<OUString> aNames = GetPropertyNames(); + + Sequence<Any> aValues(aNames.getLength()); + Any* pValues = aValues.getArray(); + + const Type& rType = ::getBooleanCppuType(); + BOOL bVal; + SvxSwAutoFmtFlags& rSwFlags = rParent.pAutoCorrect->GetSwFlags(); + for(int nProp = 0; nProp < aNames.getLength(); nProp++) + { + switch(nProp) + { + case 0: pValues[nProp].setValue(&rParent.bFileRel, rType); break; // "Text/FileLinks", + case 1: pValues[nProp].setValue(&rParent.bNetRel, rType); break; // "Text/InternetLinks", + case 2: pValues[nProp].setValue(&rParent.bAutoTextPreview, rType); break; // "Text/ShowPreview", + case 3: pValues[nProp].setValue(&rParent.bAutoTextTip, rType); break; // "Text/ShowToolTip", + case 4: pValues[nProp].setValue(&rParent.bSearchInAllCategories, rType );break; //"Text/SearchInAllCategories" + case 5: bVal = rSwFlags.bAutoCorrect; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/UseReplacementTable", + case 6: bVal = rSwFlags.bCptlSttSntnc; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/TwoCapitalsAtStart", + case 7: bVal = rSwFlags.bCptlSttWrd; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/CapitalAtStartSentence", + case 8: bVal = rSwFlags.bChgWeightUnderl; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ChangeUnderlineWeight", + case 9: bVal = rSwFlags.bSetINetAttr; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/SetInetAttribute", + case 10: bVal = rSwFlags.bChgOrdinalNumber; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ChangeOrdinalNumber", + case 11: bVal = rSwFlags.bChgFracionSymbol; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ChangeFraction", +// it doesn't exist here - the common flags are used for that -> LM + case 12: + bVal = sal_True; pValues[nProp].setValue(&bVal, rType); + break; // "Format/Option/ChangeDash", + case 13: bVal = rSwFlags.bDelEmptyNode; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/DelEmptyParagraphs", + case 14: bVal = rSwFlags.bChgUserColl; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ReplaceUserStyle", + case 15: bVal = rSwFlags.bChgEnumNum; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ChangeToBullets/Enable", + case 16: + pValues[nProp] <<= (sal_Int32)rSwFlags.cBullet; + break; // "Format/Option/ChangeToBullets/SpecialCharacter/Char", + case 17: + pValues[nProp] <<= OUString(rSwFlags.aBulletFont.GetName()); + break; // "Format/Option/ChangeToBullets/SpecialCharacter/Font", + case 18: + pValues[nProp] <<= (sal_Int32)rSwFlags.aBulletFont.GetFamily(); + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontFamily", + case 19: + pValues[nProp] <<= (sal_Int32)rSwFlags.aBulletFont.GetCharSet(); + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontCharset", + case 20: + pValues[nProp] <<= (sal_Int32)rSwFlags.aBulletFont.GetPitch(); + break; // "Format/Option/ChangeToBullets/SpecialCharacter/FontPitch", + case 21: bVal = rSwFlags.bReplaceQuote; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/ReplaceQuote", + case 22: bVal = rSwFlags.bRightMargin; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/CombineParagraphs", + case 23: + pValues[nProp] <<= (sal_Int32)rSwFlags.nRightMargin; + break; // "Format/Option/CombineValue", + case 24: bVal = rSwFlags.bAFmtDelSpacesAtSttEnd; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/DelSpacesAtStartEnd", + case 25: bVal = rSwFlags.bAFmtDelSpacesBetweenLines; pValues[nProp].setValue(&bVal, rType); break; // "Format/Option/DelSpacesBetween", + case 26: bVal = rParent.bAutoFmtByInput; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/Enable", + case 27: bVal = rSwFlags.bChgToEnEmDash; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ChangeDash", + case 28: bVal = rSwFlags.bSetNumRule; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ApplyNumbering/Enable", + case 29: bVal = rSwFlags.bSetBorder; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ChangeToBorders", + case 30: bVal = rSwFlags.bCreateTable; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ChangeToTable", + case 31: bVal = rSwFlags.bReplaceStyles; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/ReplaceStyle", + case 32: bVal = rSwFlags.bAFmtByInpDelSpacesAtSttEnd; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/DelSpacesAtStartEnd", + case 33: bVal = rSwFlags.bAFmtByInpDelSpacesBetweenLines; pValues[nProp].setValue(&bVal, rType); break; // "Format/ByInput/DelSpacesBetween", + case 34: bVal = rSwFlags.bAutoCompleteWords; pValues[nProp].setValue(&bVal, rType); break; // "Completion/Enable", + case 35: + pValues[nProp] <<= (sal_Int32)rSwFlags.nAutoCmpltWordLen; + break; // "Completion/MinWordLen", + case 36: + pValues[nProp] <<= (sal_Int32)rSwFlags.nAutoCmpltListLen; + break; // "Completion/MaxListLen", + case 37: bVal = rSwFlags.bAutoCmpltCollectWords; pValues[nProp].setValue(&bVal, rType); break; // "Completion/CollectWords", + case 38: bVal = rSwFlags.bAutoCmpltEndless; pValues[nProp].setValue(&bVal, rType); break; // "Completion/EndlessList", + case 39: bVal = rSwFlags.bAutoCmpltAppendBlanc; pValues[nProp].setValue(&bVal, rType); break; // "Completion/AppendBlank", + case 40: bVal = rSwFlags.bAutoCmpltShowAsTip; pValues[nProp].setValue(&bVal, rType); break; // "Completion/ShowAsTip", + case 41: + pValues[nProp] <<= (sal_Int32)rSwFlags.nAutoCmpltExpandKey; + break; // "Completion/AcceptKey" + case 42 :bVal = rSwFlags.bAutoCmpltKeepList; pValues[nProp].setValue(&bVal, rType); break;// "Completion/KeepList" + case 43 : + pValues[nProp] <<= (sal_Int32)rSwFlags.cByInputBullet; + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/Char", + case 44 : + pValues[nProp] <<= OUString(rSwFlags.aByInputBulletFont.GetName()); + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/Font", + case 45 : + pValues[nProp] <<= (sal_Int32)rSwFlags.aByInputBulletFont.GetFamily(); + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontFamily", + case 46 : + pValues[nProp] <<= (sal_Int32)rSwFlags.aByInputBulletFont.GetCharSet(); + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontCharset", + case 47 : + pValues[nProp] <<= (sal_Int32)rSwFlags.aByInputBulletFont.GetPitch(); + break;// "Format/ByInput/ApplyNumbering/SpecialCharacter/FontPitch", + } + } + PutProperties(aNames, aValues); +} +/*-- 12.10.00 11:51:49--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxSwAutoCorrCfg::Notify( const Sequence<OUString>& /* aPropertyNames */ ) +{ + Load(sal_False); +} + +SvxAutoCorrCfg* SvxAutoCorrCfg::Get() +{ + if( !pAutoCorrCfg ) + pAutoCorrCfg = new SvxAutoCorrCfg; + return pAutoCorrCfg; +} diff --git a/editeng/source/misc/edtdlg.cxx b/editeng/source/misc/edtdlg.cxx new file mode 100755 index 000000000000..3a4e209f3d4f --- /dev/null +++ b/editeng/source/misc/edtdlg.cxx @@ -0,0 +1,43 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: sfxdlg.cxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/edtdlg.hxx> + +EditAbstractDialogFactory* EditAbstractDialogFactory::Create() +{ + return dynamic_cast <EditAbstractDialogFactory*>( VclAbstractDialogFactory::Create() ); +} + +EditAbstractDialogFactory::~EditAbstractDialogFactory() +{ +} diff --git a/editeng/source/misc/forbiddencharacterstable.cxx b/editeng/source/misc/forbiddencharacterstable.cxx new file mode 100644 index 000000000000..83383ed43bc7 --- /dev/null +++ b/editeng/source/misc/forbiddencharacterstable.cxx @@ -0,0 +1,95 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: forbiddencharacterstable.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/forbiddencharacterstable.hxx> + +#include <unotools/localedatawrapper.hxx> +#include <editeng/unolingu.hxx> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +SvxForbiddenCharactersTable::SvxForbiddenCharactersTable( ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF, USHORT nISize, USHORT nGrow ) + : SvxForbiddenCharactersTableImpl( nISize, nGrow ) +{ + mxMSF = xMSF; +} + + +SvxForbiddenCharactersTable::~SvxForbiddenCharactersTable() +{ + for ( ULONG n = Count(); n; ) + delete GetObject( --n ); +} + + + +const com::sun::star::i18n::ForbiddenCharacters* SvxForbiddenCharactersTable::GetForbiddenCharacters( USHORT nLanguage, BOOL bGetDefault ) const +{ + ForbiddenCharactersInfo* pInf = Get( nLanguage ); + if ( !pInf && bGetDefault && mxMSF.is() ) + { + const SvxForbiddenCharactersTableImpl *pConstImpl = dynamic_cast<const SvxForbiddenCharactersTableImpl*>(this); + SvxForbiddenCharactersTableImpl* pImpl = const_cast<SvxForbiddenCharactersTableImpl*>(pConstImpl); + pInf = new ForbiddenCharactersInfo; + pImpl->Insert( nLanguage, pInf ); + + pInf->bTemporary = TRUE; + LocaleDataWrapper aWrapper( mxMSF, SvxCreateLocale( nLanguage ) ); + pInf->aForbiddenChars = aWrapper.getForbiddenCharacters(); + } + return pInf ? &pInf->aForbiddenChars : NULL; +} + + + +void SvxForbiddenCharactersTable::SetForbiddenCharacters( USHORT nLanguage, const com::sun::star::i18n::ForbiddenCharacters& rForbiddenChars ) +{ + ForbiddenCharactersInfo* pInf = Get( nLanguage ); + if ( !pInf ) + { + pInf = new ForbiddenCharactersInfo; + Insert( nLanguage, pInf ); + } + pInf->bTemporary = FALSE; + pInf->aForbiddenChars = rForbiddenChars; +} + +void SvxForbiddenCharactersTable::ClearForbiddenCharacters( USHORT nLanguage ) +{ + ForbiddenCharactersInfo* pInf = Get( nLanguage ); + if ( pInf ) + { + Remove( nLanguage ); + delete pInf; + } +} diff --git a/editeng/source/misc/hangulhanja.cxx b/editeng/source/misc/hangulhanja.cxx new file mode 100644 index 000000000000..adc624eeaec5 --- /dev/null +++ b/editeng/source/misc/hangulhanja.cxx @@ -0,0 +1,1174 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: hangulhanja.cxx,v $ + * $Revision: 1.20.102.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <editeng/hangulhanja.hxx> +#include <vcl/msgbox.hxx> +#include <vcl/button.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/linguprops.hxx> + +#include <set> +#include <map> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/i18n/XBreakIterator.hpp> +#include <com/sun/star/i18n/ScriptType.hpp> +#include <com/sun/star/i18n/UnicodeScript.hpp> +#include <com/sun/star/i18n/XTextConversion.hpp> +#include <com/sun/star/i18n/XExtendedTextConversion.hpp> +#include <com/sun/star/i18n/TextConversionType.hpp> +#include <com/sun/star/i18n/TextConversionOption.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <vcl/stdtext.hxx> +#include <unotools/charclass.hxx> + +#include <editeng/edtdlg.hxx> +#include <editeng/editrids.hrc> +#include <editeng/unolingu.hxx> + +#define HHC HangulHanjaConversion + +//............................................................................. +namespace editeng +{ +//............................................................................. + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::i18n; + using namespace ::com::sun::star::i18n::TextConversionOption; + using namespace ::com::sun::star::i18n::TextConversionType; + using namespace ::com::sun::star::lang; +/* + using HangulHanjaConversion::ReplacementAction; + using HangulHanjaConversion::eExchange; + using HangulHanjaConversion::eReplacementBracketed; + using HangulHanjaConversion::eOriginalBracketed; + using HangulHanjaConversion::eReplacementAbove; + using HangulHanjaConversion::eOriginalAbove; + using HangulHanjaConversion::eReplacementBelow; + using HangulHanjaConversion::eOriginalBelow; + + using HangulHanjaConversion::eHangulToHanja; + using HangulHanjaConversion::eHanjaToHangul; + + using HangulHanjaConversion::eSimpleConversion; + using HangulHanjaConversion::eHangulBracketed; + using HangulHanjaConversion::eHanjaBracketed; + using HangulHanjaConversion::eRubyHanjaAbove; + using HangulHanjaConversion::eRubyHanjaBelow; + using HangulHanjaConversion::eRubyHangulAbove; + using HangulHanjaConversion::eRubyHangulBelow; + + using ::com::sun::star::i18n::TextConversionType::TO_HANJA; + using ::com::sun::star::i18n::TextConversionType::TO_HANGUL; + using ::com::sun::star::i18n::TextConversionOption::CHARACTER_BY_CHARACTER; + using ::com::sun::star::i18n::TextConversionOption::NONE; +*/ + //========================================================================= + //= HangulHanjaConversion_Impl + //========================================================================= + //using HangulHanjaConversion::ConversionFormat; + + class HangulHanjaConversion_Impl + { + private: + typedef ::std::set< ::rtl::OUString, ::std::less< ::rtl::OUString > > StringBag; + typedef ::std::map< ::rtl::OUString, ::rtl::OUString, ::std::less< ::rtl::OUString > > StringMap; + + private: + StringBag m_sIgnoreList; + StringMap m_aChangeList; + static StringMap m_aRecentlyUsedList; + + // general + AbstractHangulHanjaConversionDialog* //CHINA001 HangulHanjaConversionDialog* + m_pConversionDialog; // the dialog to display for user interaction + Window* m_pUIParent; // the parent window for any UI we raise + Reference< XMultiServiceFactory > + m_xORB; // the service factory to use + Reference< XTextConversion > + m_xConverter; // the text conversion service + Locale m_aSourceLocale; // the locale we're working with + + // additions for Chinese simplified / traditional conversion + HHC::ConversionType m_eConvType; // conversion type (Hangul/Hanja, simplified/traditional Chinese,...) + LanguageType m_nSourceLang; // just a 'copy' of m_aSourceLocale in order in order to + // save the applications from always converting to this + // type in their implementations + LanguageType m_nTargetLang; // target language of new replacement text + const Font* m_pTargetFont; // target font of new replacement text + sal_Int32 m_nConvOptions; // text conversion options (as used by 'getConversions') + sal_Bool m_bIsInteractive; // specifies if the conversion requires user interaction + // (and likeley a specialised dialog) or if it is to run + // automatically without any user interaction. + // True for Hangul / Hanja conversion + // False for Chinese simlified / traditional conversion + + HangulHanjaConversion* m_pAntiImpl; // our "anti-impl" instance + + // options + sal_Bool m_bByCharacter; // are we in "by character" mode currently? + HHC::ConversionFormat m_eConversionFormat; // the current format for the conversion + HHC::ConversionDirection m_ePrimaryConversionDirection; // the primary conversion direction + HHC::ConversionDirection m_eCurrentConversionDirection; // the primary conversion direction + + //options from Hangul/Hanja Options dialog (also saved to configuration) + bool m_bIgnorePostPositionalWord; + bool m_bShowRecentlyUsedFirst; + bool m_bAutoReplaceUnique; + + // state + ::rtl::OUString m_sCurrentPortion; // the text which we are currently working on + LanguageType m_nCurrentPortionLang; // language of m_sCurrentPortion found + sal_Int32 m_nCurrentStartIndex; // the start index within m_sCurrentPortion of the current convertible portion + sal_Int32 m_nCurrentEndIndex; // the end index (excluding) within m_sCurrentPortion of the current convertible portion + sal_Int32 m_nReplacementBaseIndex;// index which ReplaceUnit-calls need to be relative to + sal_Int32 m_nCurrentConversionOption; + sal_Int16 m_nCurrentConversionType; + Sequence< ::rtl::OUString > + m_aCurrentSuggestions; // the suggestions for the current unit + // (means for the text [m_nCurrentStartIndex, m_nCurrentEndIndex) in m_sCurrentPortion) + sal_Bool m_bTryBothDirections; // specifies if other conversion directions should be tried when looking for convertible characters + + + public: + HangulHanjaConversion_Impl( + Window* _pUIParent, + const Reference< XMultiServiceFactory >& _rxORB, + const Locale& _rSourceLocale, + const Locale& _rTargetLocale, + const Font* _pTargetFont, + sal_Int32 _nConvOptions, + sal_Bool _bIsInteractive, + HangulHanjaConversion* _pAntiImpl ); + + public: + + static void SetUseSavedConversionDirectionState( sal_Bool bVal ); + + void DoDocumentConversion( ); + + inline sal_Bool IsByCharacter( ) const { return m_bByCharacter; } + + inline sal_Bool IsValid() const { return m_xConverter.is(); } + + inline LanguageType GetSourceLang() const { return m_nSourceLang; } + inline LanguageType GetTargetLang() const { return m_nTargetLang; } + inline const Font * GetTargetFont() const { return m_pTargetFont; } + inline sal_Int32 GetConvOptions() const { return m_nConvOptions; } + inline sal_Bool IsInteractive() const { return m_bIsInteractive; } + + protected: + void createDialog(); + + /** continue with the conversion, return <TRUE/> if and only if the complete conversion is done + @param _bRepeatCurrentUnit + if <TRUE/>, an implNextConvertible will be called initially to advance to the next convertible. + if <FALSE/>, the method will initially work with the current convertible unit + */ + sal_Bool ContinueConversion( bool _bRepeatCurrentUnit ); + + private: + DECL_LINK( OnOptionsChanged, void* ); + DECL_LINK( OnIgnore, void* ); + DECL_LINK( OnIgnoreAll, void* ); + DECL_LINK( OnChange, void* ); + DECL_LINK( OnChangeAll, void* ); + DECL_LINK( OnByCharClicked, CheckBox* ); + DECL_LINK( OnConversionTypeChanged, void* ); + DECL_LINK( OnFind, void* ); + + /** proceed, after the current convertible has been handled + + <p><b>Attention:</b> + When returning from this method, the dialog may have been deleted!</p> + + @param _bRepeatCurrentUnit + will be passed to the <member>ContinueConversion</member> call + */ + void implProceed( bool _bRepeatCurrentUnit ); + + // change the current convertible, and do _not_ proceed + void implChange( const ::rtl::OUString& _rChangeInto ); + + /** find the next convertible piece of text, with possibly advancing to the next portion + + @see HangulHanjaConversion::GetNextPortion + */ + sal_Bool implNextConvertible( bool _bRepeatUnit ); + + /** find the next convertible unit within the current portion + @param _bRepeatUnit + if <TRUE/>, the search will start at the beginning of the current unit, + if <FALSE/>, it will start at the end of the current unit + */ + bool implNextConvertibleUnit( const sal_Int32 _nStartAt ); + + /** retrieves the next portion, with setting the index members properly + @return + <TRUE/> if and only if there is a next portion + */ + bool implRetrieveNextPortion( ); + + /** determine the ConversionDirection for m_sCurrentPortion + @return + <FALSE/> if and only if something went wrong + */ + bool implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection ); + + /** member m_aCurrentSuggestions and m_nCurrentEndIndex are updated according to the other settings and current dictionaries + + if _bAllowSearchNextConvertibleText is true _nStartAt is used as starting point to search the next + convertible text portion. This may result in changing of the member m_nCurrentStartIndex additionally. + + @return + <TRUE/> if Suggestions were found + */ + bool implUpdateSuggestions( const bool _bAllowSearchNextConvertibleText=false, const sal_Int32 _nStartAt=-1 ); + + /** reads the options from Hangul/Hanja Options dialog that are saved to configuration + */ + void implReadOptionsFromConfiguration(); + + /** get the string currently considered to be replaced or ignored + */ + ::rtl::OUString GetCurrentUnit() const; + + /** read options from configuration, update suggestion list and dialog content + */ + void implUpdateData(); + + /** get the conversion direction dependent from m_eConvType and m_eCurrentConversionDirection + in case of switching the direction is allowed this can be triggered with parameter bSwitchDirection + */ + sal_Int16 implGetConversionType( bool bSwitchDirection=false ) const; + }; + + //========================================================================= + //= HangulHanjaConversion_Impl + //========================================================================= + //------------------------------------------------------------------------- + // static member initialization + HangulHanjaConversion_Impl::StringMap HangulHanjaConversion_Impl::m_aRecentlyUsedList = HangulHanjaConversion_Impl::StringMap(); + + //------------------------------------------------------------------------- + HangulHanjaConversion_Impl::HangulHanjaConversion_Impl( Window* _pUIParent, + const Reference< XMultiServiceFactory >& _rxORB, + const Locale& _rSourceLocale, + const Locale& _rTargetLocale, + const Font* _pTargetFont, + sal_Int32 _nOptions, + sal_Bool _bIsInteractive, + HangulHanjaConversion* _pAntiImpl ) +: m_pConversionDialog( NULL ) +, m_pUIParent( _pUIParent ) +, m_xORB( _rxORB ) +, m_aSourceLocale( _rSourceLocale ) +, m_nSourceLang( SvxLocaleToLanguage( _rSourceLocale ) ) +, m_nTargetLang( SvxLocaleToLanguage( _rTargetLocale ) ) +, m_pTargetFont( _pTargetFont ) +, m_bIsInteractive( _bIsInteractive ) +, m_pAntiImpl( _pAntiImpl ) +, m_nCurrentPortionLang( LANGUAGE_NONE ) +, m_nCurrentStartIndex( 0 ) +, m_nCurrentEndIndex( 0 ) +, m_nReplacementBaseIndex( 0 ) +, m_nCurrentConversionOption( TextConversionOption::NONE ) +, m_nCurrentConversionType( -1 ) // not yet known +, m_bTryBothDirections( sal_True ) + { + implReadOptionsFromConfiguration(); + + DBG_ASSERT( m_xORB.is(), "HangulHanjaConversion_Impl::HangulHanjaConversion_Impl: no ORB!" ); + + // determine conversion type + if (m_nSourceLang == LANGUAGE_KOREAN && m_nTargetLang == LANGUAGE_KOREAN) + m_eConvType = HHC::eConvHangulHanja; + else if ( (m_nSourceLang == LANGUAGE_CHINESE_TRADITIONAL && m_nTargetLang == LANGUAGE_CHINESE_SIMPLIFIED) || + (m_nSourceLang == LANGUAGE_CHINESE_SIMPLIFIED && m_nTargetLang == LANGUAGE_CHINESE_TRADITIONAL) ) + m_eConvType = HHC::eConvSimplifiedTraditional; + else + { + DBG_ERROR( "failed to determine conversion type from languages" ); + } + + // set remaining conversion parameters to their default values + m_nConvOptions = _nOptions; + m_bByCharacter = 0 != (_nOptions & CHARACTER_BY_CHARACTER); + m_eConversionFormat = HHC::eSimpleConversion; + m_ePrimaryConversionDirection = HHC::eHangulToHanja; // used for eConvHangulHanja + m_eCurrentConversionDirection = HHC::eHangulToHanja; // used for eConvHangulHanja + + if ( m_xORB.is() ) + { + ::rtl::OUString sTextConversionService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.TextConversion" ) ); + m_xConverter = m_xConverter.query( m_xORB->createInstance( sTextConversionService ) ); + if ( !m_xConverter.is() ) + ShowServiceNotAvailableError( m_pUIParent, sTextConversionService, sal_True ); + } + + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::createDialog() + { + DBG_ASSERT( m_bIsInteractive, "createDialog when the conversion should not be interactive?" ); + if ( m_bIsInteractive && !m_pConversionDialog ) + { + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + if(pFact) + { + m_pConversionDialog = pFact->CreateHangulHanjaConversionDialog(m_pUIParent, m_ePrimaryConversionDirection ); + DBG_ASSERT(m_pConversionDialog, "Dialogdiet fail!");//CHINA001 + + m_pConversionDialog->EnableRubySupport( m_pAntiImpl->HasRubySupport() ); + + m_pConversionDialog->SetByCharacter( m_bByCharacter ); + m_pConversionDialog->SetConversionFormat( m_eConversionFormat ); + m_pConversionDialog->SetConversionDirectionState( m_bTryBothDirections, m_ePrimaryConversionDirection ); + + // the handlers + m_pConversionDialog->SetOptionsChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnOptionsChanged ) ); + m_pConversionDialog->SetIgnoreHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnore ) ); + m_pConversionDialog->SetIgnoreAllHdl( LINK( this, HangulHanjaConversion_Impl, OnIgnoreAll ) ); + m_pConversionDialog->SetChangeHdl( LINK( this, HangulHanjaConversion_Impl, OnChange ) ); + m_pConversionDialog->SetChangeAllHdl( LINK( this, HangulHanjaConversion_Impl, OnChangeAll ) ); + m_pConversionDialog->SetClickByCharacterHdl( LINK( this, HangulHanjaConversion_Impl, OnByCharClicked ) ); + m_pConversionDialog->SetConversionFormatChangedHdl( LINK( this, HangulHanjaConversion_Impl, OnConversionTypeChanged ) ); + m_pConversionDialog->SetFindHdl( LINK( this, HangulHanjaConversion_Impl, OnFind ) ); + } + } + } + + //------------------------------------------------------------------------- + sal_Int16 HangulHanjaConversion_Impl::implGetConversionType( bool bSwitchDirection ) const + { + sal_Int16 nConversionType = -1; + if (m_eConvType == HHC::eConvHangulHanja) + nConversionType = HHC::eHangulToHanja == ( m_eCurrentConversionDirection && !bSwitchDirection ) ? TO_HANJA : TO_HANGUL; + else if (m_eConvType == HHC::eConvSimplifiedTraditional) + nConversionType = LANGUAGE_CHINESE_SIMPLIFIED == m_nTargetLang ? TO_SCHINESE : TO_TCHINESE; + DBG_ASSERT( nConversionType != -1, "unexpected conversion type" ); + return nConversionType; + } + + //------------------------------------------------------------------------- + bool HangulHanjaConversion_Impl::implUpdateSuggestions( bool _bAllowSearchNextConvertibleText, const sal_Int32 _nStartAt ) + { + // parameters for the converter + sal_Int32 nStartSearch = m_nCurrentStartIndex; + if( _bAllowSearchNextConvertibleText ) + nStartSearch = _nStartAt; + + sal_Int32 nLength = m_sCurrentPortion.getLength() - nStartSearch; + m_nCurrentConversionType = implGetConversionType(); + m_nCurrentConversionOption = IsByCharacter() ? CHARACTER_BY_CHARACTER : NONE; + if( m_bIgnorePostPositionalWord ) + m_nCurrentConversionOption = m_nCurrentConversionOption | IGNORE_POST_POSITIONAL_WORD; + + // no need to check both directions for chinese conversion (saves time) + if (m_eConvType == HHC::eConvSimplifiedTraditional) + m_bTryBothDirections = sal_False; + + sal_Bool bFoundAny = sal_True; + try + { + TextConversionResult aResult = m_xConverter->getConversions( + m_sCurrentPortion, + nStartSearch, + nLength, + m_aSourceLocale, + m_nCurrentConversionType, + m_nCurrentConversionOption + ); + sal_Bool bFoundPrimary = aResult.Boundary.startPos < aResult.Boundary.endPos; + bFoundAny = bFoundPrimary; + + if ( m_bTryBothDirections ) + { // see if we find another convertible when assuming the other direction + TextConversionResult aSecondResult = m_xConverter->getConversions( + m_sCurrentPortion, + nStartSearch, + nLength, + m_aSourceLocale, + implGetConversionType( true ), // switched! + m_nCurrentConversionOption + ); + if ( aSecondResult.Boundary.startPos < aSecondResult.Boundary.endPos ) + { // we indeed found such a convertible + + // in case the first attempt (with the original conversion direction) + // didn't find anything + if ( !bFoundPrimary + // or if the second location is _before_ the first one + || ( aSecondResult.Boundary.startPos < aResult.Boundary.startPos ) + ) + { + // then use the second finding + aResult = aSecondResult; + + // our current conversion direction changed now + m_eCurrentConversionDirection = ( HHC::eHangulToHanja == m_eCurrentConversionDirection ) + ? HHC::eHanjaToHangul : HHC::eHangulToHanja; + bFoundAny = sal_True; + } + } + } + + if( _bAllowSearchNextConvertibleText ) + { + //this might change the current position + m_aCurrentSuggestions = aResult.Candidates; + m_nCurrentStartIndex = aResult.Boundary.startPos; + m_nCurrentEndIndex = aResult.Boundary.endPos; + } + else + { + //the change of starting position is not allowed + if( m_nCurrentStartIndex == aResult.Boundary.startPos + && aResult.Boundary.endPos != aResult.Boundary.startPos ) + { + m_aCurrentSuggestions = aResult.Candidates; + m_nCurrentEndIndex = aResult.Boundary.endPos; + } + else + { + m_aCurrentSuggestions.realloc( 0 ); + if( m_sCurrentPortion.getLength() >= m_nCurrentStartIndex+1 ) + m_nCurrentEndIndex = m_nCurrentStartIndex+1; + } + } + + //put recently used string to front: + if( m_bShowRecentlyUsedFirst && m_aCurrentSuggestions.getLength()>1 ) + { + ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); + StringMap::const_iterator aRecentlyUsed = m_aRecentlyUsedList.find( sCurrentUnit ); + bool bUsedBefore = aRecentlyUsed != m_aRecentlyUsedList.end(); + if( bUsedBefore && m_aCurrentSuggestions[0] != aRecentlyUsed->second ) + { + sal_Int32 nCount = m_aCurrentSuggestions.getLength(); + Sequence< ::rtl::OUString > aTmp(nCount); + aTmp[0]=aRecentlyUsed->second; + sal_Int32 nDiff = 1; + for( sal_Int32 n=1; n<nCount; n++)//we had 0 already + { + if( nDiff && m_aCurrentSuggestions[n-nDiff]==aRecentlyUsed->second ) + nDiff=0; + aTmp[n]=m_aCurrentSuggestions[n-nDiff]; + } + m_aCurrentSuggestions = aTmp; + } + } + } + catch( const Exception& ) + { + DBG_ERROR( "HangulHanjaConversion_Impl::implNextConvertibleUnit: caught an exception!" ); + + //!!! at least we want to move on in the text in order + //!!! to avoid an endless loop... + return false; + } + return bFoundAny; + } + + //------------------------------------------------------------------------- + bool HangulHanjaConversion_Impl::implNextConvertibleUnit( const sal_Int32 _nStartAt ) + { + m_aCurrentSuggestions.realloc( 0 ); + + // ask the TextConversion service for the next convertible piece of text + + // get current values from dialog + if( m_eConvType == HHC::eConvHangulHanja && m_pConversionDialog ) + { + m_bTryBothDirections = m_pConversionDialog->GetUseBothDirections(); + HHC::ConversionDirection eDialogDirection = HHC::eHangulToHanja; + eDialogDirection = m_pConversionDialog->GetDirection( eDialogDirection ); + + if( !m_bTryBothDirections && eDialogDirection != m_eCurrentConversionDirection ) + { + m_eCurrentConversionDirection = eDialogDirection; + } + + // save curently used value for possible later use + m_pAntiImpl->m_bTryBothDirectionsSave = m_bTryBothDirections; + m_pAntiImpl->m_ePrimaryConversionDirectionSave = m_eCurrentConversionDirection; + } + + bool bFoundAny = implUpdateSuggestions( true, _nStartAt ); + + return bFoundAny && + (m_nCurrentStartIndex < m_sCurrentPortion.getLength()); + } + + //------------------------------------------------------------------------- + bool HangulHanjaConversion_Impl::implRetrieveNextPortion( ) + { + sal_Bool bAllowImplicitChanges = m_eConvType == HHC::eConvSimplifiedTraditional; + + m_sCurrentPortion = ::rtl::OUString(); + m_nCurrentPortionLang = LANGUAGE_NONE; + m_pAntiImpl->GetNextPortion( m_sCurrentPortion, m_nCurrentPortionLang, bAllowImplicitChanges ); + m_nReplacementBaseIndex = 0; + m_nCurrentStartIndex = m_nCurrentEndIndex = 0; + + bool bRet = 0 != m_sCurrentPortion.getLength(); + + if (m_eConvType == HHC::eConvHangulHanja && m_bTryBothDirections) + implGetConversionDirectionForCurrentPortion( m_eCurrentConversionDirection ); + + return bRet; + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion_Impl::implNextConvertible( bool _bRepeatUnit ) + { + if ( _bRepeatUnit || ( m_nCurrentEndIndex < m_sCurrentPortion.getLength() ) ) + { + if ( implNextConvertibleUnit( + _bRepeatUnit + ? ( IsByCharacter() ? m_nCurrentStartIndex : m_nCurrentStartIndex ) + : m_nCurrentEndIndex + ) ) + return sal_True; + } + + // no convertible text in the current portion anymore + // -> advance to the next portion + do + { + // next portion + if ( implRetrieveNextPortion( ) ) + { // there is a next portion + // -> find the next convertible unit in the current portion + if ( implNextConvertibleUnit( 0 ) ) + return sal_True; + } + } + while ( m_sCurrentPortion.getLength() ); + + // no more portions + return sal_False; + } + + //------------------------------------------------------------------------- + ::rtl::OUString HangulHanjaConversion_Impl::GetCurrentUnit() const + { + DBG_ASSERT( m_nCurrentStartIndex < m_sCurrentPortion.getLength(), + "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" ); + DBG_ASSERT( m_nCurrentEndIndex <= m_sCurrentPortion.getLength(), + "HangulHanjaConversion_Impl::GetCurrentUnit: invalid index into current portion!" ); + DBG_ASSERT( m_nCurrentStartIndex <= m_nCurrentEndIndex, + "HangulHanjaConversion_Impl::GetCurrentUnit: invalid interval!" ); + + ::rtl::OUString sCurrentUnit = m_sCurrentPortion.copy( m_nCurrentStartIndex, m_nCurrentEndIndex - m_nCurrentStartIndex ); + return sCurrentUnit; + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion_Impl::ContinueConversion( bool _bRepeatCurrentUnit ) + { + sal_Bool bNeedUserInteraction = sal_False; // when we leave here, do we need user interaction? + sal_Bool bDocumentDone = sal_False; // did we already check the whole document? + + while ( !bDocumentDone && !bNeedUserInteraction && implNextConvertible( _bRepeatCurrentUnit ) ) + { + ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); + + // do we need to ignore it? + sal_Bool bAlwaysIgnoreThis = m_sIgnoreList.end() != m_sIgnoreList.find( sCurrentUnit ); + + // do we need to change it? + StringMap::const_iterator aChangeListPos = m_aChangeList.find( sCurrentUnit ); + sal_Bool bAlwaysChangeThis = m_aChangeList.end() != aChangeListPos; + + // do we automatically change this? + sal_Bool bAutoChange = m_bAutoReplaceUnique && m_aCurrentSuggestions.getLength() == 1; + + if (!m_bIsInteractive) + { + // silent conversion (e.g. for simplified/traditional Chinese)... + if(m_aCurrentSuggestions.getLength()>0) + implChange( m_aCurrentSuggestions.getConstArray()[0] ); + } + else if (bAutoChange) + { + implChange( m_aCurrentSuggestions.getConstArray()[0] ); + } + else if ( bAlwaysChangeThis ) + { + implChange( aChangeListPos->second ); + } + else if ( !bAlwaysIgnoreThis ) + { + // here we need to ask the user for what to do with the text + // for this, allow derivees to highlight the current text unit in a possible document view + m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex ); + + DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); + if( m_pConversionDialog ) + m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions ); + + // do not look for the next convertible: We have to wait for the user to interactivly + // decide what happens with the current convertible + bNeedUserInteraction = sal_True; + } + } + + /* + if ( bDocumentDone ) + return sal_True; // we explicitly know that the complete document is done + else if ( bNeedUserInteraction ) + return sal_False; // the doc is not done, we found a convertible, but need the user to decide + else + return sal_True; // we did not find a next convertible, so the document is implicitly done + */ + + return bDocumentDone || !bNeedUserInteraction; + } + + //------------------------------------------------------------------------- + bool HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion( HHC::ConversionDirection& rDirection ) + { + // - For eConvHangulHanja the direction is determined by + // the first encountered Korean character. + // - For eConvSimplifiedTraditional the conversion direction + // is already specified by the source language. + + bool bSuccess = true; + + if (m_eConvType == HHC::eConvHangulHanja) + { + bSuccess = false; + try + { + // get the break iterator service + ::rtl::OUString sBreakIteratorService( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.i18n.BreakIterator" ) ); + Reference< XInterface > xBI( m_xORB->createInstance( ::rtl::OUString( sBreakIteratorService ) ) ); + Reference< XBreakIterator > xBreakIter( xBI, UNO_QUERY ); + if ( !xBreakIter.is() ) + { + ShowServiceNotAvailableError( m_pUIParent, sBreakIteratorService, sal_True ); + } + else + { + sal_Int32 nNextAsianScript = xBreakIter->beginOfScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN ); + if ( -1 == nNextAsianScript ) + nNextAsianScript = xBreakIter->nextScript( m_sCurrentPortion, m_nCurrentStartIndex, com::sun::star::i18n::ScriptType::ASIAN ); + if ( ( nNextAsianScript >= m_nCurrentStartIndex ) && ( nNextAsianScript < m_sCurrentPortion.getLength() ) ) + { // found asian text + + // determine if it's Hangul + CharClass aCharClassificaton( m_xORB, m_aSourceLocale ); + sal_Int16 nScript = aCharClassificaton.getScript( m_sCurrentPortion, sal::static_int_cast< USHORT >(nNextAsianScript) ); + if ( ( UnicodeScript_kHangulJamo == nScript ) + || ( UnicodeScript_kHangulCompatibilityJamo == nScript ) + || ( UnicodeScript_kHangulSyllable == nScript ) + ) + { + rDirection = HHC::eHangulToHanja; + } + else + { + rDirection = HHC::eHanjaToHangul; + } + + bSuccess = true; + } + } + } + catch( const Exception& ) + { + DBG_ERROR( "HangulHanjaConversion_Impl::implGetConversionDirectionForCurrentPortion: caught an exception!" ); + } + } + + return bSuccess; + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::DoDocumentConversion( ) + { + // clear the change-all list - it's to be re-initialized for every single document + { + StringMap aEmpty; + m_aChangeList.swap( aEmpty ); + } + + // first of all, we need to guess the direction of our conversion - it is determined by the first + // hangul or hanja character in the first text + if ( !implRetrieveNextPortion() ) + { + DBG_WARNING( "HangulHanjaConversion_Impl::DoDocumentConversion: why did you call me if you do have nothing to convert?" ); + // nothing to do + return; + } + if( m_eConvType == HHC::eConvHangulHanja ) + { + //init conversion direction from saved value + HHC::ConversionDirection eDirection = HHC::eHangulToHanja; + if(!implGetConversionDirectionForCurrentPortion( eDirection )) + // something went wrong, has already been asserted + return; + + if (m_pAntiImpl->IsUseSavedConversionDirectionState()) + { + m_ePrimaryConversionDirection = m_pAntiImpl->m_ePrimaryConversionDirectionSave; + m_bTryBothDirections = m_pAntiImpl->m_bTryBothDirectionsSave; + if( m_bTryBothDirections ) + m_eCurrentConversionDirection = eDirection; + else + m_eCurrentConversionDirection = m_ePrimaryConversionDirection; + } + else + { + m_ePrimaryConversionDirection = eDirection; + m_eCurrentConversionDirection = eDirection; + } + } + + if (m_bIsInteractive && m_eConvType == HHC::eConvHangulHanja) + { + //always open dialog if at least having a hangul or hanja text portion + createDialog(); + if(m_pAntiImpl->IsUseSavedConversionDirectionState()) + ContinueConversion( sal_False ); + else + implUpdateData(); + m_pConversionDialog->Execute(); + DELETEZ( m_pConversionDialog ); + } + else + { +#ifdef DBG_UTIL + sal_Bool bCompletelyDone = +#endif + ContinueConversion( sal_False ); + DBG_ASSERT( bCompletelyDone, "HangulHanjaConversion_Impl::DoDocumentConversion: ContinueConversion should have returned true here!" ); + } + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::implProceed( bool _bRepeatCurrentUnit ) + { + if ( ContinueConversion( _bRepeatCurrentUnit ) ) + { // we're done with the whole document + DBG_ASSERT( !m_bIsInteractive || m_pConversionDialog, "HangulHanjaConversion_Impl::implProceed: we should not reach this here without dialog!" ); + if ( m_pConversionDialog ) + m_pConversionDialog->EndDialog( RET_OK ); + } + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::implChange( const ::rtl::OUString& _rChangeInto ) + { + if( !_rChangeInto.getLength() ) + return; + + // translate the conversion format into a replacement action + // this translation depends on whether we have a Hangul original, or a Hanja original + + HHC::ReplacementAction eAction( HHC::eExchange ); + + if (m_eConvType == HHC::eConvHangulHanja) + { + // is the original we're about to change in Hangul? + sal_Bool bOriginalIsHangul = HHC::eHangulToHanja == m_eCurrentConversionDirection; + + switch ( m_eConversionFormat ) + { + case HHC::eSimpleConversion: eAction = HHC::eExchange; break; + case HHC::eHangulBracketed: eAction = bOriginalIsHangul ? HHC::eOriginalBracketed : HHC::eReplacementBracketed; break; + case HHC::eHanjaBracketed: eAction = bOriginalIsHangul ? HHC::eReplacementBracketed : HHC::eOriginalBracketed; break; + case HHC::eRubyHanjaAbove: eAction = bOriginalIsHangul ? HHC::eReplacementAbove : HHC::eOriginalAbove; break; + case HHC::eRubyHanjaBelow: eAction = bOriginalIsHangul ? HHC::eReplacementBelow : HHC::eOriginalBelow; break; + case HHC::eRubyHangulAbove: eAction = bOriginalIsHangul ? HHC::eOriginalAbove : HHC::eReplacementAbove; break; + case HHC::eRubyHangulBelow: eAction = bOriginalIsHangul ? HHC::eOriginalBelow : HHC::eReplacementBelow; break; + default: + DBG_ERROR( "HangulHanjaConversion_Impl::implChange: invalid/unexpected conversion format!" ); + } + } + + // the proper indicies (the wrapper implementation needs indicies relative to the + // previous replacement) + DBG_ASSERT( ( m_nReplacementBaseIndex <= m_nCurrentStartIndex ) && ( m_nReplacementBaseIndex <= m_nCurrentEndIndex ), + "HangulHanjaConversion_Impl::implChange: invalid replacement base!" ); + + sal_Int32 nStartIndex = m_nCurrentStartIndex - m_nReplacementBaseIndex; + sal_Int32 nEndIndex = m_nCurrentEndIndex - m_nReplacementBaseIndex; + + //remind this decision + m_aRecentlyUsedList[ GetCurrentUnit() ] = _rChangeInto; + + LanguageType *pNewUnitLang = 0; + LanguageType nNewUnitLang = LANGUAGE_NONE; + if (m_eConvType == HHC::eConvSimplifiedTraditional) + { + // check if language needs to be changed + if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_TRADITIONAL && + !m_pAntiImpl->IsTraditional( m_nCurrentPortionLang )) + nNewUnitLang = LANGUAGE_CHINESE_TRADITIONAL; + else if ( m_pAntiImpl->GetTargetLanguage() == LANGUAGE_CHINESE_SIMPLIFIED && + !m_pAntiImpl->IsSimplified( m_nCurrentPortionLang )) + nNewUnitLang = LANGUAGE_CHINESE_SIMPLIFIED; + if (nNewUnitLang != LANGUAGE_NONE) + pNewUnitLang = &nNewUnitLang; + } + + // according to FT we should not (yet) bother about Hangul/Hanja conversion here + // + // aOffsets is needed in ReplaceUnit below in order to to find out + // exactly which characters are really changed in order to keep as much + // from attributation for the text as possible. + Sequence< sal_Int32 > aOffsets; + Reference< XExtendedTextConversion > xExtConverter( m_xConverter, UNO_QUERY ); + if (m_eConvType == HHC::eConvSimplifiedTraditional && xExtConverter.is()) + { + try + { + ::rtl::OUString aConvText = xExtConverter->getConversionWithOffset( + m_sCurrentPortion, + m_nCurrentStartIndex, + m_nCurrentEndIndex - m_nCurrentStartIndex, + m_aSourceLocale, + m_nCurrentConversionType, + m_nCurrentConversionOption, + aOffsets + ); + } + catch( const Exception& ) + { + DBG_ERROR( "HangulHanjaConversion_Impl::implChange: caught unexpected exception!" ); + aOffsets.realloc(0); + } + } + + // do the replacement + m_pAntiImpl->ReplaceUnit( nStartIndex, nEndIndex, m_sCurrentPortion, + _rChangeInto, aOffsets, eAction, pNewUnitLang ); + + + // adjust the replacement base + m_nReplacementBaseIndex = m_nCurrentEndIndex; + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::implReadOptionsFromConfiguration() + { + SvtLinguConfig aLngCfg; + aLngCfg.GetProperty( UPH_IS_IGNORE_POST_POSITIONAL_WORD ) >>= m_bIgnorePostPositionalWord; + aLngCfg.GetProperty( UPH_IS_SHOW_ENTRIES_RECENTLY_USED_FIRST ) >>= m_bShowRecentlyUsedFirst; + aLngCfg.GetProperty( UPH_IS_AUTO_REPLACE_UNIQUE_ENTRIES ) >>= m_bAutoReplaceUnique; + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion_Impl::implUpdateData() + { + implReadOptionsFromConfiguration(); + implUpdateSuggestions(); + + if(m_pConversionDialog) + { + ::rtl::OUString sCurrentUnit( GetCurrentUnit() ); + + m_pConversionDialog->SetCurrentString( sCurrentUnit, m_aCurrentSuggestions ); + m_pConversionDialog->FocusSuggestion(); + } + + m_pAntiImpl->HandleNewUnit( m_nCurrentStartIndex - m_nReplacementBaseIndex, m_nCurrentEndIndex - m_nReplacementBaseIndex ); + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnOptionsChanged, void*, EMPTYARG ) + { + //options and dictionaries might have been changed + //-> update our internal settings and the dialog + implUpdateData(); + + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnIgnore, void*, EMPTYARG ) + { + // simply ignore, and proceed + implProceed( sal_False ); + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnIgnoreAll, void*, EMPTYARG ) + { + DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnIgnoreAll: no dialog! How this?" ); + + if ( m_pConversionDialog ) + { + String sCurrentUnit = m_pConversionDialog->GetCurrentString(); + DBG_ASSERT( m_sIgnoreList.end() == m_sIgnoreList.find( sCurrentUnit ), + "HangulHanjaConversion_Impl, OnIgnoreAll: shouldn't this have been ignored before" ); + + // put into the "ignore all" list + m_sIgnoreList.insert( sCurrentUnit ); + + // and proceed + implProceed( sal_False ); + } + + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnChange, void*, EMPTYARG ) + { + // change + DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); + if( m_pConversionDialog ) + implChange( m_pConversionDialog->GetCurrentSuggestion( ) ); + // and proceed + implProceed( sal_False ); + + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnChangeAll, void*, EMPTYARG ) + { + DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnChangeAll: no dialog! How this?" ); + if ( m_pConversionDialog ) + { + ::rtl::OUString sCurrentUnit( m_pConversionDialog->GetCurrentString() ); + ::rtl::OUString sChangeInto( m_pConversionDialog->GetCurrentSuggestion( ) ); + + if( sChangeInto.getLength() ) + { + // change the current occurence + implChange( sChangeInto ); + + // put into the "change all" list + m_aChangeList.insert( StringMap::value_type( sCurrentUnit, sChangeInto ) ); + } + + // and proceed + implProceed( sal_False ); + } + + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnByCharClicked, CheckBox*, _pBox ) + { + m_bByCharacter = _pBox->IsChecked(); + + // continue conversion, without advancing to the next unit, but instead continuing with the current unit + implProceed( sal_True ); + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnConversionTypeChanged, void*, EMPTYARG ) + { + DBG_ASSERT( m_pConversionDialog, "we should always have a dialog here!" ); + if( m_pConversionDialog ) + m_eConversionFormat = m_pConversionDialog->GetConversionFormat( ); + return 0L; + } + + //------------------------------------------------------------------------- + IMPL_LINK( HangulHanjaConversion_Impl, OnFind, void*, EMPTYARG ) + { + DBG_ASSERT( m_pConversionDialog, "HangulHanjaConversion_Impl::OnFind: where did this come from?" ); + if ( m_pConversionDialog ) + { + try + { + ::rtl::OUString sNewOriginal( m_pConversionDialog->GetCurrentSuggestion( ) ); + Sequence< ::rtl::OUString > aSuggestions; + + DBG_ASSERT( m_xConverter.is(), "HangulHanjaConversion_Impl::OnFind: no converter!" ); + TextConversionResult aToHanja = m_xConverter->getConversions( + sNewOriginal, + 0, sNewOriginal.getLength(), + m_aSourceLocale, + TextConversionType::TO_HANJA, + TextConversionOption::NONE + ); + TextConversionResult aToHangul = m_xConverter->getConversions( + sNewOriginal, + 0, sNewOriginal.getLength(), + m_aSourceLocale, + TextConversionType::TO_HANGUL, + TextConversionOption::NONE + ); + + bool bHaveToHanja = ( aToHanja.Boundary.startPos < aToHanja.Boundary.endPos ); + bool bHaveToHangul = ( aToHangul.Boundary.startPos < aToHangul.Boundary.endPos ); + + TextConversionResult* pResult = NULL; + if ( bHaveToHanja && bHaveToHangul ) + { // it found convertibles in both directions -> use the first + if ( aToHangul.Boundary.startPos < aToHanja.Boundary.startPos ) + pResult = &aToHangul; + else + pResult = &aToHanja; + } + else if ( bHaveToHanja ) + { // only found toHanja + pResult = &aToHanja; + } + else + { // only found toHangul + pResult = &aToHangul; + } + if ( pResult ) + aSuggestions = pResult->Candidates; + + m_pConversionDialog->SetCurrentString( sNewOriginal, aSuggestions, false ); + m_pConversionDialog->FocusSuggestion(); + } + catch( const Exception& ) + { + DBG_ERROR( "HangulHanjaConversion_Impl::OnFind: caught an exception!" ); + } + } + return 0L; + } + + //========================================================================= + //= HangulHanjaConversion + //========================================================================= + //------------------------------------------------------------------------- + + // static member initialization + sal_Bool HangulHanjaConversion::m_bUseSavedValues = sal_False; + sal_Bool HangulHanjaConversion::m_bTryBothDirectionsSave = sal_False; + HHC::ConversionDirection HangulHanjaConversion::m_ePrimaryConversionDirectionSave = HHC::eHangulToHanja; + + //------------------------------------------------------------------------- + HangulHanjaConversion::HangulHanjaConversion( Window* _pUIParent, + const Reference< XMultiServiceFactory >& _rxORB, + const Locale& _rSourceLocale, const Locale& _rTargetLocale, + const Font* _pTargetFont, + sal_Int32 _nOptions, sal_Bool _bIsInteractive) + :m_pImpl( new HangulHanjaConversion_Impl( _pUIParent, _rxORB, _rSourceLocale, _rTargetLocale, _pTargetFont, _nOptions, _bIsInteractive, this ) ) + { + } + + //------------------------------------------------------------------------- + HangulHanjaConversion::~HangulHanjaConversion( ) + { + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::SetUseSavedConversionDirectionState( sal_Bool bVal ) + { + m_bUseSavedValues = bVal; + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion::IsUseSavedConversionDirectionState() + { + return m_bUseSavedValues; + } + + //------------------------------------------------------------------------- + LanguageType HangulHanjaConversion::GetSourceLanguage( ) const + { + return m_pImpl->GetSourceLang(); + } + + //------------------------------------------------------------------------- + LanguageType HangulHanjaConversion::GetTargetLanguage( ) const + { + return m_pImpl->GetTargetLang(); + } + + //------------------------------------------------------------------------- + const Font * HangulHanjaConversion::GetTargetFont( ) const + { + return m_pImpl->GetTargetFont(); + } + + //------------------------------------------------------------------------- + sal_Int32 HangulHanjaConversion::GetConversionOptions( ) const + { + return m_pImpl->GetConvOptions(); + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion::IsInteractive( ) const + { + return m_pImpl->IsInteractive(); + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::HandleNewUnit( const sal_Int32, const sal_Int32 ) + { + // nothing to do, only derived classes need this. + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::GetNextPortion( ::rtl::OUString&, LanguageType&, sal_Bool ) + { + DBG_ERROR( "HangulHanjaConversion::GetNextPortion: to be overridden!" ); + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::ReplaceUnit( + const sal_Int32, const sal_Int32, + const ::rtl::OUString&, + const ::rtl::OUString&, + const ::com::sun::star::uno::Sequence< sal_Int32 > &, + ReplacementAction, + LanguageType * ) + { + DBG_ERROR( "HangulHanjaConversion::ReplaceUnit: to be overridden!" ); + } + + //------------------------------------------------------------------------- + sal_Bool HangulHanjaConversion::HasRubySupport() const + { + DBG_ERROR( "HangulHanjaConversion::HasRubySupport: to be overridden!" ); + return sal_False; + } + + //------------------------------------------------------------------------- + void HangulHanjaConversion::ConvertDocument() + { + if ( m_pImpl->IsValid() ) + m_pImpl->DoDocumentConversion( ); + } + +//............................................................................. +} // namespace svx +//............................................................................. + diff --git a/editeng/source/misc/lingu.src b/editeng/source/misc/lingu.src new file mode 100644 index 000000000000..4fb0058d8654 --- /dev/null +++ b/editeng/source/misc/lingu.src @@ -0,0 +1,107 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: lingu.src,v $ + * $Revision: 1.33 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + // include --------------------------------------------------------------- +#include <editeng/editrids.hrc> + // pragma ---------------------------------------------------------------- + + // QueryBoxen --------------------------------------------------------------- +QueryBox RID_SVXQB_CONTINUE +{ + BUTTONS = WB_YES_NO ; + DEFBUTTON = WB_DEF_YES ; + /* ### ACHTUNG: Neuer Text in Resource? Überprüfung am Anfang des Dokumentes fortsetzen? : šberpr³fung am Anfang des Dokumentes fortsetzen? */ + /* ### ACHTUNG: Neuer Text in Resource? Überprüfung am Anfang des Dokumentes fortsetzen? : šberpr³fung am Anfang des Dokumentes fortsetzen? */ + Message [ en-US ] = "Continue checking at beginning of document?" ; +}; +QueryBox RID_SVXQB_BW_CONTINUE +{ + BUTTONS = WB_YES_NO ; + DEFBUTTON = WB_DEF_YES ; + /* ### ACHTUNG: Neuer Text in Resource? Überprüfung am Ende des Dokumentes fortsetzen? : šberpr³fung am Ende des Dokumentes fortsetzen? */ + /* ### ACHTUNG: Neuer Text in Resource? Überprüfung am Ende des Dokumentes fortsetzen? : šberpr³fung am Ende des Dokumentes fortsetzen? */ + Message [ en-US ] = "Continue checking at end of document?" ; +}; +String RID_SVXSTR_HMERR_THESAURUS +{ + /* ### ACHTUNG: Neuer Text in Resource? Ein Thesaurus für die eingestellte Sprache ist nicht verfügbar. \nÜberprüfen Sie bitte Ihre Installation und installieren Sie \ngegebenenfalls die gewünschte Sprache : Ein Thesaurus f³r die eingestellte Sprache ist nicht verf³gbar. \nšberpr³fen Sie bitte Ihre Installation und installieren Sie \ngegebenenfalls die gew³nschte Sprache */ + /* ### ACHTUNG: Neuer Text in Resource? Ein Thesaurus für die eingestellte Sprache ist nicht verfügbar. \nÜberprüfen Sie bitte Ihre Installation und installieren Sie \ngegebenenfalls die gewünschte Sprache : Ein Thesaurus f³r die eingestellte Sprache ist nicht verf³gbar. \nšberpr³fen Sie bitte Ihre Installation und installieren Sie \ngegebenenfalls die gew³nschte Sprache */ + Text [ en-US ] = "No thesaurus is available for the selected language. \nPlease check your installation and install the desired language\n" ; +}; +String RID_SVXSTR_DIC_ERR_UNKNOWN +{ + Text [ en-US ] = "Word cannot be added to dictionary\ndue to unknown reason."; +}; +String RID_SVXSTR_DIC_ERR_FULL +{ + Text [ en-US ] = "The dictionary is already full."; +}; +String RID_SVXSTR_DIC_ERR_READONLY +{ + Text [ en-US ] = "The dictionary is read-only."; +}; + + // ********************************************************************** EOF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/editeng/source/misc/makefile.mk b/editeng/source/misc/makefile.mk new file mode 100644 index 000000000000..7eb2d80447a1 --- /dev/null +++ b/editeng/source/misc/makefile.mk @@ -0,0 +1,71 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.18 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/.. + +PRJNAME=editeng +TARGET=misc + +#PROJECTPCH4DLL=TRUE +#PROJECTPCH=eeng_pch +#PROJECTPCHSOURCE=eeng_pch + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Allgemein ---------------------------------------------------------- + +.IF "$(editdebug)" != "" || "$(EDITDEBUG)" != "" +CDEFS+=-DEDITDEBUG +.ENDIF + +SLOFILES = \ + $(SLO)$/edtdlg.obj \ + $(SLO)$/unolingu.obj \ + $(SLO)$/acorrcfg.obj \ + $(SLO)$/forbiddencharacterstable.obj \ + $(SLO)$/hangulhanja.obj \ + $(SLO)$/splwrap.obj \ + $(SLO)$/svxacorr.obj \ + $(SLO)$/SvXMLAutoCorrectExport.obj \ + $(SLO)$/SvXMLAutoCorrectImport.obj \ + $(SLO)$/swafopt.obj \ + $(SLO)$/txtrange.obj + +SRS1NAME=misc +SRC1FILES = \ + lingu.src + +.INCLUDE : target.mk + diff --git a/editeng/source/misc/splwrap.cxx b/editeng/source/misc/splwrap.cxx new file mode 100644 index 000000000000..4f68b68e8c45 --- /dev/null +++ b/editeng/source/misc/splwrap.cxx @@ -0,0 +1,635 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: splwrap.cxx,v $ + * $Revision: 1.19 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include<rtl/ustring.hxx> +#include <tools/shl.hxx> +#include <vcl/wrkwin.hxx> +#include <vcl/svapp.hxx> +#include <vcl/msgbox.hxx> +#include <tools/debug.hxx> +#include <svtools/langtab.hxx> + +#ifndef __RSC +#include <tools/errinf.hxx> +#endif +#include <editeng/unolingu.hxx> +#include <linguistic/lngprops.hxx> +#include <com/sun/star/frame/XStorable.hpp> + +#include <map> + +#include <editeng/svxenum.hxx> +#include <editeng/splwrap.hxx> // Der Wrapper +#include <editeng/edtdlg.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/editrids.hrc> +#include <editeng/editids.hrc> +#include <editeng/editerr.hxx> + +#define WAIT_ON() if(pWin != NULL) { pWin->EnterWait(); } + +#define WAIT_OFF() if(pWin != NULL) { pWin->LeaveWait(); } + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::linguistic2; + + +// misc functions --------------------------------------------- + +void SvxPrepareAutoCorrect( String &rOldText, String &rNewText ) +{ + // This function should be used to strip (or add) trailing '.' from + // the strings before passing them on to the autocorrect function in + // order that the autocorrect function will hopefully + // works properly with normal words and abbreviations (with trailing '.') + // independ of if they are at the end of the sentence or not. + // + // rOldText: text to be replaced + // rNewText: replacement text + + xub_StrLen nOldLen = rOldText.Len(), + nNewLen = rNewText.Len(); + if (nOldLen && nNewLen) + { + sal_Bool bOldHasDot = sal_Unicode( '.' ) == rOldText.GetChar( nOldLen - 1 ), + bNewHasDot = sal_Unicode( '.' ) == rNewText.GetChar( nNewLen - 1 ); + if (bOldHasDot && !bNewHasDot + /*this is: !(bOldHasDot && bNewHasDot) && bOldHasDot*/) + rOldText.Erase( nOldLen - 1 ); + } +} + +// ----------------------------------------------------------------------- + +#define SVX_LANG_NEED_CHECK 0 +#define SVX_LANG_OK 1 +#define SVX_LANG_MISSING 2 +#define SVX_LANG_MISSING_DO_WARN 3 + +#define SVX_FLAGS_NEW + + +struct lt_LanguageType +{ + bool operator()( LanguageType n1, LanguageType n2 ) const + { + return n1 < n2; + } +}; + +typedef std::map< LanguageType, USHORT, lt_LanguageType > LangCheckState_map_t; + +static LangCheckState_map_t & GetLangCheckState() +{ + static LangCheckState_map_t aLangCheckState; + return aLangCheckState; +} + +void SvxSpellWrapper::ShowLanguageErrors() +{ + // display message boxes for languages not available for + // spellchecking or hyphenation + LangCheckState_map_t &rLCS = GetLangCheckState(); + LangCheckState_map_t::iterator aIt( rLCS.begin() ); + while (aIt != rLCS.end()) + { + LanguageType nLang = aIt->first; + sal_uInt16 nVal = aIt->second; + sal_uInt16 nTmpSpell = nVal & 0x00FF; + sal_uInt16 nTmpHyph = (nVal >> 8) & 0x00FF; + + if (SVX_LANG_MISSING_DO_WARN == nTmpSpell) + { + String aErr( SvtLanguageTable::GetLanguageString( nLang ) ); + ErrorHandler::HandleError( + *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); + nTmpSpell = SVX_LANG_MISSING; + } + if (SVX_LANG_MISSING_DO_WARN == nTmpHyph) + { + String aErr( SvtLanguageTable::GetLanguageString( nLang ) ); + ErrorHandler::HandleError( + *new StringErrorInfo( ERRCODE_SVX_LINGU_LANGUAGENOTEXISTS, aErr ) ); + nTmpHyph = SVX_LANG_MISSING; + } + + rLCS[ nLang ] = (nTmpHyph << 8) | nTmpSpell; + ++aIt; + } + +} + +SvxSpellWrapper::~SvxSpellWrapper() +{ +} + +/*-------------------------------------------------------------------- + * Beschreibung: Ctor, die Pruefreihenfolge wird festgelegt + * + * !bStart && !bOtherCntnt: BODY_END, BODY_START, OTHER + * !bStart && bOtherCntnt: OTHER, BODY + * bStart && !bOtherCntnt: BODY_END, OTHER + * bStart && bOtherCntnt: OTHER + * + --------------------------------------------------------------------*/ + +SvxSpellWrapper::SvxSpellWrapper( Window* pWn, + Reference< XSpellChecker1 > &xSpellChecker, + const sal_Bool bStart, const sal_Bool bIsAllRight, + const sal_Bool bOther, const sal_Bool bRevAllow ) : + + pWin ( pWn ), + xSpell ( xSpellChecker ), + bOtherCntnt ( bOther ), + bDialog ( sal_False ), + bHyphen ( sal_False ), + bAuto ( sal_False ), + bStartChk ( bOther ), + bRevAllowed ( bRevAllow ), + bAllRight ( bIsAllRight ) +{ + Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() ); + sal_Bool bWrapReverse = xProp.is() ? + *(sal_Bool*)xProp->getPropertyValue( + ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue() + : sal_False; + bReverse = bRevAllow && bWrapReverse; + bStartDone = bOther || ( !bReverse && bStart ); + bEndDone = bReverse && bStart && !bOther; +} + +// ----------------------------------------------------------------------- + +SvxSpellWrapper::SvxSpellWrapper( Window* pWn, + Reference< XHyphenator > &xHyphenator, + const sal_Bool bStart, const sal_Bool bOther ) : + pWin ( pWn ), + xHyph ( xHyphenator ), + bOtherCntnt ( bOther ), + bDialog ( sal_False ), + bHyphen ( sal_False ), + bAuto ( sal_False ), + bReverse ( sal_False ), + bStartDone ( bOther || ( !bReverse && bStart ) ), + bEndDone ( bReverse && bStart && !bOther ), + bStartChk ( bOther ), + bRevAllowed ( sal_False ), + bAllRight ( sal_True ) +{ +} + +// ----------------------------------------------------------------------- + +sal_Int16 SvxSpellWrapper::CheckSpellLang( + Reference< XSpellChecker1 > xSpell, sal_Int16 nLang) +{ + LangCheckState_map_t &rLCS = GetLangCheckState(); + + LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) ); + sal_uInt16 nVal = aIt == rLCS.end() ? SVX_LANG_NEED_CHECK : aIt->second; + + if (aIt == rLCS.end()) + rLCS[ nLang ] = nVal; + + if (SVX_LANG_NEED_CHECK == (nVal & 0x00FF)) + { + sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN; + if (xSpell.is() && xSpell->hasLanguage( nLang )) + nTmpVal = SVX_LANG_OK; + nVal &= 0xFF00; + nVal |= nTmpVal; + + rLCS[ nLang ] = nVal; + } + + return (sal_Int16) nVal; +} + +sal_Int16 SvxSpellWrapper::CheckHyphLang( + Reference< XHyphenator > xHyph, sal_Int16 nLang) +{ + LangCheckState_map_t &rLCS = GetLangCheckState(); + + LangCheckState_map_t::iterator aIt( rLCS.find( nLang ) ); + sal_uInt16 nVal = aIt == rLCS.end() ? 0 : aIt->second; + + if (aIt == rLCS.end()) + rLCS[ nLang ] = nVal; + + if (SVX_LANG_NEED_CHECK == ((nVal >> 8) & 0x00FF)) + { + sal_uInt16 nTmpVal = SVX_LANG_MISSING_DO_WARN; + if (xHyph.is() && xHyph->hasLocale( SvxCreateLocale( nLang ) )) + nTmpVal = SVX_LANG_OK; + nVal &= 0x00FF; + nVal |= nTmpVal << 8; + + rLCS[ nLang ] = nVal; + } + + return (sal_Int16) nVal; +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::SpellStart( SvxSpellArea /*eSpell*/ ) +{ // Hier muessen die notwendigen Vorbereitungen fuer SpellContinue +} // im uebergebenen Bereich getroffen werden. + +// ----------------------------------------------------------------------- + + +sal_Bool SvxSpellWrapper::HasOtherCnt() +{ + return sal_False; // Gibt es ueberhaupt einen Sonderbereich? +} + +// ----------------------------------------------------------------------- + + +sal_Bool SvxSpellWrapper::SpellMore() +{ + return sal_False; // Sollen weitere Dokumente geprueft werden? +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::SpellEnd() +{ // Bereich ist abgeschlossen, ggf. Aufraeumen + + // display error for last language not found + ShowLanguageErrors(); +} + +// ----------------------------------------------------------------------- + + +sal_Bool SvxSpellWrapper::SpellContinue() +{ + return sal_False; +} + +// ----------------------------------------------------------------------- + +void SvxSpellWrapper::AutoCorrect( const String&, const String& ) +{ +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::ScrollArea() +{ // Scrollarea einstellen +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::ChangeWord( const String&, const sal_uInt16 ) +{ // Wort ersetzen +} + +// ----------------------------------------------------------------------- + + +String SvxSpellWrapper::GetThesWord() +{ + // Welches Wort soll nachgeschlagen werden? + return String(); +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::ChangeThesWord( const String& ) +{ + // Wort wg. Thesaurus ersetzen +} + +// ----------------------------------------------------------------------- + +void SvxSpellWrapper::StartThesaurus( const String &rWord, sal_uInt16 nLanguage ) +{ + Reference< XThesaurus > xThes( SvxGetThesaurus() ); + if (!xThes.is()) + { + InfoBox( pWin, EE_RESSTR( RID_SVXSTR_HMERR_THESAURUS ) ).Execute(); + return; + } + + WAIT_ON(); // while looking up for initial word + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + AbstractThesaurusDialog* pDlg = pFact->CreateThesaurusDialog( pWin, xThes, rWord, nLanguage ); + WAIT_OFF(); + if ( pDlg->Execute()== RET_OK ) + { + ChangeThesWord( pDlg->GetWord() ); + } + delete pDlg; +} + +// ----------------------------------------------------------------------- + +void SvxSpellWrapper::ReplaceAll( const String &, sal_Int16 ) +{ // Wort aus der Replace-Liste ersetzen +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::SetLanguage( const sal_uInt16 ) +{ // Sprache aendern +} + +// ----------------------------------------------------------------------- + + +void SvxSpellWrapper::InsertHyphen( const sal_uInt16 ) +{ // Hyphen einfuegen bzw. loeschen +} + +// ----------------------------------------------------------------------- +// Pruefung der Dokumentbereiche in der durch die Flags angegebenen Reihenfolge + + +void SvxSpellWrapper::SpellDocument( ) +{ + if ( bOtherCntnt ) + { + bReverse = sal_False; + SpellStart( SVX_SPELL_OTHER ); + } + else + { + bStartChk = bReverse; + SpellStart( bReverse ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END ); + } + + if ( FindSpellError() ) + { + Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY ); + Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY ); + + Window *pOld = pWin; + bDialog = sal_True; + if (xHyphWord.is()) + { + EditAbstractDialogFactory* pFact = EditAbstractDialogFactory::Create(); + AbstractHyphenWordDialog* pDlg = pFact->CreateHyphenWordDialog( pWin, + xHyphWord->getWord(), + SvxLocaleToLanguage( xHyphWord->getLocale() ), + xHyph, this ); + pWin = pDlg->GetWindow(); + pDlg->Execute(); + delete pDlg; + } + bDialog = sal_False; + pWin = pOld; + }; +} + +// ----------------------------------------------------------------------- +// Naechsten Bereich auswaehlen + + +sal_Bool SvxSpellWrapper::SpellNext( ) +{ + Reference< beans::XPropertySet > xProp( SvxGetLinguPropertySet() ); + sal_Bool bWrapReverse = xProp.is() ? + *(sal_Bool*)xProp->getPropertyValue( + ::rtl::OUString::createFromAscii(UPN_IS_WRAP_REVERSE) ).getValue() + : sal_False; + sal_Bool bActRev = bRevAllowed && bWrapReverse; + + // bActRev ist die Richtung nach dem Spellen, bReverse die am Anfang. + if( bActRev == bReverse ) + { // Keine Richtungsaenderung, also ist + if( bStartChk ) // der gewuenschte Bereich ( bStartChk ) + bStartDone = sal_True; // vollstaendig abgearbeitet. + else + bEndDone = sal_True; + } + else if( bReverse == bStartChk ) // Bei einer Richtungsaenderung kann + { // u.U. auch ein Bereich abgearbeitet sein. + if( bStartChk ) // Sollte der vordere Teil rueckwaerts gespellt + bEndDone = sal_True; // werden und wir kehren unterwegs um, so ist + else // der hintere Teil abgearbeitet (und umgekehrt). + bStartDone = sal_True; + } + + bReverse = bActRev; + if( bOtherCntnt && bStartDone && bEndDone ) // Dokument komplett geprueft? + { + if ( SpellMore() ) // ein weiteres Dokument pruefen? + { + bOtherCntnt = sal_False; + bStartDone = !bReverse; + bEndDone = bReverse; + SpellStart( SVX_SPELL_BODY ); + return sal_True; + } + return sal_False; + } + + sal_Bool bGoOn = sal_False; + + if ( bOtherCntnt ) + { + bStartChk = sal_False; + SpellStart( SVX_SPELL_BODY ); + bGoOn = sal_True; + } + else if ( bStartDone && bEndDone ) + { + sal_Bool bIsSpellSpecial = xProp.is() ? + *(sal_Bool*)xProp->getPropertyValue( + ::rtl::OUString::createFromAscii(UPN_IS_SPELL_SPECIAL) ).getValue() + : sal_False; + // Bodybereich erledigt, Frage nach Sonderbereich + if( !IsHyphen() && bIsSpellSpecial && HasOtherCnt() ) + { + SpellStart( SVX_SPELL_OTHER ); + bOtherCntnt = bGoOn = sal_True; + } + else if ( SpellMore() ) // ein weiteres Dokument pruefen? + { + bOtherCntnt = sal_False; + bStartDone = !bReverse; + bEndDone = bReverse; + SpellStart( SVX_SPELL_BODY ); + return sal_True; + } + } + else + { + // Ein BODY_Bereich erledigt, Frage nach dem anderen BODY_Bereich + WAIT_OFF(); + +// Sobald im Dialog das DontWrapAround gesetzt werden kann, kann der +// folgende #ifdef-Zweig aktiviert werden ... +#ifdef USED + sal_Bool bDontWrapAround = IsHyphen() ? + pSpell->GetOptions() & DONT_WRAPAROUND : + pSpell->GetHyphOptions() & HYPH_DONT_WRAPAROUND; + if( bDontWrapAround ) +#else + sal_uInt16 nResId = bReverse ? RID_SVXQB_BW_CONTINUE : RID_SVXQB_CONTINUE; + QueryBox aBox( pWin, EditResId( nResId ) ); + if ( aBox.Execute() != RET_YES ) +#endif + + { + // Verzicht auf den anderen Bereich, ggf. Frage nach Sonderbereich + WAIT_ON(); + bStartDone = bEndDone = sal_True; + return SpellNext(); + } + else + { + bStartChk = !bStartDone; + SpellStart( bStartChk ? SVX_SPELL_BODY_START : SVX_SPELL_BODY_END ); + bGoOn = sal_True; + } + WAIT_ON(); + } + return bGoOn; +} + +// ----------------------------------------------------------------------- + +Reference< XDictionary > SvxSpellWrapper::GetAllRightDic() const +{ + Reference< XDictionary > xDic; + + Reference< XDictionaryList > xDicList( SvxGetDictionaryList() ); + if (xDicList.is()) + { + Sequence< Reference< XDictionary > > aDics( xDicList->getDictionaries() ); + const Reference< XDictionary > *pDic = aDics.getConstArray(); + sal_Int32 nCount = aDics.getLength(); + + sal_Int32 i = 0; + while (!xDic.is() && i < nCount) + { + Reference< XDictionary > xTmp( pDic[i], UNO_QUERY ); + if (xTmp.is()) + { + if ( xTmp->isActive() && + xTmp->getDictionaryType() != DictionaryType_NEGATIVE && + SvxLocaleToLanguage( xTmp->getLocale() ) == LANGUAGE_NONE ) + { + Reference< frame::XStorable > xStor( xTmp, UNO_QUERY ); + if (xStor.is() && xStor->hasLocation() && !xStor->isReadonly()) + { + xDic = xTmp; + } + } + } + ++i; + } + + if (!xDic.is()) + { + xDic = SvxGetOrCreatePosDic( xDicList ); + if (xDic.is()) + xDic->setActive( sal_True ); + } + } + + return xDic; +} + +// ----------------------------------------------------------------------- + +sal_Bool SvxSpellWrapper::FindSpellError() +{ + ShowLanguageErrors(); + + Reference< XInterface > xRef; + + WAIT_ON(); + sal_Bool bSpell = sal_True; + + Reference< XDictionary > xAllRightDic; + if (IsAllRight()) + xAllRightDic = GetAllRightDic(); + + while ( bSpell ) + { + SpellContinue(); + + Reference< XSpellAlternatives > xAlt( GetLast(), UNO_QUERY ); + Reference< XHyphenatedWord > xHyphWord( GetLast(), UNO_QUERY ); + + if (xAlt.is()) + { + if (IsAllRight() && xAllRightDic.is()) + { + xAllRightDic->add( xAlt->getWord(), sal_False, ::rtl::OUString() ); + } + else + { + // look up in ChangeAllList for misspelled word + Reference< XDictionary > xChangeAllList( + SvxGetChangeAllList(), UNO_QUERY ); + Reference< XDictionaryEntry > xEntry; + if (xChangeAllList.is()) + xEntry = xChangeAllList->getEntry( xAlt->getWord() ); + + if (xEntry.is()) + { + // replace word without asking + ReplaceAll( xEntry->getReplacementText(), + SvxLocaleToLanguage( xAlt->getLocale() ) ); + } + else + bSpell = sal_False; + } + } + else if (xHyphWord.is()) + bSpell = sal_False; + else + { + SpellEnd(); + bSpell = SpellNext(); + } + } + WAIT_OFF(); + return GetLast().is(); +} + + + diff --git a/editeng/source/misc/svxacorr.cxx b/editeng/source/misc/svxacorr.cxx new file mode 100644 index 000000000000..4427c1fef69e --- /dev/null +++ b/editeng/source/misc/svxacorr.cxx @@ -0,0 +1,2706 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: svxacorr.cxx,v $ + * $Revision: 1.62 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + + +#include <com/sun/star/io/XStream.hpp> +#include <tools/urlobj.hxx> +#include <tools/table.hxx> +#include <i18npool/mslangid.hxx> +#include <vcl/svapp.hxx> +#include <sot/storinfo.hxx> +// fuer die Sort-String-Arrays aus dem SVMEM.HXX +#define _SVSTDARR_STRINGSISORTDTOR +#define _SVSTDARR_STRINGSDTOR +#include <svl/svstdarr.hxx> +#include <svl/fstathelper.hxx> +#include <svtools/helpopt.hxx> +#include <svl/urihelper.hxx> +#include <unotools/charclass.hxx> +#include <com/sun/star/i18n/UnicodeType.hdl> +#include <unotools/collatorwrapper.hxx> +#include <com/sun/star/i18n/CollatorOptions.hpp> +#include <unotools/localedatawrapper.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <editeng/editids.hrc> +#include <sot/storage.hxx> +#include <comphelper/storagehelper.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/svxacorr.hxx> +#include <editeng/unolingu.hxx> +#include <helpid.hrc> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/xml/sax/InputSource.hpp> +#include <com/sun/star/xml/sax/XParser.hpp> +#include <unotools/streamwrap.hxx> +#include <SvXMLAutoCorrectImport.hxx> +#include <SvXMLAutoCorrectExport.hxx> +#include <ucbhelper/content.hxx> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/TransferInfo.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <xmloff/xmltoken.hxx> +#include <vcl/help.hxx> + +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::rtl; +using namespace ::utl; + +const int C_NONE = 0x00; +const int C_FULL_STOP = 0x01; +const int C_EXCLAMATION_MARK = 0x02; +const int C_QUESTION_MARK = 0x04; + +static const sal_Char pImplWrdStt_ExcptLstStr[] = "WordExceptList"; +static const sal_Char pImplCplStt_ExcptLstStr[] = "SentenceExceptList"; +static const sal_Char pImplAutocorr_ListStr[] = "DocumentList"; +static const sal_Char pXMLImplWrdStt_ExcptLstStr[] = "WordExceptList.xml"; +static const sal_Char pXMLImplCplStt_ExcptLstStr[] = "SentenceExceptList.xml"; +static const sal_Char pXMLImplAutocorr_ListStr[] = "DocumentList.xml"; + +static const sal_Char + /* auch bei diesen Anfaengen - Klammern auf und alle Arten von Anf.Zei. */ + sImplSttSkipChars[] = "\"\'([{\x83\x84\x89\x91\x92\x93\x94", + /* auch bei diesen Ende - Klammern auf und alle Arten von Anf.Zei. */ + sImplEndSkipChars[] = "\"\')]}\x83\x84\x89\x91\x92\x93\x94"; + +// diese Zeichen sind in Worten erlaubt: (fuer FnCptlSttSntnc) +static const sal_Char sImplWordChars[] = "-'"; + +void EncryptBlockName_Imp( String& rName ); +void DecryptBlockName_Imp( String& rName ); + + +// FileVersions Nummern fuer die Ersetzungs-/Ausnahmelisten getrennt +#define WORDLIST_VERSION_358 1 +#define EXEPTLIST_VERSION_358 0 + + +_SV_IMPL_SORTAR_ALG( SvxAutocorrWordList, SvxAutocorrWordPtr ) +TYPEINIT0(SvxAutoCorrect) + +typedef SvxAutoCorrectLanguageLists* SvxAutoCorrectLanguageListsPtr; +DECLARE_TABLE( SvxAutoCorrLanguageTable_Impl, SvxAutoCorrectLanguageListsPtr) + +DECLARE_TABLE( SvxAutoCorrLastFileAskTable_Impl, long ) + + +inline int IsWordDelim( const sal_Unicode c ) +{ + return ' ' == c || '\t' == c || 0x0a == c || + 0xA0 == c || 0x2011 == c || 0x1 == c; +} + +inline int IsLowerLetter( sal_Int32 nCharType ) +{ + return CharClass::isLetterType( nCharType ) && + 0 == ( ::com::sun::star::i18n::KCharacterType::UPPER & nCharType); +} +inline int IsUpperLetter( sal_Int32 nCharType ) +{ + return CharClass::isLetterType( nCharType ) && + 0 == ( ::com::sun::star::i18n::KCharacterType::LOWER & nCharType); +} + +BOOL lcl_IsSymbolChar( CharClass& rCC, const String& rTxt, + xub_StrLen nStt, xub_StrLen nEnd ) +{ + for( ; nStt < nEnd; ++nStt ) + { +#if OSL_DEBUG_LEVEL > 1 + sal_Int32 nCharType; + sal_Int32 nChType; + nCharType = rCC.getCharacterType( rTxt, nStt ); + nChType = rCC.getType( rTxt, nStt ); +#endif + if( ::com::sun::star::i18n::UnicodeType::PRIVATE_USE == + rCC.getType( rTxt, nStt )) + return TRUE; + } + return FALSE; +} + + +static BOOL lcl_IsInAsciiArr( const sal_Char* pArr, const sal_Unicode c ) +{ + BOOL bRet = FALSE; + for( ; *pArr; ++pArr ) + if( *pArr == c ) + { + bRet = TRUE; + break; + } + return bRet; +} + +SvxAutoCorrDoc::~SvxAutoCorrDoc() +{ +} + + + // wird nach dem austauschen der Zeichen von den Funktionen + // - FnCptlSttWrd + // - FnCptlSttSntnc + // gerufen. Dann koennen die Worte ggfs. in die Ausnahmelisten + // aufgenommen werden. +void SvxAutoCorrDoc::SaveCpltSttWord( ULONG, xub_StrLen, const String&, + sal_Unicode ) +{ +} + +LanguageType SvxAutoCorrDoc::GetLanguage( xub_StrLen , BOOL ) const +{ + return LANGUAGE_SYSTEM; +} + +static ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory >& GetProcessFact() +{ + static ::com::sun::star::uno::Reference< + ::com::sun::star::lang::XMultiServiceFactory > xMSF = + ::comphelper::getProcessServiceFactory(); + return xMSF; +} + +static USHORT GetAppLang() +{ + return Application::GetSettings().GetLanguage(); +} +static LocaleDataWrapper& GetLocaleDataWrapper( USHORT nLang ) +{ + static LocaleDataWrapper aLclDtWrp( GetProcessFact(), + SvxCreateLocale( GetAppLang() ) ); + ::com::sun::star::lang::Locale aLcl( SvxCreateLocale( nLang )); + const ::com::sun::star::lang::Locale& rLcl = aLclDtWrp.getLoadedLocale(); + if( aLcl.Language != rLcl.Language || + aLcl.Country != rLcl.Country || + aLcl.Variant != rLcl.Variant ) + aLclDtWrp.setLocale( aLcl ); + return aLclDtWrp; +} +static TransliterationWrapper& GetIgnoreTranslWrapper() +{ + static int bIsInit = 0; + static TransliterationWrapper aWrp( GetProcessFact(), + ::com::sun::star::i18n::TransliterationModules_IGNORE_CASE | + ::com::sun::star::i18n::TransliterationModules_IGNORE_KANA | + ::com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH ); + if( !bIsInit ) + { + aWrp.loadModuleIfNeeded( GetAppLang() ); + bIsInit = 1; + } + return aWrp; +} +static CollatorWrapper& GetCollatorWrapper() +{ + static int bIsInit = 0; + static CollatorWrapper aCollWrp( GetProcessFact() ); + if( !bIsInit ) + { + aCollWrp.loadDefaultCollator( SvxCreateLocale( GetAppLang() ), 0 ); + bIsInit = 1; + } + return aCollWrp; +} + + +void SvxAutocorrWordList::DeleteAndDestroy( USHORT nP, USHORT nL ) +{ + if( nL ) + { + DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" ); + for( USHORT n=nP; n < nP + nL; n++ ) + delete *((SvxAutocorrWordPtr*)pData+n); + SvPtrarr::Remove( nP, nL ); + } +} + + +BOOL SvxAutocorrWordList::Seek_Entry( const SvxAutocorrWordPtr aE, USHORT* pP ) const +{ + register USHORT nO = SvxAutocorrWordList_SAR::Count(), + nM, + nU = 0; + if( nO > 0 ) + { + CollatorWrapper& rCmp = ::GetCollatorWrapper(); + nO--; + while( nU <= nO ) + { + nM = nU + ( nO - nU ) / 2; + long nCmp = rCmp.compareString( aE->GetShort(), + (*((SvxAutocorrWordPtr*)pData + nM))->GetShort() ); + if( 0 == nCmp ) + { + if( pP ) *pP = nM; + return TRUE; + } + else if( 0 < nCmp ) + nU = nM + 1; + else if( nM == 0 ) + { + if( pP ) *pP = nU; + return FALSE; + } + else + nO = nM - 1; + } + } + if( pP ) *pP = nU; + return FALSE; +} + +/* -----------------18.11.98 15:28------------------- + * + * --------------------------------------------------*/ +void lcl_ClearTable(SvxAutoCorrLanguageTable_Impl& rLangTable) +{ + SvxAutoCorrectLanguageListsPtr pLists = rLangTable.Last(); + while(pLists) + { + delete pLists; + pLists = rLangTable.Prev(); + } + rLangTable.Clear(); +} + +/* -----------------03.11.06 10:15------------------- + * + * --------------------------------------------------*/ + +sal_Bool SvxAutoCorrect::IsAutoCorrectChar( sal_Unicode cChar ) +{ + return cChar == '\0' || cChar == '\t' || cChar == 0x0a || + cChar == ' ' || cChar == '\'' || cChar == '\"' || + cChar == '*' || cChar == '_' || + cChar == '.' || cChar == ',' || cChar == ';' || + cChar == ':' || cChar == '?' || cChar == '!'; +} + +/* -----------------19.11.98 10:15------------------- + * + * --------------------------------------------------*/ +long SvxAutoCorrect::GetDefaultFlags() +{ + long nRet = Autocorrect + | CptlSttSntnc + | CptlSttWrd + | ChgFractionSymbol + | ChgOrdinalNumber + | ChgToEnEmDash + | ChgWeightUnderl + | SetINetAttr + | ChgQuotes + | SaveWordCplSttLst + | SaveWordWrdSttLst; + LanguageType eLang = GetAppLang(); + switch( eLang ) + { + case LANGUAGE_ENGLISH: + case LANGUAGE_ENGLISH_US: + case LANGUAGE_ENGLISH_UK: + case LANGUAGE_ENGLISH_AUS: + case LANGUAGE_ENGLISH_CAN: + case LANGUAGE_ENGLISH_NZ: + case LANGUAGE_ENGLISH_EIRE: + case LANGUAGE_ENGLISH_SAFRICA: + case LANGUAGE_ENGLISH_JAMAICA: + case LANGUAGE_ENGLISH_CARRIBEAN: + nRet &= ~(ChgQuotes|ChgSglQuotes); + break; + } + return nRet; +} + + +SvxAutoCorrect::SvxAutoCorrect( const String& rShareAutocorrFile, + const String& rUserAutocorrFile ) + : sShareAutoCorrFile( rShareAutocorrFile ), + sUserAutoCorrFile( rUserAutocorrFile ), + pLangTable( new SvxAutoCorrLanguageTable_Impl ), + pLastFileTable( new SvxAutoCorrLastFileAskTable_Impl ), + pCharClass( 0 ), + cStartDQuote( 0 ), cEndDQuote( 0 ), cStartSQuote( 0 ), cEndSQuote( 0 ) +{ + nFlags = SvxAutoCorrect::GetDefaultFlags(); + + c1Div2 = ByteString::ConvertToUnicode( '\xBD', RTL_TEXTENCODING_MS_1252 ); + c1Div4 = ByteString::ConvertToUnicode( '\xBC', RTL_TEXTENCODING_MS_1252 ); + c3Div4 = ByteString::ConvertToUnicode( '\xBE', RTL_TEXTENCODING_MS_1252 ); + cEmDash = ByteString::ConvertToUnicode( '\x97', RTL_TEXTENCODING_MS_1252 ); + cEnDash = ByteString::ConvertToUnicode( '\x96', RTL_TEXTENCODING_MS_1252 ); +} + +SvxAutoCorrect::SvxAutoCorrect( const SvxAutoCorrect& rCpy ) +: sShareAutoCorrFile( rCpy.sShareAutoCorrFile ), + sUserAutoCorrFile( rCpy.sUserAutoCorrFile ), + + aSwFlags( rCpy.aSwFlags ), + + pLangTable( new SvxAutoCorrLanguageTable_Impl ), + pLastFileTable( new SvxAutoCorrLastFileAskTable_Impl ), + pCharClass( 0 ), + + nFlags( rCpy.nFlags & ~(ChgWordLstLoad|CplSttLstLoad|WrdSttLstLoad)), + cStartDQuote( rCpy.cStartDQuote ), cEndDQuote( rCpy.cEndDQuote ), + cStartSQuote( rCpy.cStartSQuote ), cEndSQuote( rCpy.cEndSQuote ), + c1Div2( rCpy.c1Div2 ), c1Div4( rCpy.c1Div4 ), c3Div4( rCpy.c3Div4 ), + cEmDash( rCpy.cEmDash ), cEnDash( rCpy.cEnDash ) +{ +} + + +SvxAutoCorrect::~SvxAutoCorrect() +{ + lcl_ClearTable(*pLangTable); + delete pLangTable; + delete pLastFileTable; + delete pCharClass; +} + +void SvxAutoCorrect::_GetCharClass( LanguageType eLang ) +{ + delete pCharClass; + pCharClass = new CharClass( SvxCreateLocale( eLang )); + eCharClassLang = eLang; +} + +void SvxAutoCorrect::SetAutoCorrFlag( long nFlag, BOOL bOn ) +{ + long nOld = nFlags; + nFlags = bOn ? nFlags | nFlag + : nFlags & ~nFlag; + + if( !bOn ) + { + if( (nOld & CptlSttSntnc) != (nFlags & CptlSttSntnc) ) + nFlags &= ~CplSttLstLoad; + if( (nOld & CptlSttWrd) != (nFlags & CptlSttWrd) ) + nFlags &= ~WrdSttLstLoad; + if( (nOld & Autocorrect) != (nFlags & Autocorrect) ) + nFlags &= ~ChgWordLstLoad; + } +} + + + // Zwei Grossbuchstaben am Wort-Anfang ?? +BOOL SvxAutoCorrect::FnCptlSttWrd( SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ + BOOL bRet = FALSE; + CharClass& rCC = GetCharClass( eLang ); + + // loesche alle nicht alpanum. Zeichen am Wortanfang/-ende und + // teste dann ( erkennt: "(min.", "/min.", usw.) + for( ; nSttPos < nEndPos; ++nSttPos ) + if( rCC.isLetterNumeric( rTxt, nSttPos )) + break; + for( ; nSttPos < nEndPos; --nEndPos ) + if( rCC.isLetterNumeric( rTxt, nEndPos - 1 )) + break; + + // Zwei Grossbuchstaben am Wort-Anfang ?? + if( nSttPos+2 < nEndPos && + IsUpperLetter( rCC.getCharacterType( rTxt, nSttPos )) && + IsUpperLetter( rCC.getCharacterType( rTxt, ++nSttPos )) && + // ist das 3. Zeichen ein klein geschiebenes Alpha-Zeichen + IsLowerLetter( rCC.getCharacterType( rTxt, nSttPos +1 )) && + // keine Sonder-Attribute ersetzen + 0x1 != rTxt.GetChar( nSttPos ) && 0x2 != rTxt.GetChar( nSttPos )) + { + // teste ob das Wort in einer Ausnahmeliste steht + String sWord( rTxt.Copy( nSttPos - 1, nEndPos - nSttPos + 1 )); + if( !FindInWrdSttExceptList(eLang, sWord) ) + { + sal_Unicode cSave = rTxt.GetChar( nSttPos ); + String sChar( cSave ); + rCC.toLower( sChar ); + if( sChar.GetChar(0) != cSave && rDoc.Replace( nSttPos, sChar )) + { + if( SaveWordWrdSttLst & nFlags ) + rDoc.SaveCpltSttWord( CptlSttWrd, nSttPos, sWord, cSave ); + bRet = TRUE; + } + } + } + return bRet; +} + + +BOOL SvxAutoCorrect::FnChgFractionSymbol( + SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos ) +{ + sal_Unicode cChar = 0; + + for( ; nSttPos < nEndPos; ++nSttPos ) + if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nSttPos ) )) + break; + for( ; nSttPos < nEndPos; --nEndPos ) + if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nEndPos - 1 ) )) + break; + + // 1/2, 1/4, ... ersetzen durch das entsprechende Zeichen vom Font + if( 3 == nEndPos - nSttPos && '/' == rTxt.GetChar( nSttPos+1 )) + { + switch( ( rTxt.GetChar( nSttPos )) * 256 + rTxt.GetChar( nEndPos-1 )) + { + case '1' * 256 + '2': cChar = c1Div2; break; + case '1' * 256 + '4': cChar = c1Div4; break; + case '3' * 256 + '4': cChar = c3Div4; break; + } + + if( cChar ) + { + // also austauschen: + rDoc.Delete( nSttPos+1, nEndPos ); + rDoc.Replace( nSttPos, cChar ); + } + } + return 0 != cChar; +} + + +BOOL SvxAutoCorrect::FnChgOrdinalNumber( + SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ +// 1st, 2nd, 3rd, 4 - 0th +// 201th oder 201st +// 12th oder 12nd + CharClass& rCC = GetCharClass( eLang ); + BOOL bChg = FALSE; + + for( ; nSttPos < nEndPos; ++nSttPos ) + if( !lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nSttPos ) )) + break; + for( ; nSttPos < nEndPos; --nEndPos ) + if( !lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nEndPos - 1 ) )) + break; + + if( 2 < nEndPos - nSttPos && + rCC.isDigit( rTxt, nEndPos - 3 ) ) + { + static sal_Char __READONLY_DATA + sAll[] = "th", /* rest */ + sFirst[] = "st", /* 1 */ + sSecond[] = "nd", /* 2 */ + sThird[] = "rd"; /* 3 */ + static const sal_Char* __READONLY_DATA aNumberTab[ 4 ] = + { + sAll, sFirst, sSecond, sThird + }; + + sal_Unicode c = rTxt.GetChar( nEndPos - 3 ); + if( ( c -= '0' ) > 3 ) + c = 0; + + bChg = ( ((sal_Unicode)*((aNumberTab[ c ])+0)) == + rTxt.GetChar( nEndPos - 2 ) && + ((sal_Unicode)*((aNumberTab[ c ])+1)) == + rTxt.GetChar( nEndPos - 1 )) || + ( 3 < nEndPos - nSttPos && + ( ((sal_Unicode)*(sAll+0)) == rTxt.GetChar( nEndPos - 2 ) && + ((sal_Unicode)*(sAll+1)) == rTxt.GetChar( nEndPos - 1 ))); + + if( bChg ) + { + // dann pruefe mal, ob alle bis zum Start alle Zahlen sind + for( xub_StrLen n = nEndPos - 3; nSttPos < n; ) + if( !rCC.isDigit( rTxt, --n ) ) + { + bChg = !rCC.isLetter( rTxt, n ); + break; + } + + if( bChg ) // dann setze mal das Escapement Attribut + { + SvxEscapementItem aSvxEscapementItem( DFLT_ESC_AUTO_SUPER, + DFLT_ESC_PROP, SID_ATTR_CHAR_ESCAPEMENT ); + rDoc.SetAttr( nEndPos - 2, nEndPos, + SID_ATTR_CHAR_ESCAPEMENT, + aSvxEscapementItem); + } + } + + } + return bChg; +} + + +BOOL SvxAutoCorrect::FnChgToEnEmDash( + SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ + BOOL bRet = FALSE; + CharClass& rCC = GetCharClass( eLang ); + if (eLang == LANGUAGE_SYSTEM) + eLang = GetAppLang(); + bool bAlwaysUseEmDash = (cEmDash && (eLang == LANGUAGE_RUSSIAN || eLang == LANGUAGE_UKRAINIAN)); + + // ersetze " - " oder " --" durch "enDash" + if( cEnDash && 1 < nSttPos && 1 <= nEndPos - nSttPos ) + { + sal_Unicode cCh = rTxt.GetChar( nSttPos ); + if( '-' == cCh ) + { + if( ' ' == rTxt.GetChar( nSttPos-1 ) && + '-' == rTxt.GetChar( nSttPos+1 )) + { + xub_StrLen n; + for( n = nSttPos+2; n < nEndPos && lcl_IsInAsciiArr( + sImplSttSkipChars,(cCh = rTxt.GetChar( n ))); + ++n ) + ; + + // found: " --[<AnySttChars>][A-z0-9] + if( rCC.isLetterNumeric( cCh ) ) + { + for( n = nSttPos-1; n && lcl_IsInAsciiArr( + sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); ) + ; + + // found: "[A-z0-9][<AnyEndChars>] --[<AnySttChars>][A-z0-9] + if( rCC.isLetterNumeric( cCh )) + { + rDoc.Delete( nSttPos, nSttPos + 2 ); + rDoc.Insert( nSttPos, bAlwaysUseEmDash ? cEmDash : cEnDash ); + bRet = TRUE; + } + } + } + } + else if( 3 < nSttPos && + ' ' == rTxt.GetChar( nSttPos-1 ) && + '-' == rTxt.GetChar( nSttPos-2 )) + { + xub_StrLen n, nLen = 1, nTmpPos = nSttPos - 2; + if( '-' == ( cCh = rTxt.GetChar( nTmpPos-1 )) ) + { + --nTmpPos; + ++nLen; + cCh = rTxt.GetChar( nTmpPos-1 ); + } + if( ' ' == cCh ) + { + for( n = nSttPos; n < nEndPos && lcl_IsInAsciiArr( + sImplSttSkipChars,(cCh = rTxt.GetChar( n ))); + ++n ) + ; + + // found: " - [<AnySttChars>][A-z0-9] + if( rCC.isLetterNumeric( cCh ) ) + { + cCh = ' '; + for( n = nTmpPos-1; n && lcl_IsInAsciiArr( + sImplEndSkipChars,(cCh = rTxt.GetChar( --n ))); ) + ; + // found: "[A-z0-9][<AnyEndChars>] - [<AnySttChars>][A-z0-9] + if( rCC.isLetterNumeric( cCh )) + { + rDoc.Delete( nTmpPos, nTmpPos + nLen ); + rDoc.Insert( nTmpPos, bAlwaysUseEmDash ? cEmDash : cEnDash ); + bRet = TRUE; + } + } + } + } + } + + // Replace [A-z0-9]--[A-z0-9] double dash with "emDash" or "enDash". + // Finnish and Hungarian use enDash instead of emDash. + bool bEnDash = (eLang == LANGUAGE_HUNGARIAN || eLang == LANGUAGE_FINNISH); + if( ((cEmDash && !bEnDash) || (cEnDash && bEnDash)) && 4 <= nEndPos - nSttPos ) + { + String sTmp( rTxt.Copy( nSttPos, nEndPos - nSttPos ) ); + xub_StrLen nFndPos = sTmp.SearchAscii( "--" ); + if( STRING_NOTFOUND != nFndPos && nFndPos && + nFndPos + 2 < sTmp.Len() && + ( rCC.isLetterNumeric( sTmp, nFndPos - 1 ) || + lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nFndPos - 1 ) )) && + ( rCC.isLetterNumeric( sTmp, nFndPos + 2 ) || + lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nFndPos + 2 ) ))) + { + nSttPos = nSttPos + nFndPos; + rDoc.Delete( nSttPos, nSttPos + 2 ); + rDoc.Insert( nSttPos, (bEnDash ? cEnDash : cEmDash) ); + bRet = TRUE; + } + } + return bRet; +} + + +BOOL SvxAutoCorrect::FnSetINetAttr( SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ + String sURL( URIHelper::FindFirstURLInText( rTxt, nSttPos, nEndPos, + GetCharClass( eLang ) )); + BOOL bRet = 0 != sURL.Len(); + if( bRet ) // also Attribut setzen: + rDoc.SetINetAttr( nSttPos, nEndPos, sURL ); + return bRet; +} + + +BOOL SvxAutoCorrect::FnChgWeightUnderl( SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen, xub_StrLen nEndPos, + LanguageType eLang ) +{ + // Bedingung: + // Am Anfang: _ oder * hinter Space mit nachfolgenden !Space + // Am Ende: _ oder * vor Space (Worttrenner?) + + sal_Unicode c, cInsChar = rTxt.GetChar( nEndPos ); // unterstreichen oder fett + if( ++nEndPos != rTxt.Len() && + !IsWordDelim( rTxt.GetChar( nEndPos ) ) ) + return FALSE; + + --nEndPos; + + BOOL bAlphaNum = FALSE; + xub_StrLen nPos = nEndPos, nFndPos = STRING_NOTFOUND; + CharClass& rCC = GetCharClass( eLang ); + + while( nPos ) + { + switch( c = rTxt.GetChar( --nPos ) ) + { + case '_': + case '*': + if( c == cInsChar ) + { + if( bAlphaNum && nPos+1 < nEndPos && ( !nPos || + IsWordDelim( rTxt.GetChar( nPos-1 ))) && + !IsWordDelim( rTxt.GetChar( nPos+1 ))) + nFndPos = nPos; + else + // Bedingung ist nicht erfuellt, also abbrechen + nFndPos = STRING_NOTFOUND; + nPos = 0; + } + break; + default: + if( !bAlphaNum ) + bAlphaNum = rCC.isLetterNumeric( rTxt, nPos ); + } + } + + if( STRING_NOTFOUND != nFndPos ) + { + // ueber den gefundenen Bereich das Attribut aufspannen und + // das gefunde und am Ende stehende Zeichen loeschen + if( '*' == cInsChar ) // Fett + { + SvxWeightItem aSvxWeightItem( WEIGHT_BOLD, SID_ATTR_CHAR_WEIGHT ); + rDoc.SetAttr( nFndPos + 1, nEndPos, + SID_ATTR_CHAR_WEIGHT, + aSvxWeightItem); + } + else // unterstrichen + { + SvxUnderlineItem aSvxUnderlineItem( UNDERLINE_SINGLE, SID_ATTR_CHAR_UNDERLINE ); + rDoc.SetAttr( nFndPos + 1, nEndPos, + SID_ATTR_CHAR_UNDERLINE, + aSvxUnderlineItem); + } + rDoc.Delete( nEndPos, nEndPos + 1 ); + rDoc.Delete( nFndPos, nFndPos + 1 ); + } + + return STRING_NOTFOUND != nFndPos; +} + + +BOOL SvxAutoCorrect::FnCptlSttSntnc( SvxAutoCorrDoc& rDoc, + const String& rTxt, BOOL bNormalPos, + xub_StrLen nSttPos, xub_StrLen nEndPos, + LanguageType eLang ) +{ + // Grossbuchstabe am Satz-Anfang ?? + if( !rTxt.Len() || nEndPos <= nSttPos ) + return FALSE; + + CharClass& rCC = GetCharClass( eLang ); + String aText( rTxt ); + const sal_Unicode *pStart = aText.GetBuffer(), + *pStr = pStart + nEndPos, + *pWordStt = 0, + *pDelim = 0; + + BOOL bAtStart = FALSE, bPrevPara = FALSE; + do { + --pStr; + if( rCC.isLetter( + aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ) + { + if( !pWordStt ) + pDelim = pStr+1; + pWordStt = pStr; + } + else if( pWordStt && + !rCC.isDigit( + aText, + sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ) + { + if( lcl_IsInAsciiArr( sImplWordChars, *pStr ) && + pWordStt - 1 == pStr && + // --> FME 2005-02-14 #i38971# + // l'intallazione at beginning of paragraph. Replaced < by <= + (long)(pStart + 1) <= (long)pStr && + // <-- + rCC.isLetter( + aText, + sal::static_int_cast< xub_StrLen >( pStr-1 - pStart ) ) ) + pWordStt = --pStr; + else + break; + } + } while( 0 == ( bAtStart = (pStart == pStr)) ); + + + if( !pWordStt || + rCC.isDigit( + aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) || + IsUpperLetter( + rCC.getCharacterType( + aText, + sal::static_int_cast< xub_StrLen >( pWordStt - pStart ) ) ) || + 0x1 == *pWordStt || 0x2 == *pWordStt ) + return FALSE; // kein zu ersetzendes Zeichen, oder schon ok + + // JP 27.10.97: wenn das Wort weniger als 3 Zeichen hat und der Trenner + // ein "Num"-Trenner ist, dann nicht ersetzen! + // Damit wird ein "a.", "a)", "a-a" nicht ersetzt! + if( *pDelim && 2 >= pDelim - pWordStt && + lcl_IsInAsciiArr( ".-)>", *pDelim ) ) + return FALSE; + + if( !bAtStart ) // noch kein Absatz Anfang ? + { + if ( IsWordDelim( *pStr ) ) + { + while( 0 == ( bAtStart = (pStart == pStr--) ) && IsWordDelim( *pStr )) + ; + } + // Asian full stop, full width full stop, full width exclamation mark + // and full width question marks are treated as word delimiters + else if ( 0x3002 != *pStr && 0xFF0E != *pStr && 0xFF01 != *pStr && + 0xFF1F != *pStr ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + } + + if( bAtStart ) // am Absatz Anfang ? + { + // Ueberpruefe den vorherigen Absatz, wenn es diesen gibt. + // Wenn ja, dann pruefe auf SatzTrenner am Ende. + const String* pPrevPara = rDoc.GetPrevPara( bNormalPos ); + if( !pPrevPara ) + { + // gueltiger Trenner -> Ersetze + String sChar( *pWordStt ); + rCC.toUpper( sChar ); + return sChar != *pWordStt && + rDoc.Replace( xub_StrLen( pWordStt - pStart ), sChar ); + } + + aText = *pPrevPara; + bPrevPara = TRUE; + bAtStart = FALSE; + pStart = aText.GetBuffer(); + pStr = pStart + aText.Len(); + + do { // alle Blanks ueberlesen + --pStr; + if( !IsWordDelim( *pStr )) + break; + } while( 0 == ( bAtStart = (pStart == pStr)) ); + + if( bAtStart ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + } + + // bis hierhier wurde [ \t]+[A-Z0-9]+ gefunden. Test jetzt auf den + // Satztrenner. Es koennen alle 3 vorkommen, aber nicht mehrfach !! + const sal_Unicode* pExceptStt = 0; + if( !bAtStart ) + { + BOOL bWeiter = TRUE; + int nFlag = C_NONE; + do { + switch( *pStr ) + { + // Western and Asian full stop + case '.': + case 0x3002 : + case 0xFF0E : + { + if( nFlag & C_FULL_STOP ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + nFlag |= C_FULL_STOP; + pExceptStt = pStr; + } + break; + case '!': + case 0xFF01 : + { + if( nFlag & C_EXCLAMATION_MARK ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + nFlag |= C_EXCLAMATION_MARK; + } + break; + case '?': + case 0xFF1F : + { + if( nFlag & C_QUESTION_MARK) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + nFlag |= C_QUESTION_MARK; + } + break; + default: + if( !nFlag ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + else + bWeiter = FALSE; + break; + } + + if( bWeiter && pStr-- == pStart ) + { +// !!! wenn am Anfang, dann nie ersetzen. +// if( !nFlag ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung +// ++pStr; +// break; // Schleife beenden + } + } while( bWeiter ); + if( C_FULL_STOP != nFlag ) + pExceptStt = 0; + } + + if( 2 > ( pStr - pStart ) ) + return FALSE; + + if( !rCC.isLetterNumeric( + aText, sal::static_int_cast< xub_StrLen >( pStr-- - pStart ) ) ) + { + BOOL bValid = FALSE, bAlphaFnd = FALSE; + const sal_Unicode* pTmpStr = pStr; + while( !bValid ) + { + if( rCC.isDigit( + aText, + sal::static_int_cast< xub_StrLen >( pTmpStr - pStart ) ) ) + { + bValid = TRUE; + pStr = pTmpStr - 1; + } + else if( rCC.isLetter( + aText, + sal::static_int_cast< xub_StrLen >( + pTmpStr - pStart ) ) ) + { + if( bAlphaFnd ) + { + bValid = TRUE; + pStr = pTmpStr; + } + else + bAlphaFnd = TRUE; + } + else if( bAlphaFnd || IsWordDelim( *pTmpStr ) ) + break; + + if( pTmpStr == pStart ) + break; + + --pTmpStr; + } + + if( !bValid ) + return FALSE; // kein gueltiger Trenner -> keine Ersetzung + } + + BOOL bNumericOnly = '0' <= *(pStr+1) && *(pStr+1) <= '9'; + + // suche den Anfang vom Wort + while( !IsWordDelim( *pStr )) + { + if( bNumericOnly && + rCC.isLetter( + aText, sal::static_int_cast< xub_StrLen >( pStr - pStart ) ) ) + bNumericOnly = FALSE; + + if( pStart == pStr ) + break; + + --pStr; + } + + if( bNumericOnly ) // besteht nur aus Zahlen, dann nicht + return FALSE; + + if( IsWordDelim( *pStr )) + ++pStr; + + String sWord; + + // ueberpruefe anhand der Exceptionliste + if( pExceptStt ) + { + sWord = String( + pStr, sal::static_int_cast< xub_StrLen >( pExceptStt - pStr + 1 ) ); + if( FindInCplSttExceptList(eLang, sWord) ) + return FALSE; + + // loesche alle nicht alpanum. Zeichen am Wortanfang/-ende und + // teste dann noch mal ( erkennt: "(min.", "/min.", usw.) + String sTmp( sWord ); + while( sTmp.Len() && + !rCC.isLetterNumeric( sTmp, 0 ) ) + sTmp.Erase( 0, 1 ); + + // alle hinteren nicht alphanumerische Zeichen bis auf das + // Letzte entfernen + xub_StrLen nLen = sTmp.Len(); + while( nLen && !rCC.isLetterNumeric( sTmp, nLen-1 ) ) + --nLen; + if( nLen + 1 < sTmp.Len() ) + sTmp.Erase( nLen + 1 ); + + if( sTmp.Len() && sTmp.Len() != sWord.Len() && + FindInCplSttExceptList(eLang, sTmp)) + return FALSE; + + if(FindInCplSttExceptList(eLang, sWord, TRUE)) + return FALSE; + } + + // Ok, dann ersetze mal + sal_Unicode cSave = *pWordStt; + nSttPos = sal::static_int_cast< xub_StrLen >( pWordStt - rTxt.GetBuffer() ); + String sChar( cSave ); + rCC.toUpper( sChar ); + BOOL bRet = sChar.GetChar(0) != cSave && rDoc.Replace( nSttPos, sChar ); + + // das Wort will vielleicht jemand haben + if( bRet && SaveWordCplSttLst & nFlags ) + rDoc.SaveCpltSttWord( CptlSttSntnc, nSttPos, sWord, cSave ); + + return bRet; +} +//The method below is renamed from _GetQuote to GetQuote by BerryJia for Bug95846 Time:2002-8-13 15:50 +sal_Unicode SvxAutoCorrect::GetQuote( sal_Unicode cInsChar, BOOL bSttQuote, + LanguageType eLang ) const +{ + sal_Unicode cRet = bSttQuote ? ( '\"' == cInsChar + ? GetStartDoubleQuote() + : GetStartSingleQuote() ) + : ( '\"' == cInsChar + ? GetEndDoubleQuote() + : GetEndSingleQuote() ); + if( !cRet ) + { + // dann ueber die Language das richtige Zeichen heraussuchen + if( LANGUAGE_NONE == eLang ) + cRet = cInsChar; + else + { + LocaleDataWrapper& rLcl = GetLocaleDataWrapper( eLang ); + String sRet( bSttQuote + ? ( '\"' == cInsChar + ? rLcl.getDoubleQuotationMarkStart() + : rLcl.getQuotationMarkStart() ) + : ( '\"' == cInsChar + ? rLcl.getDoubleQuotationMarkEnd() + : rLcl.getQuotationMarkEnd() )); + cRet = sRet.Len() ? sRet.GetChar( 0 ) : cInsChar; + } + } + return cRet; +} + +void SvxAutoCorrect::InsertQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos, + sal_Unicode cInsChar, BOOL bSttQuote, + BOOL bIns ) +{ + LanguageType eLang = rDoc.GetLanguage( nInsPos, FALSE ); + sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang ); + + //JP 13.02.99: damit beim Undo das "einfuegte" Zeichen wieder erscheint, + // wird es erstmal eingefuegt und dann ueberschrieben + String sChg( cInsChar ); + if( bIns ) + rDoc.Insert( nInsPos, sChg ); + else + rDoc.Replace( nInsPos, sChg ); + + //JP 13.08.97: Bug 42477 - bei doppelten Anfuehrungszeichen muss bei + // franzoesischer Sprache an Anfang ein Leerzeichen dahinter + // und am Ende ein Leerzeichen dahinter eingefuegt werden. + sChg = cRet; + + if( '\"' == cInsChar ) + { + if( LANGUAGE_SYSTEM == eLang ) + eLang = GetAppLang(); + switch( eLang ) + { + case LANGUAGE_FRENCH: + case LANGUAGE_FRENCH_BELGIAN: + case LANGUAGE_FRENCH_CANADIAN: + case LANGUAGE_FRENCH_SWISS: + case LANGUAGE_FRENCH_LUXEMBOURG: + // JP 09.02.99: das zusaetzliche Zeichen immer per Insert einfuegen. + // Es ueberschreibt nichts! + { + String s( static_cast< sal_Unicode >(0xA0) ); + // UNICODE code for no break space + if( rDoc.Insert( bSttQuote ? nInsPos+1 : nInsPos, s )) + { + if( !bSttQuote ) + ++nInsPos; + } + } + break; + } + } + + rDoc.Replace( nInsPos, sChg ); +} + +String SvxAutoCorrect::GetQuote( SvxAutoCorrDoc& rDoc, xub_StrLen nInsPos, + sal_Unicode cInsChar, BOOL bSttQuote ) +{ + LanguageType eLang = rDoc.GetLanguage( nInsPos, FALSE ); + sal_Unicode cRet = GetQuote( cInsChar, bSttQuote, eLang ); + + String sRet( cRet ); + //JP 13.08.97: Bug 42477 - bei doppelten Anfuehrungszeichen muss bei + // franzoesischer Sprache an Anfang ein Leerzeichen dahinter + // und am Ende ein Leerzeichen dahinter eingefuegt werden. + if( '\"' == cInsChar ) + { + if( LANGUAGE_SYSTEM == eLang ) + eLang = GetAppLang(); + switch( eLang ) + { + case LANGUAGE_FRENCH: + case LANGUAGE_FRENCH_BELGIAN: + case LANGUAGE_FRENCH_CANADIAN: + case LANGUAGE_FRENCH_SWISS: + case LANGUAGE_FRENCH_LUXEMBOURG: + if( bSttQuote ) + sRet += ' '; + else + sRet.Insert( ' ', 0 ); + break; + } + } + return sRet; +} + +ULONG SvxAutoCorrect::AutoCorrect( SvxAutoCorrDoc& rDoc, const String& rTxt, + xub_StrLen nInsPos, sal_Unicode cChar, + BOOL bInsert ) +{ + ULONG nRet = 0; + do{ // only for middle check loop !! + if( cChar ) + { + //JP 10.02.97: doppelte Spaces verhindern + if( nInsPos && ' ' == cChar && + IsAutoCorrFlag( IngnoreDoubleSpace ) && + ' ' == rTxt.GetChar( nInsPos - 1 ) ) + { + nRet = IngnoreDoubleSpace; + break; + } + + BOOL bSingle = '\'' == cChar; + BOOL bIsReplaceQuote = + (IsAutoCorrFlag( ChgQuotes ) && ('\"' == cChar )) || + (IsAutoCorrFlag( ChgSglQuotes ) && bSingle ); + if( bIsReplaceQuote ) + { + sal_Unicode cPrev; + BOOL bSttQuote = !nInsPos || + IsWordDelim( ( cPrev = rTxt.GetChar( nInsPos-1 ))) || +// os: #56034# - Warum kein schliessendes Anfuehrungszeichen nach dem Bindestrich? +// strchr( "-([{", cPrev ) || + lcl_IsInAsciiArr( "([{", cPrev ) || + ( cEmDash && cEmDash == cPrev ) || + ( cEnDash && cEnDash == cPrev ); + + InsertQuote( rDoc, nInsPos, cChar, bSttQuote, bInsert ); + nRet = bSingle ? ChgSglQuotes : ChgQuotes; + break; + } + + if( bInsert ) + rDoc.Insert( nInsPos, cChar ); + else + rDoc.Replace( nInsPos, cChar ); + } + + if( !nInsPos ) + break; + + xub_StrLen nPos = nInsPos - 1; + + // Bug 19286: nur direkt hinter dem "Wort" aufsetzen + if( IsWordDelim( rTxt.GetChar( nPos ))) + break; + + // automatisches Fett oder Unterstreichen setzen? + if( '*' == cChar || '_' == cChar ) + { + if( IsAutoCorrFlag( ChgWeightUnderl ) && + FnChgWeightUnderl( rDoc, rTxt, 0, nPos+1 ) ) + nRet = ChgWeightUnderl; + break; + } + + while( nPos && !IsWordDelim( rTxt.GetChar( --nPos ))) + ; + + // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort + // Kuerzel im Auto + xub_StrLen nCapLttrPos = nPos+1; // auf das 1. Zeichen + if( !nPos && !IsWordDelim( rTxt.GetChar( 0 ))) + --nCapLttrPos; // Absatz Anfang und kein Blank ! + + LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, FALSE ); + if( LANGUAGE_SYSTEM == eLang ) + eLang = MsLangId::getSystemLanguage(); + CharClass& rCC = GetCharClass( eLang ); + + // Bug 19285: Symbolzeichen nicht anfassen + if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nInsPos )) + break; + + if( IsAutoCorrFlag( Autocorrect ) ) + { + const String* pPara = 0; + const String** ppPara = IsAutoCorrFlag(CptlSttSntnc) ? &pPara : 0; + + BOOL bChgWord = rDoc.ChgAutoCorrWord( nCapLttrPos, nInsPos, + *this, ppPara ); + if( !bChgWord ) + { + // JP 16.06.98: dann versuche mal alle !AlphaNum. Zeichen los zu + // werden und teste dann nochmals + //JP 22.04.99: Bug 63883 - entferne nur die "Klammern Start/-Anfaenge", + // alle anderen Zeichen muessen drin bleiben. + xub_StrLen nCapLttrPos1 = nCapLttrPos, nInsPos1 = nInsPos; + while( nCapLttrPos1 < nInsPos && + lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos1 ) ) + ) + ++nCapLttrPos1; + while( nCapLttrPos1 < nInsPos1 && nInsPos1 && + lcl_IsInAsciiArr( sImplEndSkipChars, rTxt.GetChar( nInsPos1-1 ) ) + ) + --nInsPos1; + + if( (nCapLttrPos1 != nCapLttrPos || nInsPos1 != nInsPos ) && + nCapLttrPos1 < nInsPos1 && + rDoc.ChgAutoCorrWord( nCapLttrPos1, nInsPos1, *this, ppPara )) + { + bChgWord = TRUE; + nCapLttrPos = nCapLttrPos1; + } + } + + if( bChgWord ) + { + nRet = Autocorrect; + if( pPara ) + { + xub_StrLen nEnd = nCapLttrPos; + while( nEnd < pPara->Len() && + !IsWordDelim( pPara->GetChar( nEnd ))) + ++nEnd; + + // Grossbuchstabe am Satz-Anfang ?? + if( IsAutoCorrFlag( CptlSttSntnc ) && + FnCptlSttSntnc( rDoc, *pPara, FALSE, + nCapLttrPos, nEnd, eLang ) ) + nRet |= CptlSttSntnc; + + if( IsAutoCorrFlag( ChgToEnEmDash ) && + FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nEnd, eLang ) ) + nRet |= ChgToEnEmDash; + } + break; + } + } + + if( ( IsAutoCorrFlag( nRet = ChgFractionSymbol ) && + FnChgFractionSymbol( rDoc, rTxt, nCapLttrPos, nInsPos ) ) || + ( IsAutoCorrFlag( nRet = ChgOrdinalNumber ) && + FnChgOrdinalNumber( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) || + ( IsAutoCorrFlag( nRet = SetINetAttr ) && + ( ' ' == cChar || '\t' == cChar || 0x0a == cChar || !cChar ) && + FnSetINetAttr( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) ) + ; + else + { + nRet = 0; + // Grossbuchstabe am Satz-Anfang ?? + if( IsAutoCorrFlag( CptlSttSntnc ) && + FnCptlSttSntnc( rDoc, rTxt, TRUE, nCapLttrPos, nInsPos, eLang ) ) + nRet |= CptlSttSntnc; + + // Zwei Grossbuchstaben am Wort-Anfang ?? + if( IsAutoCorrFlag( CptlSttWrd ) && + FnCptlSttWrd( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) + nRet |= CptlSttWrd; + + if( IsAutoCorrFlag( ChgToEnEmDash ) && + FnChgToEnEmDash( rDoc, rTxt, nCapLttrPos, nInsPos, eLang ) ) + nRet |= ChgToEnEmDash; + } + + } while( FALSE ); + + if( nRet ) + { + ULONG nHelpId = 0; + if( nRet & ( Autocorrect|CptlSttSntnc|CptlSttWrd|ChgToEnEmDash ) ) + { + // von 0 - 15 + if( nRet & ChgToEnEmDash ) + nHelpId += 8; + if( nRet & Autocorrect ) + nHelpId += 4; + if( nRet & CptlSttSntnc ) + nHelpId += 2; + if( nRet & CptlSttWrd ) + nHelpId += 1; + } + else + { + if( nRet & ChgQuotes) nHelpId = 16; + else if( nRet & ChgSglQuotes) nHelpId = 17; + else if( nRet & SetINetAttr) nHelpId = 18; + else if( nRet & IngnoreDoubleSpace) nHelpId = 19; + else if( nRet & ChgWeightUnderl) nHelpId = 20; + else if( nRet & ChgFractionSymbol ) nHelpId = 21; + else if( nRet & ChgOrdinalNumber) nHelpId = 22; + } + + if( nHelpId ) + { + nHelpId += HID_AUTOCORR_HELP_START - 1; + Application::GetHelp()->OpenHelpAgent( nHelpId ); + } + } + + + return nRet; +} + +SvxAutoCorrectLanguageLists& SvxAutoCorrect::_GetLanguageList( + LanguageType eLang ) +{ + if( !pLangTable->IsKeyValid( ULONG( eLang ))) + CreateLanguageFile( eLang, TRUE); + return *pLangTable->Seek( ULONG( eLang ) ); +} + +void SvxAutoCorrect::SaveCplSttExceptList( LanguageType eLang ) +{ + if( pLangTable->IsKeyValid( ULONG( eLang ))) + { + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang)); + if( pLists ) + pLists->SaveCplSttExceptList(); + } +#ifdef DBG_UTIL + else + { + DBG_ERROR("speichern einer leeren Liste?"); + } +#endif +} + +void SvxAutoCorrect::SaveWrdSttExceptList(LanguageType eLang) +{ + if(pLangTable->IsKeyValid(ULONG(eLang))) + { + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang)); + if(pLists) + pLists->SaveWrdSttExceptList(); + } +#ifdef DBG_UTIL + else + { + DBG_ERROR("speichern einer leeren Liste?"); + } +#endif +} + + + // fuegt ein einzelnes Wort hinzu. Die Liste wird sofort + // in die Datei geschrieben! +BOOL SvxAutoCorrect::AddCplSttException( const String& rNew, + LanguageType eLang ) +{ + SvxAutoCorrectLanguageListsPtr pLists = 0; + //entweder die richtige Sprache ist vorhanden oder es kommt in die allg. Liste + if( pLangTable->IsKeyValid(ULONG(eLang))) + pLists = pLangTable->Seek(ULONG(eLang)); + else if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| + CreateLanguageFile(LANGUAGE_DONTKNOW, TRUE)) + { + pLists = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW)); + } + DBG_ASSERT(pLists, "keine Autokorrekturdatei"); + return pLists->AddToCplSttExceptList(rNew); +} + + + // fuegt ein einzelnes Wort hinzu. Die Liste wird sofort + // in die Datei geschrieben! +BOOL SvxAutoCorrect::AddWrtSttException( const String& rNew, + LanguageType eLang ) +{ + SvxAutoCorrectLanguageListsPtr pLists = 0; + //entweder die richtige Sprache ist vorhanden oder es kommt in die allg. Liste + if(pLangTable->IsKeyValid(ULONG(eLang))) + pLists = pLangTable->Seek(ULONG(eLang)); + else if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| + CreateLanguageFile(LANGUAGE_DONTKNOW, TRUE)) + pLists = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW)); + DBG_ASSERT(pLists, "keine Autokorrekturdatei"); + return pLists->AddToWrdSttExceptList(rNew); +} + + + + +void SvxAutoCorrect::SetUserAutoCorrFileName( const String& rNew ) +{ + if( sUserAutoCorrFile != rNew ) + { + sUserAutoCorrFile = rNew; + + // sind die Listen gesetzt sind, so muessen sie jetzt geloescht + // werden + lcl_ClearTable(*pLangTable); + nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad ); + } +} + +void SvxAutoCorrect::SetShareAutoCorrFileName( const String& rNew ) +{ + if( sShareAutoCorrFile != rNew ) + { + sShareAutoCorrFile = rNew; + + // sind die Listen gesetzt sind, so muessen sie jetzt geloescht + // werden + lcl_ClearTable(*pLangTable); + nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad ); + } +} + + +BOOL SvxAutoCorrect::GetPrevAutoCorrWord( SvxAutoCorrDoc& rDoc, + const String& rTxt, xub_StrLen nPos, + String& rWord ) const +{ + if( !nPos ) + return FALSE; + + xub_StrLen nEnde = nPos; + + // dahinter muss ein Blank oder Tab folgen! + if( ( nPos < rTxt.Len() && + !IsWordDelim( rTxt.GetChar( nPos ))) || + IsWordDelim( rTxt.GetChar( --nPos ))) + return FALSE; + + while( nPos && !IsWordDelim( rTxt.GetChar( --nPos ))) + ; + + // Absatz-Anfang oder ein Blank gefunden, suche nach dem Wort + // Kuerzel im Auto + xub_StrLen nCapLttrPos = nPos+1; // auf das 1. Zeichen + if( !nPos && !IsWordDelim( rTxt.GetChar( 0 ))) + --nCapLttrPos; // Absatz Anfang und kein Blank ! + + while( lcl_IsInAsciiArr( sImplSttSkipChars, rTxt.GetChar( nCapLttrPos )) ) + if( ++nCapLttrPos >= nEnde ) + return FALSE; + + // Bug 19285: Symbolzeichen nicht anfassen + // Interresant erst ab 3 Zeichen + if( 3 > nEnde - nCapLttrPos ) + return FALSE; + + LanguageType eLang = rDoc.GetLanguage( nCapLttrPos, FALSE ); + if( LANGUAGE_SYSTEM == eLang ) + eLang = MsLangId::getSystemLanguage(); + + SvxAutoCorrect* pThis = (SvxAutoCorrect*)this; + CharClass& rCC = pThis->GetCharClass( eLang ); + + if( lcl_IsSymbolChar( rCC, rTxt, nCapLttrPos, nEnde )) + return FALSE; + + rWord = rTxt.Copy( nCapLttrPos, nEnde - nCapLttrPos ); + return TRUE; +} + +BOOL SvxAutoCorrect::CreateLanguageFile( LanguageType eLang, BOOL bNewFile ) +{ + DBG_ASSERT(!pLangTable->IsKeyValid(ULONG(eLang)), "Sprache ist bereits vorhanden"); + + String sUserDirFile( GetAutoCorrFileName( eLang, TRUE, FALSE )), + sShareDirFile( sUserDirFile ); + SvxAutoCorrectLanguageListsPtr pLists = 0; + + Time nMinTime( 0, 2 ), nAktTime, nLastCheckTime; + ULONG nFndPos; + if( TABLE_ENTRY_NOTFOUND != + pLastFileTable->SearchKey( ULONG( eLang ), &nFndPos ) && + ( nLastCheckTime.SetTime( pLastFileTable->GetObject( nFndPos )), + nLastCheckTime < nAktTime ) && + ( nAktTime - nLastCheckTime ) < nMinTime ) + { + // no need to test the file, because the last check is not older then + // 2 minutes. + if( bNewFile ) + { + sShareDirFile = sUserDirFile; + pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile, + sUserDirFile, eLang ); + pLangTable->Insert( ULONG(eLang), pLists ); + pLastFileTable->Remove( ULONG( eLang ) ); + } + } + else if( ( FStatHelper::IsDocument( sUserDirFile ) || + FStatHelper::IsDocument( sShareDirFile = + GetAutoCorrFileName( eLang, FALSE, FALSE ) ) ) || + ( sShareDirFile = sUserDirFile, bNewFile )) + { + pLists = new SvxAutoCorrectLanguageLists( *this, sShareDirFile, + sUserDirFile, eLang ); + pLangTable->Insert( ULONG(eLang), pLists ); + pLastFileTable->Remove( ULONG( eLang ) ); + } + else if( !bNewFile ) + { + if( !pLastFileTable->Insert( ULONG( eLang ), nAktTime.GetTime() )) + pLastFileTable->Replace( ULONG( eLang ), nAktTime.GetTime() ); + } + return pLists != 0; +} + +BOOL SvxAutoCorrect::PutText( const String& rShort, const String& rLong, + LanguageType eLang ) +{ + BOOL bRet = FALSE; + if( pLangTable->IsKeyValid( ULONG(eLang)) || CreateLanguageFile(eLang) ) + bRet = pLangTable->Seek( ULONG(eLang) )->PutText(rShort, rLong); + return bRet; +} + + + // - loesche einen Eintrag +BOOL SvxAutoCorrect::DeleteText( const String& rShort, LanguageType eLang ) +{ + BOOL bRet = FALSE; + if( pLangTable->IsKeyValid( ULONG( eLang )) ) + bRet = pLangTable->Seek( ULONG( eLang ))->DeleteText( rShort ); + return bRet; +} + + + // - return den Ersetzungstext (nur fuer SWG-Format, alle anderen + // koennen aus der Wortliste herausgeholt werden!) +BOOL SvxAutoCorrect::GetLongText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String& , String& ) +{ + return FALSE; +} + + // - Text mit Attributierung (kann nur der SWG - SWG-Format!) +BOOL SvxAutoCorrect::PutText( const com::sun::star::uno::Reference < com::sun::star::embed::XStorage >&, const String&, const String&, SfxObjectShell&, + String& ) +{ + return FALSE; +} + +void EncryptBlockName_Imp( String& rName ) +{ + xub_StrLen nLen, nPos = 1; + rName.Insert( '#', 0 ); + sal_Unicode* pName = rName.GetBufferAccess(); + for ( nLen = rName.Len(), ++pName; nPos < nLen; ++nPos, ++pName ) + { + if( lcl_IsInAsciiArr( "!/:.\\", *pName )) + *pName &= 0x0f; + } +} + +/* This code is copied from SwXMLTextBlocks::GeneratePackageName */ +void GeneratePackageName ( const String& rShort, String& rPackageName ) +{ + rPackageName = rShort; + xub_StrLen nPos = 0; + sal_Unicode pDelims[] = { '!', '/', ':', '.', '\\', 0 }; + ByteString sByte ( rPackageName, RTL_TEXTENCODING_UTF7); + rPackageName = String (sByte, RTL_TEXTENCODING_ASCII_US); + while( STRING_NOTFOUND != ( nPos = rPackageName.SearchChar( pDelims, nPos ))) + { + rPackageName.SetChar( nPos, '_' ); + ++nPos; + } +} + +void DecryptBlockName_Imp( String& rName ) +{ + if( '#' == rName.GetChar( 0 ) ) + { + rName.Erase( 0, 1 ); + sal_Unicode* pName = rName.GetBufferAccess(); + xub_StrLen nLen, nPos; + for ( nLen = rName.Len(), nPos = 0; nPos < nLen; ++nPos, ++pName ) + switch( *pName ) + { + case 0x01: *pName = '!'; break; + case 0x0A: *pName = ':'; break; + case 0x0C: *pName = '\\'; break; + case 0x0E: *pName = '.'; break; + case 0x0F: *pName = '/'; break; + } + } +} + + +/* -----------------18.11.98 16:00------------------- + * + * --------------------------------------------------*/ +const SvxAutocorrWord* lcl_SearchWordsInList( + SvxAutoCorrectLanguageListsPtr pList, const String& rTxt, + xub_StrLen& rStt, xub_StrLen nEndPos, SvxAutoCorrDoc& ) +{ + const SvxAutocorrWordList* pAutoCorrWordList = pList->GetAutocorrWordList(); + TransliterationWrapper& rCmp = GetIgnoreTranslWrapper(); + for( xub_StrLen nPos = 0; nPos < pAutoCorrWordList->Count(); ++nPos ) + { + const SvxAutocorrWord* pFnd = (*pAutoCorrWordList)[ nPos ]; + const String& rChk = pFnd->GetShort(); + if( nEndPos >= rChk.Len() ) + { + xub_StrLen nCalcStt = nEndPos - rChk.Len(); + if( ( !nCalcStt || nCalcStt == rStt || + ( nCalcStt < rStt && + IsWordDelim( rTxt.GetChar(nCalcStt - 1 ) ))) ) + { + String sWord( rTxt.GetBuffer() + nCalcStt, rChk.Len() ); + if( rCmp.isEqual( rChk, sWord )) + { + rStt = nCalcStt; + return pFnd; + } + } + } + } + return 0; +} + + +// suche das oder die Worte in der ErsetzungsTabelle +const SvxAutocorrWord* SvxAutoCorrect::SearchWordsInList( + const String& rTxt, xub_StrLen& rStt, xub_StrLen nEndPos, + SvxAutoCorrDoc& rDoc, LanguageType& rLang ) +{ + LanguageType eLang = rLang; + const SvxAutocorrWord* pRet = 0; + if( LANGUAGE_SYSTEM == eLang ) + eLang = MsLangId::getSystemLanguage(); + + // zuerst nach eLang suchen, dann nach der Obersprache + // US-Englisch -> Englisch und zuletzt in LANGUAGE_DONTKNOW + + if( pLangTable->IsKeyValid( ULONG( eLang ) ) || + CreateLanguageFile( eLang, FALSE )) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(eLang)); + pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc ); + if( pRet ) + { + rLang = eLang; + return pRet; + } + } + + // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen + ULONG nTmpKey1 = eLang & 0x7ff, // die Hauptsprache in vielen Faellen u.B. DE + nTmpKey2 = eLang & 0x3ff, // sonst z.B. EN + nTmp; + + if( ((nTmp = nTmpKey1) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey1 ) || + CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) || + (( nTmp = nTmpKey2) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey2 ) || + CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek( nTmp ); + pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc); + if( pRet ) + { + rLang = LanguageType( nTmp ); + return pRet; + } + } + if( pLangTable->IsKeyValid( ULONG( LANGUAGE_DONTKNOW ) ) || + CreateLanguageFile( LANGUAGE_DONTKNOW, FALSE ) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW)); + pRet = lcl_SearchWordsInList( pList, rTxt, rStt, nEndPos, rDoc); + if( pRet ) + { + rLang = LANGUAGE_DONTKNOW; + return pRet; + } + } + return 0; +} +/* -----------------18.11.98 13:46------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrect::FindInWrdSttExceptList( LanguageType eLang, + const String& sWord ) +{ + //zuerst nach eLang suchen, dann nach der Obersprace US-Englisch -> Englisch + //und zuletzt in LANGUAGE_DONTKNOW + ULONG nTmpKey1 = eLang & 0x7ff; // die Hauptsprache in vielen Faellen u.B. DE + ULONG nTmpKey2 = eLang & 0x3ff; // sonst z.B. EN + String sTemp(sWord); + if( pLangTable->IsKeyValid( ULONG( eLang )) || + CreateLanguageFile( eLang, FALSE ) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(eLang)); + String _sTemp(sWord); + if(pList->GetWrdSttExceptList()->Seek_Entry(&_sTemp)) + return TRUE; + + } + // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen + ULONG nTmp; + if( ((nTmp = nTmpKey1) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey1 ) || + CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) || + (( nTmp = nTmpKey2) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey2 ) || + CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(nTmp); + if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp)) + return TRUE; + } + if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| CreateLanguageFile(LANGUAGE_DONTKNOW, FALSE)) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pList = pLangTable->Seek(ULONG(LANGUAGE_DONTKNOW)); + if(pList->GetWrdSttExceptList()->Seek_Entry(&sTemp)) + return TRUE; + } + return FALSE; +} +/* -----------------18.11.98 14:28------------------- + * + * --------------------------------------------------*/ +BOOL lcl_FindAbbreviation( const SvStringsISortDtor* pList, const String& sWord) +{ + String sAbk( '~' ); + USHORT nPos; + pList->Seek_Entry( &sAbk, &nPos ); + if( nPos < pList->Count() ) + { + String sLowerWord( sWord ); sLowerWord.ToLowerAscii(); + const String* pAbk; + for( USHORT n = nPos; + n < pList->Count() && + '~' == ( pAbk = (*pList)[ n ])->GetChar( 0 ); + ++n ) + { + // ~ und ~. sind nicht erlaubt! + if( 2 < pAbk->Len() && pAbk->Len() - 1 <= sWord.Len() ) + { + String sLowerAbk( *pAbk ); sLowerAbk.ToLowerAscii(); + for( xub_StrLen i = sLowerAbk.Len(), ii = sLowerWord.Len(); i; ) + { + if( !--i ) // stimmt ueberein + return TRUE; + + if( sLowerAbk.GetChar( i ) != sLowerWord.GetChar( --ii )) + break; + } + } + } + } + DBG_ASSERT( !(nPos && '~' == (*pList)[ --nPos ]->GetChar( 0 ) ), + "falsch sortierte ExeptionListe?" ); + return FALSE; +} +/* -----------------18.11.98 14:49------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrect::FindInCplSttExceptList(LanguageType eLang, + const String& sWord, BOOL bAbbreviation) +{ + //zuerst nach eLang suchen, dann nach der Obersprace US-Englisch -> Englisch + //und zuletzt in LANGUAGE_DONTKNOW + ULONG nTmpKey1 = eLang & 0x7ff; // die Hauptsprache in vielen Faellen u.B. DE + ULONG nTmpKey2 = eLang & 0x3ff; // sonst z.B. EN + String sTemp( sWord ); + if( pLangTable->IsKeyValid( ULONG( eLang )) || + CreateLanguageFile( eLang, FALSE )) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(ULONG(eLang)); + const SvStringsISortDtor* pList = pLists->GetCplSttExceptList(); + if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord) + : pList->Seek_Entry( &sTemp ) ) + return TRUE; + } + // wenn es hier noch nicht gefunden werden konnte, dann weitersuchen + ULONG nTmp; + + if( ((nTmp = nTmpKey1) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey1 ) || + CreateLanguageFile( LanguageType( nTmpKey1 ), FALSE ) )) || + (( nTmp = nTmpKey2) != (ULONG)eLang && + ( pLangTable->IsKeyValid( nTmpKey2 ) || + CreateLanguageFile( LanguageType( nTmpKey2 ), FALSE ) )) ) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(nTmp); + const SvStringsISortDtor* pList = pLists->GetCplSttExceptList(); + if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord) + : pList->Seek_Entry( &sTemp ) ) + return TRUE; + } + if(pLangTable->IsKeyValid(ULONG(LANGUAGE_DONTKNOW))|| CreateLanguageFile(LANGUAGE_DONTKNOW, FALSE)) + { + //die Sprache ist vorhanden - also her damit + SvxAutoCorrectLanguageListsPtr pLists = pLangTable->Seek(LANGUAGE_DONTKNOW); + const SvStringsISortDtor* pList = pLists->GetCplSttExceptList(); + if(bAbbreviation ? lcl_FindAbbreviation( pList, sWord) + : pList->Seek_Entry( &sTemp ) ) + return TRUE; + } + return FALSE; + +} + +/* -----------------20.11.98 11:53------------------- + * + * --------------------------------------------------*/ +String SvxAutoCorrect::GetAutoCorrFileName( LanguageType eLang, + BOOL bNewFile, BOOL bTst ) const +{ + String sRet, sExt( MsLangId::convertLanguageToIsoString( eLang ) ); + sExt.Insert('_', 0); + sExt.AppendAscii( ".dat" ); + if( bNewFile ) + ( sRet = sUserAutoCorrFile ) += sExt; + else if( !bTst ) + ( sRet = sShareAutoCorrFile ) += sExt; + else + { + // test first in the user directory - if not exist, then + ( sRet = sUserAutoCorrFile ) += sExt; + if( !FStatHelper::IsDocument( sRet )) + ( sRet = sShareAutoCorrFile ) += sExt; + } + return sRet; +} + +/* -----------------18.11.98 11:16------------------- + * + * --------------------------------------------------*/ +SvxAutoCorrectLanguageLists::SvxAutoCorrectLanguageLists( + SvxAutoCorrect& rParent, + const String& rShareAutoCorrectFile, + const String& rUserAutoCorrectFile, + LanguageType eLang) +: sShareAutoCorrFile( rShareAutoCorrectFile ), + sUserAutoCorrFile( rUserAutoCorrectFile ), + eLanguage(eLang), + pCplStt_ExcptLst( 0 ), + pWrdStt_ExcptLst( 0 ), + pAutocorr_List( 0 ), + rAutoCorrect(rParent), + nFlags(0) +{ +} + +/* -----------------18.11.98 11:16------------------- + * + * --------------------------------------------------*/ +SvxAutoCorrectLanguageLists::~SvxAutoCorrectLanguageLists() +{ + delete pCplStt_ExcptLst; + delete pWrdStt_ExcptLst; + delete pAutocorr_List; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::IsFileChanged_Imp() +{ + // nur alle 2 Minuten aufs FileSystem zugreifen um den + // Dateistempel zu ueberpruefen + BOOL bRet = FALSE; + + Time nMinTime( 0, 2 ); + Time nAktTime; + if( aLastCheckTime > nAktTime || // ueberlauf ? + ( nAktTime -= aLastCheckTime ) > nMinTime ) // min Zeit vergangen + { + Date aTstDate; Time aTstTime; + if( FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile, + &aTstDate, &aTstTime ) && + ( aModifiedDate != aTstDate || aModifiedTime != aTstTime )) + { + bRet = TRUE; + // dann mal schnell alle Listen entfernen! + if( CplSttLstLoad & nFlags && pCplStt_ExcptLst ) + delete pCplStt_ExcptLst, pCplStt_ExcptLst = 0; + if( WrdSttLstLoad & nFlags && pWrdStt_ExcptLst ) + delete pWrdStt_ExcptLst, pWrdStt_ExcptLst = 0; + if( ChgWordLstLoad & nFlags && pAutocorr_List ) + delete pAutocorr_List, pAutocorr_List = 0; + nFlags &= ~(CplSttLstLoad | WrdSttLstLoad | ChgWordLstLoad ); + } + aLastCheckTime = Time(); + } + return bRet; +} + +void SvxAutoCorrectLanguageLists::LoadXMLExceptList_Imp( + SvStringsISortDtor*& rpLst, + const sal_Char* pStrmName, + SotStorageRef& rStg) +{ + if( rpLst ) + rpLst->DeleteAndDestroy( 0, rpLst->Count() ); + else + rpLst = new SvStringsISortDtor( 16, 16 ); + + { + String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 ); + String sTmp( sStrmName ); + + if( rStg.Is() && rStg->IsStream( sStrmName ) ) + { + SvStorageStreamRef xStrm = rStg->OpenSotStream( sTmp, + ( STREAM_READ | STREAM_SHARE_DENYWRITE | STREAM_NOCREATE ) ); + if( SVSTREAM_OK != xStrm->GetError()) + { + xStrm.Clear(); + rStg.Clear(); + RemoveStream_Imp( sStrmName ); + } + else + { + uno::Reference< lang::XMultiServiceFactory > xServiceFactory = + comphelper::getProcessServiceFactory(); + DBG_ASSERT( xServiceFactory.is(), + "XMLReader::Read: got no service manager" ); + if( !xServiceFactory.is() ) + { + // Throw an exception ? + } + + xml::sax::InputSource aParserInput; + aParserInput.sSystemId = sStrmName; + + xStrm->Seek( 0L ); + xStrm->SetBufferSize( 8 * 1024 ); + aParserInput.aInputStream = new utl::OInputStreamWrapper( *xStrm ); + + // get parser + uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance( + OUString::createFromAscii("com.sun.star.xml.sax.Parser") ); + DBG_ASSERT( xXMLParser.is(), + "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" ); + if( !xXMLParser.is() ) + { + // Maybe throw an exception? + } + + // get filter + // #110680# + // uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( *rpLst ); + uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLExceptionListImport ( xServiceFactory, *rpLst ); + + // connect parser and filter + uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY ); + xParser->setDocumentHandler( xFilter ); + + // parse + try + { + xParser->parseStream( aParserInput ); + } + catch( xml::sax::SAXParseException& ) + { + // re throw ? + } + catch( xml::sax::SAXException& ) + { + // re throw ? + } + catch( io::IOException& ) + { + // re throw ? + } + } + } + + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); + } + +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SaveExceptList_Imp( + const SvStringsISortDtor& rLst, + const sal_Char* pStrmName, + SotStorageRef &rStg, + BOOL bConvert ) +{ + if( rStg.Is() ) + { + String sStrmName( pStrmName, RTL_TEXTENCODING_MS_1252 ); + if( !rLst.Count() ) + { + rStg->Remove( sStrmName ); + rStg->Commit(); + } + else + { + SotStorageStreamRef xStrm = rStg->OpenSotStream( sStrmName, + ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) ); + if( xStrm.Is() ) + { + xStrm->SetSize( 0 ); + xStrm->SetBufferSize( 8192 ); + String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) ); + OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") ); + uno::Any aAny; + aAny <<= aMime; + xStrm->SetProperty( aPropName, aAny ); + + + uno::Reference< lang::XMultiServiceFactory > xServiceFactory = + comphelper::getProcessServiceFactory(); + DBG_ASSERT( xServiceFactory.is(), + "XMLReader::Read: got no service manager" ); + if( !xServiceFactory.is() ) + { + // Throw an exception ? + } + + uno::Reference < XInterface > xWriter (xServiceFactory->createInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer")))); + DBG_ASSERT(xWriter.is(),"com.sun.star.xml.sax.Writer service missing"); + uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *xStrm ); + uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY); + xSrc->setOutputStream(xOut); + + uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY); + + // #110680# + // SvXMLExceptionListExport aExp(rLst, sStrmName, xHandler); + SvXMLExceptionListExport aExp( xServiceFactory, rLst, sStrmName, xHandler ); + + aExp.exportDoc( XML_BLOCK_LIST ); + + xStrm->Commit(); + if( xStrm->GetError() == SVSTREAM_OK ) + { + xStrm.Clear(); + if (!bConvert) + { + rStg->Commit(); + if( SVSTREAM_OK != rStg->GetError() ) + { + rStg->Remove( sStrmName ); + rStg->Commit(); + } + } + } + } + } + } +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvxAutocorrWordList* SvxAutoCorrectLanguageLists::LoadAutocorrWordList() +{ + if( pAutocorr_List ) + pAutocorr_List->DeleteAndDestroy( 0, pAutocorr_List->Count() ); + else + pAutocorr_List = new SvxAutocorrWordList( 16, 16 ); + + SvStringsDtor aRemoveArr; + try + { + uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sShareAutoCorrFile, embed::ElementModes::READ ); + String aXMLWordListName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 ); + uno::Reference < io::XStream > xStrm = xStg->openStreamElement( aXMLWordListName, embed::ElementModes::READ ); + uno::Reference< lang::XMultiServiceFactory > xServiceFactory = comphelper::getProcessServiceFactory(); + + xml::sax::InputSource aParserInput; + aParserInput.sSystemId = aXMLWordListName; + aParserInput.aInputStream = xStrm->getInputStream(); + + // get parser + uno::Reference< XInterface > xXMLParser = xServiceFactory->createInstance( OUString::createFromAscii("com.sun.star.xml.sax.Parser") ); + DBG_ASSERT( xXMLParser.is(), "XMLReader::Read: com.sun.star.xml.sax.Parser service missing" ); + if( xXMLParser.is() ) + { + uno::Reference< xml::sax::XDocumentHandler > xFilter = new SvXMLAutoCorrectImport( xServiceFactory, pAutocorr_List, rAutoCorrect, xStg ); + + // connect parser and filter + uno::Reference< xml::sax::XParser > xParser( xXMLParser, UNO_QUERY ); + xParser->setDocumentHandler( xFilter ); + + // parse + xParser->parseStream( aParserInput ); + } + } + catch ( uno::Exception& ) + { + } + + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sShareAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); + + return pAutocorr_List; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ + +void SvxAutoCorrectLanguageLists::SetAutocorrWordList( SvxAutocorrWordList* pList ) +{ + if( pAutocorr_List && pList != pAutocorr_List ) + delete pAutocorr_List; + pAutocorr_List = pList; + if( !pAutocorr_List ) + { + DBG_ASSERT( !this, "keine gueltige Liste" ); + pAutocorr_List = new SvxAutocorrWordList( 16, 16 ); + } + nFlags |= ChgWordLstLoad; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +const SvxAutocorrWordList* SvxAutoCorrectLanguageLists::GetAutocorrWordList() +{ + if( !( ChgWordLstLoad & nFlags ) || IsFileChanged_Imp() ) + SetAutocorrWordList( LoadAutocorrWordList() ); + return pAutocorr_List; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetCplSttExceptList() +{ + if( !( CplSttLstLoad & nFlags ) || IsFileChanged_Imp() ) + SetCplSttExceptList( LoadCplSttExceptList() ); + return pCplStt_ExcptLst; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::AddToCplSttExceptList(const String& rNew) +{ + String* pNew = new String( rNew ); + if( rNew.Len() && GetCplSttExceptList()->Insert( pNew ) ) + { + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg ); + + xStg = 0; + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); + } + else + delete pNew, pNew = 0; + return 0 != pNew; +} +/* -----------------18.11.98 15:20------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::AddToWrdSttExceptList(const String& rNew) +{ + String* pNew = new String( rNew ); + SvStringsISortDtor* pExceptList = LoadWrdSttExceptList(); + if( rNew.Len() && pExceptList && pExceptList->Insert( pNew ) ) + { + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg ); + + xStg = 0; + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); + } + else + delete pNew, pNew = 0; + return 0 != pNew; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadCplSttExceptList() +{ + SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, TRUE ); + String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) ); + if( xStg.Is() && xStg->IsContained( sTemp ) ) + LoadXMLExceptList_Imp( pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg ); + + return pCplStt_ExcptLst; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SaveCplSttExceptList() +{ + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + SaveExceptList_Imp( *pCplStt_ExcptLst, pXMLImplCplStt_ExcptLstStr, xStg ); + + xStg = 0; + + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SetCplSttExceptList( SvStringsISortDtor* pList ) +{ + if( pCplStt_ExcptLst && pList != pCplStt_ExcptLst ) + delete pCplStt_ExcptLst; + + pCplStt_ExcptLst = pList; + if( !pCplStt_ExcptLst ) + { + DBG_ASSERT( !this, "keine gueltige Liste" ); + pCplStt_ExcptLst = new SvStringsISortDtor( 16, 16 ); + } + nFlags |= CplSttLstLoad; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvStringsISortDtor* SvxAutoCorrectLanguageLists::LoadWrdSttExceptList() +{ + SotStorageRef xStg = new SotStorage( sShareAutoCorrFile, STREAM_READ | STREAM_SHARE_DENYNONE, TRUE ); + String sTemp ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) ); + if( xStg.Is() && xStg->IsContained( sTemp ) ) + LoadXMLExceptList_Imp( pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg ); + return pWrdStt_ExcptLst; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SaveWrdSttExceptList() +{ + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + SaveExceptList_Imp( *pWrdStt_ExcptLst, pXMLImplWrdStt_ExcptLstStr, xStg ); + + xStg = 0; + // Zeitstempel noch setzen + FStatHelper::GetModifiedDateTimeOfFile( sUserAutoCorrFile, + &aModifiedDate, &aModifiedTime ); + aLastCheckTime = Time(); +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::SetWrdSttExceptList( SvStringsISortDtor* pList ) +{ + if( pWrdStt_ExcptLst && pList != pWrdStt_ExcptLst ) + delete pWrdStt_ExcptLst; + pWrdStt_ExcptLst = pList; + if( !pWrdStt_ExcptLst ) + { + DBG_ASSERT( !this, "keine gueltige Liste" ); + pWrdStt_ExcptLst = new SvStringsISortDtor( 16, 16 ); + } + nFlags |= WrdSttLstLoad; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +SvStringsISortDtor* SvxAutoCorrectLanguageLists::GetWrdSttExceptList() +{ + if( !( WrdSttLstLoad & nFlags ) || IsFileChanged_Imp() ) + SetWrdSttExceptList( LoadWrdSttExceptList() ); + return pWrdStt_ExcptLst; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +void SvxAutoCorrectLanguageLists::RemoveStream_Imp( const String& rName ) +{ + if( sShareAutoCorrFile != sUserAutoCorrFile ) + { + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + if( xStg.Is() && SVSTREAM_OK == xStg->GetError() && + xStg->IsStream( rName ) ) + { + xStg->Remove( rName ); + xStg->Commit(); + + xStg = 0; + } + } +} + +void SvxAutoCorrectLanguageLists::MakeUserStorage_Impl() +{ + // The conversion needs to happen if the file is already in the user + // directory and is in the old format. Additionally it needs to + // happen when the file is being copied from share to user. + + sal_Bool bError = sal_False, bConvert = sal_False, bCopy = sal_False; + INetURLObject aDest; + INetURLObject aSource; + +// String sDestPath = sUserAutoCorrFile.Copy ( 0, sUserAutoCorrFile.Len()-3); +// sDestPath.AppendAscii ("bak"); + + + if (sUserAutoCorrFile != sShareAutoCorrFile ) + { + aSource = INetURLObject ( sShareAutoCorrFile ); //aSource.setFSysPath ( sShareAutoCorrFile, INetURLObject::FSYS_DETECT ); + aDest = INetURLObject ( sUserAutoCorrFile ); + if ( SotStorage::IsOLEStorage ( sShareAutoCorrFile ) ) + { + aDest.SetExtension ( String::CreateFromAscii ( "bak" ) ); + bConvert = sal_True; + } + bCopy = sal_True; + } + else if ( SotStorage::IsOLEStorage ( sUserAutoCorrFile ) ) + { + aSource = INetURLObject ( sUserAutoCorrFile ); + aDest = INetURLObject ( sUserAutoCorrFile ); + aDest.SetExtension ( String::CreateFromAscii ( "bak" ) ); + bCopy = bConvert = sal_True; + } + if (bCopy) + { + try + { + String sMain(aDest.GetMainURL( INetURLObject::DECODE_TO_IURI )); + sal_Unicode cSlash = '/'; + xub_StrLen nSlashPos = sMain.SearchBackward(cSlash); + sMain.Erase(nSlashPos); + ::ucbhelper::Content aNewContent( sMain, uno::Reference< XCommandEnvironment > ()); + Any aAny; + TransferInfo aInfo; + aInfo.NameClash = NameClash::OVERWRITE; + aInfo.NewTitle = aDest.GetName(); + aInfo.SourceURL = aSource.GetMainURL( INetURLObject::DECODE_TO_IURI ); + aInfo.MoveData = FALSE; + aAny <<= aInfo; + aNewContent.executeCommand( OUString ( RTL_CONSTASCII_USTRINGPARAM( "transfer" ) ), aAny); + } + catch (...) + { + bError = sal_True; + } + } + if (bConvert && !bError) + { + SotStorageRef xSrcStg = new SotStorage( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), STREAM_READ, TRUE ); + SotStorageRef xDstStg = new SotStorage( sUserAutoCorrFile, STREAM_WRITE, TRUE ); + + if( xSrcStg.Is() && xDstStg.Is() ) + { + String sWord ( RTL_CONSTASCII_USTRINGPARAM ( pImplWrdStt_ExcptLstStr ) ); + String sSentence ( RTL_CONSTASCII_USTRINGPARAM ( pImplCplStt_ExcptLstStr ) ); + String sXMLWord ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplWrdStt_ExcptLstStr ) ); + String sXMLSentence ( RTL_CONSTASCII_USTRINGPARAM ( pXMLImplCplStt_ExcptLstStr ) ); + SvStringsISortDtor *pTmpWordList = NULL; + + if (xSrcStg->IsContained( sXMLWord ) ) + LoadXMLExceptList_Imp( pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xSrcStg ); + + if (pTmpWordList) + { + SaveExceptList_Imp( *pTmpWordList, pXMLImplWrdStt_ExcptLstStr, xDstStg, TRUE ); + pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() ); + pTmpWordList = NULL; + } + + + if (xSrcStg->IsContained( sXMLSentence ) ) + LoadXMLExceptList_Imp( pTmpWordList, pXMLImplCplStt_ExcptLstStr, xSrcStg ); + + if (pTmpWordList) + { + SaveExceptList_Imp( *pTmpWordList, pXMLImplCplStt_ExcptLstStr, xDstStg, TRUE ); + pTmpWordList->DeleteAndDestroy( 0, pTmpWordList->Count() ); + } + + GetAutocorrWordList(); + MakeBlocklist_Imp( *xDstStg ); + // xDstStg is committed in MakeBlocklist_Imp + /*xSrcStg->CopyTo( &xDstStg );*/ + sShareAutoCorrFile = sUserAutoCorrFile; + xDstStg = 0; + try + { + ::ucbhelper::Content aContent ( aDest.GetMainURL( INetURLObject::DECODE_TO_IURI ), uno::Reference < XCommandEnvironment > ()); + aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "delete" ) ), makeAny ( sal_Bool (sal_True ) ) ); + } + catch (...) + { + } + } + } + else if( bCopy && !bError ) + sShareAutoCorrFile = sUserAutoCorrFile; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::MakeBlocklist_Imp( SvStorage& rStg ) +{ + String sStrmName( pXMLImplAutocorr_ListStr, RTL_TEXTENCODING_MS_1252 ); + BOOL bRet = TRUE, bRemove = !pAutocorr_List || !pAutocorr_List->Count(); + if( !bRemove ) + { + /* + if ( rStg.IsContained( sStrmName) ) + { + rStg.Remove ( sStrmName ); + rStg.Commit(); + } + */ + SvStorageStreamRef refList = rStg.OpenSotStream( sStrmName, + ( STREAM_READ | STREAM_WRITE | STREAM_SHARE_DENYWRITE ) ); + if( refList.Is() ) + { + refList->SetSize( 0 ); + refList->SetBufferSize( 8192 ); + String aPropName( String::CreateFromAscii( RTL_CONSTASCII_STRINGPARAM("MediaType") ) ); + OUString aMime( RTL_CONSTASCII_USTRINGPARAM("text/xml") ); + uno::Any aAny; + aAny <<= aMime; + refList->SetProperty( aPropName, aAny ); + + uno::Reference< lang::XMultiServiceFactory > xServiceFactory = + comphelper::getProcessServiceFactory(); + DBG_ASSERT( xServiceFactory.is(), + "XMLReader::Read: got no service manager" ); + if( !xServiceFactory.is() ) + { + // Throw an exception ? + } + + uno::Reference < XInterface > xWriter (xServiceFactory->createInstance( + OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.xml.sax.Writer")))); + DBG_ASSERT(xWriter.is(),"com.sun.star.xml.sax.Writer service missing"); + uno::Reference < io::XOutputStream> xOut = new utl::OOutputStreamWrapper( *refList ); + uno::Reference<io::XActiveDataSource> xSrc(xWriter, uno::UNO_QUERY); + xSrc->setOutputStream(xOut); + + uno::Reference<xml::sax::XDocumentHandler> xHandler(xWriter, uno::UNO_QUERY); + + // #110680# + // SvXMLAutoCorrectExport aExp(pAutocorr_List, sStrmName, xHandler); + SvXMLAutoCorrectExport aExp( xServiceFactory, pAutocorr_List, sStrmName, xHandler ); + + aExp.exportDoc( XML_BLOCK_LIST ); + + refList->Commit(); + bRet = SVSTREAM_OK == refList->GetError(); + if( bRet ) + { + refList.Clear(); + rStg.Commit(); + if( SVSTREAM_OK != rStg.GetError() ) + { + bRemove = TRUE; + bRet = FALSE; + } + } + + /* + refList->SetSize( 0 ); + refList->SetBufferSize( 8192 ); + rtl_TextEncoding eEncoding = gsl_getSystemTextEncoding(); + + String aDummy; // Erkennungszeichen fuer neue Streams + refList->WriteByteString( aDummy, RTL_TEXTENCODING_MS_1252 ) + << (BYTE) 4 // Laenge des Headers (ohne den Leerstring) + << (USHORT)WORDLIST_VERSION_358 // Version des Streams + << (BYTE)eEncoding; // der Zeichensatz + + for( USHORT i = 0; i < pAutocorr_List->Count() && + SVSTREAM_OK == refList->GetError(); ++i ) + { + SvxAutocorrWord* p = pAutocorr_List->GetObject( i ); + refList->WriteByteString( p->GetShort(), eEncoding ). + WriteByteString( p->IsTextOnly() + ? p->GetLong() + : p->GetShort(), eEncoding ); + } + refList->Commit(); + bRet = SVSTREAM_OK == refList->GetError(); + if( bRet ) + { + refList.Clear(); + rStg.Commit(); + if( SVSTREAM_OK != rStg.GetError() ) + { + bRemove = TRUE; + bRet = FALSE; + } + } + */ + } + else + bRet = FALSE; + } + + if( bRemove ) + { + rStg.Remove( sStrmName ); + rStg.Commit(); + } + + return bRet; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ +BOOL SvxAutoCorrectLanguageLists::PutText( const String& rShort, + const String& rLong ) +{ + // erstmal akt. Liste besorgen! + GetAutocorrWordList(); + + MakeUserStorage_Impl(); + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + + BOOL bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError(); + +/* if( bRet ) + { + // PutText( *xStg, rShort ); + } +*/ + // die Wortliste aktualisieren + if( bRet ) + { + USHORT nPos; + SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, rLong, TRUE ); + if( pAutocorr_List->Seek_Entry( pNew, &nPos ) ) + { + if( !(*pAutocorr_List)[ nPos ]->IsTextOnly() ) + { + // dann ist der Storage noch zu entfernen + String sStgNm( rShort ); + if (xStg->IsOLEStorage()) + EncryptBlockName_Imp( sStgNm ); + else + GeneratePackageName ( rShort, sStgNm); + + if( xStg->IsContained( sStgNm ) ) + xStg->Remove( sStgNm ); + } + pAutocorr_List->DeleteAndDestroy( nPos ); + } + + if( pAutocorr_List->Insert( pNew ) ) + { + bRet = MakeBlocklist_Imp( *xStg ); + xStg = 0; + } + else + { + delete pNew; + bRet = FALSE; + } + } + return bRet; +} +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ + // - Text mit Attributierung (kann nur der SWG - SWG-Format!) +BOOL SvxAutoCorrectLanguageLists::PutText( const String& rShort, + SfxObjectShell& rShell ) +{ + // erstmal akt. Liste besorgen! + GetAutocorrWordList(); + + MakeUserStorage_Impl(); + + BOOL bRet = FALSE; + String sLong; + try + { + uno::Reference < embed::XStorage > xStg = comphelper::OStorageHelper::GetStorageFromURL( sUserAutoCorrFile, embed::ElementModes::READWRITE ); +// String aName( rShort ); +// EncryptBlockName_Imp( aName ); +// bRet = PutText( *xStg, aName, rShell, sLong ); + bRet = rAutoCorrect.PutText( xStg, sUserAutoCorrFile, rShort, rShell, sLong ); + xStg = 0; + + // die Wortliste aktualisieren + if( bRet ) + { + SvxAutocorrWord* pNew = new SvxAutocorrWord( rShort, sLong, FALSE ); + if( pAutocorr_List->Insert( pNew ) ) + { + SotStorageRef xStor = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + MakeBlocklist_Imp( *xStor ); + } + else + delete pNew; + } + } + catch ( uno::Exception& ) + { + } + + return bRet; +} + +/* -----------------18.11.98 11:26------------------- + * + * --------------------------------------------------*/ + // - loesche einen Eintrag +BOOL SvxAutoCorrectLanguageLists::DeleteText( const String& rShort ) +{ + // erstmal akt. Liste besorgen! + GetAutocorrWordList(); + + MakeUserStorage_Impl(); + + SotStorageRef xStg = new SotStorage( sUserAutoCorrFile, STREAM_READWRITE, TRUE ); + BOOL bRet = xStg.Is() && SVSTREAM_OK == xStg->GetError(); + if( bRet ) + { + USHORT nPos; + SvxAutocorrWord aTmp( rShort, rShort ); + if( pAutocorr_List->Seek_Entry( &aTmp, &nPos ) ) + { + SvxAutocorrWord* pFnd = (*pAutocorr_List)[ nPos ]; + if( !pFnd->IsTextOnly() ) + { + String aName( rShort ); + if (xStg->IsOLEStorage()) + EncryptBlockName_Imp( aName ); + else + GeneratePackageName ( rShort, aName ); + if( xStg->IsContained( aName ) ) + { + xStg->Remove( aName ); + bRet = xStg->Commit(); + } + + } + // die Wortliste aktualisieren + pAutocorr_List->DeleteAndDestroy( nPos ); + MakeBlocklist_Imp( *xStg ); + xStg = 0; + } + else + bRet = FALSE; + } + return bRet; +} diff --git a/editeng/source/misc/swafopt.cxx b/editeng/source/misc/swafopt.cxx new file mode 100644 index 000000000000..e150e8699b76 --- /dev/null +++ b/editeng/source/misc/swafopt.cxx @@ -0,0 +1,163 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: swafopt.cxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <vcl/keycodes.hxx> +#include <tools/string.hxx> + +#include <editeng/swafopt.hxx> + +/*------------------------------------------------------------------------ + Beschreibung: +------------------------------------------------------------------------*/ + +SvxSwAutoFmtFlags::SvxSwAutoFmtFlags() + : aBulletFont( String::CreateFromAscii( + RTL_CONSTASCII_STRINGPARAM( "StarSymbol" )), + Size( 0, 14 ) ) +{ + bReplaceQuote = + bAutoCorrect = + bCptlSttSntnc = + bCptlSttWrd = + bChkFontAttr = + bChgUserColl = + bChgEnumNum = + bChgFracionSymbol = + bChgOrdinalNumber = + bChgToEnEmDash = + bChgWeightUnderl = + bSetINetAttr = + bAFmtDelSpacesAtSttEnd = + bAFmtDelSpacesBetweenLines = + bAFmtByInpDelSpacesAtSttEnd = + bAFmtByInpDelSpacesBetweenLines = + bDummy = TRUE; + + bReplaceStyles = + bDelEmptyNode = + bWithRedlining = + bAutoCmpltEndless = + bAutoCmpltAppendBlanc = + bAutoCmpltShowAsTip = FALSE; + + bSetBorder = + bCreateTable = + bSetNumRule = + bAFmtByInput = + bRightMargin = + bAutoCompleteWords = + bAutoCmpltCollectWords = + bAutoCmpltKeepList = TRUE; + + bDummy6 = bDummy7 = bDummy8 = + FALSE; + + nRightMargin = 50; // dflt. 50 % + nAutoCmpltExpandKey = KEY_RETURN; + + aBulletFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); + aBulletFont.SetFamily( FAMILY_DONTKNOW ); + aBulletFont.SetPitch( PITCH_DONTKNOW ); + aBulletFont.SetWeight( WEIGHT_DONTKNOW ); + aBulletFont.SetTransparent( TRUE ); + + cBullet = 0x2022; + cByInputBullet = cBullet; + aByInputBulletFont = aBulletFont; + + nAutoCmpltWordLen = 10; + nAutoCmpltListLen = 500; + pAutoCmpltList = 0; + pSmartTagMgr = 0; +} + + +SvxSwAutoFmtFlags& SvxSwAutoFmtFlags::operator=( const SvxSwAutoFmtFlags& rAFFlags ) +{ + bAutoCorrect = rAFFlags.bAutoCorrect; + bReplaceQuote = rAFFlags.bReplaceQuote; + bCptlSttSntnc = rAFFlags.bCptlSttSntnc; + bCptlSttWrd = rAFFlags.bCptlSttWrd; + bChkFontAttr = rAFFlags.bChkFontAttr; + + bChgUserColl = rAFFlags.bChgUserColl; + bChgEnumNum = rAFFlags.bChgEnumNum; + bDelEmptyNode = rAFFlags.bDelEmptyNode; + bSetNumRule = rAFFlags.bSetNumRule; + bAFmtByInput = rAFFlags.bAFmtByInput; + + bChgFracionSymbol = rAFFlags.bChgFracionSymbol; + bChgOrdinalNumber = rAFFlags.bChgOrdinalNumber; + bChgToEnEmDash = rAFFlags.bChgToEnEmDash; + bChgWeightUnderl = rAFFlags.bChgWeightUnderl; + bSetINetAttr = rAFFlags.bSetINetAttr; + bSetBorder = rAFFlags.bSetBorder; + bCreateTable = rAFFlags.bCreateTable; + bReplaceStyles = rAFFlags.bReplaceStyles; + bAFmtDelSpacesAtSttEnd = rAFFlags.bAFmtDelSpacesAtSttEnd; + bAFmtDelSpacesBetweenLines = rAFFlags.bAFmtDelSpacesBetweenLines; + bAFmtByInpDelSpacesAtSttEnd = rAFFlags.bAFmtByInpDelSpacesAtSttEnd; + bAFmtByInpDelSpacesBetweenLines = rAFFlags.bAFmtByInpDelSpacesBetweenLines; + + bDummy = rAFFlags.bDummy; + + bDummy6 = rAFFlags.bDummy6; + bDummy7 = rAFFlags.bDummy7; + bDummy8 = rAFFlags.bDummy8; + + bWithRedlining = rAFFlags.bWithRedlining; + + bRightMargin = rAFFlags.bRightMargin; + nRightMargin = rAFFlags.nRightMargin; + + cBullet = rAFFlags.cBullet; + aBulletFont = rAFFlags.aBulletFont; + + cByInputBullet = rAFFlags.cByInputBullet; + aByInputBulletFont = rAFFlags.aByInputBulletFont; + + bAutoCompleteWords = rAFFlags.bAutoCompleteWords; + bAutoCmpltCollectWords = rAFFlags.bAutoCmpltCollectWords; + bAutoCmpltKeepList = rAFFlags.bAutoCmpltKeepList; + bAutoCmpltEndless = rAFFlags.bAutoCmpltEndless; + bAutoCmpltAppendBlanc = rAFFlags.bAutoCmpltAppendBlanc; + bAutoCmpltShowAsTip = rAFFlags.bAutoCmpltShowAsTip; + pAutoCmpltList = rAFFlags.pAutoCmpltList; + pSmartTagMgr = rAFFlags.pSmartTagMgr; + nAutoCmpltExpandKey = rAFFlags.nAutoCmpltExpandKey; + + nAutoCmpltWordLen = rAFFlags.nAutoCmpltWordLen; + nAutoCmpltListLen = rAFFlags.nAutoCmpltListLen; + + return *this; +} + diff --git a/editeng/source/misc/txtrange.cxx b/editeng/source/misc/txtrange.cxx new file mode 100644 index 000000000000..21009010d40a --- /dev/null +++ b/editeng/source/misc/txtrange.cxx @@ -0,0 +1,722 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: txtrange.cxx,v $ + * $Revision: 1.15 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/txtrange.hxx> +#include <math.h> +#include <tools/poly.hxx> +#include <tools/debug.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> + +/************************************************************************* +|* +|* TextRanger::TextRanger() +|* +|* Beschreibung +|* Ersterstellung 20.01.97 +|* Letzte Aenderung 20.01.97 AMA +|* +*************************************************************************/ + +#ifdef WIN +#pragma optimize ( "", off ) +#endif + +TextRanger::TextRanger( const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DPolyPolygon* pLinePolyPolygon, + USHORT nCacheSz, USHORT nLft, USHORT nRght, BOOL bSimpl, BOOL bInnr, + BOOL bVert ) : + pBound( NULL ), + nCacheSize( nCacheSz ), + nCacheIdx( 0 ), + nRight( nRght ), + nLeft( nLft ), + nUpper( 0 ), + nLower( 0 ), + nPointCount( 0 ), + bSimple( bSimpl ), + bInner( bInnr ), + bVertical( bVert ) +{ +#ifdef DBG_UTIL + bFlag3 = bFlag4 = bFlag5 = bFlag6 = bFlag7 = FALSE; +#endif + pRangeArr = new Range[ nCacheSize ]; + pCache = new SvLongsPtr[ nCacheSize ]; + memset( pRangeArr, 0, nCacheSize * sizeof( Range ) ); + memset( pCache, 0, nCacheSize * sizeof( SvLongsPtr ) ); + sal_uInt32 nCount(rPolyPolygon.count()); + mpPolyPolygon = new PolyPolygon( (sal_uInt16)nCount ); + + for(sal_uInt32 i(0L); i < nCount; i++) + { + const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(i).getDefaultAdaptiveSubdivision()); + nPointCount += aCandidate.count(); + mpPolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i ); + } + + if( pLinePolyPolygon ) + { + nCount = pLinePolyPolygon->count(); + mpLinePolyPolygon = new PolyPolygon(); + + for(sal_uInt32 i(0L); i < nCount; i++) + { + const basegfx::B2DPolygon aCandidate(pLinePolyPolygon->getB2DPolygon(i).getDefaultAdaptiveSubdivision()); + nPointCount += aCandidate.count(); + mpLinePolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i ); + } + } + else + mpLinePolyPolygon = NULL; +} + +#ifdef WIN +#pragma optimize ( "", on ) +#endif + +/************************************************************************* +|* +|* TextRanger::~TextRanger() +|* +|* Beschreibung +|* Ersterstellung 20.01.97 +|* Letzte Aenderung 20.01.97 AMA +|* +*************************************************************************/ + +TextRanger::~TextRanger() +{ + for( USHORT i = 0; i < nCacheSize; ++i ) + delete pCache[i]; + delete[] pCache; + delete[] pRangeArr; + delete mpPolyPolygon; + delete mpLinePolyPolygon; +} + +/*-----------------17.11.00 09:49------------------- + * TextRanger::SetVertical(..) + * If there's is a change in the writing direction, + * the cache has to be cleared. + * --------------------------------------------------*/ + +void TextRanger::SetVertical( BOOL bNew ) +{ + if( IsVertical() != bNew ) + { + bVertical = bNew; + for( USHORT i = 0; i < nCacheSize; ++i ) + delete pCache[i]; + memset( pRangeArr, 0, nCacheSize * sizeof( Range ) ); + memset( pCache, 0, nCacheSize * sizeof( SvLongsPtr ) ); + } +} + +/************************************************************************* +|* +|* SvxBoundArgs +|* +|* Beschreibung +|* Ersterstellung 20.01.97 +|* Letzte Aenderung 20.01.97 AMA +|* +*************************************************************************/ + +class SvxBoundArgs +{ + SvBools aBoolArr; + SvLongs *pLongArr; + TextRanger *pTextRanger; + long nMin; + long nMax; + long nTop; + long nBottom; + long nUpDiff; + long nLowDiff; + long nUpper; + long nLower; + long nStart; + long nEnd; + USHORT nCut; + USHORT nLast; + USHORT nNext; + BYTE nAct; + BYTE nFirst; + BOOL bClosed : 1; + BOOL bInner : 1; + BOOL bMultiple : 1; + BOOL bConcat : 1; + BOOL bRotate : 1; + void NoteRange( BOOL bToggle ); + long Cut( long nY, const Point& rPt1, const Point& rPt2 ); + void Add(); + void _NoteFarPoint( long nPx, long nPyDiff, long nDiff ); + void NoteFarPoint( long nPx, long nPyDiff, long nDiff ) + { if( nDiff ) _NoteFarPoint( nPx, nPyDiff, nDiff ); } + long CalcMax( const Point& rPt1, const Point& rPt2, long nRange, long nFar ); + void CheckCut( const Point& rLst, const Point& rNxt ); + inline long A( const Point& rP ) const { return bRotate ? rP.Y() : rP.X(); } + inline long B( const Point& rP ) const { return bRotate ? rP.X() : rP.Y(); } +public: + SvxBoundArgs( TextRanger* pRanger, SvLongs *pLong, const Range& rRange ); + void NotePoint( const long nA ) { NoteMargin( nA - nStart, nA + nEnd ); } + void NoteMargin( const long nL, const long nR ) + { if( nMin > nL ) nMin = nL; if( nMax < nR ) nMax = nR; } + USHORT Area( const Point& rPt ); + void NoteUpLow( long nA, const BYTE nArea ); + void Calc( const PolyPolygon& rPoly ); + void Concat( const PolyPolygon* pPoly ); + // inlines + void NoteLast() { if( bMultiple ) NoteRange( nAct == nFirst ); } + void SetClosed( const BOOL bNew ){ bClosed = bNew; } + BOOL IsClosed() const { return bClosed; } + void SetConcat( const BOOL bNew ){ bConcat = bNew; } + BOOL IsConcat() const { return bConcat; } + BYTE GetAct() const { return nAct; } +}; + +SvxBoundArgs::SvxBoundArgs( TextRanger* pRanger, SvLongs *pLong, + const Range& rRange ) + : aBoolArr( 4, 4 ), pLongArr( pLong ), pTextRanger( pRanger ), + nTop( rRange.Min() ), nBottom( rRange.Max() ), + bInner( pRanger->IsInner() ), bMultiple( bInner || !pRanger->IsSimple() ), + bConcat( FALSE ), bRotate( pRanger->IsVertical() ) +{ + if( bRotate ) + { + nStart = pRanger->GetUpper(); + nEnd = pRanger->GetLower(); + nLowDiff = pRanger->GetLeft(); + nUpDiff = pRanger->GetRight(); + } + else + { + nStart = pRanger->GetLeft(); + nEnd = pRanger->GetRight(); + nLowDiff = pRanger->GetUpper(); + nUpDiff = pRanger->GetLower(); + } + nUpper = nTop - nUpDiff; + nLower = nBottom + nLowDiff; + pLongArr->Remove( 0, pLongArr->Count() ); +} + +long SvxBoundArgs::CalcMax( const Point& rPt1, const Point& rPt2, + long nRange, long nFarRange ) +{ + double nDa = Cut( nRange, rPt1, rPt2 ) - Cut( nFarRange, rPt1, rPt2 ); + double nB; + if( nDa < 0 ) + { + nDa = -nDa; + nB = nEnd; + } + else + nB = nStart; + nB *= nB; + nB += nDa * nDa; + nB = nRange + nDa * ( nFarRange - nRange ) / sqrt( nB ); + + BOOL bNote; + if( nB < B(rPt2) ) + bNote = nB > B(rPt1); + else + bNote = nB < B(rPt1); + if( bNote ) + return( long( nB ) ); + return 0; +} + +void SvxBoundArgs::CheckCut( const Point& rLst, const Point& rNxt ) +{ + if( nCut & 1 ) + NotePoint( Cut( nBottom, rLst, rNxt ) ); + if( nCut & 2 ) + NotePoint( Cut( nTop, rLst, rNxt ) ); + if( rLst.X() != rNxt.X() && rLst.Y() != rNxt.Y() ) + { + long nYps; + if( nLowDiff && ( ( nCut & 1 ) || nLast == 1 || nNext == 1 ) ) + { + nYps = CalcMax( rLst, rNxt, nBottom, nLower ); + if( nYps ) + _NoteFarPoint( Cut( nYps, rLst, rNxt ), nLower-nYps, nLowDiff ); + } + if( nUpDiff && ( ( nCut & 2 ) || nLast == 2 || nNext == 2 ) ) + { + nYps = CalcMax( rLst, rNxt, nTop, nUpper ); + if( nYps ) + _NoteFarPoint( Cut( nYps, rLst, rNxt ), nYps-nUpper, nUpDiff ); + } + } +} + +void SvxBoundArgs::_NoteFarPoint( long nPa, long nPbDiff, long nDiff ) +{ + long nTmpA; + double nQuot = 2 * nDiff - nPbDiff; + nQuot *= nPbDiff; + nQuot = sqrt( nQuot ); + nQuot /= nDiff; + nTmpA = nPa - long( nStart * nQuot ); + nPbDiff = nPa + long( nEnd * nQuot ); + NoteMargin( nTmpA, nPbDiff ); +} + +void SvxBoundArgs::NoteRange( BOOL bToggle ) +{ + DBG_ASSERT( nMax >= nMin || bInner, "NoteRange: Min > Max?"); + if( nMax < nMin ) + return; + if( !bClosed ) + bToggle = FALSE; + USHORT nIdx = 0; + USHORT nCount = pLongArr->Count(); + DBG_ASSERT( nCount == 2 * aBoolArr.Count(), "NoteRange: Incompatible Sizes" ); + while( nIdx < nCount && (*pLongArr)[ nIdx ] < nMin ) + ++nIdx; + BOOL bOdd = nIdx % 2 ? TRUE : FALSE; + // Kein Ueberlappung mit vorhandenen Intervallen? + if( nIdx == nCount || ( !bOdd && nMax < (*pLongArr)[ nIdx ] ) ) + { // Dann wird ein neues eingefuegt ... + pLongArr->Insert( nMin, nIdx ); + pLongArr->Insert( nMax, nIdx + 1 ); + aBoolArr.Insert( bToggle, nIdx / 2 ); + } + else + { // ein vorhandes Intervall erweitern ... + USHORT nMaxIdx = nIdx; + // Wenn wir auf einer linken Intervallgrenze gelandet sind, muss diese + // auf nMin gesenkt werden. + if( bOdd ) + --nIdx; + else + (*pLongArr)[ nIdx ] = nMin; + while( nMaxIdx < nCount && (*pLongArr)[ nMaxIdx ] < nMax ) + ++nMaxIdx; + DBG_ASSERT( nMaxIdx > nIdx || nMin == nMax, "NoteRange: Funny Situation." ); + if( nMaxIdx ) + --nMaxIdx; + if( nMaxIdx < nIdx ) + nMaxIdx = nIdx; + // Wenn wir auf einer rechten Intervallgrenze landen, muss diese + // auf nMax angehoben werden. + if( nMaxIdx % 2 ) + (*pLongArr)[ nMaxIdx-- ] = nMax; + // Jetzt werden eventuell noch Intervalle verschmolzen + USHORT nDiff = nMaxIdx - nIdx; + nMaxIdx = nIdx / 2; // Ab hier ist nMaxIdx der Index im BoolArray. + if( nDiff ) + { + (*pLongArr).Remove( nIdx + 1, nDiff ); + nDiff /= 2; + USHORT nStop = nMaxIdx + nDiff; + for( USHORT i = nMaxIdx; i < nStop; ++i ) + bToggle ^= aBoolArr[ i ]; + aBoolArr.Remove( nMaxIdx, nDiff ); + } + DBG_ASSERT( nMaxIdx < aBoolArr.Count(), "NoteRange: Too much deleted" ); + aBoolArr[ nMaxIdx ] ^= bToggle; + } +} + +void SvxBoundArgs::Calc( const PolyPolygon& rPoly ) +{ + USHORT nCount; + nAct = 0; + for( USHORT i = 0; i < rPoly.Count(); ++i ) + { + const Polygon& rPol = rPoly[ i ]; + nCount = rPol.GetSize(); + if( nCount ) + { + const Point& rNull = rPol[ 0 ]; + SetClosed( IsConcat() || ( rNull == rPol[ nCount - 1 ] ) ); + nLast = Area( rNull ); + if( nLast & 12 ) + { + nFirst = 3; + if( bMultiple ) + nAct = 0; + } + else + { + // Der erste Punkt des Polygons liegt innerhalb der Zeile. + if( nLast ) + { + if( bMultiple || !nAct ) + { + nMin = USHRT_MAX; + nMax = 0; + } + if( nLast & 1 ) + NoteFarPoint( A(rNull), nLower - B(rNull), nLowDiff ); + else + NoteFarPoint( A(rNull), B(rNull) - nUpper, nUpDiff ); + } + else + { + if( bMultiple || !nAct ) + { + nMin = A(rNull); + nMax = nMin + nEnd; + nMin -= nStart; + } + else + NotePoint( A(rNull) ); + } + nFirst = 0; // In welcher Richtung wird die Zeile verlassen? + nAct = 3; // Wir sind z.Z. innerhalb der Zeile. + } + if( nCount > 1 ) + { + USHORT nIdx = 1; + while( TRUE ) + { + const Point& rLast = rPol[ nIdx - 1 ]; + if( nIdx == nCount ) + nIdx = 0; + const Point& rNext = rPol[ nIdx ]; + nNext = Area( rNext ); + nCut = nNext ^ nLast; + USHORT nOldAct = nAct; + if( nAct ) + CheckCut( rLast, rNext ); + if( nCut & 4 ) + { + NoteUpLow( Cut( nLower, rLast, rNext ), 2 ); + if( nAct && nAct != nOldAct ) + { + nOldAct = nAct; + CheckCut( rLast, rNext ); + } + } + if( nCut & 8 ) + { + NoteUpLow( Cut( nUpper, rLast, rNext ), 1 ); + if( nAct && nAct != nOldAct ) + CheckCut( rLast, rNext ); + } + if( !nIdx ) + { + if( !( nNext & 12 ) ) + NoteLast(); + break; + } + if( !( nNext & 12 ) ) + { + if( !nNext ) + NotePoint( A(rNext) ); + else if( nNext & 1 ) + NoteFarPoint( A(rNext), nLower-B(rNext), nLowDiff ); + else + NoteFarPoint( A(rNext), B(rNext)-nUpper, nUpDiff ); + } + nLast = nNext; + if( ++nIdx == nCount && !IsClosed() ) + { + if( !( nNext & 12 ) ) + NoteLast(); + break; + } + } + } + if( bMultiple && IsConcat() ) + { + Add(); + nAct = 0; + } + } + } + if( !bMultiple ) + { + DBG_ASSERT( pLongArr->Count() == 0, "I said: Simple!" ); + if( nAct ) + { + if( bInner ) + { + long nTmpMin, nTmpMax; + { + nTmpMin = nMin + 2 * nStart; + nTmpMax = nMax - 2 * nEnd; + if( nTmpMin <= nTmpMax ) + { + pLongArr->Insert( nTmpMin, 0 ); + pLongArr->Insert( nTmpMax, 1 ); + } + } + } + else + { + pLongArr->Insert( nMin, 0 ); + pLongArr->Insert( nMax, 1 ); + } + } + } + else if( !IsConcat() ) + Add(); +} + +void SvxBoundArgs::Add() +{ + USHORT nLongIdx = 1; + USHORT nCount = aBoolArr.Count(); + if( nCount && ( !bInner || !pTextRanger->IsSimple() ) ) + { + BOOL bDelete = aBoolArr[ 0 ]; + if( bInner ) + bDelete = !bDelete; + for( USHORT nBoolIdx = 1; nBoolIdx < nCount; ++nBoolIdx ) + { + if( bDelete ) + { + USHORT next = 2; + while( nBoolIdx < nCount && !aBoolArr[ nBoolIdx++ ] && + (!bInner || nBoolIdx < nCount ) ) + next += 2; + pLongArr->Remove( nLongIdx, next ); + next /= 2; + nBoolIdx = nBoolIdx - next; + nCount = nCount - next; + aBoolArr.Remove( nBoolIdx, next ); + if( nBoolIdx ) + aBoolArr[ nBoolIdx - 1 ] = FALSE; +#if OSL_DEBUG_LEVEL > 1 + else + ++next; +#endif + } + bDelete = nBoolIdx < nCount && aBoolArr[ nBoolIdx ]; + nLongIdx += 2; + DBG_ASSERT( nLongIdx == 2*nBoolIdx+1, "BoundArgs: Array-Idx Confusion" ); + DBG_ASSERT( aBoolArr.Count()*2 == pLongArr->Count(), + "BoundArgs: Array-Count: Confusion" ); + } + } + if( 0 != ( nCount = pLongArr->Count() ) ) + { + if( bInner ) + { + pLongArr->Remove( 0, 1 ); + pLongArr->Remove( pLongArr->Count() - 1, 1 ); + + // Hier wird die Zeile beim "einfachen" Konturumfluss im Innern + // in ein grosses Rechteck zusammengefasst. + // Zur Zeit (April 1999) wertet die EditEngine nur das erste Rechteck + // aus, falls sie eines Tages in der Lage ist, eine Zeile in mehreren + // Teilen auszugeben, kann es sinnvoll sein, die folgenden Zeilen + // zu loeschen. + if( pTextRanger->IsSimple() && pLongArr->Count() > 2 ) + pLongArr->Remove( 1, pLongArr->Count() - 2 ); + + } + } +} + +void SvxBoundArgs::Concat( const PolyPolygon* pPoly ) +{ + SetConcat( TRUE ); + DBG_ASSERT( pPoly, "Nothing to do?" ); + SvLongs *pOld = pLongArr; + pLongArr = new SvLongs( 2, 8 ); + aBoolArr.Remove( 0, aBoolArr.Count() ); + bInner = FALSE; + Calc( *pPoly ); + USHORT nCount = pLongArr->Count(); + USHORT nIdx = 0; + USHORT i = 0; + BOOL bSubtract = pTextRanger->IsInner(); + while( i < nCount ) + { + USHORT nOldCount = pOld->Count(); + if( nIdx == nOldCount ) + { // Am Ende des alten Arrays angelangt... + if( !bSubtract ) + pOld->Insert( pLongArr, nIdx, i, USHRT_MAX ); + break; + } + long nLeft = (*pLongArr)[ i++ ]; + long nRight = (*pLongArr)[ i++ ]; + USHORT nLeftPos = nIdx + 1; + while( nLeftPos < nOldCount && nLeft > (*pOld)[ nLeftPos ] ) + nLeftPos += 2; + if( nLeftPos >= nOldCount ) + { // Das aktuelle Intervall gehoert ans Ende des alten Arrays... + if( !bSubtract ) + pOld->Insert( pLongArr, nOldCount, i - 2, USHRT_MAX ); + break; + } + USHORT nRightPos = nLeftPos - 1; + while( nRightPos < nOldCount && nRight >= (*pOld)[ nRightPos ] ) + nRightPos += 2; + if( nRightPos < nLeftPos ) + { // Das aktuelle Intervall gehoert zwischen zwei alte Intervalle + if( !bSubtract ) + pOld->Insert( pLongArr, nRightPos, i - 2, i ); + nIdx = nRightPos + 2; + } + else if( bSubtract ) // Subtrahieren ggf. Trennen + { + long nOld; + if( nLeft > ( nOld = (*pOld)[ nLeftPos - 1 ] ) ) + { // Jetzt spalten wir den linken Teil ab... + if( nLeft - 1 > nOld ) + { + pOld->Insert( nOld, nLeftPos - 1 ); + pOld->Insert( nLeft - 1, nLeftPos ); + nLeftPos += 2; + nRightPos += 2; + } + } + if( nRightPos - nLeftPos > 1 ) + pOld->Remove( nLeftPos, nRightPos - nLeftPos - 1 ); + if( ++nRight >= ( nOld = (*pOld)[ nLeftPos ] ) ) + pOld->Remove( nLeftPos - 1, 2 ); + else + (*pOld)[ nLeftPos - 1 ] = nRight; + } + else // Verschmelzen + { + if( nLeft < (*pOld)[ nLeftPos - 1 ] ) + (*pOld)[ nLeftPos - 1 ] = nLeft; + if( nRight > (*pOld)[ nRightPos - 1 ] ) + (*pOld)[ nRightPos - 1 ] = nRight; + if( nRightPos - nLeftPos > 1 ) + pOld->Remove( nLeftPos, nRightPos - nLeftPos - 1 ); + + } + nIdx = nLeftPos - 1; + } + delete pLongArr; +} + +/************************************************************************* + * SvxBoundArgs::Area ermittelt den Bereich, in dem sich der Punkt befindet + * 0 = innerhalb der Zeile + * 1 = unterhalb, aber innerhalb der oberen Randes + * 2 = oberhalb, aber innerhalb der unteren Randes + * 5 = unterhalb des oberen Randes + *10 = oberhalb des unteren Randes + *************************************************************************/ + +USHORT SvxBoundArgs::Area( const Point& rPt ) +{ + long nB = B( rPt ); + if( nB >= nBottom ) + { + if( nB >= nLower ) + return 5; + return 1; + } + if( nB <= nTop ) + { + if( nB <= nUpper ) + return 10; + return 2; + } + return 0; +} + +/************************************************************************* + * lcl_Cut berechnet die X-Koordinate der Strecke (Pt1-Pt2) auf der + * Y-Koordinate nY. + * Vorausgesetzt wird, dass einer der Punkte oberhalb und der andere + * unterhalb der Y-Koordinate liegt. + *************************************************************************/ + +long SvxBoundArgs::Cut( long nB, const Point& rPt1, const Point& rPt2 ) +{ + if( pTextRanger->IsVertical() ) + { + double nQuot = nB - rPt1.X(); + nQuot /= ( rPt2.X() - rPt1.X() ); + nQuot *= ( rPt2.Y() - rPt1.Y() ); + return long( rPt1.Y() + nQuot ); + } + double nQuot = nB - rPt1.Y(); + nQuot /= ( rPt2.Y() - rPt1.Y() ); + nQuot *= ( rPt2.X() - rPt1.X() ); + return long( rPt1.X() + nQuot ); +} + +void SvxBoundArgs::NoteUpLow( long nA, const BYTE nArea ) +{ + if( nAct ) + { + NoteMargin( nA, nA ); + if( bMultiple ) + { + NoteRange( nArea != nAct ); + nAct = 0; + } + if( !nFirst ) + nFirst = nArea; + } + else + { + nAct = nArea; + nMin = nA; + nMax = nA; + } +} + +SvLongsPtr TextRanger::GetTextRanges( const Range& rRange ) +{ + DBG_ASSERT( rRange.Min() || rRange.Max(), "Zero-Range not allowed, Bye Bye" ); + USHORT nIndex = 0; + while( nIndex < nCacheSize && rRange != pRangeArr[ nIndex ] ) + ++nIndex; + if( nIndex >= nCacheSize ) + { + ++nCacheIdx; + nCacheIdx %= nCacheSize; + pRangeArr[ nCacheIdx ] = rRange; + if( !pCache[ nCacheIdx ] ) + pCache[ nCacheIdx ] = new SvLongs( 2, 8 ); + nIndex = nCacheIdx; + SvxBoundArgs aArg( this, pCache[ nCacheIdx ], rRange ); + aArg.Calc( *mpPolyPolygon ); + if( mpLinePolyPolygon ) + aArg.Concat( mpLinePolyPolygon ); + } + return pCache[ nIndex ]; +} + +const Rectangle& TextRanger::_GetBoundRect() +{ + DBG_ASSERT( 0 == pBound, "Don't call twice." ); + pBound = new Rectangle( mpPolyPolygon->GetBoundRect() ); + return *pBound; +} + + diff --git a/editeng/source/misc/unolingu.cxx b/editeng/source/misc/unolingu.cxx new file mode 100644 index 000000000000..8fcd4214c371 --- /dev/null +++ b/editeng/source/misc/unolingu.cxx @@ -0,0 +1,1377 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unolingu.cxx,v $ + * $Revision: 1.39 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <map> +#include <set> +#include <vector> +#include <slist> +#include <memory> +#include <editeng/unolingu.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <rtl/logfile.hxx> +#include <unotools/pathoptions.hxx> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/linguistic2/XAvailableLocales.hpp> +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp> +#include <com/sun/star/ucb/NumberedSortingInfo.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <com/sun/star/sdbc/XResultSet.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/util/DateTime.hpp> + +#include <comphelper/processfactory.hxx> +#include <cppuhelper/implbase1.hxx> // helper for implementations +#include <i18npool/mslangid.hxx> +#include <unotools/lingucfg.hxx> +#include <unotools/ucbhelper.hxx> +#include <unotools/localfilehelper.hxx> +#include <ucbhelper/commandenvironment.hxx> +#include <ucbhelper/content.hxx> +#include <comphelper/processfactory.hxx> +#include <vcl/msgbox.hxx> +#include <tools/shl.hxx> +#include <linguistic/misc.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/editrids.hrc> + +using namespace ::rtl; +using namespace ::comphelper; +using namespace ::linguistic; +using namespace ::com::sun::star; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::linguistic2; + +#define CSS com::sun::star + +/////////////////////////////////////////////////////////////////////////// + + +static uno::Reference< XLinguServiceManager > GetLngSvcMgr_Impl() +{ + uno::Reference< XLinguServiceManager > xRes; + uno::Reference< XMultiServiceFactory > xMgr = getProcessServiceFactory(); + if (xMgr.is()) + { + xRes = uno::Reference< XLinguServiceManager > ( xMgr->createInstance( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.linguistic2.LinguServiceManager" ) ) ), UNO_QUERY ) ; + } + return xRes; +} + +/////////////////////////////////////////////////////////////////////////// + +BOOL lcl_FindEntry( const OUString &rEntry, const Sequence< OUString > &rCfgSvcs ) +{ + INT32 nRes = -1; + INT32 nEntries = rCfgSvcs.getLength(); + const OUString *pEntry = rCfgSvcs.getConstArray(); + for (INT32 i = 0; i < nEntries && nRes == -1; ++i) + { + if (rEntry == pEntry[i]) + nRes = i; + } + return nRes != -1; +} + + +Sequence< OUString > lcl_RemoveMissingEntries( + const Sequence< OUString > &rCfgSvcs, + const Sequence< OUString > &rAvailSvcs ) +{ + Sequence< OUString > aRes( rCfgSvcs.getLength() ); + OUString *pRes = aRes.getArray(); + INT32 nCnt = 0; + + INT32 nEntries = rCfgSvcs.getLength(); + const OUString *pEntry = rCfgSvcs.getConstArray(); + for (INT32 i = 0; i < nEntries; ++i) + { + if (pEntry[i].getLength() && lcl_FindEntry( pEntry[i], rAvailSvcs )) + pRes[ nCnt++ ] = pEntry[i]; + } + + aRes.realloc( nCnt ); + return aRes; +} + + +Sequence< OUString > lcl_GetLastFoundSvcs( + SvtLinguConfig &rCfg, + const OUString &rLastFoundList , + const Locale &rAvailLocale ) +{ + Sequence< OUString > aRes; + + OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString( + SvxLocaleToLanguage( rAvailLocale ) ) ); + + Sequence< OUString > aNodeNames( rCfg.GetNodeNames(rLastFoundList) ); + BOOL bFound = lcl_FindEntry( aCfgLocaleStr, aNodeNames); + + if (bFound) + { + Sequence< OUString > aNames(1); + OUString &rNodeName = aNames.getArray()[0]; + rNodeName = rLastFoundList; + rNodeName += OUString::valueOf( (sal_Unicode)'/' ); + rNodeName += aCfgLocaleStr; + Sequence< Any > aValues( rCfg.GetProperties( aNames ) ); +#if OSL_DEBUG_LEVEL > 1 + const Any *pValue; + pValue = aValues.getConstArray(); +#endif + if (aValues.getLength()) + { + DBG_ASSERT( aValues.getLength() == 1, "unexpected length of sequence" ); + Sequence< OUString > aSvcImplNames; + if (aValues.getConstArray()[0] >>= aSvcImplNames) + aRes = aSvcImplNames; + else + { + DBG_ERROR( "type mismatch" ); + } + } + } + + return aRes; +} + + +Sequence< OUString > lcl_GetNewEntries( + const Sequence< OUString > &rLastFoundSvcs, + const Sequence< OUString > &rAvailSvcs ) +{ + INT32 nLen = rAvailSvcs.getLength(); + Sequence< OUString > aRes( nLen ); + OUString *pRes = aRes.getArray(); + INT32 nCnt = 0; + + const OUString *pEntry = rAvailSvcs.getConstArray(); + for (INT32 i = 0; i < nLen; ++i) + { + if (pEntry[i].getLength() && !lcl_FindEntry( pEntry[i], rLastFoundSvcs )) + pRes[ nCnt++ ] = pEntry[i]; + } + + aRes.realloc( nCnt ); + return aRes; +} + + +Sequence< OUString > lcl_MergeSeq( + const Sequence< OUString > &rCfgSvcs, + const Sequence< OUString > &rNewSvcs ) +{ + Sequence< OUString > aRes( rCfgSvcs.getLength() + rNewSvcs.getLength() ); + OUString *pRes = aRes.getArray(); + INT32 nCnt = 0; + + for (INT32 k = 0; k < 2; ++k) + { + // add previously configuerd service first and append + // new found services at the end + const Sequence< OUString > &rSeq = k == 0 ? rCfgSvcs : rNewSvcs; + + INT32 nLen = rSeq.getLength(); + const OUString *pEntry = rSeq.getConstArray(); + for (INT32 i = 0; i < nLen; ++i) + { + if (pEntry[i].getLength() && !lcl_FindEntry( pEntry[i], aRes )) + pRes[ nCnt++ ] = pEntry[i]; + } + } + + aRes.realloc( nCnt ); + return aRes; +} + +/////////////////////////////////////////////////////////////////////////// + +// static member initialization +INT16 SvxLinguConfigUpdate::nNeedUpdating = -1; +INT32 SvxLinguConfigUpdate::nCurrentDataFilesChangedCheckValue = -1; + +void SvxLinguConfigUpdate::UpdateAll( sal_Bool bForceCheck ) +{ + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::UpdateAll" ); + + if (IsNeedUpdateAll( bForceCheck )) + { + typedef OUString OUstring_t; + typedef Sequence< OUString > Sequence_OUString_t; + typedef std::vector< OUstring_t > OUString_vector_t; + typedef std::set< OUstring_t > OUString_set_t; + std::vector< OUString_vector_t > aVector; + typedef std::map< OUstring_t, Sequence_OUString_t > list_entry_map_t; + + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::UpdateAll - updating..." ); + + DBG_ASSERT( nNeedUpdating == 1, "SvxLinguConfigUpdate::UpdateAll already updated!" ); + + uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); + DBG_ASSERT( xLngSvcMgr.is(), "service manager missing"); + if (!xLngSvcMgr.is()) + return; + + SvtLinguConfig aCfg; + + const int nNumServices = 4; + const sal_Char * apServices[nNumServices] = { SN_SPELLCHECKER, SN_GRAMMARCHECKER, SN_HYPHENATOR, SN_THESAURUS }; + const sal_Char * apCurLists[nNumServices] = { "ServiceManager/SpellCheckerList", "ServiceManager/GrammarCheckerList", "ServiceManager/HyphenatorList", "ServiceManager/ThesaurusList" }; + const sal_Char * apLastFoundLists[nNumServices] = { "ServiceManager/LastFoundSpellCheckers", "ServiceManager/LastFoundGrammarCheckers", "ServiceManager/LastFoundHyphenators", "ServiceManager/LastFoundThesauri" }; + + // usage of indices as above: 0 = spell checker, 1 = grammar checker, 2 = hyphenator, 3 = thesaurus + std::vector< list_entry_map_t > aLastFoundSvcs(nNumServices); + std::vector< list_entry_map_t > aCurSvcs(nNumServices); + + for (int k = 0; k < nNumServices; ++k) + { + OUString aService( A2OU( apServices[k] ) ); + OUString aActiveList( A2OU( apCurLists[k] ) ); + OUString aLastFoundList( A2OU( apLastFoundLists[k] ) ); + INT32 i; + + // + // remove configured but not available language/services entries + // + Sequence< OUString > aNodeNames( aCfg.GetNodeNames( aActiveList ) ); // list of configured locales + INT32 nNodeNames = aNodeNames.getLength(); + const OUString *pNodeName = aNodeNames.getConstArray(); + for (i = 0; i < nNodeNames; ++i) + { + Locale aLocale( SvxCreateLocale( MsLangId::convertIsoStringToLanguage(pNodeName[i]) ) ); + Sequence< OUString > aCfgSvcs( + xLngSvcMgr->getConfiguredServices( aService, aLocale )); + Sequence< OUString > aAvailSvcs( + xLngSvcMgr->getAvailableServices( aService, aLocale )); +#if OSL_DEBUG_LEVEL > 1 + const OUString * pCfgSvcs = aCfgSvcs.getConstArray();; + const OUString * pAvailSvcs = aAvailSvcs.getConstArray();; + (void) pCfgSvcs; + (void) pAvailSvcs; +#endif + aCfgSvcs = lcl_RemoveMissingEntries( aCfgSvcs, aAvailSvcs ); + + aCurSvcs[k][ pNodeName[i] ] = aCfgSvcs; + } + + // + // add new available language/servcice entries + // + uno::Reference< XAvailableLocales > xAvail( xLngSvcMgr, UNO_QUERY ); + Sequence< Locale > aAvailLocales( xAvail->getAvailableLocales(aService) ); + INT32 nAvailLocales = aAvailLocales.getLength(); + const Locale *pAvailLocale = aAvailLocales.getConstArray(); + for (i = 0; i < nAvailLocales; ++i) + { + Sequence< OUString > aAvailSvcs( + xLngSvcMgr->getAvailableServices( aService, pAvailLocale[i] )); + Sequence< OUString > aLastSvcs( + lcl_GetLastFoundSvcs( aCfg, aLastFoundList , pAvailLocale[i] )); + Sequence< OUString > aNewSvcs = + lcl_GetNewEntries( aLastSvcs, aAvailSvcs ); +#if OSL_DEBUG_LEVEL > 1 + const OUString * pAvailSvcs = aAvailSvcs.getConstArray(); + const OUString * pLastSvcs = aLastSvcs.getConstArray(); + const OUString * pNewSvcs = aNewSvcs.getConstArray(); + (void) pAvailSvcs; + (void) pLastSvcs; + (void) pNewSvcs; +#endif + + OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString( + SvxLocaleToLanguage( pAvailLocale[i] ) ) ); + Sequence< OUString > aCfgSvcs( aCurSvcs[k][ aCfgLocaleStr ] ); + + // merge services list (previously configured to be listed first). + aCfgSvcs = lcl_MergeSeq( aCfgSvcs, aNewSvcs ); + +/* + // there is at most one Hyphenator per language allowed + // to be configured, thus we only use the first one found. + if (k == 2 && aCfgSvcs.getLength() > 1) + aCfgSvcs.realloc(1); +*/ + aCurSvcs[k][ aCfgLocaleStr ] = aCfgSvcs; + } + + // + // set last found services to currently available ones + // + for (i = 0; i < nAvailLocales; ++i) + { + Sequence< OUString > aSvcImplNames( + xLngSvcMgr->getAvailableServices( aService, pAvailLocale[i] ) ); + +#if OSL_DEBUG_LEVEL > 1 + INT32 nSvcs = aSvcImplNames.getLength(); + const OUString *pSvcImplName = aSvcImplNames.getConstArray(); + for (INT32 j = 0; j < nSvcs; ++j) + { + OUString aImplName( pSvcImplName[j] ); + } +#endif + + OUString aCfgLocaleStr( MsLangId::convertLanguageToIsoString( + SvxLocaleToLanguage( pAvailLocale[i] ) ) ); + aLastFoundSvcs[k][ aCfgLocaleStr ] = aSvcImplNames; + } + } + + // + // write new data back to configuration + // + for (int k = 0; k < nNumServices; ++k) + { + for (int i = 0; i < 2; ++i) + { + const sal_Char *pSubNodeName = (i == 0) ? apCurLists[k] : apLastFoundLists[k]; + OUString aSubNodeName( A2OU(pSubNodeName) ); + + list_entry_map_t &rCurMap = (i == 0) ? aCurSvcs[k] : aLastFoundSvcs[k]; + list_entry_map_t::const_iterator aIt( rCurMap.begin() ); + sal_Int32 nVals = static_cast< sal_Int32 >( rCurMap.size() ); + Sequence< PropertyValue > aNewValues( nVals ); + PropertyValue *pNewValue = aNewValues.getArray(); + while (aIt != rCurMap.end()) + { + OUString aCfgEntryName( aSubNodeName ); + aCfgEntryName += OUString::valueOf( (sal_Unicode) '/' ); + aCfgEntryName += (*aIt).first; + +#if OSL_DEBUG_LEVEL > 1 + Sequence< OUString > aSvcImplNames( (*aIt).second ); + INT32 nSvcs = aSvcImplNames.getLength(); + const OUString *pSvcImplName = aSvcImplNames.getConstArray(); + for (INT32 j = 0; j < nSvcs; ++j) + { + OUString aImplName( pSvcImplName[j] ); + } +#endif + pNewValue->Name = aCfgEntryName; + pNewValue->Value <<= (*aIt).second; + ++pNewValue; + ++aIt; + } + DBG_ASSERT( pNewValue - aNewValues.getArray() == nVals, + "possible mismatch of sequence size and property number" ); + + { + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::UpdateAll - ReplaceSetProperties" ); + // add new or replace existing entries. + BOOL bRes = aCfg.ReplaceSetProperties( aSubNodeName, aNewValues ); + if (!bRes) + { +#if OSL_DEBUG_LEVEL > 1 + DBG_ERROR( "failed to set new configuration values" ); +#endif + } + } + } + } + DBG_ASSERT( nCurrentDataFilesChangedCheckValue != -1, "SvxLinguConfigUpdate::UpdateAll DataFilesChangedCheckValue not yet calculated!" ); + Any aAny; + + // for the time being (developer builds until OOo 3.0) + // we should always check for everything available + // otherwise we may miss a new installed extension dicitonary + // just because e.g. the spellchecker is not asked what + // languages it does support currently... + // Since the check is on-demand occuring and executed once it should + // not be too troublesome. + // In OOo 3.0 we will not need the respective code anymore at all. +// aAny <<= nCurrentDataFilesChangedCheckValue; + aAny <<= (INT32) -1; // keep the value set to 'need to check' + + aCfg.SetProperty( A2OU( "DataFilesChangedCheckValue" ), aAny ); + + //! Note 1: the new values are commited when the 'aCfg' object + //! gets destroyed. + //! Note 2: the new settings in the configuration get applied + //! because the 'LngSvcMgr' (in linguistic/source/lngsvcmgr.hxx) + //! listens to the configuration for changes of the relevant + //! properties and then applies the new settings. + + // nothing needs to be done anymore + nNeedUpdating = 0; + } +} + + +INT32 SvxLinguConfigUpdate::CalcDataFilesChangedCheckValue() +{ + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::CalcDataFilesChangedCheckValue" ); + + INT32 nHashVal = 0; + // nothing to be checked anymore since those old directory paths are gone by now + return nHashVal; +} + + +BOOL SvxLinguConfigUpdate::IsNeedUpdateAll( sal_Bool bForceCheck ) +{ + RTL_LOGFILE_CONTEXT( aLog, "svx: SvxLinguConfigUpdate::IsNeedUpdateAll" ); + if (nNeedUpdating == -1 || bForceCheck ) // need to check if updating is necessary + { + // calculate hash value for current data files + nCurrentDataFilesChangedCheckValue = CalcDataFilesChangedCheckValue(); + + // compare hash value and check value to see if anything has changed + // and thus the configuration needs to be updated + SvtLinguOptions aLinguOpt; + SvtLinguConfig aCfg; + aCfg.GetOptions( aLinguOpt ); + nNeedUpdating = (nCurrentDataFilesChangedCheckValue == aLinguOpt.nDataFilesChangedCheckValue) ? 0 : 1; + } + DBG_ASSERT( nNeedUpdating != -1, + "need for linguistic configuration update should have been already checked." ); + + return nNeedUpdating == 1; +} + +/////////////////////////////////////////////////////////////////////////// + + +//! Dummy implementation in order to avoid loading of lingu DLL +//! when only the XSupportedLocales interface is used. +//! The dummy accesses the real implementation (and thus loading the DLL) +//! when "real" work needs to be done only. +class ThesDummy_Impl : + public cppu::WeakImplHelper1< XThesaurus > +{ + uno::Reference< XThesaurus > xThes; // the real one... + Sequence< Locale > *pLocaleSeq; + + void GetCfgLocales(); + + void GetThes_Impl(); + +public: + ThesDummy_Impl() : pLocaleSeq(0) {} + ~ThesDummy_Impl(); + + // XSupportedLocales + virtual ::com::sun::star::uno::Sequence< + ::com::sun::star::lang::Locale > SAL_CALL + getLocales() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL + hasLocale( const ::com::sun::star::lang::Locale& rLocale ) + throw(::com::sun::star::uno::RuntimeException); + + // XThesaurus + virtual ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XMeaning > > SAL_CALL + queryMeanings( const ::rtl::OUString& rTerm, + const ::com::sun::star::lang::Locale& rLocale, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); +}; + + +ThesDummy_Impl::~ThesDummy_Impl() +{ + delete pLocaleSeq; +} + + +void ThesDummy_Impl::GetCfgLocales() +{ + if (!pLocaleSeq) + { + SvtLinguConfig aCfg; + String aNode( A2OU( "ServiceManager/ThesaurusList" ) ); + Sequence < OUString > aNodeNames( aCfg.GetNodeNames( aNode ) ); + const OUString *pNodeNames = aNodeNames.getConstArray(); + INT32 nLen = aNodeNames.getLength(); + pLocaleSeq = new Sequence< Locale >( nLen ); + Locale *pLocale = pLocaleSeq->getArray(); + for (INT32 i = 0; i < nLen; ++i) + { + pLocale[i] = SvxCreateLocale( + MsLangId::convertIsoStringToLanguage( pNodeNames[i] ) ); + } + } +} + + +void ThesDummy_Impl::GetThes_Impl() +{ + // update configuration before accessing the service + if (SvxLinguConfigUpdate::IsNeedUpdateAll()) + SvxLinguConfigUpdate::UpdateAll(); + + if (!xThes.is()) + { + uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); + if (xLngSvcMgr.is()) + xThes = xLngSvcMgr->getThesaurus(); + + if (xThes.is()) + { + // no longer needed... + delete pLocaleSeq; pLocaleSeq = 0; + } + } +} + + +uno::Sequence< lang::Locale > SAL_CALL + ThesDummy_Impl::getLocales() + throw(uno::RuntimeException) +{ + if (!SvxLinguConfigUpdate::IsNeedUpdateAll()) // configuration already update and thus lingu DLL's already loaded ? + GetThes_Impl(); + if (xThes.is()) + return xThes->getLocales(); + else if (!pLocaleSeq) // if not already loaded save startup time by avoiding loading them now + GetCfgLocales(); + return *pLocaleSeq; +} + + +sal_Bool SAL_CALL + ThesDummy_Impl::hasLocale( const lang::Locale& rLocale ) + throw(uno::RuntimeException) +{ + if (!SvxLinguConfigUpdate::IsNeedUpdateAll()) // configuration already update and thus lingu DLL's already loaded ? + GetThes_Impl(); + if (xThes.is()) + return xThes->hasLocale( rLocale ); + else if (!pLocaleSeq) // if not already loaded save startup time by avoiding loading them now + GetCfgLocales(); + GetCfgLocales(); + BOOL bFound = FALSE; + INT32 nLen = pLocaleSeq->getLength(); + const Locale *pLocale = pLocaleSeq->getConstArray(); + const Locale *pEnd = pLocale + nLen; + for ( ; pLocale < pEnd && !bFound; ++pLocale) + { + bFound = pLocale->Language == rLocale.Language && + pLocale->Country == rLocale.Country && + pLocale->Variant == rLocale.Variant; + } + return bFound; +} + + +uno::Sequence< uno::Reference< linguistic2::XMeaning > > SAL_CALL + ThesDummy_Impl::queryMeanings( + const rtl::OUString& rTerm, + const lang::Locale& rLocale, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetThes_Impl(); + uno::Sequence< uno::Reference< linguistic2::XMeaning > > aRes; + DBG_ASSERT( xThes.is(), "Thesaurus missing" ); + if (xThes.is()) + aRes = xThes->queryMeanings( rTerm, rLocale, rProperties ); + return aRes; +} + + +/////////////////////////////////////////////////////////////////////////// + + +//! Dummy implementation in order to avoid loading of lingu DLL. +//! The dummy accesses the real implementation (and thus loading the DLL) +//! when it needs to be done only. +class SpellDummy_Impl : + public cppu::WeakImplHelper1< XSpellChecker1 > +{ + uno::Reference< XSpellChecker1 > xSpell; // the real one... + + void GetSpell_Impl(); + +public: + + // XSupportedLanguages (for XSpellChecker1) + virtual ::com::sun::star::uno::Sequence< sal_Int16 > SAL_CALL + getLanguages() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL + hasLanguage( sal_Int16 nLanguage ) + throw(::com::sun::star::uno::RuntimeException); + + // XSpellChecker1 (same as XSpellChecker but sal_Int16 for language) + virtual sal_Bool SAL_CALL + isValid( const ::rtl::OUString& rWord, sal_Int16 nLanguage, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XSpellAlternatives > SAL_CALL + spell( const ::rtl::OUString& rWord, sal_Int16 nLanguage, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); +}; + + +void SpellDummy_Impl::GetSpell_Impl() +{ + // update configuration before accessing the service + if (SvxLinguConfigUpdate::IsNeedUpdateAll()) + SvxLinguConfigUpdate::UpdateAll(); + + if (!xSpell.is()) + { + uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); + if (xLngSvcMgr.is()) + xSpell = uno::Reference< XSpellChecker1 >( xLngSvcMgr->getSpellChecker(), UNO_QUERY ); + } +} + + +uno::Sequence< sal_Int16 > SAL_CALL + SpellDummy_Impl::getLanguages() + throw(uno::RuntimeException) +{ + GetSpell_Impl(); + if (xSpell.is()) + return xSpell->getLanguages(); + else + return uno::Sequence< sal_Int16 >(); +} + + +sal_Bool SAL_CALL + SpellDummy_Impl::hasLanguage( sal_Int16 nLanguage ) + throw(uno::RuntimeException) +{ + GetSpell_Impl(); + BOOL bRes = FALSE; + if (xSpell.is()) + bRes = xSpell->hasLanguage( nLanguage ); + return bRes; +} + + +sal_Bool SAL_CALL + SpellDummy_Impl::isValid( const rtl::OUString& rWord, sal_Int16 nLanguage, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetSpell_Impl(); + BOOL bRes = TRUE; + if (xSpell.is()) + bRes = xSpell->isValid( rWord, nLanguage, rProperties ); + return bRes; +} + + +uno::Reference< linguistic2::XSpellAlternatives > SAL_CALL + SpellDummy_Impl::spell( const rtl::OUString& rWord, sal_Int16 nLanguage, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetSpell_Impl(); + uno::Reference< linguistic2::XSpellAlternatives > xRes; + if (xSpell.is()) + xRes = xSpell->spell( rWord, nLanguage, rProperties ); + return xRes; +} + + +/////////////////////////////////////////////////////////////////////////// + + +//! Dummy implementation in order to avoid loading of lingu DLL. +//! The dummy accesses the real implementation (and thus loading the DLL) +//! when it needs to be done only. +class HyphDummy_Impl : + public cppu::WeakImplHelper1< XHyphenator > +{ + uno::Reference< XHyphenator > xHyph; // the real one... + + void GetHyph_Impl(); + +public: + + // XSupportedLocales + virtual ::com::sun::star::uno::Sequence< + ::com::sun::star::lang::Locale > SAL_CALL + getLocales() + throw(::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL + hasLocale( const ::com::sun::star::lang::Locale& rLocale ) + throw(::com::sun::star::uno::RuntimeException); + + // XHyphenator + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenatedWord > SAL_CALL + hyphenate( const ::rtl::OUString& rWord, + const ::com::sun::star::lang::Locale& rLocale, + sal_Int16 nMaxLeading, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenatedWord > SAL_CALL + queryAlternativeSpelling( const ::rtl::OUString& rWord, + const ::com::sun::star::lang::Locale& rLocale, + sal_Int16 nIndex, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XPossibleHyphens > SAL_CALL + createPossibleHyphens( + const ::rtl::OUString& rWord, + const ::com::sun::star::lang::Locale& rLocale, + const ::com::sun::star::beans::PropertyValues& rProperties ) + throw(::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); +}; + + +void HyphDummy_Impl::GetHyph_Impl() +{ + // update configuration before accessing the service + if (SvxLinguConfigUpdate::IsNeedUpdateAll()) + SvxLinguConfigUpdate::UpdateAll(); + + if (!xHyph.is()) + { + uno::Reference< XLinguServiceManager > xLngSvcMgr( GetLngSvcMgr_Impl() ); + if (xLngSvcMgr.is()) + xHyph = xLngSvcMgr->getHyphenator(); + } +} + + +uno::Sequence< lang::Locale > SAL_CALL + HyphDummy_Impl::getLocales() + throw(uno::RuntimeException) +{ + GetHyph_Impl(); + if (xHyph.is()) + return xHyph->getLocales(); + else + return uno::Sequence< lang::Locale >(); +} + + +sal_Bool SAL_CALL + HyphDummy_Impl::hasLocale( const lang::Locale& rLocale ) + throw(uno::RuntimeException) +{ + GetHyph_Impl(); + BOOL bRes = FALSE; + if (xHyph.is()) + bRes = xHyph->hasLocale( rLocale ); + return bRes; +} + + +uno::Reference< linguistic2::XHyphenatedWord > SAL_CALL + HyphDummy_Impl::hyphenate( + const rtl::OUString& rWord, + const lang::Locale& rLocale, + sal_Int16 nMaxLeading, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetHyph_Impl(); + uno::Reference< linguistic2::XHyphenatedWord > xRes; + if (xHyph.is()) + xRes = xHyph->hyphenate( rWord, rLocale, nMaxLeading, rProperties ); + return xRes; +} + + +uno::Reference< linguistic2::XHyphenatedWord > SAL_CALL + HyphDummy_Impl::queryAlternativeSpelling( + const rtl::OUString& rWord, + const lang::Locale& rLocale, + sal_Int16 nIndex, + const PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetHyph_Impl(); + uno::Reference< linguistic2::XHyphenatedWord > xRes; + if (xHyph.is()) + xRes = xHyph->queryAlternativeSpelling( rWord, rLocale, nIndex, rProperties ); + return xRes; +} + + +uno::Reference< linguistic2::XPossibleHyphens > SAL_CALL + HyphDummy_Impl::createPossibleHyphens( + const rtl::OUString& rWord, + const lang::Locale& rLocale, + const beans::PropertyValues& rProperties ) + throw(lang::IllegalArgumentException, + uno::RuntimeException) +{ + GetHyph_Impl(); + uno::Reference< linguistic2::XPossibleHyphens > xRes; + if (xHyph.is()) + xRes = xHyph->createPossibleHyphens( rWord, rLocale, rProperties ); + return xRes; +} + + +/////////////////////////////////////////////////////////////////////////// + + +typedef cppu::WeakImplHelper1 < XEventListener > LinguMgrAppExitLstnrBaseClass; + +class LinguMgrAppExitLstnr : public LinguMgrAppExitLstnrBaseClass +{ + uno::Reference< XComponent > xDesktop; + +public: + LinguMgrAppExitLstnr(); + virtual ~LinguMgrAppExitLstnr(); + + virtual void AtExit() = 0; + + + // lang::XEventListener + virtual void SAL_CALL disposing(const EventObject& rSource) + throw( RuntimeException ); +}; + +LinguMgrAppExitLstnr::LinguMgrAppExitLstnr() +{ + // add object to frame::Desktop EventListeners in order to properly call + // the AtExit function at appliction exit. + + uno::Reference< XMultiServiceFactory > xMgr = getProcessServiceFactory(); + if ( xMgr.is() ) + { + xDesktop = uno::Reference< XComponent > ( xMgr->createInstance( + OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.frame.Desktop" ) ) ), UNO_QUERY ) ; + if (xDesktop.is()) + xDesktop->addEventListener( this ); + } +} + +LinguMgrAppExitLstnr::~LinguMgrAppExitLstnr() +{ + if (xDesktop.is()) + { + xDesktop->removeEventListener( this ); + xDesktop = NULL; //! release reference to desktop + } + DBG_ASSERT(!xDesktop.is(), "reference to desktop should be realeased"); +} + +void LinguMgrAppExitLstnr::disposing(const EventObject& rSource) + throw( RuntimeException ) +{ + if (xDesktop.is() && rSource.Source == xDesktop) + { + xDesktop->removeEventListener( this ); + xDesktop = NULL; //! release reference to desktop + + AtExit(); + } +} + +/////////////////////////////////////////////////////////////////////////// + +class LinguMgrExitLstnr : public LinguMgrAppExitLstnr +{ +public: + virtual void AtExit(); +}; + +void LinguMgrExitLstnr::AtExit() +{ + // release references + LinguMgr::xLngSvcMgr = 0; + LinguMgr::xSpell = 0; + LinguMgr::xHyph = 0; + LinguMgr::xThes = 0; + LinguMgr::xDicList = 0; + LinguMgr::xProp = 0; + LinguMgr::xIgnoreAll = 0; + LinguMgr::xChangeAll = 0; + + LinguMgr::bExiting = sal_True; + + //TL:TODO: MBA fragen wie ich ohne Absturz hier meinen Speicher + // wieder freibekomme... + //delete LinguMgr::pExitLstnr; + LinguMgr::pExitLstnr = 0; +} + +/////////////////////////////////////////////////////////////////////////// + + +// static member initialization +LinguMgrExitLstnr * LinguMgr::pExitLstnr = 0; +sal_Bool LinguMgr::bExiting = sal_False; +uno::Reference< XLinguServiceManager > LinguMgr::xLngSvcMgr = 0; +uno::Reference< XSpellChecker1 > LinguMgr::xSpell = 0; +uno::Reference< XHyphenator > LinguMgr::xHyph = 0; +uno::Reference< XThesaurus > LinguMgr::xThes = 0; +uno::Reference< XDictionaryList > LinguMgr::xDicList = 0; +uno::Reference< XPropertySet > LinguMgr::xProp = 0; +uno::Reference< XDictionary > LinguMgr::xIgnoreAll = 0; +uno::Reference< XDictionary > LinguMgr::xChangeAll = 0; + + +uno::Reference< XLinguServiceManager > LinguMgr::GetLngSvcMgr() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + if (!xLngSvcMgr.is()) + xLngSvcMgr = GetLngSvcMgr_Impl(); + + return xLngSvcMgr; +} + + +uno::Reference< XSpellChecker1 > LinguMgr::GetSpellChecker() +{ + return xSpell.is() ? xSpell : GetSpell(); +} + +uno::Reference< XHyphenator > LinguMgr::GetHyphenator() +{ + return xHyph.is() ? xHyph : GetHyph(); +} + +uno::Reference< XThesaurus > LinguMgr::GetThesaurus() +{ + return xThes.is() ? xThes : GetThes(); +} + +uno::Reference< XDictionaryList > LinguMgr::GetDictionaryList() +{ + return xDicList.is() ? xDicList : GetDicList(); +} + +uno::Reference< XPropertySet > LinguMgr::GetLinguPropertySet() +{ + return xProp.is() ? xProp : GetProp(); +} + +uno::Reference< XDictionary > LinguMgr::GetStandardDic() +{ + //! don't hold reference to this + //! (it may be removed from dictionary list and needs to be + //! created empty if accessed again) + return GetStandard(); +} + +uno::Reference< XDictionary > LinguMgr::GetIgnoreAllList() +{ + return xIgnoreAll.is() ? xIgnoreAll : GetIgnoreAll(); +} + +uno::Reference< XDictionary > LinguMgr::GetChangeAllList() +{ + return xChangeAll.is() ? xChangeAll : GetChangeAll(); +} + +uno::Reference< XSpellChecker1 > LinguMgr::GetSpell() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + //! use dummy implementation in order to avoid loading of lingu DLL + xSpell = new SpellDummy_Impl; + +/* if (!xLngSvcMgr.is()) + xLngSvcMgr = GetLngSvcMgr_Impl(); + + if (xLngSvcMgr.is()) + { + xSpell = uno::Reference< XSpellChecker1 > ( + xLngSvcMgr->getSpellChecker(), UNO_QUERY ); + } +*/ + return xSpell; +} + +uno::Reference< XHyphenator > LinguMgr::GetHyph() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + //! use dummy implementation in order to avoid loading of lingu DLL + xHyph = new HyphDummy_Impl; + +/* + if (!xLngSvcMgr.is()) + xLngSvcMgr = GetLngSvcMgr_Impl(); + + if (xLngSvcMgr.is()) + { + xHyph = xLngSvcMgr->getHyphenator(); + } +*/ + return xHyph; +} + +uno::Reference< XThesaurus > LinguMgr::GetThes() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + //! use dummy implementation in order to avoid loading of lingu DLL + //! when only the XSupportedLocales interface is used. + //! The dummy accesses the real implementation (and thus loading the DLL) + //! when "real" work needs to be done only. + xThes = new ThesDummy_Impl; +/* + if (!xLngSvcMgr.is()) + xLngSvcMgr = GetLngSvcMgr_Impl(); + + if (xLngSvcMgr.is()) + { + xThes = xLngSvcMgr->getThesaurus(); + } +*/ + return xThes; +} + + +void LinguMgr::UpdateAll() +{ +} + + +uno::Reference< XDictionaryList > LinguMgr::GetDicList() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + uno::Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); + if (xMgr.is()) + { + xDicList = uno::Reference< XDictionaryList > ( xMgr->createInstance( + A2OU("com.sun.star.linguistic2.DictionaryList") ), UNO_QUERY ); + } + return xDicList; +} + +uno::Reference< XPropertySet > LinguMgr::GetProp() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + uno::Reference< XMultiServiceFactory > xMgr( getProcessServiceFactory() ); + if (xMgr.is()) + { + xProp = uno::Reference< XPropertySet > ( xMgr->createInstance( + A2OU("com.sun.star.linguistic2.LinguProperties") ), UNO_QUERY ); + } + return xProp; +} + +uno::Reference< XDictionary > LinguMgr::GetIgnoreAll() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + uno::Reference< XDictionaryList > xTmpDicList( GetDictionaryList() ); + if (xTmpDicList.is()) + { + xIgnoreAll = uno::Reference< XDictionary > ( xTmpDicList->getDictionaryByName( + A2OU("IgnoreAllList") ), UNO_QUERY ); + } + return xIgnoreAll; +} + +uno::Reference< XDictionary > LinguMgr::GetChangeAll() +{ + if (bExiting) + return 0; + + if (!pExitLstnr) + pExitLstnr = new LinguMgrExitLstnr; + + uno::Reference< XDictionaryList > _xDicList( GetDictionaryList() , UNO_QUERY ); + if (_xDicList.is()) + { + xChangeAll = uno::Reference< XDictionary > ( + _xDicList->createDictionary( + A2OU("ChangeAllList"), + SvxCreateLocale( LANGUAGE_NONE ), + DictionaryType_NEGATIVE, String() ), UNO_QUERY ); + } + return xChangeAll; +} + +uno::Reference< XDictionary > LinguMgr::GetStandard() +{ + // Tries to return a dictionary which may hold positive entries is + // persistent and not read-only. + + if (bExiting) + return 0; + + uno::Reference< XDictionaryList > xTmpDicList( GetDictionaryList() ); + if (!xTmpDicList.is()) + return NULL; + + const OUString aDicName( RTL_CONSTASCII_USTRINGPARAM( "standard.dic" ) ); + uno::Reference< XDictionary > xDic( xTmpDicList->getDictionaryByName( aDicName ), + UNO_QUERY ); + if (!xDic.is()) + { + // try to create standard dictionary + uno::Reference< XDictionary > xTmp; + try + { + xTmp = xTmpDicList->createDictionary( aDicName, + SvxCreateLocale( LANGUAGE_NONE ), + DictionaryType_POSITIVE, + linguistic::GetWritableDictionaryURL( aDicName ) ); + } + catch(com::sun::star::uno::Exception &) + { + } + + // add new dictionary to list + if (xTmp.is()) + xTmpDicList->addDictionary( xTmp ); + xDic = uno::Reference< XDictionary > ( xTmp, UNO_QUERY ); + } +#if OSL_DEBUG_LEVEL > 1 + uno::Reference< XStorable > xStor( xDic, UNO_QUERY ); + DBG_ASSERT( xDic.is() && xDic->getDictionaryType() == DictionaryType_POSITIVE, + "wrong dictionary type"); + DBG_ASSERT( xDic.is() && SvxLocaleToLanguage( xDic->getLocale() ) == LANGUAGE_NONE, + "wrong dictionary language"); + DBG_ASSERT( !xStor.is() || (xStor->hasLocation() && !xStor->isReadonly()), + "dictionary not editable" ); +#endif + + return xDic; +} + +/////////////////////////////////////////////////////////////////////////// + +uno::Reference< XSpellChecker1 > SvxGetSpellChecker() +{ + return LinguMgr::GetSpellChecker(); +} + +uno::Reference< XHyphenator > SvxGetHyphenator() +{ + return LinguMgr::GetHyphenator(); +} + +uno::Reference< XThesaurus > SvxGetThesaurus() +{ + return LinguMgr::GetThesaurus(); +} + +uno::Reference< XDictionaryList > SvxGetDictionaryList() +{ + return LinguMgr::GetDictionaryList(); +} + +uno::Reference< XPropertySet > SvxGetLinguPropertySet() +{ + return LinguMgr::GetLinguPropertySet(); +} + +//TL:TODO: remove argument or provide SvxGetIgnoreAllList with the same one +uno::Reference< XDictionary > SvxGetOrCreatePosDic( + uno::Reference< XDictionaryList > /* xDicList */ ) +{ + return LinguMgr::GetStandardDic(); +} + +uno::Reference< XDictionary > SvxGetIgnoreAllList() +{ + return LinguMgr::GetIgnoreAllList(); +} + +uno::Reference< XDictionary > SvxGetChangeAllList() +{ + return LinguMgr::GetChangeAllList(); +} + +/////////////////////////////////////////////////////////////////////////// + + +#include <com/sun/star/linguistic2/XHyphenatedWord.hpp> + +SvxAlternativeSpelling SvxGetAltSpelling( + const ::com::sun::star::uno::Reference< + ::com::sun::star::linguistic2::XHyphenatedWord > & rHyphWord ) +{ + SvxAlternativeSpelling aRes; + if (rHyphWord.is() && rHyphWord->isAlternativeSpelling()) + { + OUString aWord( rHyphWord->getWord() ), + aAltWord( rHyphWord->getHyphenatedWord() ); + INT16 nHyphenationPos = rHyphWord->getHyphenationPos(), + nHyphenPos = rHyphWord->getHyphenPos(); + INT16 nLen = (INT16)aWord.getLength(); + INT16 nAltLen = (INT16)aAltWord.getLength(); + const sal_Unicode *pWord = aWord.getStr(), + *pAltWord = aAltWord.getStr(); + + // count number of chars from the left to the + // hyphenation pos / hyphen pos that are equal + INT16 nL = 0; + while (nL <= nHyphenationPos && nL <= nHyphenPos + && pWord[ nL ] == pAltWord[ nL ]) + ++nL; + // count number of chars from the right to the + // hyphenation pos / hyphen pos that are equal + INT16 nR = 0; + INT32 nIdx = nLen - 1; + INT32 nAltIdx = nAltLen - 1; + while (nIdx > nHyphenationPos && nAltIdx > nHyphenPos + && pWord[ nIdx-- ] == pAltWord[ nAltIdx-- ]) + ++nR; + + aRes.aReplacement = OUString( aAltWord.copy( nL, nAltLen - nL - nR ) ); + aRes.nChangedPos = (INT16) nL; + aRes.nChangedLength = nLen - nL - nR; + aRes.bIsAltSpelling = TRUE; + aRes.xHyphWord = rHyphWord; + } + return aRes; +} + + +/////////////////////////////////////////////////////////////////////////// + +SvxDicListChgClamp::SvxDicListChgClamp( uno::Reference< XDictionaryList > &rxDicList ) : + xDicList ( rxDicList ) +{ + if (xDicList.is()) + { + xDicList->beginCollectEvents(); + } +} + +SvxDicListChgClamp::~SvxDicListChgClamp() +{ + if (xDicList.is()) + { + xDicList->endCollectEvents(); + } +} + +/////////////////////////////////////////////////////////////////////////// + +short SvxDicError( Window *pParent, sal_Int16 nError ) +{ + short nRes = 0; + if (DIC_ERR_NONE != nError) + { + int nRid; + switch (nError) + { + case DIC_ERR_FULL : nRid = RID_SVXSTR_DIC_ERR_FULL; break; + case DIC_ERR_READONLY : nRid = RID_SVXSTR_DIC_ERR_READONLY; break; + default: + nRid = RID_SVXSTR_DIC_ERR_UNKNOWN; + DBG_ASSERT(0, "unexpected case"); + } + nRes = InfoBox( pParent, EE_RESSTR( nRid ) ).Execute(); + } + return nRes; +} + +LanguageType SvxLocaleToLanguage( const Locale& rLocale ) +{ + // empty Locale -> LANGUAGE_NONE + if ( rLocale.Language.getLength() == 0 ) + return LANGUAGE_NONE; + + return MsLangId::convertLocaleToLanguage( rLocale ); +} + +Locale& SvxLanguageToLocale( Locale& rLocale, LanguageType eLang ) +{ + if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */) + MsLangId::convertLanguageToLocale( eLang, rLocale ); + else + rLocale = Locale(); + + return rLocale; +} + +Locale SvxCreateLocale( LanguageType eLang ) +{ + Locale aLocale; + if ( eLang != LANGUAGE_NONE /* && eLang != LANGUAGE_SYSTEM */) + MsLangId::convertLanguageToLocale( eLang, aLocale ); + + return aLocale; +} + + diff --git a/editeng/source/outliner/makefile.mk b/editeng/source/outliner/makefile.mk new file mode 100644 index 000000000000..4c7245eeb316 --- /dev/null +++ b/editeng/source/outliner/makefile.mk @@ -0,0 +1,64 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.6 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=editeng +TARGET=outliner +AUTOSEG=true +ENABLE_EXCEPTIONS=TRUE + +PROJECTPCH4DLL=TRUE +PROJECTPCH=outl_pch +PROJECTPCHSOURCE=outl_pch + + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Allgemein ---------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/outlundo.obj \ + $(SLO)$/outliner.obj \ + $(SLO)$/outlin2.obj \ + $(SLO)$/paralist.obj \ + $(SLO)$/outlvw.obj \ + $(SLO)$/outleeng.obj \ + $(SLO)$/outlobj.obj + +SRS1NAME=$(TARGET) +SRC1FILES= outliner.src + +.INCLUDE : target.mk + diff --git a/editeng/source/outliner/outl_pch.cxx b/editeng/source/outliner/outl_pch.cxx new file mode 100644 index 000000000000..5951398e7beb --- /dev/null +++ b/editeng/source/outliner/outl_pch.cxx @@ -0,0 +1,34 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outl_pch.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <outl_pch.hxx> + diff --git a/editeng/source/outliner/outl_pch.hxx b/editeng/source/outliner/outl_pch.hxx new file mode 100644 index 000000000000..e8470c2e4177 --- /dev/null +++ b/editeng/source/outliner/outl_pch.hxx @@ -0,0 +1,36 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outl_pch.hxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <svl/intitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/editdata.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/fhgtitem.hxx> diff --git a/editeng/source/outliner/outleeng.cxx b/editeng/source/outliner/outleeng.cxx new file mode 100644 index 000000000000..7196e694ca6a --- /dev/null +++ b/editeng/source/outliner/outleeng.cxx @@ -0,0 +1,247 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outleeng.cxx,v $ + * $Revision: 1.19 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <svl/intitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/editdata.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/fhgtitem.hxx> + +#define _OUTLINER_CXX +#include <editeng/outliner.hxx> +#include <outleeng.hxx> +#include <paralist.hxx> +#include <editeng/editrids.hrc> +#include <svl/itemset.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/editstat.hxx> +#include "outlundo.hxx" + +OutlinerEditEng::OutlinerEditEng( Outliner* pEngOwner, SfxItemPool* pPool ) + : EditEngine( pPool ) +{ + pOwner = pEngOwner; +} + +OutlinerEditEng::~OutlinerEditEng() +{ +} + +void OutlinerEditEng::PaintingFirstLine( USHORT nPara, const Point& rStartPos, long nBaseLineY, const Point& rOrigin, short nOrientation, OutputDevice* pOutDev ) +{ + if( GetControlWord() && EE_CNTRL_OUTLINER ) + { + PaintFirstLineInfo aInfo( nPara, rStartPos, nBaseLineY, rOrigin, nOrientation, pOutDev ); + pOwner->maPaintFirstLineHdl.Call( &aInfo ); + } + + pOwner->PaintBullet( nPara, rStartPos, rOrigin, nOrientation, pOutDev ); +} + +const SvxNumberFormat* OutlinerEditEng::GetNumberFormat( USHORT nPara ) const +{ + const SvxNumberFormat* pFmt = NULL; + if (pOwner) + pFmt = pOwner->GetNumberFormat( nPara ); + return pFmt; +} + + +Rectangle OutlinerEditEng::GetBulletArea( USHORT nPara ) +{ + Rectangle aBulletArea = Rectangle( Point(), Point() ); + if ( nPara < pOwner->pParaList->GetParagraphCount() ) + { + if ( pOwner->ImplHasBullet( nPara ) ) + aBulletArea = pOwner->ImpCalcBulletArea( nPara, FALSE, FALSE ); + } + return aBulletArea; +} + +void OutlinerEditEng::ParagraphInserted( USHORT nNewParagraph ) +{ + pOwner->ParagraphInserted( nNewParagraph ); + + EditEngine::ParagraphInserted( nNewParagraph ); +} + +void OutlinerEditEng::ParagraphDeleted( USHORT nDeletedParagraph ) +{ + pOwner->ParagraphDeleted( nDeletedParagraph ); + + EditEngine::ParagraphDeleted( nDeletedParagraph ); +} + +void OutlinerEditEng::ParagraphConnected( USHORT /*nLeftParagraph*/, USHORT nRightParagraph ) +{ + if( pOwner && pOwner->IsUndoEnabled() && !const_cast<EditEngine&>(pOwner->GetEditEngine()).IsInUndo() ) + { + Paragraph* pPara = pOwner->GetParagraph( nRightParagraph ); + if( pPara && pOwner->HasParaFlag( pPara, PARAFLAG_ISPAGE ) ) + { + pOwner->InsertUndo( new OutlinerUndoChangeParaFlags( pOwner, nRightParagraph, PARAFLAG_ISPAGE, 0 ) ); + } + } +} + + +void OutlinerEditEng::StyleSheetChanged( SfxStyleSheet* pStyle ) +{ + pOwner->StyleSheetChanged( pStyle ); +} + +void OutlinerEditEng::ParaAttribsChanged( USHORT nPara ) +{ + pOwner->ParaAttribsChanged( nPara ); +} + +BOOL OutlinerEditEng::SpellNextDocument() +{ + return pOwner->SpellNextDocument(); +} + +BOOL OutlinerEditEng::ConvertNextDocument() +{ + return pOwner->ConvertNextDocument(); +} + +XubString OutlinerEditEng::GetUndoComment( USHORT nUndoId ) const +{ + switch( nUndoId ) + { + case OLUNDO_DEPTH: + return XubString( EditResId( RID_OUTLUNDO_DEPTH )); + + case OLUNDO_EXPAND: + return XubString( EditResId( RID_OUTLUNDO_EXPAND )); + + case OLUNDO_COLLAPSE: + return XubString( EditResId( RID_OUTLUNDO_COLLAPSE )); + + case OLUNDO_ATTR: + return XubString( EditResId( RID_OUTLUNDO_ATTR )); + + case OLUNDO_INSERT: + return XubString( EditResId( RID_OUTLUNDO_INSERT )); + + default: + return EditEngine::GetUndoComment( nUndoId ); + } +} + +// #101498# +void OutlinerEditEng::DrawingText( const Point& rStartPos, const XubString& rText, USHORT nTextStart, USHORT nTextLen, + const sal_Int32* pDXArray, const SvxFont& rFont, USHORT nPara, USHORT nIndex, BYTE nRightToLeft, + const EEngineData::WrongSpellVector* pWrongSpellVector, + const SvxFieldData* pFieldData, + bool bEndOfLine, + bool bEndOfParagraph, + bool bEndOfBullet, + const ::com::sun::star::lang::Locale* pLocale, + const Color& rOverlineColor, + const Color& rTextLineColor) +{ + // why do bullet here at all? Just use GetEditEnginePtr()->PaintingFirstLine + // inside of ImpEditEngine::Paint which calls pOwner->PaintBullet with the correct + // values for hor and ver. No change for not-layouting (painting). + // changed, bullet rendering now using PaintBullet via +/* if ( nIndex == 0 ) + { + // Dann das Bullet 'malen', dort wird bStrippingPortions ausgewertet + // und Outliner::DrawingText gerufen + + // DrawingText liefert die BaseLine, DrawBullet braucht Top(). + + if(true) + { + // ## + // another error: This call happens when only stripping, but the position + // is already aligned to text output. For bullet rendering, it needs to be reset + // to the correct value in x and y. PaintBullet takes care of X-start offset itself + const Point aDocPosTopLeft(GetDocPosTopLeft( nPara )); + const Point aCorrectedPos(rStartPos.X() - aDocPosTopLeft.X(), aDocPosTopLeft.Y() + GetFirstLineOffset( nPara )); + pOwner->PaintBullet( nPara, aCorrectedPos, Point(), 0, GetRefDevice() ); + } + else + { + Point aCorrectedPos( rStartPos ); + aCorrectedPos.Y() = GetDocPosTopLeft( nPara ).Y(); + aCorrectedPos.Y() += GetFirstLineOffset( nPara ); + pOwner->PaintBullet( nPara, aCorrectedPos, Point(), 0, GetRefDevice() ); + } + } */ + + // #101498# + pOwner->DrawingText(rStartPos,rText,nTextStart,nTextLen,pDXArray,rFont,nPara,nIndex,nRightToLeft, + pWrongSpellVector, pFieldData, bEndOfLine, bEndOfParagraph, bEndOfBullet, pLocale, rOverlineColor, rTextLineColor); +} + +void OutlinerEditEng::FieldClicked( const SvxFieldItem& rField, USHORT nPara, USHORT nPos ) +{ + EditEngine::FieldClicked( rField, nPara, nPos ); // Falls URL + pOwner->FieldClicked( rField, nPara, nPos ); +} + +void OutlinerEditEng::FieldSelected( const SvxFieldItem& rField, USHORT nPara, USHORT nPos ) +{ + pOwner->FieldSelected( rField, nPara, nPos ); +} + +XubString OutlinerEditEng::CalcFieldValue( const SvxFieldItem& rField, USHORT nPara, USHORT nPos, Color*& rpTxtColor, Color*& rpFldColor ) +{ + return pOwner->CalcFieldValue( rField, nPara, nPos, rpTxtColor, rpFldColor ); +} + +void OutlinerEditEng::SetParaAttribs( USHORT nPara, const SfxItemSet& rSet ) +{ + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + if( pPara ) + { + if ( !IsInUndo() && IsUndoEnabled() ) + pOwner->UndoActionStart( OLUNDO_ATTR ); + + EditEngine::SetParaAttribs( (USHORT)nPara, rSet ); + + pOwner->ImplCheckNumBulletItem( (USHORT)nPara ); + // --> OD 2009-03-10 #i100014# + // It is not a good idea to substract 1 from a count and cast the result + // to USHORT without check, if the count is 0. + pOwner->ImplCheckParagraphs( (USHORT)nPara, (USHORT) (pOwner->pParaList->GetParagraphCount()) ); + // <-- + + if ( !IsInUndo() && IsUndoEnabled() ) + pOwner->UndoActionEnd( OLUNDO_ATTR ); + } +} + diff --git a/editeng/source/outliner/outleeng.hxx b/editeng/source/outliner/outleeng.hxx new file mode 100644 index 000000000000..0f6d5fd59f54 --- /dev/null +++ b/editeng/source/outliner/outleeng.hxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outleeng.hxx,v $ + * $Revision: 1.15 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _OUTLEENG_HXX +#define _OUTLEENG_HXX + +#include <editeng/outliner.hxx> +#ifndef _EDITENG_HXX +#include <editeng/editeng.hxx> +#endif + +typedef EENotify* EENotifyPtr; +SV_DECL_PTRARR_DEL( NotifyList, EENotifyPtr, 1, 1 ) + +class OutlinerEditEng : public EditEngine +{ + Outliner* pOwner; + +protected: + + // derived from EditEngine. Allows Outliner objetcs to provide + // bullet access to the EditEngine. + virtual const SvxNumberFormat* GetNumberFormat( USHORT nPara ) const; + +public: + OutlinerEditEng( Outliner* pOwner, SfxItemPool* pPool ); + ~OutlinerEditEng(); + + virtual void PaintingFirstLine( USHORT nPara, const Point& rStartPos, long nBaseLineY, const Point& rOrigin, short nOrientation, OutputDevice* pOutDev ); + + virtual void ParagraphInserted( USHORT nNewParagraph ); + virtual void ParagraphDeleted( USHORT nDeletedParagraph ); + virtual void ParagraphConnected( USHORT nLeftParagraph, USHORT nRightParagraph ); + + // #101498# + virtual void DrawingText( + const Point& rStartPos, const XubString& rText, USHORT nTextStart, USHORT nTextLen, const sal_Int32* pDXArray, const SvxFont& rFont, + USHORT nPara, USHORT nIndex, BYTE nRightToLeft, + const EEngineData::WrongSpellVector* pWrongSpellVector, + const SvxFieldData* pFieldData, + bool bEndOfLine, + bool bEndOfParagraph, + bool bEndOfBullet, + const ::com::sun::star::lang::Locale* pLocale, + const Color& rOverlineColor, + const Color& rTextLineColor); + + virtual void StyleSheetChanged( SfxStyleSheet* pStyle ); + virtual void ParaAttribsChanged( USHORT nPara ); + virtual BOOL SpellNextDocument(); + virtual XubString GetUndoComment( USHORT nUndoId ) const; + + // for text conversion + virtual BOOL ConvertNextDocument(); + + virtual void FieldClicked( const SvxFieldItem& rField, USHORT nPara, USHORT nPos ); + virtual void FieldSelected( const SvxFieldItem& rField, USHORT nPara, USHORT nPos ); + virtual XubString CalcFieldValue( const SvxFieldItem& rField, USHORT nPara, USHORT nPos, Color*& rTxtColor, Color*& rFldColor ); + + virtual Rectangle GetBulletArea( USHORT nPara ); + + virtual void SetParaAttribs( USHORT nPara, const SfxItemSet& rSet ); + + // belongs into class Outliner, move there before incompatible update! + Link aOutlinerNotifyHdl; + NotifyList aNotifyCache; +}; + +#endif + diff --git a/editeng/source/outliner/outlin2.cxx b/editeng/source/outliner/outlin2.cxx new file mode 100644 index 000000000000..f417e3ea32d0 --- /dev/null +++ b/editeng/source/outliner/outlin2.cxx @@ -0,0 +1,816 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outlin2.cxx,v $ + * $Revision: 1.37 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <svl/intitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/editdata.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <tools/list.hxx> +#include <svl/style.hxx> +#include <vcl/mapmod.hxx> + +#include <editeng/forbiddencharacterstable.hxx> + +#define _OUTLINER_CXX + +#include <editeng/outliner.hxx> +#include <paralist.hxx> +#include <editeng/outlobj.hxx> +#include <outleeng.hxx> +#include <outlundo.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/editstat.hxx> + +DBG_NAMEEX(Outliner) + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; + +// ===================================================================== +// ====================== Einfache Durchreicher ======================= +// ====================================================================== + +void Outliner::SetUpdateMode( BOOL bUpdate ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetUpdateMode( bUpdate ); +} + + +BOOL Outliner::GetUpdateMode() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetUpdateMode(); +} + +const SfxItemSet& Outliner::GetEmptyItemSet() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetEmptyItemSet(); +} + +void Outliner::EnableUndo( BOOL bEnable ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->EnableUndo( bEnable ); +} + +BOOL Outliner::IsUndoEnabled() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsUndoEnabled(); +} + +MapMode Outliner::GetRefMapMode() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetRefMapMode(); +} + +void Outliner::SetRefMapMode( const MapMode& rMMode ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetRefMapMode( rMMode ); +} + +void Outliner::SetBackgroundColor( const Color& rColor ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetBackgroundColor( rColor ); +} + +Color Outliner::GetBackgroundColor() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetBackgroundColor(); +} + + +void Outliner::ClearModifyFlag() +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->ClearModifyFlag(); +} + +BOOL Outliner::IsModified() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsModified(); +} + +ULONG Outliner::GetTextHeight() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetTextHeight(); +} + +void Outliner::SetModifyHdl( const Link& rLink ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetModifyHdl( rLink ); +} + +Link Outliner::GetModifyHdl() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetModifyHdl(); +} + +void Outliner::SetNotifyHdl( const Link& rLink ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->aOutlinerNotifyHdl = rLink; + + if ( rLink.IsSet() ) + pEditEngine->SetNotifyHdl( LINK( this, Outliner, EditEngineNotifyHdl ) ); + else + pEditEngine->SetNotifyHdl( Link() ); + +} + +Link Outliner::GetNotifyHdl() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->aOutlinerNotifyHdl; +} + +void Outliner::SetStatusEventHdl( const Link& rLink ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetStatusEventHdl( rLink ); +} + +Link Outliner::GetStatusEventHdl() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetStatusEventHdl(); +} + +void Outliner::SetDefTab( USHORT nTab ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetDefTab( nTab ); +} + +USHORT Outliner::GetDefTab() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetDefTab(); +} + +BOOL Outliner::IsFlatMode() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsFlatMode(); +} + +BOOL Outliner::UpdateFields() +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->UpdateFields(); +} + +void Outliner::RemoveFields( BOOL bKeepFieldText, TypeId aType ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->RemoveFields( bKeepFieldText, aType ); +} + +void Outliner::SetWordDelimiters( const String& rDelimiters ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetWordDelimiters( rDelimiters ); +} + +String Outliner::GetWordDelimiters() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetWordDelimiters(); +} + +String Outliner::GetWord( USHORT nPara, USHORT nIndex ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetWord( nPara, nIndex ); +} + +void Outliner::Draw( OutputDevice* pOutDev, const Rectangle& rOutRect ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->Draw( pOutDev, rOutRect ); +} + +void Outliner::Draw( OutputDevice* pOutDev, const Rectangle& rOutRect, const Point& rStartDocPos ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->Draw( pOutDev, rOutRect, rStartDocPos ); +} + + +void Outliner::Draw( OutputDevice* pOutDev, const Point& rStartPos, short nOrientation ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->Draw( pOutDev, rStartPos, nOrientation ); +} + +void Outliner::SetPaperSize( const Size& rSize ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetPaperSize( rSize ); +} + +const Size& Outliner::GetPaperSize() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetPaperSize(); +} + +void Outliner::SetPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon ) +{ + DBG_CHKTHIS( Outliner, 0 ); + pEditEngine->SetPolygon( rPolyPolygon ); +} + +void Outliner::SetPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DPolyPolygon* pLinePolyPolygon) +{ + DBG_CHKTHIS( Outliner, 0 ); + pEditEngine->SetPolygon( rPolyPolygon, pLinePolyPolygon); +} + +void Outliner::ClearPolygon() +{ + DBG_CHKTHIS( Outliner, 0 ); + pEditEngine->ClearPolygon(); +} + +const PolyPolygon* Outliner::GetPolygon() +{ + DBG_CHKTHIS( Outliner, 0 ); + return pEditEngine->GetPolygon(); +} + +const Size& Outliner::GetMinAutoPaperSize() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetMinAutoPaperSize(); +} + +void Outliner::SetMinAutoPaperSize( const Size& rSz ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetMinAutoPaperSize( rSz ); +} + +const Size& Outliner::GetMaxAutoPaperSize() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetMaxAutoPaperSize(); +} + +void Outliner::SetMaxAutoPaperSize( const Size& rSz ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetMaxAutoPaperSize( rSz ); +} + +BOOL Outliner::IsExpanded( Paragraph* pPara ) const +{ + DBG_CHKTHIS(Outliner,0); + return pParaList->HasVisibleChilds( pPara ); +} + +Paragraph* Outliner::GetParent( Paragraph* pParagraph ) const +{ + DBG_CHKTHIS(Outliner,0); + return pParaList->GetParent( pParagraph ); +} + +ULONG Outliner::GetChildCount( Paragraph* pParent ) const +{ + DBG_CHKTHIS(Outliner,0); + return pParaList->GetChildCount( pParent ); +} + +Size Outliner::CalcTextSize() +{ + DBG_CHKTHIS(Outliner,0); + return Size(pEditEngine->CalcTextWidth(),pEditEngine->GetTextHeight()); +} + +Point Outliner::GetDocPos( Paragraph* pPara ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetDocPosTopLeft( (USHORT)pParaList->GetAbsPos( pPara ) ); +} + +void Outliner::SetStyleSheetPool( SfxStyleSheetPool* pSPool ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetStyleSheetPool( pSPool ); +} + +SfxStyleSheetPool* Outliner::GetStyleSheetPool() +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetStyleSheetPool(); +} + +SfxStyleSheet* Outliner::GetStyleSheet( ULONG nPara ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetStyleSheet( (USHORT)nPara ); +} + +BOOL Outliner::IsInSelectionMode() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsInSelectionMode(); +} + +void Outliner::SetControlWord( ULONG nWord ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetControlWord( nWord ); +} + +ULONG Outliner::GetControlWord() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetControlWord(); +} + +void Outliner::SetAsianCompressionMode( USHORT n ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetAsianCompressionMode( n ); +} + +USHORT Outliner::GetAsianCompressionMode() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetAsianCompressionMode(); +} + +void Outliner::SetKernAsianPunctuation( BOOL b ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetKernAsianPunctuation( b ); +} + +BOOL Outliner::IsKernAsianPunctuation() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsKernAsianPunctuation(); +} + +void Outliner::SetAddExtLeading( BOOL bExtLeading ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetAddExtLeading( bExtLeading ); +} + +BOOL Outliner::IsAddExtLeading() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsAddExtLeading(); +} + +void Outliner::UndoActionStart( USHORT nId ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->UndoActionStart( nId ); +} + +void Outliner::UndoActionEnd( USHORT nId ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->UndoActionEnd( nId ); +} + +void Outliner::InsertUndo( EditUndo* pUndo ) +{ +#ifndef SVX_LIGHT + DBG_CHKTHIS(Outliner,0); + pEditEngine->GetUndoManager().AddUndoAction( pUndo, FALSE ); +#endif +} + +BOOL Outliner::IsInUndo() +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsInUndo(); +} + +ULONG Outliner::GetLineCount( ULONG nParagraph ) const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetLineCount( (USHORT)nParagraph ); +} + +USHORT Outliner::GetLineLen( ULONG nParagraph, USHORT nLine ) const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetLineLen( (USHORT)nParagraph, nLine ); +} + +ULONG Outliner::GetLineHeight( ULONG nParagraph, ULONG nLine ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetLineHeight( (USHORT)nParagraph, (USHORT)nLine ); +} + +void Outliner::QuickRemoveCharAttribs( USHORT nPara, USHORT nWhich ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->QuickRemoveCharAttribs( nPara, nWhich ); +} + +EESpellState Outliner::HasSpellErrors() +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->HasSpellErrors(); +} + +sal_Bool Outliner::HasConvertibleTextPortion( LanguageType nLang ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->HasConvertibleTextPortion( nLang ); +} + +BOOL Outliner::ConvertNextDocument() +{ + DBG_CHKTHIS(Outliner,0); + return FALSE; +} + +void Outliner::SetDefaultLanguage( LanguageType eLang ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetDefaultLanguage( eLang ); +} + +LanguageType Outliner::GetDefaultLanguage() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetDefaultLanguage(); +} + +BOOL Outliner::HasOnlineSpellErrors() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->HasOnlineSpellErrors(); +} + +void Outliner::CompleteOnlineSpelling() +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->CompleteOnlineSpelling(); +} + +BOOL Outliner::HasText( const SvxSearchItem& rSearchItem ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->HasText( rSearchItem ); +} + +void Outliner::SetEditTextObjectPool( SfxItemPool* pPool ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetEditTextObjectPool( pPool ); +} + +SfxItemPool* Outliner::GetEditTextObjectPool() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetEditTextObjectPool(); +} + +BOOL Outliner::SpellNextDocument() +{ + DBG_CHKTHIS(Outliner,0); + return FALSE; +} + + +void Outliner::SetSpeller( Reference< XSpellChecker1 > &xSpeller ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetSpeller( xSpeller ); +} +Reference< XSpellChecker1 > Outliner::GetSpeller() +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetSpeller(); +} + +void Outliner::SetForbiddenCharsTable( vos::ORef<SvxForbiddenCharactersTable> xForbiddenChars ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetForbiddenCharsTable( xForbiddenChars ); +} + +vos::ORef<SvxForbiddenCharactersTable> Outliner::GetForbiddenCharsTable() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetForbiddenCharsTable(); +} + + +Reference< XHyphenator > Outliner::GetHyphenator() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetHyphenator(); +} + +void Outliner::SetHyphenator( Reference< XHyphenator >& xHyph ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetHyphenator( xHyph ); +} + +OutputDevice* Outliner::GetRefDevice() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetRefDevice(); +} + +USHORT Outliner::GetFirstLineOffset( ULONG nParagraph ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetFirstLineOffset( (USHORT)nParagraph ); +} + +ULONG Outliner::GetTextHeight( ULONG nParagraph ) const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetTextHeight((USHORT)nParagraph ); +} + +Point Outliner::GetDocPos( const Point& rPaperPos ) const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetDocPos( rPaperPos ); +} + +Point Outliner::GetDocPosTopLeft( ULONG nParagraph ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetDocPosTopLeft( (USHORT)nParagraph ); +} + +BOOL Outliner::IsTextPos( const Point& rPaperPos, USHORT nBorder ) +{ + return IsTextPos( rPaperPos, nBorder, NULL ); +} + +BOOL Outliner::IsTextPos( const Point& rPaperPos, USHORT nBorder, BOOL* pbBullet ) +{ + DBG_CHKTHIS(Outliner,0); + if ( pbBullet) + *pbBullet = FALSE; + BOOL bTextPos = pEditEngine->IsTextPos( rPaperPos, nBorder ); + if ( !bTextPos ) + { + Point aDocPos = GetDocPos( rPaperPos ); + USHORT nPara = pEditEngine->FindParagraph( aDocPos.Y() ); + if ( ( nPara != EE_PARA_NOT_FOUND ) && ImplHasBullet( nPara ) ) + { + Rectangle aBulArea = ImpCalcBulletArea( nPara, TRUE, TRUE ); + if ( aBulArea.IsInside( rPaperPos ) ) + { + bTextPos = TRUE; + if ( pbBullet) + *pbBullet = TRUE; + } + } + } + + return bTextPos; +} + +void Outliner::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->QuickSetAttribs( rSet, rSel ); +} + +void Outliner::QuickInsertText( const XubString& rText, const ESelection& rSel ) +{ + bFirstParaIsEmpty = FALSE; + pEditEngine->QuickInsertText( rText, rSel ); +} + +void Outliner::QuickDelete( const ESelection& rSel ) +{ + bFirstParaIsEmpty = FALSE; + pEditEngine->QuickDelete( rSel ); +} + +void Outliner::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + DBG_CHKTHIS(Outliner,0); + bFirstParaIsEmpty = FALSE; + pEditEngine->QuickInsertField( rFld, rSel ); +} + +void Outliner::QuickInsertLineBreak( const ESelection& rSel ) +{ + DBG_CHKTHIS(Outliner,0); + bFirstParaIsEmpty = FALSE; + pEditEngine->QuickInsertLineBreak( rSel ); +} + +void Outliner::QuickFormatDoc( BOOL bFull ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->QuickFormatDoc( bFull ); +} + +void Outliner::SetGlobalCharStretching( USHORT nX, USHORT nY ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetGlobalCharStretching( nX, nY ); +} + +void Outliner::GetGlobalCharStretching( USHORT& rX, USHORT& rY ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->GetGlobalCharStretching( rX, rY ); +} + + +void Outliner::DoStretchChars( USHORT nX, USHORT nY ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->DoStretchChars( nX, nY ); +} + +void Outliner::EraseVirtualDevice() +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->EraseVirtualDevice(); +} + +void Outliner::SetBigTextObjectStart( USHORT nStartAtPortionCount ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetBigTextObjectStart( nStartAtPortionCount ); +} + +USHORT Outliner::GetBigTextObjectStart() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetBigTextObjectStart(); +} + +BOOL Outliner::ShouldCreateBigTextObject() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->ShouldCreateBigTextObject(); +} + +void Outliner::SetVertical( BOOL b ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetVertical( b ); +} + +BOOL Outliner::IsVertical() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsVertical(); +} + +void Outliner::SetFixedCellHeight( BOOL bUseFixedCellHeight ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetFixedCellHeight( bUseFixedCellHeight ); +} + +BOOL Outliner::IsFixedCellHeight() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsFixedCellHeight(); +} + + +void Outliner::SetDefaultHorizontalTextDirection( EEHorizontalTextDirection eHTextDir ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetDefaultHorizontalTextDirection( eHTextDir ); +} + +EEHorizontalTextDirection Outliner::GetDefaultHorizontalTextDirection() const +{ + return pEditEngine->GetDefaultHorizontalTextDirection(); +} + +USHORT Outliner::GetScriptType( const ESelection& rSelection ) const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetScriptType( rSelection ); +} + +LanguageType Outliner::GetLanguage( USHORT nPara, USHORT nPos ) const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetLanguage( nPara, nPos ); +} + +void Outliner::RemoveAttribs( const ESelection& rSelection, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->RemoveAttribs( rSelection, bRemoveParaAttribs, nWhich ); +} + +void Outliner::EnableAutoColor( BOOL b ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->EnableAutoColor( b ); +} + +BOOL Outliner::IsAutoColorEnabled() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsAutoColorEnabled(); +} + +void Outliner::ForceAutoColor( BOOL b ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->ForceAutoColor( b ); +} + +BOOL Outliner::IsForceAutoColor() const +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->IsForceAutoColor(); +} +/*-- 13.10.2003 16:56:23--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void Outliner::StartSpelling(EditView& rEditView, sal_Bool bMultipleDoc) +{ + pEditEngine->StartSpelling(rEditView, bMultipleDoc); +} +/*-- 13.10.2003 16:56:23--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void Outliner::EndSpelling() +{ + pEditEngine->EndSpelling(); +} +/*-- 13.10.2003 16:56:23--------------------------------------------------- + + -----------------------------------------------------------------------*/ +bool Outliner::SpellSentence(EditView& rEditView, ::svx::SpellPortions& rToFill, bool bIsGrammarChecking ) +{ + return pEditEngine->SpellSentence(rEditView, rToFill, bIsGrammarChecking ); +} +/*-- 08.09.2008 11:39:05--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void Outliner::PutSpellingToSentenceStart( EditView& rEditView ) +{ + pEditEngine->PutSpellingToSentenceStart( rEditView ); +} +/*-- 13.10.2003 16:56:25--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void Outliner::ApplyChangedSentence(EditView& rEditView, const ::svx::SpellPortions& rNewPortions, bool bIsGrammarChecking ) +{ + pEditEngine->ApplyChangedSentence( rEditView, rNewPortions, bIsGrammarChecking ); +} diff --git a/editeng/source/outliner/outliner.cxx b/editeng/source/outliner/outliner.cxx new file mode 100644 index 000000000000..2556f2a7f663 --- /dev/null +++ b/editeng/source/outliner/outliner.cxx @@ -0,0 +1,2184 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outliner.cxx,v $ + * $Revision: 1.75.20.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <svl/intitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/editdata.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/fhgtitem.hxx> + +#include <math.h> +#include <svl/style.hxx> +#include <vcl/wrkwin.hxx> +#define _OUTLINER_CXX +#include <editeng/outliner.hxx> +#include <paralist.hxx> +#include <editeng/outlobj.hxx> +#include <outleeng.hxx> +#include <outlundo.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/editstat.hxx> +#include <editeng/scripttypeitem.hxx> +#include <editeng/editobj.hxx> +#include <svl/itemset.hxx> +#include <svl/whiter.hxx> +#include <vcl/metric.hxx> +#include <editeng/numitem.hxx> +#include <editeng/adjitem.hxx> +#include <vcl/graph.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/metaact.hxx> +#include <svtools/grfmgr.hxx> +#include <editeng/svxfont.hxx> +#include <editeng/brshitem.hxx> +#include <svl/itempool.hxx> + +// #101498# calculate if it's RTL or not +#include <unicode/ubidi.h> + +#define DEFAULT_SCALE 75 + +static const USHORT nDefStyles = 3; // Sonderbehandlung fuer die ersten 3 Ebenen +static const USHORT nDefBulletIndent = 800; +static const USHORT nDefBulletWidth = 700; +static const USHORT pDefBulletIndents[nDefStyles]= { 1400, 800, 800 }; +static const USHORT pDefBulletWidths[nDefStyles] = { 1000, 850, 700 }; + +USHORT lcl_ImplGetDefBulletWidth( sal_Int16 nDepth ) +{ + return ( nDepth < nDefStyles ) ? pDefBulletWidths[nDepth] : nDefBulletWidth; +} + +USHORT lcl_ImplGetDefBulletIndent( sal_Int16 nDepth ) +{ + USHORT nI = 0; + + if( nDepth >= 0 ) + { + for ( sal_Int16 n = 0; n <= nDepth; n++ ) + nI = nI + + ( ( n < nDefStyles ) ? pDefBulletIndents[n] : nDefBulletIndent ); + } + return nI; +} + + +// ---------------------------------------------------------------------- +// Outliner +// ---------------------------------------------------------------------- +DBG_NAME(Outliner); + +void Outliner::ImplCheckDepth( sal_Int16& rnDepth ) const +{ + if( rnDepth < nMinDepth ) + rnDepth = nMinDepth; + else if( rnDepth > nMaxDepth ) + rnDepth = nMaxDepth; +} + +Paragraph* Outliner::Insert(const XubString& rText, ULONG nAbsPos, sal_Int16 nDepth) +{ + DBG_CHKTHIS(Outliner,0); + DBG_ASSERT(pParaList->GetParagraphCount(),"Insert:No Paras"); + + Paragraph* pPara; + + ImplCheckDepth( nDepth ); + + ULONG nParagraphCount = pParaList->GetParagraphCount(); + if( nAbsPos > nParagraphCount ) + nAbsPos = nParagraphCount; + + if( bFirstParaIsEmpty ) + { + pPara = pParaList->GetParagraph( 0 ); + if( pPara->GetDepth() != nDepth ) + { + nDepthChangedHdlPrevDepth = pPara->GetDepth(); + mnDepthChangeHdlPrevFlags = pPara->nFlags; + pPara->SetDepth( nDepth ); + pHdlParagraph = pPara; + DepthChangedHdl(); + } + pPara->nFlags |= PARAFLAG_HOLDDEPTH; + SetText( rText, pPara ); + } + else + { + BOOL bUpdate = pEditEngine->GetUpdateMode(); + pEditEngine->SetUpdateMode( FALSE ); + ImplBlockInsertionCallbacks( TRUE ); + pPara = new Paragraph( nDepth ); + pParaList->Insert( pPara, nAbsPos ); + pEditEngine->InsertParagraph( (USHORT)nAbsPos, String() ); + DBG_ASSERT(pPara==pParaList->GetParagraph(nAbsPos),"Insert:Failed"); + ImplInitDepth( (USHORT)nAbsPos, nDepth, FALSE ); + pHdlParagraph = pPara; + ParagraphInsertedHdl(); + pPara->nFlags |= PARAFLAG_HOLDDEPTH; + SetText( rText, pPara ); + ImplBlockInsertionCallbacks( FALSE ); + pEditEngine->SetUpdateMode( bUpdate ); + } + bFirstParaIsEmpty = FALSE; + DBG_ASSERT(pEditEngine->GetParagraphCount()==pParaList->GetParagraphCount(),"SetText failed"); + return pPara; +} + + +void Outliner::ParagraphInserted( USHORT nPara ) +{ + DBG_CHKTHIS(Outliner,0); + + if ( bBlockInsCallback ) + return; + + if( bPasting || pEditEngine->IsInUndo() ) + { + Paragraph* pPara = new Paragraph( -1 ); + pParaList->Insert( pPara, nPara ); + if( pEditEngine->IsInUndo() ) + { + pPara->nFlags = PARAFLAG_SETBULLETTEXT; + pPara->bVisible = TRUE; + const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL ); + pPara->SetDepth( rLevel.GetValue() ); + } + } + else + { + sal_Int16 nDepth = -1; + Paragraph* pParaBefore = pParaList->GetParagraph( nPara-1 ); + if ( pParaBefore ) + nDepth = pParaBefore->GetDepth(); + + Paragraph* pPara = new Paragraph( nDepth ); + pParaList->Insert( pPara, nPara ); + + if( !pEditEngine->IsInUndo() ) + { + ImplCalcBulletText( nPara, TRUE, FALSE ); + pHdlParagraph = pPara; + ParagraphInsertedHdl(); + } + } +} + +void Outliner::ParagraphDeleted( USHORT nPara ) +{ + DBG_CHKTHIS(Outliner,0); + + if ( bBlockInsCallback || ( nPara == EE_PARA_ALL ) ) + return; + + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if (!pPara) + return; + + sal_Int16 nDepth = pPara->GetDepth(); + + if( !pEditEngine->IsInUndo() ) + { + pHdlParagraph = pPara; + ParagraphRemovingHdl(); + } + + pParaList->Remove( nPara ); + delete pPara; + + if( !pEditEngine->IsInUndo() && !bPasting ) + { + pPara = pParaList->GetParagraph( nPara ); + if ( pPara && ( pPara->GetDepth() > nDepth ) ) + { + ImplCalcBulletText( nPara, TRUE, FALSE ); + // naechsten auf gleicher Ebene suchen... + while ( pPara && pPara->GetDepth() > nDepth ) + pPara = pParaList->GetParagraph( ++nPara ); + } + + if ( pPara && ( pPara->GetDepth() == nDepth ) ) + ImplCalcBulletText( nPara, TRUE, FALSE ); + } +} + +void Outliner::Init( USHORT nMode ) +{ + nOutlinerMode = nMode; + + Clear(); + + ULONG nCtrl = pEditEngine->GetControlWord(); + nCtrl &= ~(EE_CNTRL_OUTLINER|EE_CNTRL_OUTLINER2); + + SetMaxDepth( 9 ); + + switch ( ImplGetOutlinerMode() ) + { + case OUTLINERMODE_TEXTOBJECT: + case OUTLINERMODE_TITLEOBJECT: + break; + + case OUTLINERMODE_OUTLINEOBJECT: + nCtrl |= EE_CNTRL_OUTLINER2; + break; + case OUTLINERMODE_OUTLINEVIEW: + nCtrl |= EE_CNTRL_OUTLINER; + break; + + default: DBG_ERROR( "Outliner::Init - Invalid Mode!" ); + } + + pEditEngine->SetControlWord( nCtrl ); + + ImplInitDepth( 0, GetMinDepth(), FALSE ); + + GetUndoManager().Clear(); +} + +void Outliner::SetMaxDepth( sal_Int16 nDepth, BOOL bCheckParagraphs ) +{ + if( nMaxDepth != nDepth ) + { + nMaxDepth = Min( nDepth, (sal_Int16)(SVX_MAX_NUM-1) ); + + if( bCheckParagraphs ) + { + USHORT nParagraphs = (USHORT)pParaList->GetParagraphCount(); + for ( USHORT nPara = 0; nPara < nParagraphs; nPara++ ) + { + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if( pPara && pPara->GetDepth() > nMaxDepth ) + { + SetDepth( pPara, nMaxDepth ); + } + } + } + } +} + +sal_Int16 Outliner::GetDepth( ULONG nPara ) const +{ + Paragraph* pPara = pParaList->GetParagraph( nPara ); + DBG_ASSERT( pPara, "Outliner::GetDepth - Paragraph not found!" ); + return pPara ? pPara->GetDepth() : -1; +} + +void Outliner::SetDepth( Paragraph* pPara, sal_Int16 nNewDepth ) +{ + DBG_CHKTHIS(Outliner,0); + + ImplCheckDepth( nNewDepth ); + + if ( nNewDepth != pPara->GetDepth() ) + { + nDepthChangedHdlPrevDepth = pPara->GetDepth(); + mnDepthChangeHdlPrevFlags = pPara->nFlags; + pHdlParagraph = pPara; + + USHORT nPara = (USHORT)GetAbsPos( pPara ); + ImplInitDepth( nPara, nNewDepth, TRUE ); + ImplCalcBulletText( nPara, FALSE, FALSE ); + + if ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) + ImplSetLevelDependendStyleSheet( nPara ); + + DepthChangedHdl(); + } +} + +sal_Int16 Outliner::GetNumberingStartValue( sal_uInt16 nPara ) +{ + Paragraph* pPara = pParaList->GetParagraph( nPara ); + DBG_ASSERT( pPara, "Outliner::GetNumberingStartValue - Paragraph not found!" ); + return pPara ? pPara->GetNumberingStartValue() : -1; +} + +void Outliner::SetNumberingStartValue( sal_uInt16 nPara, sal_Int16 nNumberingStartValue ) +{ + Paragraph* pPara = pParaList->GetParagraph( nPara ); + DBG_ASSERT( pPara, "Outliner::GetNumberingStartValue - Paragraph not found!" ); + if( pPara && pPara->GetNumberingStartValue() != nNumberingStartValue ) + { + if( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new OutlinerUndoChangeParaNumberingRestart( this, nPara, + pPara->GetNumberingStartValue(), nNumberingStartValue, + pPara->IsParaIsNumberingRestart(), pPara->IsParaIsNumberingRestart() ) ); + + pPara->SetNumberingStartValue( nNumberingStartValue ); + // --> OD 2009-03-10 #i100014# + // It is not a good idea to substract 1 from a count and cast the result + // to USHORT without check, if the count is 0. + ImplCheckParagraphs( nPara, (USHORT) (pParaList->GetParagraphCount()) ); + // <-- + pEditEngine->SetModified(); + } +} + +sal_Bool Outliner::IsParaIsNumberingRestart( sal_uInt16 nPara ) +{ + Paragraph* pPara = pParaList->GetParagraph( nPara ); + DBG_ASSERT( pPara, "Outliner::IsParaIsNumberingRestart - Paragraph not found!" ); + return pPara ? pPara->IsParaIsNumberingRestart() : sal_False; +} + +void Outliner::SetParaIsNumberingRestart( sal_uInt16 nPara, sal_Bool bParaIsNumberingRestart ) +{ + Paragraph* pPara = pParaList->GetParagraph( nPara ); + DBG_ASSERT( pPara, "Outliner::SetParaIsNumberingRestart - Paragraph not found!" ); + if( pPara && (pPara->IsParaIsNumberingRestart() != bParaIsNumberingRestart) ) + { + if( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new OutlinerUndoChangeParaNumberingRestart( this, nPara, + pPara->GetNumberingStartValue(), pPara->GetNumberingStartValue(), + pPara->IsParaIsNumberingRestart(), bParaIsNumberingRestart ) ); + + pPara->SetParaIsNumberingRestart( bParaIsNumberingRestart ); + // --> OD 2009-03-10 #i100014# + // It is not a good idea to substract 1 from a count and cast the result + // to USHORT without check, if the count is 0. + ImplCheckParagraphs( nPara, (USHORT) (pParaList->GetParagraphCount()) ); + // <-- + pEditEngine->SetModified(); + } +} + +OutlinerParaObject* Outliner::CreateParaObject( USHORT nStartPara, USHORT nCount ) const +{ + DBG_CHKTHIS(Outliner,0); + + if ( sal::static_int_cast< ULONG >( nStartPara + nCount ) > + pParaList->GetParagraphCount() ) + nCount = sal::static_int_cast< USHORT >( + pParaList->GetParagraphCount() - nStartPara ); + + // When a new OutlinerParaObject is created because a paragraph is just beeing deleted, + // it can happen that the ParaList is not updated yet... + if ( ( nStartPara + nCount ) > pEditEngine->GetParagraphCount() ) + nCount = pEditEngine->GetParagraphCount() - nStartPara; + + if( !nCount ) + return NULL; + + EditTextObject* pText = pEditEngine->CreateTextObject( nStartPara, nCount ); + const bool bIsEditDoc(OUTLINERMODE_TEXTOBJECT == ImplGetOutlinerMode()); + ParagraphDataVector aParagraphDataVector(nCount); + const sal_uInt16 nLastPara(nStartPara + nCount - 1); + + for(sal_uInt16 nPara(nStartPara); nPara <= nLastPara; nPara++) + { + aParagraphDataVector[nPara-nStartPara] = *GetParagraph(nPara); + } + + OutlinerParaObject* pPObj = new OutlinerParaObject(*pText, aParagraphDataVector, bIsEditDoc); + pPObj->SetOutlinerMode(GetMode()); + delete pText; + + return pPObj; +} + +void Outliner::SetText( const XubString& rText, Paragraph* pPara ) +{ + DBG_CHKTHIS(Outliner,0); + DBG_ASSERT(pPara,"SetText:No Para"); + + BOOL bUpdate = pEditEngine->GetUpdateMode(); + pEditEngine->SetUpdateMode( FALSE ); + ImplBlockInsertionCallbacks( TRUE ); + + USHORT nPara = (USHORT)pParaList->GetAbsPos( pPara ); + + if( !rText.Len() ) + { + pEditEngine->SetText( nPara, rText ); + ImplInitDepth( nPara, pPara->GetDepth(), FALSE ); + } + else + { + XubString aText( rText ); + aText.ConvertLineEnd( LINEEND_LF ); + + if( aText.GetChar( aText.Len()-1 ) == '\x0A' ) + aText.Erase( aText.Len()-1, 1 ); // letzten Umbruch loeschen + + USHORT nCount = aText.GetTokenCount( '\x0A' ); + USHORT nPos = 0; + USHORT nInsPos = nPara+1; + while( nCount > nPos ) + { + XubString aStr = aText.GetToken( nPos, '\x0A' ); + + sal_Int16 nCurDepth; + if( nPos ) + { + pPara = new Paragraph( -1 ); + nCurDepth = -1; + } + else + nCurDepth = pPara->GetDepth(); + + // Im Outliner-Modus die Tabulatoren filtern und die + // Einrueckung ueber ein LRSpaceItem einstellen + // Im EditEngine-Modus ueber Maltes Tabulatoren einruecken + if( ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) || + ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEVIEW ) ) + { + // Tabs raus + USHORT nTabs = 0; + while ( ( nTabs < aStr.Len() ) && ( aStr.GetChar( nTabs ) == '\t' ) ) + nTabs++; + if ( nTabs ) + aStr.Erase( 0, nTabs ); + + // Tiefe beibehalten ? (siehe Outliner::Insert) + if( !(pPara->nFlags & PARAFLAG_HOLDDEPTH) ) + { + nCurDepth = nTabs-1; + ImplCheckDepth( nCurDepth ); + pPara->SetDepth( nCurDepth ); + pPara->nFlags &= (~PARAFLAG_HOLDDEPTH); + } + } + if( nPos ) // nicht mit dem ersten Absatz + { + pParaList->Insert( pPara, nInsPos ); + pEditEngine->InsertParagraph( nInsPos, aStr ); + pHdlParagraph = pPara; + ParagraphInsertedHdl(); + } + else + { + nInsPos--; + pEditEngine->SetText( nInsPos, aStr ); + } + ImplInitDepth( nInsPos, nCurDepth, FALSE ); + nInsPos++; + nPos++; + } + } + + DBG_ASSERT(pParaList->GetParagraphCount()==pEditEngine->GetParagraphCount(),"SetText failed!"); + bFirstParaIsEmpty = FALSE; + ImplBlockInsertionCallbacks( FALSE ); + pEditEngine->SetUpdateMode( bUpdate ); +} + +// pView == 0 -> Tabulatoren nicht beachten + +bool Outliner::ImpConvertEdtToOut( sal_uInt32 nPara,EditView* pView) +{ + DBG_CHKTHIS(Outliner,0); + + bool bConverted = false; + USHORT nTabs = 0; + ESelection aDelSel; + +// const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( (sal_uInt16)nPara ); +// bool bAlreadyOutliner = rAttrs.GetItemState( EE_PARA_OUTLLRSPACE ) == SFX_ITEM_ON ? true : false; + + XubString aName; + XubString aHeading_US( RTL_CONSTASCII_USTRINGPARAM( "heading" ) ); + XubString aNumber_US( RTL_CONSTASCII_USTRINGPARAM( "Numbering" ) ); + + XubString aStr( pEditEngine->GetText( (USHORT)nPara ) ); + xub_Unicode* pPtr = (xub_Unicode*)aStr.GetBuffer(); + + USHORT nHeadingNumberStart = 0; + USHORT nNumberingNumberStart = 0; + SfxStyleSheet* pStyle= pEditEngine->GetStyleSheet( (USHORT)nPara ); + if( pStyle ) + { + aName = pStyle->GetName(); + USHORT nSearch; + if ( ( nSearch = aName.Search( aHeading_US ) ) != STRING_NOTFOUND ) + nHeadingNumberStart = nSearch + aHeading_US.Len(); + else if ( ( nSearch = aName.Search( aNumber_US ) ) != STRING_NOTFOUND ) + nNumberingNumberStart = nSearch + aNumber_US.Len(); + } + + if ( nHeadingNumberStart || nNumberingNumberStart ) + { + // PowerPoint-Import ? + if( nHeadingNumberStart && ( aStr.Len() >= 2 ) && + ( pPtr[0] != '\t' ) && ( pPtr[1] == '\t' ) ) + { + // Bullet & Tab raus + aDelSel = ESelection( (USHORT)nPara, 0, (USHORT)nPara, 2 ); + } + + USHORT nPos = nHeadingNumberStart ? nHeadingNumberStart : nNumberingNumberStart; + String aLevel = aName.Copy( nPos ); + aLevel.EraseLeadingChars( ' ' ); + nTabs = sal::static_int_cast< USHORT >(aLevel.ToInt32()); + if( nTabs ) + nTabs--; // ebene 0 = "heading 1" + bConverted = TRUE; + } + else + { + // Fuehrende Tabulatoren filtern + while( *pPtr == '\t' ) + { + pPtr++; + nTabs++; + } + // Tabulatoren aus dem Text entfernen + if( nTabs ) + aDelSel = ESelection( (USHORT)nPara, 0, (USHORT)nPara, nTabs ); + } + + if ( aDelSel.HasRange() ) + { + if ( pView ) + { + pView->SetSelection( aDelSel ); + pView->DeleteSelected(); + } + else + pEditEngine->QuickDelete( aDelSel ); + } + + const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( sal::static_int_cast< sal_uInt16 >(nPara), EE_PARA_OUTLLEVEL ); + sal_Int16 nOutlLevel = rLevel.GetValue(); + + ImplCheckDepth( nOutlLevel ); + ImplInitDepth( sal::static_int_cast< sal_uInt16 >(nPara), nOutlLevel, FALSE ); + + return bConverted; +} + +void Outliner::SetText( const OutlinerParaObject& rPObj ) +{ + DBG_CHKTHIS(Outliner,0); + + BOOL bUpdate = pEditEngine->GetUpdateMode(); + pEditEngine->SetUpdateMode( FALSE ); + + BOOL bUndo = pEditEngine->IsUndoEnabled(); + EnableUndo( FALSE ); + + Init( rPObj.GetOutlinerMode() ); + + ImplBlockInsertionCallbacks( TRUE ); + pEditEngine->SetText(rPObj.GetTextObject()); + if( rPObj.Count() != pEditEngine->GetParagraphCount() ) + { + int nop=0;nop++; + } + + bFirstParaIsEmpty = FALSE; + + pParaList->Clear( TRUE ); + for( USHORT nCurPara = 0; nCurPara < rPObj.Count(); nCurPara++ ) + { + Paragraph* pPara = new Paragraph( rPObj.GetParagraphData(nCurPara)); + ImplCheckDepth( pPara->nDepth ); + + pParaList->Insert( pPara, LIST_APPEND ); + ImplCheckNumBulletItem( nCurPara ); + } + + // --> OD 2009-03-10 #i100014# + // It is not a good idea to substract 1 from a count and cast the result + // to USHORT without check, if the count is 0. + ImplCheckParagraphs( 0, (USHORT) (pParaList->GetParagraphCount()) ); + // <-- + + EnableUndo( bUndo ); + ImplBlockInsertionCallbacks( FALSE ); + pEditEngine->SetUpdateMode( bUpdate ); + + DBG_ASSERT( pParaList->GetParagraphCount()==rPObj.Count(),"SetText failed"); + DBG_ASSERT( pEditEngine->GetParagraphCount()==rPObj.Count(),"SetText failed"); +} + +void Outliner::AddText( const OutlinerParaObject& rPObj ) +{ + DBG_CHKTHIS(Outliner,0); + Paragraph* pPara; + + BOOL bUpdate = pEditEngine->GetUpdateMode(); + pEditEngine->SetUpdateMode( FALSE ); + + ImplBlockInsertionCallbacks( TRUE ); + ULONG nPara; + if( bFirstParaIsEmpty ) + { + pParaList->Clear( TRUE ); + pEditEngine->SetText(rPObj.GetTextObject()); + nPara = 0; + } + else + { + nPara = pParaList->GetParagraphCount(); + pEditEngine->InsertParagraph( EE_PARA_APPEND, rPObj.GetTextObject() ); + } + bFirstParaIsEmpty = FALSE; + + for( USHORT n = 0; n < rPObj.Count(); n++ ) + { + pPara = new Paragraph( rPObj.GetParagraphData(n) ); + pParaList->Insert( pPara, LIST_APPEND ); + USHORT nP = sal::static_int_cast< USHORT >(nPara+n); + DBG_ASSERT(pParaList->GetAbsPos(pPara)==nP,"AddText:Out of sync"); + ImplInitDepth( nP, pPara->GetDepth(), FALSE ); + } + DBG_ASSERT( pEditEngine->GetParagraphCount()==pParaList->GetParagraphCount(), "SetText: OutOfSync" ); + + // --> OD 2009-03-10 #i100014# + // It is not a good idea to substract 1 from a count and cast the result + // to USHORT without check, if the count is 0. + ImplCheckParagraphs( (USHORT)nPara, (USHORT) (pParaList->GetParagraphCount()) ); + // <-- + + ImplBlockInsertionCallbacks( FALSE ); + pEditEngine->SetUpdateMode( bUpdate ); +} + +void __EXPORT Outliner::FieldClicked( const SvxFieldItem& rField, USHORT nPara, USHORT nPos ) +{ + DBG_CHKTHIS(Outliner,0); + + if ( aFieldClickedHdl.IsSet() ) + { + EditFieldInfo aFldInfo( this, rField, nPara, nPos ); + aFldInfo.SetSimpleClick( TRUE ); + aFieldClickedHdl.Call( &aFldInfo ); + } +} + + +void __EXPORT Outliner::FieldSelected( const SvxFieldItem& rField, USHORT nPara, USHORT nPos ) +{ + DBG_CHKTHIS(Outliner,0); + if ( !aFieldClickedHdl.IsSet() ) + return; + + EditFieldInfo aFldInfo( this, rField, nPara, nPos ); + aFldInfo.SetSimpleClick( FALSE ); + aFieldClickedHdl.Call( &aFldInfo ); +} + + +XubString __EXPORT Outliner::CalcFieldValue( const SvxFieldItem& rField, USHORT nPara, USHORT nPos, Color*& rpTxtColor, Color*& rpFldColor ) +{ + DBG_CHKTHIS(Outliner,0); + if ( !aCalcFieldValueHdl.IsSet() ) + return String( ' ' ); + + EditFieldInfo aFldInfo( this, rField, nPara, nPos ); + // Die FldColor ist mit COL_LIGHTGRAY voreingestellt. + if ( rpFldColor ) + aFldInfo.SetFldColor( *rpFldColor ); + + aCalcFieldValueHdl.Call( &aFldInfo ); + if ( aFldInfo.GetTxtColor() ) + { + delete rpTxtColor; + rpTxtColor = new Color( *aFldInfo.GetTxtColor() ); + } + + delete rpFldColor; + rpFldColor = aFldInfo.GetFldColor() ? new Color( *aFldInfo.GetFldColor() ) : 0; + + return aFldInfo.GetRepresentation(); +} + +void Outliner::SetStyleSheet( ULONG nPara, SfxStyleSheet* pStyle ) +{ + DBG_CHKTHIS(Outliner,0); + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if (pPara) + { + pEditEngine->SetStyleSheet( (USHORT)nPara, pStyle ); + pPara->nFlags |= PARAFLAG_SETBULLETTEXT; + ImplCheckNumBulletItem( (USHORT) nPara ); + } +} + +void Outliner::SetVisible( Paragraph* pPara, BOOL bVisible ) +{ + DBG_CHKTHIS(Outliner,0); + DBG_ASSERT( pPara, "SetVisible: pPara = NULL" ); + + if (pPara) + { + pPara->bVisible = bVisible; + ULONG nPara = pParaList->GetAbsPos( pPara ); + pEditEngine->ShowParagraph( (USHORT)nPara, bVisible ); + } +} + +void Outliner::ImplCheckNumBulletItem( USHORT nPara ) +{ + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if (pPara) + pPara->aBulSize.Width() = -1; +} + +void Outliner::ImplSetLevelDependendStyleSheet( USHORT nPara, SfxStyleSheet* pLevelStyle ) +{ + DBG_CHKTHIS(Outliner,0); + + DBG_ASSERT( ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) || ( ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEVIEW ), "SetLevelDependendStyleSheet: Wrong Mode!" ); + + SfxStyleSheet* pStyle = pLevelStyle; + if ( !pStyle ) + pStyle = GetStyleSheet( nPara ); + + if ( pStyle ) + { + sal_Int16 nDepth = GetDepth( nPara ); + if( nDepth < 0 ) + nDepth = 0; + + String aNewStyleSheetName( pStyle->GetName() ); + aNewStyleSheetName.Erase( aNewStyleSheetName.Len()-1, 1 ); + aNewStyleSheetName += String::CreateFromInt32( nDepth+1 ); + SfxStyleSheet* pNewStyle = (SfxStyleSheet*)GetStyleSheetPool()->Find( aNewStyleSheetName, pStyle->GetFamily() ); + DBG_ASSERT( pNewStyle, "AutoStyleSheetName - Style not found!" ); + if ( pNewStyle && ( pNewStyle != GetStyleSheet( nPara ) ) ) + { + SfxItemSet aOldAttrs( GetParaAttribs( nPara ) ); + SetStyleSheet( nPara, pNewStyle ); + if ( aOldAttrs.GetItemState( EE_PARA_NUMBULLET ) == SFX_ITEM_ON ) + { + SfxItemSet aAttrs( GetParaAttribs( nPara ) ); + aAttrs.Put( aOldAttrs.Get( EE_PARA_NUMBULLET ) ); + SetParaAttribs( nPara, aAttrs ); + } + } + } +} + +void Outliner::ImplInitDepth( USHORT nPara, sal_Int16 nDepth, BOOL bCreateUndo, BOOL bUndoAction ) +{ + DBG_CHKTHIS(Outliner,0); + + DBG_ASSERT( ( nDepth >= nMinDepth ) && ( nDepth <= nMaxDepth ), "ImplInitDepth - Depth is invalid!" ); + + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if (!pPara) + return; + sal_Int16 nOldDepth = pPara->GetDepth(); + pPara->SetDepth( nDepth ); + + // Bei IsInUndo brauchen Attribute und Style nicht eingestellt werden, + // dort werden die alten Werte durch die EditEngine restauriert. + + if( !IsInUndo() ) + { + BOOL bUpdate = pEditEngine->GetUpdateMode(); + pEditEngine->SetUpdateMode( FALSE ); + + BOOL bUndo = bCreateUndo && IsUndoEnabled(); + if ( bUndo && bUndoAction ) + UndoActionStart( OLUNDO_DEPTH ); + + SfxItemSet aAttrs( pEditEngine->GetParaAttribs( nPara ) ); + aAttrs.Put( SfxInt16Item( EE_PARA_OUTLLEVEL, nDepth ) ); + pEditEngine->SetParaAttribs( nPara, aAttrs ); + ImplCheckNumBulletItem( nPara ); + ImplCalcBulletText( nPara, FALSE, FALSE ); + + if ( bUndo ) + { + InsertUndo( new OutlinerUndoChangeDepth( this, nPara, nOldDepth, nDepth ) ); + if ( bUndoAction ) + UndoActionEnd( OLUNDO_DEPTH ); + } + + pEditEngine->SetUpdateMode( bUpdate ); + } +} + +void Outliner::SetParaAttribs( USHORT nPara, const SfxItemSet& rSet ) +{ + DBG_CHKTHIS(Outliner,0); + + pEditEngine->SetParaAttribs( nPara, rSet ); +} + +BOOL Outliner::Expand( Paragraph* pPara ) +{ + DBG_CHKTHIS(Outliner,0); + + if ( pParaList->HasHiddenChilds( pPara ) ) + { + OLUndoExpand* pUndo = 0; + BOOL bUndo = IsUndoEnabled() && !IsInUndo(); + if( bUndo ) + { + UndoActionStart( OLUNDO_EXPAND ); + pUndo = new OLUndoExpand( this, OLUNDO_EXPAND ); + pUndo->pParas = 0; + pUndo->nCount = (USHORT)pParaList->GetAbsPos( pPara ); + } + pHdlParagraph = pPara; + bIsExpanding = TRUE; + pParaList->Expand( pPara ); + ExpandHdl(); + InvalidateBullet( pPara, pParaList->GetAbsPos(pPara) ); + if( bUndo ) + { + InsertUndo( pUndo ); + UndoActionEnd( OLUNDO_EXPAND ); + } + return TRUE; + } + return FALSE; +} + + +BOOL Outliner::Collapse( Paragraph* pPara ) +{ + DBG_CHKTHIS(Outliner,0); + if ( pParaList->HasVisibleChilds( pPara ) ) // expandiert + { + OLUndoExpand* pUndo = 0; + BOOL bUndo = FALSE; + + if( !IsInUndo() && IsUndoEnabled() ) + bUndo = TRUE; + if( bUndo ) + { + UndoActionStart( OLUNDO_COLLAPSE ); + pUndo = new OLUndoExpand( this, OLUNDO_COLLAPSE ); + pUndo->pParas = 0; + pUndo->nCount = (USHORT)pParaList->GetAbsPos( pPara ); + } + + pHdlParagraph = pPara; + bIsExpanding = FALSE; + pParaList->Collapse( pPara ); + ExpandHdl(); + InvalidateBullet( pPara, pParaList->GetAbsPos(pPara) ); + if( bUndo ) + { + InsertUndo( pUndo ); + UndoActionEnd( OLUNDO_COLLAPSE ); + } + return TRUE; + } + return FALSE; +} + + +Font Outliner::ImpCalcBulletFont( USHORT nPara ) const +{ + const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); + DBG_ASSERT( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) && ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ), "ImpCalcBulletFont: Missing or BitmapBullet!" ); + + Font aStdFont; //#107508# + if ( !pEditEngine->IsFlatMode() ) + { + ESelection aSel( nPara, 0, nPara, 0 ); + aStdFont = EditEngine::CreateFontFromItemSet( pEditEngine->GetAttribs( aSel ), GetScriptType( aSel ) ); + } + else + { + aStdFont = pEditEngine->GetStandardFont( nPara ); + } + + Font aBulletFont; + if ( pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL ) + { + aBulletFont = *pFmt->GetBulletFont(); + } + else + { + aBulletFont = aStdFont; + aBulletFont.SetUnderline( UNDERLINE_NONE ); + aBulletFont.SetOverline( UNDERLINE_NONE ); + aBulletFont.SetStrikeout( STRIKEOUT_NONE ); + aBulletFont.SetEmphasisMark( EMPHASISMARK_NONE ); + aBulletFont.SetRelief( RELIEF_NONE ); + } + + // #107508# Use original scale... + USHORT nScale = /* pEditEngine->IsFlatMode() ? DEFAULT_SCALE : */ pFmt->GetBulletRelSize(); + ULONG nScaledLineHeight = aStdFont.GetSize().Height(); + nScaledLineHeight *= nScale*10; + nScaledLineHeight /= 1000; + + aBulletFont.SetAlign( ALIGN_BOTTOM ); + aBulletFont.SetSize( Size( 0, nScaledLineHeight ) ); + BOOL bVertical = IsVertical(); + aBulletFont.SetVertical( bVertical ); + aBulletFont.SetOrientation( bVertical ? 2700 : 0 ); + + Color aColor( COL_AUTO ); + if( !pEditEngine->IsFlatMode() && !( pEditEngine->GetControlWord() & EE_CNTRL_NOCOLORS ) ) + { + aColor = pFmt->GetBulletColor(); + } + + if ( ( aColor == COL_AUTO ) || ( IsForceAutoColor() ) ) + aColor = pEditEngine->GetAutoColor(); + + aBulletFont.SetColor( aColor ); + return aBulletFont; +} + +void Outliner::PaintBullet( USHORT nPara, const Point& rStartPos, + const Point& rOrigin, short nOrientation, OutputDevice* pOutDev ) +{ + DBG_CHKTHIS(Outliner,0); + + bool bDrawBullet = false; + if (pEditEngine) + { + const SfxBoolItem& rBulletState = (const SfxBoolItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE ); + bDrawBullet = rBulletState.GetValue() ? true : false; + } + + if ( ImplHasBullet( nPara ) && bDrawBullet) + { + BOOL bVertical = IsVertical(); + + BOOL bRightToLeftPara = pEditEngine->IsRightToLeft( nPara ); + + Rectangle aBulletArea( ImpCalcBulletArea( nPara, TRUE, FALSE ) ); + + Paragraph* pPara = pParaList->GetParagraph( nPara ); + const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); + if ( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) ) + { + if( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) + { + Font aBulletFont( ImpCalcBulletFont( nPara ) ); + // #2338# Use base line + BOOL bSymbol = pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL; + aBulletFont.SetAlign( bSymbol ? ALIGN_BOTTOM : ALIGN_BASELINE ); + Font aOldFont = pOutDev->GetFont(); + pOutDev->SetFont( aBulletFont ); + + ParagraphInfos aParaInfos = pEditEngine->GetParagraphInfos( nPara ); + Point aTextPos; + if ( !bVertical ) + { +// aTextPos.Y() = rStartPos.Y() + aBulletArea.Bottom(); + aTextPos.Y() = rStartPos.Y() + ( bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent ); + if ( !bRightToLeftPara ) + aTextPos.X() = rStartPos.X() + aBulletArea.Left(); + else + aTextPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Left(); + } + else + { +// aTextPos.X() = rStartPos.X() - aBulletArea.Bottom(); + aTextPos.X() = rStartPos.X() - ( bSymbol ? aBulletArea.Bottom() : aParaInfos.nFirstLineMaxAscent ); + aTextPos.Y() = rStartPos.Y() + aBulletArea.Left(); + } + + if ( nOrientation ) + { + // Sowohl TopLeft als auch BottomLeft nicht ganz richtig, da + // in EditEngine BaseLine... + double nRealOrientation = nOrientation*F_PI1800; + double nCos = cos( nRealOrientation ); + double nSin = sin( nRealOrientation ); + Point aRotatedPos; + // Translation... + aTextPos -= rOrigin; + // Rotation... + aRotatedPos.X()=(long) (nCos*aTextPos.X() + nSin*aTextPos.Y()); + aRotatedPos.Y()=(long) - (nSin*aTextPos.X() - nCos*aTextPos.Y()); + aTextPos = aRotatedPos; + // Translation... + aTextPos += rOrigin; + Font aRotatedFont( aBulletFont ); + aRotatedFont.SetOrientation( nOrientation ); + pOutDev->SetFont( aRotatedFont ); + } + + // #105803# VCL will care for brackets and so on... + ULONG nLayoutMode = pOutDev->GetLayoutMode(); + nLayoutMode &= ~(TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_COMPLEX_DISABLED|TEXT_LAYOUT_BIDI_STRONG); + if ( bRightToLeftPara ) + nLayoutMode |= TEXT_LAYOUT_BIDI_RTL; + pOutDev->SetLayoutMode( nLayoutMode ); + + if(bStrippingPortions) + { + const Font aSvxFont(pOutDev->GetFont()); + sal_Int32* pBuf = new sal_Int32[ pPara->GetText().Len() ]; + pOutDev->GetTextArray( pPara->GetText(), pBuf ); + + if(bSymbol) + { + // aTextPos is Bottom, go to Baseline + FontMetric aMetric(pOutDev->GetFontMetric()); + aTextPos.Y() -= aMetric.GetDescent(); + } + + DrawingText(aTextPos, pPara->GetText(), 0, pPara->GetText().Len(), pBuf, + aSvxFont, nPara, 0xFFFF, 0xFF, 0, 0, false, false, true, 0, Color(), Color()); + + delete[] pBuf; + } + else + { + pOutDev->DrawText( aTextPos, pPara->GetText() ); + } + + pOutDev->SetFont( aOldFont ); + } + else + { + if ( pFmt->GetBrush()->GetGraphicObject() ) + { + Point aBulletPos; + if ( !bVertical ) + { + aBulletPos.Y() = rStartPos.Y() + aBulletArea.Top(); + if ( !bRightToLeftPara ) + aBulletPos.X() = rStartPos.X() + aBulletArea.Left(); + else + aBulletPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Right(); + } + else + { + aBulletPos.X() = rStartPos.X() - aBulletArea.Bottom(); + aBulletPos.Y() = rStartPos.Y() + aBulletArea.Left(); + } + + if(bStrippingPortions) + { + if(aDrawBulletHdl.IsSet()) + { + // call something analog to aDrawPortionHdl (if set) and feed it something + // analog to DrawPortionInfo... + // created aDrawBulletHdl, Set/GetDrawBulletHdl. + // created DrawBulletInfo and added handling to sdrtextdecomposition.cxx + DrawBulletInfo aDrawBulletInfo( + *pFmt->GetBrush()->GetGraphicObject(), + aBulletPos, + pPara->aBulSize); + + aDrawBulletHdl.Call(&aDrawBulletInfo); + } + } + else + { + // MT: Remove CAST when KA made the Draw-Method const + ((GraphicObject*)pFmt->GetBrush()->GetGraphicObject())->Draw( pOutDev, aBulletPos, pPara->aBulSize ); + } + } + } + } + + // Bei zusammengeklappten Absaetzen einen Strich vor den Text malen. + if( pParaList->HasChilds(pPara) && !pParaList->HasVisibleChilds(pPara) && + !bStrippingPortions && !nOrientation ) + { + long nWidth = pOutDev->PixelToLogic( Size( 10, 0 ) ).Width(); + + Point aStartPos, aEndPos; + if ( !bVertical ) + { + aStartPos.Y() = rStartPos.Y() + aBulletArea.Bottom(); + if ( !bRightToLeftPara ) + aStartPos.X() = rStartPos.X() + aBulletArea.Right(); + else + aStartPos.X() = rStartPos.X() + GetPaperSize().Width() - aBulletArea.Left(); + aEndPos = aStartPos; + aEndPos.X() += nWidth; + } + else + { + aStartPos.X() = rStartPos.X() - aBulletArea.Bottom(); + aStartPos.Y() = rStartPos.Y() + aBulletArea.Right(); + aEndPos = aStartPos; + aEndPos.Y() += nWidth; + } + + const Color& rOldLineColor = pOutDev->GetLineColor(); + pOutDev->SetLineColor( Color( COL_BLACK ) ); + pOutDev->DrawLine( aStartPos, aEndPos ); + pOutDev->SetLineColor( rOldLineColor ); + } + } +} + +void Outliner::InvalidateBullet( Paragraph* /*pPara*/, ULONG nPara ) +{ + DBG_CHKTHIS(Outliner,0); + + long nLineHeight = (long)pEditEngine->GetLineHeight((USHORT)nPara ); + OutlinerView* pView = aViewList.First(); + while( pView ) + { + Point aPos( pView->pEditView->GetWindowPosTopLeft((USHORT)nPara ) ); + Rectangle aRect( pView->GetOutputArea() ); + aRect.Right() = aPos.X(); + aRect.Top() = aPos.Y(); + aRect.Bottom() = aPos.Y(); + aRect.Bottom() += nLineHeight; + + pView->GetWindow()->Invalidate( aRect ); + pView = aViewList.Next(); + } +} + +ULONG Outliner::Read( SvStream& rInput, const String& rBaseURL, USHORT eFormat, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ + DBG_CHKTHIS(Outliner,0); + + BOOL bOldUndo = pEditEngine->IsUndoEnabled(); + EnableUndo( FALSE ); + + BOOL bUpdate = pEditEngine->GetUpdateMode(); + pEditEngine->SetUpdateMode( FALSE ); + + Clear(); + + ImplBlockInsertionCallbacks( TRUE ); + ULONG nRet = pEditEngine->Read( rInput, rBaseURL, (EETextFormat)eFormat, pHTTPHeaderAttrs ); + + bFirstParaIsEmpty = FALSE; + + USHORT nParas = pEditEngine->GetParagraphCount(); + pParaList->Clear( TRUE ); + USHORT n; + for ( n = 0; n < nParas; n++ ) + { + Paragraph* pPara = new Paragraph( 0 ); + pParaList->Insert( pPara, LIST_APPEND ); + + if ( eFormat == EE_FORMAT_BIN ) + { + const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( n ); + const SfxInt16Item& rLevel = (const SfxInt16Item&) rAttrs.Get( EE_PARA_OUTLLEVEL ); + sal_Int16 nDepth = rLevel.GetValue(); + ImplInitDepth( n, nDepth, FALSE ); + } + } + + if ( eFormat != EE_FORMAT_BIN ) + { + ImpFilterIndents( 0, nParas-1 ); + } + + ImplBlockInsertionCallbacks( FALSE ); + pEditEngine->SetUpdateMode( bUpdate ); + EnableUndo( bOldUndo ); + + return nRet; +} + + +void Outliner::ImpFilterIndents( ULONG nFirstPara, ULONG nLastPara ) +{ + DBG_CHKTHIS(Outliner,0); + + BOOL bUpdate = pEditEngine->GetUpdateMode(); + pEditEngine->SetUpdateMode( FALSE ); + + Paragraph* pLastConverted = NULL; + for( ULONG nPara = nFirstPara; nPara <= nLastPara; nPara++ ) + { + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if (pPara) + { + if( ImpConvertEdtToOut( nPara ) ) + { + pLastConverted = pPara; + } + else if ( pLastConverted ) + { + // Normale Absaetze unter der Ueberschrift anordnen... + pPara->SetDepth( pLastConverted->GetDepth() ); + } + + ImplInitDepth( (USHORT)nPara, pPara->GetDepth(), FALSE ); + } + } + + pEditEngine->SetUpdateMode( bUpdate ); +} + +SfxUndoManager& Outliner::GetUndoManager() +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetUndoManager(); +} + +void Outliner::ImpTextPasted( ULONG nStartPara, USHORT nCount ) +{ + DBG_CHKTHIS(Outliner,0); + + BOOL bUpdate = pEditEngine->GetUpdateMode(); + pEditEngine->SetUpdateMode( FALSE ); + + const ULONG nStart = nStartPara; + + Paragraph* pPara = pParaList->GetParagraph( nStartPara ); +// Paragraph* pLastConverted = NULL; +// bool bFirst = true; + + while( nCount && pPara ) + { + if( ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT ) + { + nDepthChangedHdlPrevDepth = pPara->GetDepth(); + mnDepthChangeHdlPrevFlags = pPara->nFlags; + + ImpConvertEdtToOut( nStartPara ); + + pHdlParagraph = pPara; + + if( nStartPara == nStart ) + { + // the existing paragraph has changed depth or flags + if( (pPara->GetDepth() != nDepthChangedHdlPrevDepth) || (pPara->nFlags != mnDepthChangeHdlPrevFlags) ) + DepthChangedHdl(); + } + } + else // EditEngine-Modus + { + sal_Int16 nDepth = -1; + const SfxItemSet& rAttrs = pEditEngine->GetParaAttribs( (USHORT)nStartPara ); + if ( rAttrs.GetItemState( EE_PARA_OUTLLEVEL ) == SFX_ITEM_ON ) + { + const SfxInt16Item& rLevel = (const SfxInt16Item&) rAttrs.Get( EE_PARA_OUTLLEVEL ); + nDepth = rLevel.GetValue(); + } + if ( nDepth != GetDepth( nStartPara ) ) + ImplInitDepth( (USHORT)nStartPara, nDepth, FALSE ); + } + + nCount--; + nStartPara++; + pPara = pParaList->GetParagraph( nStartPara ); + } + + pEditEngine->SetUpdateMode( bUpdate ); + + DBG_ASSERT(pParaList->GetParagraphCount()==pEditEngine->GetParagraphCount(),"ImpTextPasted failed"); +} + +long Outliner::IndentingPagesHdl( OutlinerView* pView ) +{ + DBG_CHKTHIS(Outliner,0); + if( !aIndentingPagesHdl.IsSet() ) + return 1; + return aIndentingPagesHdl.Call( pView ); +} + +BOOL Outliner::ImpCanIndentSelectedPages( OutlinerView* pCurView ) +{ + DBG_CHKTHIS(Outliner,0); + // Die selektierten Seiten muessen vorher durch ImpCalcSelectedPages + // schon eingestellt sein + + // Wenn der erste Absatz auf Ebene 0 liegt darf er auf keinen Fall + // eingerueckt werden, evtl folgen aber weitere auf Ebene 0. + if ( ( mnFirstSelPage == 0 ) && ( ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT ) ) + { + if ( nDepthChangedHdlPrevDepth == 1 ) // ist die einzige Seite + return FALSE; + else + pCurView->ImpCalcSelectedPages( FALSE ); // ohne die erste + } + return (BOOL)IndentingPagesHdl( pCurView ); +} + + +BOOL Outliner::ImpCanDeleteSelectedPages( OutlinerView* pCurView ) +{ + DBG_CHKTHIS(Outliner,0); + // Die selektierten Seiten muessen vorher durch ImpCalcSelectedPages + // schon eingestellt sein + return (BOOL)RemovingPagesHdl( pCurView ); +} + +Outliner::Outliner( SfxItemPool* pPool, USHORT nMode ) +: nMinDepth( -1 ) +{ + DBG_CTOR( Outliner, 0 ); + + bStrippingPortions = FALSE; + bPasting = FALSE; + + nFirstPage = 1; + bBlockInsCallback = FALSE; + + nMaxDepth = 9; + + pParaList = new ParagraphList; + pParaList->SetVisibleStateChangedHdl( LINK( this, Outliner, ParaVisibleStateChangedHdl ) ); + Paragraph* pPara = new Paragraph( 0 ); + pParaList->Insert( pPara, LIST_APPEND ); + bFirstParaIsEmpty = TRUE; + + pEditEngine = new OutlinerEditEng( this, pPool ); + pEditEngine->SetBeginMovingParagraphsHdl( LINK( this, Outliner, BeginMovingParagraphsHdl ) ); + pEditEngine->SetEndMovingParagraphsHdl( LINK( this, Outliner, EndMovingParagraphsHdl ) ); + pEditEngine->SetBeginPasteOrDropHdl( LINK( this, Outliner, BeginPasteOrDropHdl ) ); + pEditEngine->SetEndPasteOrDropHdl( LINK( this, Outliner, EndPasteOrDropHdl ) ); + + Init( nMode ); +} + +Outliner::~Outliner() +{ + DBG_DTOR(Outliner,0); + + pParaList->Clear( TRUE ); + delete pParaList; + delete pEditEngine; +} + +ULONG Outliner::InsertView( OutlinerView* pView, ULONG nIndex ) +{ + DBG_CHKTHIS(Outliner,0); + + aViewList.Insert( pView, nIndex ); + pEditEngine->InsertView( pView->pEditView, (USHORT)nIndex ); + return aViewList.GetPos( pView ); +} + +OutlinerView* Outliner::RemoveView( OutlinerView* pView ) +{ + DBG_CHKTHIS(Outliner,0); + + ULONG nPos = aViewList.GetPos( pView ); + if ( nPos != LIST_ENTRY_NOTFOUND ) + { + pView->pEditView->HideCursor(); // HACK wg. BugId 10006 + pEditEngine->RemoveView( pView->pEditView ); + aViewList.Remove( nPos ); + } + return NULL; // MT: return ueberfluessig +} + +OutlinerView* Outliner::RemoveView( ULONG nIndex ) +{ + DBG_CHKTHIS(Outliner,0); + + EditView* pEditView = pEditEngine->GetView( (USHORT)nIndex ); + pEditView->HideCursor(); // HACK wg. BugId 10006 + + pEditEngine->RemoveView( (USHORT)nIndex ); + aViewList.Remove( nIndex ); + return NULL; // MT: return ueberfluessig +} + + +OutlinerView* Outliner::GetView( ULONG nIndex ) const +{ + DBG_CHKTHIS(Outliner,0); + return aViewList.GetObject( nIndex ); +} + +ULONG Outliner::GetViewCount() const +{ + DBG_CHKTHIS(Outliner,0); + return aViewList.Count(); +} + +void Outliner::ParagraphInsertedHdl() +{ + DBG_CHKTHIS(Outliner,0); + if( !IsInUndo() ) + aParaInsertedHdl.Call( this ); +} + + +void Outliner::ParagraphRemovingHdl() +{ + DBG_CHKTHIS(Outliner,0); + if( !IsInUndo() ) + aParaRemovingHdl.Call( this ); +} + + +void Outliner::DepthChangedHdl() +{ + DBG_CHKTHIS(Outliner,0); + if( !IsInUndo() ) + aDepthChangedHdl.Call( this ); +} + + +ULONG Outliner::GetAbsPos( Paragraph* pPara ) +{ + DBG_CHKTHIS(Outliner,0); + DBG_ASSERT(pPara,"GetAbsPos:No Para"); + return pParaList->GetAbsPos( pPara ); +} + +ULONG Outliner::GetParagraphCount() const +{ + DBG_CHKTHIS(Outliner,0); + return pParaList->GetParagraphCount(); +} + +Paragraph* Outliner::GetParagraph( ULONG nAbsPos ) const +{ + DBG_CHKTHIS(Outliner,0); + return pParaList->GetParagraph( nAbsPos ); +} + +BOOL Outliner::HasChilds( Paragraph* pParagraph ) const +{ + DBG_CHKTHIS(Outliner,0); + return pParaList->HasChilds( pParagraph ); +} + +BOOL Outliner::ImplHasBullet( USHORT nPara ) const +{ + return GetNumberFormat(nPara) != 0; +} + +const SvxNumberFormat* Outliner::GetNumberFormat( USHORT nPara ) const +{ + const SvxNumberFormat* pFmt = NULL; + + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if (pPara == NULL) + return NULL; + + sal_Int16 nDepth = pPara? pPara->GetDepth() : -1; + + if( nDepth >= 0 ) + { + const SvxNumBulletItem& rNumBullet = (const SvxNumBulletItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_NUMBULLET ); + if ( rNumBullet.GetNumRule()->GetLevelCount() > nDepth ) + pFmt = rNumBullet.GetNumRule()->Get( nDepth ); + } + + return pFmt; +} + +Size Outliner::ImplGetBulletSize( USHORT nPara ) +{ + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if (!pPara) + return Size(); + + if( pPara->aBulSize.Width() == -1 ) + { + const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); + DBG_ASSERT( pFmt, "ImplGetBulletSize - no Bullet!" ); + + if ( pFmt->GetNumberingType() == SVX_NUM_NUMBER_NONE ) + { + pPara->aBulSize = Size( 0, 0 ); + } + else if( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) + { + String aBulletText = ImplGetBulletText( nPara ); + OutputDevice* pRefDev = pEditEngine->GetRefDevice(); + Font aBulletFont( ImpCalcBulletFont( nPara ) ); + Font aRefFont( pRefDev->GetFont()); + pRefDev->SetFont( aBulletFont ); + pPara->aBulSize.Width() = pRefDev->GetTextWidth( aBulletText ); + pPara->aBulSize.Height() = pRefDev->GetTextHeight(); + pRefDev->SetFont( aRefFont ); + } + else + { + pPara->aBulSize = OutputDevice::LogicToLogic( pFmt->GetGraphicSize(), MAP_100TH_MM, pEditEngine->GetRefDevice()->GetMapMode() ); + } + } + + return pPara->aBulSize; +} + +void Outliner::ImplCheckParagraphs( USHORT nStart, USHORT nEnd ) +{ + DBG_CHKTHIS( Outliner, 0 ); + + // --> OD 2009-03-10 #i100014# + // assure that the following for-loop does not loop forever + for ( USHORT n = nStart; n < nEnd; n++ ) + // <-- + { + Paragraph* pPara = pParaList->GetParagraph( n ); + if (pPara) + { + pPara->Invalidate(); + ImplCalcBulletText( n, FALSE, FALSE ); + } + } +} + +void Outliner::SetRefDevice( OutputDevice* pRefDev ) +{ + DBG_CHKTHIS(Outliner,0); + pEditEngine->SetRefDevice( pRefDev ); + for ( USHORT n = (USHORT) pParaList->GetParagraphCount(); n; ) + { + Paragraph* pPara = pParaList->GetParagraph( --n ); + pPara->Invalidate(); + } +} + +void Outliner::ParaAttribsChanged( USHORT nPara ) +{ + DBG_CHKTHIS(Outliner,0); + + // Der Outliner hat kein eigenes Undo, wenn Absaetz getrennt/verschmolzen werden. + // Beim ParagraphInserted ist das Attribut EE_PARA_OUTLLEVEL + // ggf. noch nicht eingestellt, dies wird aber benoetigt um die Tiefe + // des Absatzes zu bestimmen. + + if( pEditEngine->IsInUndo() ) + { + if ( pParaList->GetParagraphCount() == pEditEngine->GetParagraphCount() ) + { + Paragraph* pPara = pParaList->GetParagraph( nPara ); + const SfxInt16Item& rLevel = (const SfxInt16Item&) pEditEngine->GetParaAttrib( nPara, EE_PARA_OUTLLEVEL ); + if ( pPara && pPara->GetDepth() != rLevel.GetValue() ) + { + pPara->SetDepth( rLevel.GetValue() ); + ImplCalcBulletText( nPara, TRUE, TRUE ); + } + } + } +} + +void Outliner::StyleSheetChanged( SfxStyleSheet* pStyle ) +{ + DBG_CHKTHIS(Outliner,0); + + // Die EditEngine ruft StyleSheetChanged auch fuer abgeleitete Styles. + // MT: Hier wurde frueher alle Absaetze durch ein ImpRecalcParaAttribs + // gejagt, die die besagte Vorlage haben, warum? + // => Eigentlich kann sich nur die Bullet-Repraesentation aendern... + + USHORT nParas = (USHORT)pParaList->GetParagraphCount(); + for( USHORT nPara = 0; nPara < nParas; nPara++ ) + { + if ( pEditEngine->GetStyleSheet( nPara ) == pStyle ) + { + ImplCheckNumBulletItem( nPara ); + ImplCalcBulletText( nPara, FALSE, FALSE ); + // #97333# EditEngine formats changed paragraphs before calling this method, + // so they are not reformatted now and use wrong bullet indent + pEditEngine->QuickMarkInvalid( ESelection( nPara, 0, nPara, 0 ) ); + } + } +} + +Rectangle Outliner::ImpCalcBulletArea( USHORT nPara, BOOL bAdjust, BOOL bReturnPaperPos ) +{ + // Bullet-Bereich innerhalb des Absatzes... + Rectangle aBulletArea; + + const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); + if ( pFmt ) + { + Point aTopLeft; + Size aBulletSize( ImplGetBulletSize( nPara ) ); + + BOOL bOutlineMode = ( pEditEngine->GetControlWord() & EE_CNTRL_OUTLINER ) != 0; + + // the ODF attribut text:space-before which holds the spacing to add to the left of the label + const short nSpaceBefore = pFmt->GetAbsLSpace() + pFmt->GetFirstLineOffset(); + + const SvxLRSpaceItem& rLR = (const SvxLRSpaceItem&) pEditEngine->GetParaAttrib( nPara, bOutlineMode ? EE_PARA_OUTLLRSPACE : EE_PARA_LRSPACE ); + aTopLeft.X() = rLR.GetTxtLeft() + rLR.GetTxtFirstLineOfst() + nSpaceBefore; + + long nBulletWidth = Max( (long) -rLR.GetTxtFirstLineOfst(), (long) ((-pFmt->GetFirstLineOffset()) + pFmt->GetCharTextDistance()) ); + if ( nBulletWidth < aBulletSize.Width() ) // Bullet macht sich Platz + nBulletWidth = aBulletSize.Width(); + + if ( bAdjust && !bOutlineMode ) + { + // Bei zentriert/rechtsbuendig anpassen + const SvxAdjustItem& rItem = (const SvxAdjustItem&)pEditEngine->GetParaAttrib( nPara, EE_PARA_JUST ); + if ( ( !pEditEngine->IsRightToLeft( nPara ) && ( rItem.GetAdjust() != SVX_ADJUST_LEFT ) ) || + ( pEditEngine->IsRightToLeft( nPara ) && ( rItem.GetAdjust() != SVX_ADJUST_RIGHT ) ) ) + { + aTopLeft.X() = pEditEngine->GetFirstLineStartX( nPara ) - nBulletWidth; + } + } + + // Vertikal: + ParagraphInfos aInfos = pEditEngine->GetParagraphInfos( nPara ); + if ( aInfos.bValid ) + { + aTopLeft.Y() = /* aInfos.nFirstLineOffset + */ // #91076# nFirstLineOffset is already added to the StartPos (PaintBullet) from the EditEngine + aInfos.nFirstLineHeight - aInfos.nFirstLineTextHeight + + aInfos.nFirstLineTextHeight / 2 + - aBulletSize.Height() / 2; + // ggf. lieber auf der Baseline ausgeben... + if( ( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) && ( pFmt->GetNumberingType() != SVX_NUM_CHAR_SPECIAL ) ) + { + Font aBulletFont( ImpCalcBulletFont( nPara ) ); + if ( aBulletFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) + { + OutputDevice* pRefDev = pEditEngine->GetRefDevice(); + Font aOldFont = pRefDev->GetFont(); + pRefDev->SetFont( aBulletFont ); + FontMetric aMetric( pRefDev->GetFontMetric() ); + // Leading der ersten Zeile... + aTopLeft.Y() = /* aInfos.nFirstLineOffset + */ aInfos.nFirstLineMaxAscent; + aTopLeft.Y() -= aMetric.GetAscent(); + pRefDev->SetFont( aOldFont ); + } + } + } + + // Horizontal: + if( pFmt->GetNumAdjust() == SVX_ADJUST_RIGHT ) + { + aTopLeft.X() += nBulletWidth - aBulletSize.Width(); + } + else if( pFmt->GetNumAdjust() == SVX_ADJUST_CENTER ) + { + aTopLeft.X() += ( nBulletWidth - aBulletSize.Width() ) / 2; + } + + if ( aTopLeft.X() < 0 ) // dann draengeln + aTopLeft.X() = 0; + + aBulletArea = Rectangle( aTopLeft, aBulletSize ); + } + if ( bReturnPaperPos ) + { + Size aBulletSize( aBulletArea.GetSize() ); + Point aBulletDocPos( aBulletArea.TopLeft() ); + aBulletDocPos.Y() += pEditEngine->GetDocPosTopLeft( nPara ).Y(); + Point aBulletPos( aBulletDocPos ); + + if ( IsVertical() ) + { + aBulletPos.Y() = aBulletDocPos.X(); + aBulletPos.X() = GetPaperSize().Width() - aBulletDocPos.Y(); + // Rotate: + aBulletPos.X() -= aBulletSize.Height(); + Size aSz( aBulletSize ); + aBulletSize.Width() = aSz.Height(); + aBulletSize.Height() = aSz.Width(); + } + else if ( pEditEngine->IsRightToLeft( nPara ) ) + { + aBulletPos.X() = GetPaperSize().Width() - aBulletDocPos.X() - aBulletSize.Width(); + } + + aBulletArea = Rectangle( aBulletPos, aBulletSize ); + } + return aBulletArea; +} + +void Outliner::ExpandHdl() +{ + DBG_CHKTHIS(Outliner,0); + aExpandHdl.Call( this ); +} + +EBulletInfo Outliner::GetBulletInfo( USHORT nPara ) +{ + EBulletInfo aInfo; + + aInfo.nParagraph = nPara; + aInfo.bVisible = ImplHasBullet( nPara ); + + const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); + aInfo.nType = pFmt ? pFmt->GetNumberingType() : 0; + + if( pFmt ) + { + if( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) + { + aInfo.aText = ImplGetBulletText( nPara ); + + if( pFmt->GetBulletFont() ) + aInfo.aFont = *pFmt->GetBulletFont(); + } + else if ( pFmt->GetBrush()->GetGraphicObject() ) + { + aInfo.aGraphic = pFmt->GetBrush()->GetGraphicObject()->GetGraphic(); + } + } + + if ( aInfo.bVisible ) + { + aInfo.aBounds = ImpCalcBulletArea( nPara, TRUE, TRUE ); + } + + return aInfo; +} + +XubString Outliner::GetText( Paragraph* pParagraph, ULONG nCount ) const +{ + DBG_CHKTHIS(Outliner,0); + + XubString aText; + USHORT nStartPara = (USHORT) pParaList->GetAbsPos( pParagraph ); + for ( USHORT n = 0; n < nCount; n++ ) + { + aText += pEditEngine->GetText( nStartPara + n ); + if ( (n+1) < (USHORT)nCount ) + aText += '\n'; + } + return aText; +} + +void Outliner::Remove( Paragraph* pPara, ULONG nParaCount ) +{ + DBG_CHKTHIS(Outliner,0); + + ULONG nPos = pParaList->GetAbsPos( pPara ); + if( !nPos && ( nParaCount >= pParaList->GetParagraphCount() ) ) + { + Clear(); + } + else + { + for( USHORT n = 0; n < (USHORT)nParaCount; n++ ) + pEditEngine->RemoveParagraph( (USHORT) nPos ); + } +} + +void Outliner::StripPortions() +{ + DBG_CHKTHIS(Outliner,0); + bStrippingPortions = TRUE; + pEditEngine->StripPortions(); + bStrippingPortions = FALSE; +} + +// #101498# +void Outliner::DrawingText( const Point& rStartPos, const XubString& rText, USHORT nTextStart, USHORT nTextLen, const sal_Int32* pDXArray,const SvxFont& rFont, + USHORT nPara, USHORT nIndex, BYTE nRightToLeft, + const EEngineData::WrongSpellVector* pWrongSpellVector, + const SvxFieldData* pFieldData, + bool bEndOfLine, + bool bEndOfParagraph, + bool bEndOfBullet, + const ::com::sun::star::lang::Locale* pLocale, + const Color& rOverlineColor, + const Color& rTextLineColor) +{ + DBG_CHKTHIS(Outliner,0); + + if(aDrawPortionHdl.IsSet()) + { + // #101498# + DrawPortionInfo aInfo( rStartPos, rText, nTextStart, nTextLen, rFont, nPara, nIndex, pDXArray, pWrongSpellVector, + pFieldData, pLocale, rOverlineColor, rTextLineColor, nRightToLeft, bEndOfLine, bEndOfParagraph, bEndOfBullet); + + aDrawPortionHdl.Call( &aInfo ); + } +} + +long Outliner::RemovingPagesHdl( OutlinerView* pView ) +{ + DBG_CHKTHIS(Outliner,0); + return aRemovingPagesHdl.IsSet() ? aRemovingPagesHdl.Call( pView ) : TRUE; +} + +BOOL Outliner::ImpCanDeleteSelectedPages( OutlinerView* pCurView, USHORT _nFirstPage, USHORT nPages ) +{ + DBG_CHKTHIS(Outliner,0); + + nDepthChangedHdlPrevDepth = nPages; + mnFirstSelPage = _nFirstPage; + pHdlParagraph = 0; + return (BOOL)RemovingPagesHdl( pCurView ); +} + +SfxItemSet Outliner::GetParaAttribs( USHORT nPara ) +{ + DBG_CHKTHIS(Outliner,0); + return pEditEngine->GetParaAttribs( nPara ); +} + +IMPL_LINK( Outliner, ParaVisibleStateChangedHdl, Paragraph*, pPara ) +{ + DBG_CHKTHIS(Outliner,0); + + ULONG nPara = pParaList->GetAbsPos( pPara ); + pEditEngine->ShowParagraph( (USHORT)nPara, pPara->IsVisible() ); + + return 0; +} + +IMPL_LINK( Outliner, BeginMovingParagraphsHdl, MoveParagraphsInfo*, EMPTYARG ) +{ + DBG_CHKTHIS(Outliner,0); + + if( !IsInUndo() ) + GetBeginMovingHdl().Call( this ); + + return 0; +} + +IMPL_LINK( Outliner, BeginPasteOrDropHdl, PasteOrDropInfos*, pInfos ) +{ + UndoActionStart( EDITUNDO_DRAGANDDROP ); + maBeginPasteOrDropHdl.Call(pInfos); + return 0; +} + +IMPL_LINK( Outliner, EndPasteOrDropHdl, PasteOrDropInfos*, pInfos ) +{ + bPasting = FALSE; + ImpTextPasted( pInfos->nStartPara, pInfos->nEndPara - pInfos->nStartPara + 1 ); + maEndPasteOrDropHdl.Call( pInfos ); + UndoActionEnd( EDITUNDO_DRAGANDDROP ); + return 0; +} + +IMPL_LINK( Outliner, EndMovingParagraphsHdl, MoveParagraphsInfo*, pInfos ) +{ + DBG_CHKTHIS(Outliner,0); + + pParaList->MoveParagraphs( pInfos->nStartPara, pInfos->nDestPara, pInfos->nEndPara - pInfos->nStartPara + 1 ); + USHORT nChangesStart = Min( pInfos->nStartPara, pInfos->nDestPara ); + USHORT nParas = (USHORT)pParaList->GetParagraphCount(); + for ( USHORT n = nChangesStart; n < nParas; n++ ) + ImplCalcBulletText( n, FALSE, FALSE ); + + if( !IsInUndo() ) + aEndMovingHdl.Call( this ); + + return 0; +} + +static bool isSameNumbering( const SvxNumberFormat& rN1, const SvxNumberFormat& rN2 ) +{ + if( rN1.GetNumberingType() != rN2.GetNumberingType() ) + return false; + + if( rN1.GetNumStr(1) != rN2.GetNumStr(1) ) + return false; + + if( (rN1.GetPrefix() != rN2.GetPrefix()) || (rN1.GetSuffix() != rN2.GetSuffix()) ) + return false; + + return true; +} + +sal_uInt16 Outliner::ImplGetNumbering( USHORT nPara, const SvxNumberFormat* pParaFmt ) +{ + sal_uInt16 nNumber = pParaFmt->GetStart() - 1; + + Paragraph* pPara = pParaList->GetParagraph( nPara ); + const sal_Int16 nParaDepth = pPara->GetDepth(); + + do + { + pPara = pParaList->GetParagraph( nPara ); + const sal_Int16 nDepth = pPara->GetDepth(); + + // ignore paragraphs that are below our paragraph or have no numbering + if( (nDepth > nParaDepth) || (nDepth == -1) ) + continue; + + // stop on paragraphs that are above our paragraph + if( nDepth < nParaDepth ) + break; + + const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); + + if( pFmt == 0 ) + continue; // ignore paragraphs without bullets + + // check if numbering is the same + if( !isSameNumbering( *pFmt, *pParaFmt ) ) + break; + + const SfxBoolItem& rBulletState = (const SfxBoolItem&) pEditEngine->GetParaAttrib( nPara, EE_PARA_BULLETSTATE ); + + if( rBulletState.GetValue() ) + nNumber += 1; + + // same depth, same number format, check for restart + const sal_Int16 nNumberingStartValue = pPara->GetNumberingStartValue(); + if( (nNumberingStartValue != -1) || pPara->IsParaIsNumberingRestart() ) + { + if( nNumberingStartValue != -1 ) + nNumber += nNumberingStartValue - 1; + break; + } + } + while( nPara-- ); + + return nNumber; +} + +void Outliner::ImplCalcBulletText( USHORT nPara, BOOL bRecalcLevel, BOOL bRecalcChilds ) +{ + DBG_CHKTHIS(Outliner,0); + + Paragraph* pPara = pParaList->GetParagraph( nPara ); + USHORT nRelPos = 0xFFFF; + + while ( pPara ) + { + XubString aBulletText; + const SvxNumberFormat* pFmt = GetNumberFormat( nPara ); + if( pFmt && ( pFmt->GetNumberingType() != SVX_NUM_BITMAP ) ) + { + aBulletText += pFmt->GetPrefix(); + if( pFmt->GetNumberingType() == SVX_NUM_CHAR_SPECIAL ) + { + aBulletText += pFmt->GetBulletChar(); + } + else if( pFmt->GetNumberingType() != SVX_NUM_NUMBER_NONE ) + { + aBulletText += pFmt->GetNumStr( ImplGetNumbering( nPara, pFmt ) ); + } + aBulletText += pFmt->GetSuffix(); + } + + if( aBulletText != pPara->GetText() ) + pPara->SetText( aBulletText ); + + pPara->nFlags &= (~PARAFLAG_SETBULLETTEXT); + + if ( bRecalcLevel ) + { + if ( nRelPos != 0xFFFF ) + nRelPos++; + + sal_Int16 nDepth = pPara->GetDepth(); + pPara = pParaList->GetParagraph( ++nPara ); + if ( !bRecalcChilds ) + { + while ( pPara && ( pPara->GetDepth() > nDepth ) ) + pPara = pParaList->GetParagraph( ++nPara ); + } + + if ( pPara && ( pPara->GetDepth() < nDepth ) ) + pPara = NULL; + } + else + { + pPara = NULL; + } + } +} + +void Outliner::Clear() +{ + DBG_CHKTHIS(Outliner,0); + + if( !bFirstParaIsEmpty ) + { + ImplBlockInsertionCallbacks( TRUE ); + pEditEngine->Clear(); + pParaList->Clear( TRUE ); + pParaList->Insert( new Paragraph( nMinDepth ), LIST_APPEND ); + bFirstParaIsEmpty = TRUE; + ImplBlockInsertionCallbacks( FALSE ); + } + else + { + Paragraph* pPara = pParaList->GetParagraph( 0 ); + if(pPara) + pPara->SetDepth( nMinDepth ); + } +} + +void Outliner::SetFlatMode( BOOL bFlat ) +{ + DBG_CHKTHIS(Outliner,0); + + if( bFlat != pEditEngine->IsFlatMode() ) + { + for ( USHORT nPara = (USHORT)pParaList->GetParagraphCount(); nPara; ) + pParaList->GetParagraph( --nPara )->aBulSize.Width() = -1; + + pEditEngine->SetFlatMode( bFlat ); + } +} + +String Outliner::ImplGetBulletText( USHORT nPara ) +{ + String aRes; + Paragraph* pPara = pParaList->GetParagraph( nPara ); + if (pPara) + { + // MT: Optimierung mal wieder aktivieren... +// if( pPara->nFlags & PARAFLAG_SETBULLETTEXT ) + ImplCalcBulletText( nPara, FALSE, FALSE ); + aRes = pPara->GetText(); + } + return aRes; +} + +// this is needed for StarOffice Api +void Outliner::SetLevelDependendStyleSheet( USHORT nPara ) +{ + SfxItemSet aOldAttrs( pEditEngine->GetParaAttribs( nPara ) ); + ImplSetLevelDependendStyleSheet( nPara ); + pEditEngine->SetParaAttribs( nPara, aOldAttrs ); +} + +SV_IMPL_PTRARR( NotifyList, EENotifyPtr ); + +void Outliner::ImplBlockInsertionCallbacks( BOOL b ) +{ + if ( b ) + { + bBlockInsCallback++; + } + else + { + DBG_ASSERT( bBlockInsCallback, "ImplBlockInsertionCallbacks ?!" ); + bBlockInsCallback--; + if ( !bBlockInsCallback ) + { + // Call blocked notify events... + while ( pEditEngine->aNotifyCache.Count() ) + { + EENotify* pNotify = pEditEngine->aNotifyCache[0]; + // Remove from list before calling, maybe we enter LeaveBlockNotifications while calling the handler... + pEditEngine->aNotifyCache.Remove( 0 ); + pEditEngine->aOutlinerNotifyHdl.Call( pNotify ); + delete pNotify; + } + } + } +} + +IMPL_LINK( Outliner, EditEngineNotifyHdl, EENotify*, pNotify ) +{ + if ( !bBlockInsCallback ) + { + pEditEngine->aOutlinerNotifyHdl.Call( pNotify ); + } + else + { + EENotify* pNewNotify = new EENotify( *pNotify ); + pEditEngine->aNotifyCache.Insert( pNewNotify, pEditEngine->aNotifyCache.Count() ); + } + + return 0; +} + +/** sets a link that is called at the beginning of a drag operation at an edit view */ +void Outliner::SetBeginDropHdl( const Link& rLink ) +{ + pEditEngine->SetBeginDropHdl( rLink ); +} + +Link Outliner::GetBeginDropHdl() const +{ + return pEditEngine->GetBeginDropHdl(); +} + +/** sets a link that is called at the end of a drag operation at an edit view */ +void Outliner::SetEndDropHdl( const Link& rLink ) +{ + pEditEngine->SetEndDropHdl( rLink ); +} + +Link Outliner::GetEndDropHdl() const +{ + return pEditEngine->GetEndDropHdl(); +} + +/** sets a link that is called before a drop or paste operation. */ +void Outliner::SetBeginPasteOrDropHdl( const Link& rLink ) +{ + maBeginPasteOrDropHdl = rLink; +} + +/** sets a link that is called after a drop or paste operation. */ +void Outliner::SetEndPasteOrDropHdl( const Link& rLink ) +{ + maEndPasteOrDropHdl = rLink; +} + +void Outliner::SetParaFlag( Paragraph* pPara, sal_uInt16 nFlag ) +{ + if( pPara && !pPara->HasFlag( nFlag ) ) + { + if( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new OutlinerUndoChangeParaFlags( this, (sal_uInt16)GetAbsPos( pPara ), pPara->nFlags, pPara->nFlags|nFlag ) ); + + pPara->SetFlag( nFlag ); + } +} + +void Outliner::RemoveParaFlag( Paragraph* pPara, sal_uInt16 nFlag ) +{ + if( pPara && pPara->HasFlag( nFlag ) ) + { + if( IsUndoEnabled() && !IsInUndo() ) + InsertUndo( new OutlinerUndoChangeParaFlags( this, (sal_uInt16)GetAbsPos( pPara ), pPara->nFlags, pPara->nFlags & ~nFlag ) ); + + pPara->RemoveFlag( nFlag ); + } +} + +bool Outliner::HasParaFlag( const Paragraph* pPara, sal_uInt16 nFlag ) const +{ + return pPara && pPara->HasFlag( nFlag ); +} + + +sal_Bool DrawPortionInfo::IsRTL() const +{ + if(0xFF == mnBiDiLevel) + { + // Use Bidi functions from icu 2.0 to calculate if this portion + // is RTL or not. + UErrorCode nError(U_ZERO_ERROR); + UBiDi* pBidi = ubidi_openSized(mrText.Len(), 0, &nError); + nError = U_ZERO_ERROR; + + // I do not have this info here. Is it necessary? I'll have to ask MT. + const BYTE nDefaultDir = UBIDI_LTR; //IsRightToLeft( nPara ) ? UBIDI_RTL : UBIDI_LTR; + + ubidi_setPara(pBidi, reinterpret_cast<const UChar *>(mrText.GetBuffer()), mrText.Len(), nDefaultDir, NULL, &nError); // UChar != sal_Unicode in MinGW + nError = U_ZERO_ERROR; + +// sal_Int32 nCount(ubidi_countRuns(pBidi, &nError)); + + int32_t nStart(0); + int32_t nEnd; + UBiDiLevel nCurrDir; + + ubidi_getLogicalRun(pBidi, nStart, &nEnd, &nCurrDir); + + ubidi_close(pBidi); + + // remember on-demand calculated state + ((DrawPortionInfo*)this)->mnBiDiLevel = nCurrDir; + } + + return (1 == (mnBiDiLevel % 2)); +} + +// eof diff --git a/editeng/source/outliner/outliner.src b/editeng/source/outliner/outliner.src new file mode 100644 index 000000000000..eac8f3e5ad4a --- /dev/null +++ b/editeng/source/outliner/outliner.src @@ -0,0 +1,87 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outliner.src,v $ + * $Revision: 1.20 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <editeng/editrids.hrc> + +String RID_OUTLUNDO_HEIGHT +{ + Text [ en-US ] = "Move" ; +}; +String RID_OUTLUNDO_DEPTH +{ + Text [ en-US ] = "Indent" ; +}; +String RID_OUTLUNDO_EXPAND +{ + Text [ en-US ] = "Show subpoints" ; +}; +String RID_OUTLUNDO_COLLAPSE +{ + Text [ en-US ] = "Collapse" ; +}; +String RID_OUTLUNDO_ATTR +{ + Text [ en-US ] = "Apply attributes" ; +}; +String RID_OUTLUNDO_INSERT +{ + Text [ en-US ] = "Insert" ; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/editeng/source/outliner/outlobj.cxx b/editeng/source/outliner/outlobj.cxx new file mode 100644 index 000000000000..98d050268b70 --- /dev/null +++ b/editeng/source/outliner/outlobj.cxx @@ -0,0 +1,274 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outlobj.cxx,v $ + * $Revision: 1.12.78.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <outl_pch.hxx> + +#define _OUTLINER_CXX +#include <editeng/outliner.hxx> +#include <editeng/outlobj.hxx> +#include <outleeng.hxx> +#include <editeng/editobj.hxx> +#include <vcl/bitmap.hxx> +#include <tools/stream.hxx> + +////////////////////////////////////////////////////////////////////////////// + +class ImplOutlinerParaObject +{ +public: + // data members + EditTextObject* mpEditTextObject; + ParagraphDataVector maParagraphDataVector; + bool mbIsEditDoc; + + // refcounter + sal_uInt32 mnRefCount; + + // constuctor + ImplOutlinerParaObject(EditTextObject* pEditTextObject, const ParagraphDataVector& rParagraphDataVector, bool bIsEditDoc) + : mpEditTextObject(pEditTextObject), + maParagraphDataVector(rParagraphDataVector), + mbIsEditDoc(bIsEditDoc), + mnRefCount(0) + { + if( (maParagraphDataVector.size() == 0) && (pEditTextObject->GetParagraphCount() != 0) ) + maParagraphDataVector.resize(pEditTextObject->GetParagraphCount()); + } + + // destructor + ~ImplOutlinerParaObject() + { + delete mpEditTextObject; + } + + bool operator==(const ImplOutlinerParaObject& rCandidate) const + { + return (*mpEditTextObject == *rCandidate.mpEditTextObject + && maParagraphDataVector == rCandidate.maParagraphDataVector + && mbIsEditDoc == rCandidate.mbIsEditDoc); + } + + // #i102062# + bool isWrongListEqual(const ImplOutlinerParaObject& rCompare) const + { + return mpEditTextObject->isWrongListEqual(*rCompare.mpEditTextObject); + } +}; + +////////////////////////////////////////////////////////////////////////////// + +void OutlinerParaObject::ImplMakeUnique() +{ + if(mpImplOutlinerParaObject->mnRefCount) + { + ImplOutlinerParaObject* pNew = new ImplOutlinerParaObject( + mpImplOutlinerParaObject->mpEditTextObject->Clone(), + mpImplOutlinerParaObject->maParagraphDataVector, + mpImplOutlinerParaObject->mbIsEditDoc); + mpImplOutlinerParaObject->mnRefCount--; + mpImplOutlinerParaObject = pNew; + } +} + +OutlinerParaObject::OutlinerParaObject(const EditTextObject& rEditTextObject, const ParagraphDataVector& rParagraphDataVector, bool bIsEditDoc) +: mpImplOutlinerParaObject(new ImplOutlinerParaObject(rEditTextObject.Clone(), rParagraphDataVector, bIsEditDoc)) +{ +} + +OutlinerParaObject::OutlinerParaObject(const OutlinerParaObject& rCandidate) +: mpImplOutlinerParaObject(rCandidate.mpImplOutlinerParaObject) +{ + mpImplOutlinerParaObject->mnRefCount++; +} + +OutlinerParaObject::~OutlinerParaObject() +{ + if(mpImplOutlinerParaObject->mnRefCount) + { + mpImplOutlinerParaObject->mnRefCount--; + } + else + { + delete mpImplOutlinerParaObject; + } +} + +OutlinerParaObject& OutlinerParaObject::operator=(const OutlinerParaObject& rCandidate) +{ + if(rCandidate.mpImplOutlinerParaObject != mpImplOutlinerParaObject) + { + if(mpImplOutlinerParaObject->mnRefCount) + { + mpImplOutlinerParaObject->mnRefCount--; + } + else + { + delete mpImplOutlinerParaObject; + } + + mpImplOutlinerParaObject = rCandidate.mpImplOutlinerParaObject; + mpImplOutlinerParaObject->mnRefCount++; + } + + return *this; +} + +bool OutlinerParaObject::operator==(const OutlinerParaObject& rCandidate) const +{ + if(rCandidate.mpImplOutlinerParaObject == mpImplOutlinerParaObject) + { + return true; + } + + return (*rCandidate.mpImplOutlinerParaObject == *mpImplOutlinerParaObject); +} + +// #i102062# +bool OutlinerParaObject::isWrongListEqual(const OutlinerParaObject& rCompare) const +{ + if(rCompare.mpImplOutlinerParaObject == mpImplOutlinerParaObject) + { + return true; + } + + return mpImplOutlinerParaObject->isWrongListEqual(*rCompare.mpImplOutlinerParaObject); +} + +sal_uInt16 OutlinerParaObject::GetOutlinerMode() const +{ + return mpImplOutlinerParaObject->mpEditTextObject->GetUserType(); +} + +void OutlinerParaObject::SetOutlinerMode(sal_uInt16 nNew) +{ + if(mpImplOutlinerParaObject->mpEditTextObject->GetUserType() != nNew) + { + ImplMakeUnique(); + mpImplOutlinerParaObject->mpEditTextObject->SetUserType(nNew); + } +} + +bool OutlinerParaObject::IsVertical() const +{ + return mpImplOutlinerParaObject->mpEditTextObject->IsVertical(); +} + +void OutlinerParaObject::SetVertical(bool bNew) +{ + if((bool)mpImplOutlinerParaObject->mpEditTextObject->IsVertical() != bNew) + { + ImplMakeUnique(); + mpImplOutlinerParaObject->mpEditTextObject->SetVertical(bNew); + } +} + +sal_uInt32 OutlinerParaObject::Count() const +{ + return mpImplOutlinerParaObject->maParagraphDataVector.size(); +} + +sal_Int16 OutlinerParaObject::GetDepth(sal_uInt16 nPara) const +{ + if(nPara < mpImplOutlinerParaObject->maParagraphDataVector.size()) + { + return mpImplOutlinerParaObject->maParagraphDataVector[nPara].getDepth(); + } + else + { + return -1; + } +} + +const EditTextObject& OutlinerParaObject::GetTextObject() const +{ + return *mpImplOutlinerParaObject->mpEditTextObject; +} + +bool OutlinerParaObject::IsEditDoc() const +{ + return mpImplOutlinerParaObject->mbIsEditDoc; +} + +const ParagraphData& OutlinerParaObject::GetParagraphData(sal_uInt32 nIndex) const +{ + if(nIndex < mpImplOutlinerParaObject->maParagraphDataVector.size()) + { + return mpImplOutlinerParaObject->maParagraphDataVector[nIndex]; + } + else + { + OSL_ENSURE(false, "OutlinerParaObject::GetParagraphData: Access out of range (!)"); + static ParagraphData aEmptyParagraphData; + return aEmptyParagraphData; + } +} + +void OutlinerParaObject::ClearPortionInfo() +{ + ImplMakeUnique(); + mpImplOutlinerParaObject->mpEditTextObject->ClearPortionInfo(); +} + +bool OutlinerParaObject::ChangeStyleSheets(const XubString& rOldName, SfxStyleFamily eOldFamily, const XubString& rNewName, SfxStyleFamily eNewFamily) +{ + ImplMakeUnique(); + return mpImplOutlinerParaObject->mpEditTextObject->ChangeStyleSheets(rOldName, eOldFamily, rNewName, eNewFamily); +} + +void OutlinerParaObject::ChangeStyleSheetName(SfxStyleFamily eFamily, const XubString& rOldName, const XubString& rNewName) +{ + ImplMakeUnique(); + mpImplOutlinerParaObject->mpEditTextObject->ChangeStyleSheetName(eFamily, rOldName, rNewName); +} + +void OutlinerParaObject::SetStyleSheets(sal_uInt16 nLevel, const XubString rNewName, const SfxStyleFamily& rNewFamily) +{ + const sal_uInt32 nCount(mpImplOutlinerParaObject->maParagraphDataVector.size()); + + if(nCount) + { + ImplMakeUnique(); + sal_uInt16 nDecrementer(sal::static_int_cast< sal_uInt16 >(nCount)); + + for(;nDecrementer;) + { + if(GetDepth(--nDecrementer) == nLevel) + { + mpImplOutlinerParaObject->mpEditTextObject->SetStyleSheet(nDecrementer, rNewName, rNewFamily); + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/editeng/source/outliner/outlundo.cxx b/editeng/source/outliner/outlundo.cxx new file mode 100644 index 000000000000..9c87576a92b8 --- /dev/null +++ b/editeng/source/outliner/outlundo.cxx @@ -0,0 +1,237 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outlundo.cxx,v $ + * $Revision: 1.9 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <svl/intitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/editdata.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/fhgtitem.hxx> + +#define _OUTLINER_CXX +#include <editeng/outliner.hxx> +#include <outlundo.hxx> + + +OutlinerUndoBase::OutlinerUndoBase( USHORT _nId, Outliner* pOutliner ) + : EditUndo( _nId, NULL ) +{ + DBG_ASSERT( pOutliner, "Undo: Outliner?!" ); + mpOutliner = pOutliner; +} + +OutlinerUndoChangeParaFlags::OutlinerUndoChangeParaFlags( Outliner* pOutliner, sal_uInt16 nPara, sal_uInt16 nOldFlags, sal_uInt16 nNewFlags ) +: OutlinerUndoBase( OLUNDO_DEPTH, pOutliner ) +{ + mnPara = nPara; + mnOldFlags = nOldFlags; + mnNewFlags = nNewFlags; +} + +void OutlinerUndoChangeParaFlags::Undo() +{ + ImplChangeFlags( mnOldFlags ); +} + +void OutlinerUndoChangeParaFlags::Redo() +{ + ImplChangeFlags( mnNewFlags ); +} + +void OutlinerUndoChangeParaFlags::ImplChangeFlags( sal_uInt16 nFlags ) +{ + Outliner* pOutliner = GetOutliner(); + Paragraph* pPara = pOutliner->GetParagraph( mnPara ); + if( pPara ) + { + pOutliner->nDepthChangedHdlPrevDepth = pPara->GetDepth(); + pOutliner->mnDepthChangeHdlPrevFlags = pPara->nFlags; + pOutliner->pHdlParagraph = pPara; + + pPara->nFlags = nFlags; + pOutliner->DepthChangedHdl(); + } +} + +OutlinerUndoChangeParaNumberingRestart::OutlinerUndoChangeParaNumberingRestart( Outliner* pOutliner, sal_uInt16 nPara, + sal_Int16 nOldNumberingStartValue, sal_Int16 nNewNumberingStartValue, + sal_Bool bOldParaIsNumberingRestart, sal_Bool bNewParaIsNumberingRestart ) +: OutlinerUndoBase( OLUNDO_DEPTH, pOutliner ) +{ + mnPara = nPara; + + maUndoData.mnNumberingStartValue = nOldNumberingStartValue; + maUndoData.mbParaIsNumberingRestart = bOldParaIsNumberingRestart; + maRedoData.mnNumberingStartValue = nNewNumberingStartValue; + maRedoData.mbParaIsNumberingRestart = bNewParaIsNumberingRestart; +} + +void OutlinerUndoChangeParaNumberingRestart::Undo() +{ + ImplApplyData( maUndoData ); +} + +void OutlinerUndoChangeParaNumberingRestart::Redo() +{ + ImplApplyData( maRedoData ); +} + +void OutlinerUndoChangeParaNumberingRestart::ImplApplyData( const ParaRestartData& rData ) +{ + Outliner* pOutliner = GetOutliner(); + pOutliner->SetNumberingStartValue( mnPara, rData.mnNumberingStartValue ); + pOutliner->SetParaIsNumberingRestart( mnPara, rData.mbParaIsNumberingRestart ); +} + +OutlinerUndoChangeDepth::OutlinerUndoChangeDepth( Outliner* pOutliner, USHORT nPara, sal_Int16 nOldDepth, sal_Int16 nNewDepth ) + : OutlinerUndoBase( OLUNDO_DEPTH, pOutliner ) +{ + mnPara = nPara; + mnOldDepth = nOldDepth; + mnNewDepth = nNewDepth; +} + +void OutlinerUndoChangeDepth::Undo() +{ + GetOutliner()->ImplInitDepth( mnPara, mnOldDepth, FALSE ); +} + +void OutlinerUndoChangeDepth::Redo() +{ + GetOutliner()->ImplInitDepth( mnPara, mnNewDepth, FALSE ); +} + +void OutlinerUndoChangeDepth::Repeat() +{ + DBG_ERROR( "Repeat not implemented!" ); +} + + +OutlinerUndoCheckPara::OutlinerUndoCheckPara( Outliner* pOutliner, USHORT nPara ) + : OutlinerUndoBase( OLUNDO_DEPTH, pOutliner ) +{ + mnPara = nPara; +} + +void OutlinerUndoCheckPara::Undo() +{ + Paragraph* pPara = GetOutliner()->GetParagraph( mnPara ); + pPara->Invalidate(); + GetOutliner()->ImplCalcBulletText( mnPara, FALSE, FALSE ); +} + +void OutlinerUndoCheckPara::Redo() +{ + Paragraph* pPara = GetOutliner()->GetParagraph( mnPara ); + pPara->Invalidate(); + GetOutliner()->ImplCalcBulletText( mnPara, FALSE, FALSE ); +} + +void OutlinerUndoCheckPara::Repeat() +{ + DBG_ERROR( "Repeat not implemented!" ); +} + +DBG_NAME(OLUndoExpand); + +OLUndoExpand::OLUndoExpand(Outliner* pOut, USHORT _nId ) + : EditUndo( _nId, 0 ) +{ + DBG_CTOR(OLUndoExpand,0); + DBG_ASSERT(pOut,"Undo:No Outliner"); + pOutliner = pOut; + nCount = 0; + pParas = 0; +} + + +OLUndoExpand::~OLUndoExpand() +{ + DBG_DTOR(OLUndoExpand,0); + delete pParas; +} + + +void OLUndoExpand::Restore( BOOL bUndo ) +{ + DBG_CHKTHIS(OLUndoExpand,0); + DBG_ASSERT(pOutliner,"Undo:No Outliner"); + DBG_ASSERT(pOutliner->pEditEngine,"Outliner already deleted"); + Paragraph* pPara; + + BOOL bExpand = FALSE; + USHORT _nId = GetId(); + if((_nId == OLUNDO_EXPAND && !bUndo) || (_nId == OLUNDO_COLLAPSE && bUndo)) + bExpand = TRUE; + if( !pParas ) + { + pPara = pOutliner->GetParagraph( (ULONG)nCount ); + if( bExpand ) + pOutliner->Expand( pPara ); + else + pOutliner->Collapse( pPara ); + } + else + { + for( USHORT nIdx = 0; nIdx < nCount; nIdx++ ) + { + pPara = pOutliner->GetParagraph( (ULONG)(pParas[nIdx]) ); + if( bExpand ) + pOutliner->Expand( pPara ); + else + pOutliner->Collapse( pPara ); + } + } +} + + +void OLUndoExpand::Undo() +{ + DBG_CHKTHIS(OLUndoExpand,0); + Restore( TRUE ); +} + + +void OLUndoExpand::Redo() +{ + DBG_CHKTHIS(OLUndoExpand,0); + Restore( FALSE ); +} + + +void OLUndoExpand::Repeat() +{ + DBG_CHKTHIS(OLUndoExpand,0); + DBG_ERROR("Not implemented"); +} diff --git a/editeng/source/outliner/outlundo.hxx b/editeng/source/outliner/outlundo.hxx new file mode 100644 index 000000000000..5b31e36b1fd2 --- /dev/null +++ b/editeng/source/outliner/outlundo.hxx @@ -0,0 +1,143 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outlundo.hxx,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _OUTLUNDO_HXX +#define _OUTLUNDO_HXX + +#include <editeng/outliner.hxx> +#include <editeng/editdata.hxx> +#include <editeng/editund2.hxx> + +class OutlinerUndoBase : public EditUndo +{ +private: + Outliner* mpOutliner; + +public: + OutlinerUndoBase( USHORT nId, Outliner* pOutliner ); + + Outliner* GetOutliner() const { return mpOutliner; } +}; + +class OutlinerUndoChangeParaFlags : public OutlinerUndoBase +{ +private: + sal_uInt16 mnPara; + sal_uInt16 mnOldFlags; + sal_uInt16 mnNewFlags; + + void ImplChangeFlags( sal_uInt16 nFlags ); + +public: + OutlinerUndoChangeParaFlags( Outliner* pOutliner, sal_uInt16 nPara, sal_uInt16 nOldDepth, sal_uInt16 nNewDepth ); + + virtual void Undo(); + virtual void Redo(); +}; + +class OutlinerUndoChangeParaNumberingRestart : public OutlinerUndoBase +{ +private: + sal_uInt16 mnPara; + + struct ParaRestartData + { + sal_Int16 mnNumberingStartValue; + sal_Bool mbParaIsNumberingRestart; + }; + + ParaRestartData maUndoData; + ParaRestartData maRedoData; + + void ImplApplyData( const ParaRestartData& rData ); +public: + OutlinerUndoChangeParaNumberingRestart( Outliner* pOutliner, sal_uInt16 nPara, + sal_Int16 nOldNumberingStartValue, sal_Int16 mnNewNumberingStartValue, + sal_Bool nOldbParaIsNumberingRestart, sal_Bool nbNewParaIsNumberingRestart ); + + virtual void Undo(); + virtual void Redo(); +}; + +class OutlinerUndoChangeDepth : public OutlinerUndoBase +{ + using SfxUndoAction::Repeat; +private: + USHORT mnPara; + sal_Int16 mnOldDepth; + sal_Int16 mnNewDepth; + +public: + OutlinerUndoChangeDepth( Outliner* pOutliner, USHORT nPara, sal_Int16 nOldDepth, sal_Int16 nNewDepth ); + + virtual void Undo(); + virtual void Redo(); + virtual void Repeat(); +}; + +// Hilfs-Undo: Wenn es fuer eine Aktion keine OutlinerUndoAction gibst, weil +// die EditEngine das handelt, aber z.B. noch das Bullet neu berechnet werden muss. + +class OutlinerUndoCheckPara : public OutlinerUndoBase +{ + using SfxUndoAction::Repeat; +private: + USHORT mnPara; + +public: + OutlinerUndoCheckPara( Outliner* pOutliner, USHORT nPara ); + + virtual void Undo(); + virtual void Redo(); + virtual void Repeat(); +}; + + + +// ------------------------------------- + + +class OLUndoExpand : public EditUndo +{ + using SfxUndoAction::Repeat; + void Restore( BOOL bUndo ); +public: + OLUndoExpand( Outliner* pOut, USHORT nId ); + ~OLUndoExpand(); + virtual void Undo(); + virtual void Redo(); + virtual void Repeat(); + + USHORT* pParas; // 0 == nCount enthaelt Absatznummer + Outliner* pOutliner; + USHORT nCount; +}; + +#endif diff --git a/editeng/source/outliner/outlvw.cxx b/editeng/source/outliner/outlvw.cxx new file mode 100644 index 000000000000..6ac4c3e35e1a --- /dev/null +++ b/editeng/source/outliner/outlvw.cxx @@ -0,0 +1,1675 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: outlvw.cxx,v $ + * $Revision: 1.34.150.2 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <svl/intitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/editdata.hxx> +#include <editeng/eerdll.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <svl/style.hxx> + +#define _OUTLINER_CXX +#include <editeng/outliner.hxx> +#include <outleeng.hxx> +#include <paralist.hxx> +#include <outlundo.hxx> +#include <editeng/outlobj.hxx> +#include <editeng/flditem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/numitem.hxx> +#include <vcl/window.hxx> +#include <svl/itemset.hxx> +#include <editeng/editstat.hxx> + + +// Breite der Randzonen innerhalb derer beim D&D gescrollt wird +#define OL_SCROLL_LRBORDERWIDTHPIX 10 +#define OL_SCROLL_TBBORDERWIDTHPIX 10 + +// Wert, um den Fensterinhalt beim D&D gescrollt wird +#define OL_SCROLL_HOROFFSET 20 /* in % von VisibleSize.Width */ +#define OL_SCROLL_VEROFFSET 20 /* in % von VisibleSize.Height */ + +DBG_NAME(OutlinerView) + + +OutlinerView::OutlinerView( Outliner* pOut, Window* pWin ) +{ + DBG_CTOR( OutlinerView, 0 ); + + pOwner = pOut; + bDDCursorVisible = FALSE; + bInDragMode = FALSE; + nDDScrollLRBorderWidthWin = 0; + nDDScrollTBBorderWidthWin = 0; + pHorTabArrDoc = 0; + + pEditView = new EditView( pOut->pEditEngine, pWin ); + pEditView->SetSelectionMode( EE_SELMODE_TXTONLY ); +} + +OutlinerView::~OutlinerView() +{ + DBG_DTOR(OutlinerView,0); + delete pEditView; +} + +void OutlinerView::Paint( const Rectangle& rRect ) +{ + DBG_CHKTHIS(OutlinerView,0); + + // beim ersten Paint/KeyInput/Drop wird aus einem leeren Outliner ein + // Outliner mit genau einem Absatz + if( pOwner->bFirstParaIsEmpty ) + pOwner->Insert( String() ); + + pEditView->Paint( rRect ); +} + +BOOL OutlinerView::PostKeyEvent( const KeyEvent& rKEvt ) +{ + DBG_CHKTHIS( OutlinerView, 0 ); + + // beim ersten Paint/KeyInput/Drop wird aus einem leeren Outliner ein + // Outliner mit genau einem Absatz + if( pOwner->bFirstParaIsEmpty ) + pOwner->Insert( String() ); + + + BOOL bKeyProcessed = FALSE; + ESelection aSel( pEditView->GetSelection() ); + BOOL bSelection = aSel.HasRange(); + KeyCode aKeyCode = rKEvt.GetKeyCode(); + KeyFuncType eFunc = aKeyCode.GetFunction(); + USHORT nCode = aKeyCode.GetCode(); + BOOL bReadOnly = IsReadOnly(); + + if( bSelection && ( nCode != KEY_TAB ) && EditEngine::DoesKeyChangeText( rKEvt ) ) + { + if ( ImpCalcSelectedPages( FALSE ) && !pOwner->ImpCanDeleteSelectedPages( this ) ) + return TRUE; + } + + if ( eFunc != KEYFUNC_DONTKNOW ) + { + switch ( eFunc ) + { + case KEYFUNC_CUT: + { + if ( !bReadOnly ) + { + Cut(); + bKeyProcessed = TRUE; + } + } + break; + case KEYFUNC_COPY: + { + Copy(); + bKeyProcessed = TRUE; + } + break; + case KEYFUNC_PASTE: + { + if ( !bReadOnly ) + { + PasteSpecial(); + bKeyProcessed = TRUE; + } + } + break; + case KEYFUNC_DELETE: + { + if( !bReadOnly && !bSelection && ( pOwner->ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT ) ) + { + if( aSel.nEndPos == pOwner->pEditEngine->GetTextLen( aSel.nEndPara ) ) + { + Paragraph* pNext = pOwner->pParaList->GetParagraph( aSel.nEndPara+1 ); + if( pNext && pNext->HasFlag(PARAFLAG_ISPAGE) ) + { + if( !pOwner->ImpCanDeleteSelectedPages( this, aSel.nEndPara, 1 ) ) + return FALSE; + } + } + } + } + break; + default: // wird dann evtl. unten bearbeitet. + eFunc = KEYFUNC_DONTKNOW; + } + } + if ( eFunc == KEYFUNC_DONTKNOW ) + { + switch ( nCode ) + { + case KEY_TAB: + { + if ( !bReadOnly && !aKeyCode.IsMod1() && !aKeyCode.IsMod2() ) + { + if ( ( pOwner->ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT ) && + ( pOwner->ImplGetOutlinerMode() != OUTLINERMODE_TITLEOBJECT ) && + ( bSelection || !aSel.nStartPos ) ) + { + Indent( aKeyCode.IsShift() ? (-1) : (+1) ); + bKeyProcessed = TRUE; + } + else if ( ( pOwner->ImplGetOutlinerMode() == OUTLINERMODE_TEXTOBJECT ) && + !bSelection && !aSel.nEndPos && pOwner->ImplHasBullet( aSel.nEndPara ) ) + { + Indent( aKeyCode.IsShift() ? (-1) : (+1) ); + bKeyProcessed = TRUE; + } + } + } + break; + case KEY_BACKSPACE: + { + if( !bReadOnly && !bSelection && aSel.nEndPara && !aSel.nEndPos ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( aSel.nEndPara ); + Paragraph* pPrev = pOwner->pParaList->GetParagraph( aSel.nEndPara-1 ); + if( !pPrev->IsVisible() ) + return TRUE; + if( !pPara->GetDepth() ) + { + if(!pOwner->ImpCanDeleteSelectedPages(this, aSel.nEndPara , 1 ) ) + return TRUE; + } + } + } + break; + case KEY_RETURN: + { + if ( !bReadOnly ) + { + // Sonderbehandlung: Hartes Return am Ende eines Absatzes, + // der eingeklappte Unterabsaetze besitzt + Paragraph* pPara = pOwner->pParaList->GetParagraph( aSel.nEndPara ); + + if( !aKeyCode.IsShift() ) + { + // Nochmal ImpGetCursor ??? + if( !bSelection && + aSel.nEndPos == pOwner->pEditEngine->GetTextLen( aSel.nEndPara ) ) + { + ULONG nChilds = pOwner->pParaList->GetChildCount(pPara); + if( nChilds && !pOwner->pParaList->HasVisibleChilds(pPara)) + { + pOwner->UndoActionStart( OLUNDO_INSERT ); + ULONG nTemp = aSel.nEndPara; + nTemp += nChilds; + nTemp++; // einfuegen ueber naechstem Non-Child + pOwner->Insert( String(),nTemp,pPara->GetDepth()); + // Cursor positionieren + ESelection aTmpSel((USHORT)nTemp,0,(USHORT)nTemp,0); + pEditView->SetSelection( aTmpSel ); + pEditView->ShowCursor( TRUE, TRUE ); + pOwner->UndoActionEnd( OLUNDO_INSERT ); + bKeyProcessed = TRUE; + } + } + } + if( !bKeyProcessed && !bSelection && + !aKeyCode.IsShift() && aKeyCode.IsMod1() && + ( aSel.nEndPos == pOwner->pEditEngine->GetTextLen(aSel.nEndPara) ) ) + { + pOwner->UndoActionStart( OLUNDO_INSERT ); + ULONG nTemp = aSel.nEndPara; + nTemp++; + pOwner->Insert( String(), nTemp, pPara->GetDepth()+1 ); + + // Cursor positionieren + ESelection aTmpSel((USHORT)nTemp,0,(USHORT)nTemp,0); + pEditView->SetSelection( aTmpSel ); + pEditView->ShowCursor( TRUE, TRUE ); + pOwner->UndoActionEnd( OLUNDO_INSERT ); + bKeyProcessed = TRUE; + } + } + } + break; + } + } + + return bKeyProcessed ? TRUE : pEditView->PostKeyEvent( rKEvt ); +} + + +ULONG OutlinerView::ImpCheckMousePos(const Point& rPosPix, MouseTarget& reTarget) +{ + DBG_CHKTHIS(OutlinerView,0); + ULONG nPara = EE_PARA_NOT_FOUND; + + Point aMousePosWin = pEditView->GetWindow()->PixelToLogic( rPosPix ); + if( !pEditView->GetOutputArea().IsInside( aMousePosWin ) ) + { + reTarget = MouseOutside; + } + else + { + reTarget = MouseText; + + Point aPaperPos( aMousePosWin ); + Rectangle aOutArea = pEditView->GetOutputArea(); + Rectangle aVisArea = pEditView->GetVisArea(); + aPaperPos.X() -= aOutArea.Left(); + aPaperPos.X() += aVisArea.Left(); + aPaperPos.Y() -= aOutArea.Top(); + aPaperPos.Y() += aVisArea.Top(); + + BOOL bBullet; + if ( pOwner->IsTextPos( aPaperPos, 0, &bBullet ) ) + { + Point aDocPos = pOwner->GetDocPos( aPaperPos ); + nPara = pOwner->pEditEngine->FindParagraph( aDocPos.Y() ); + + if ( bBullet ) + { + reTarget = MouseBullet; + } + else + { + // Check for hyperlink + const SvxFieldItem* pFieldItem = pEditView->GetField( aMousePosWin ); + if ( pFieldItem && pFieldItem->GetField() && pFieldItem->GetField()->ISA( SvxURLField ) ) + reTarget = MouseHypertext; + } + } + } + return nPara; +} + +BOOL __EXPORT OutlinerView::MouseMove( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(OutlinerView,0); + + if( ( pOwner->ImplGetOutlinerMode() == OUTLINERMODE_TEXTOBJECT ) || pEditView->GetEditEngine()->IsInSelectionMode()) + return pEditView->MouseMove( rMEvt ); + + Point aMousePosWin( pEditView->GetWindow()->PixelToLogic( rMEvt.GetPosPixel() ) ); + if( !pEditView->GetOutputArea().IsInside( aMousePosWin ) ) + return FALSE; + + Pointer aPointer = GetPointer( rMEvt.GetPosPixel() ); + pEditView->GetWindow()->SetPointer( aPointer ); + return pEditView->MouseMove( rMEvt ); +} + + +BOOL __EXPORT OutlinerView::MouseButtonDown( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(OutlinerView,0); + if ( ( pOwner->ImplGetOutlinerMode() == OUTLINERMODE_TEXTOBJECT ) || pEditView->GetEditEngine()->IsInSelectionMode() ) + return pEditView->MouseButtonDown( rMEvt ); + + Point aMousePosWin( pEditView->GetWindow()->PixelToLogic( rMEvt.GetPosPixel() ) ); + if( !pEditView->GetOutputArea().IsInside( aMousePosWin ) ) + return FALSE; + + Pointer aPointer = GetPointer( rMEvt.GetPosPixel() ); + pEditView->GetWindow()->SetPointer( aPointer ); + + MouseTarget eTarget; + ULONG nPara = ImpCheckMousePos( rMEvt.GetPosPixel(), eTarget ); + if ( eTarget == MouseBullet ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + BOOL bHasChilds = (pPara && pOwner->pParaList->HasChilds(pPara)); + if( rMEvt.GetClicks() == 1 ) + { + ULONG nEndPara = nPara; + if ( bHasChilds && pOwner->pParaList->HasVisibleChilds(pPara) ) + nEndPara += pOwner->pParaList->GetChildCount( pPara ); + // umgekehrt rum selektieren, damit EditEngine nicht scrollt + ESelection aSel((USHORT)nEndPara, 0xffff,(USHORT)nPara, 0 ); + pEditView->SetSelection( aSel ); + } + else if( rMEvt.GetClicks() == 2 && bHasChilds ) + ImpToggleExpand( pPara ); + + aDDStartPosPix = rMEvt.GetPosPixel(); + aDDStartPosRef=pEditView->GetWindow()->PixelToLogic( aDDStartPosPix,pOwner->GetRefMapMode()); + return TRUE; + } + + // special case for outliner view in impress, check if double click hits the page icon for toggle + if( (nPara == EE_PARA_NOT_FOUND) && (pOwner->ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEVIEW) && (eTarget == MouseText) && (rMEvt.GetClicks() == 2) ) + { + ESelection aSel( pEditView->GetSelection() ); + nPara = aSel.nStartPara; + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + if( (pPara && pOwner->pParaList->HasChilds(pPara)) && pPara->HasFlag(PARAFLAG_ISPAGE) ) + { + ImpToggleExpand( pPara ); + } + } + return pEditView->MouseButtonDown( rMEvt ); +} + + +BOOL __EXPORT OutlinerView::MouseButtonUp( const MouseEvent& rMEvt ) +{ + DBG_CHKTHIS(OutlinerView,0); + if ( ( pOwner->ImplGetOutlinerMode() == OUTLINERMODE_TEXTOBJECT ) || pEditView->GetEditEngine()->IsInSelectionMode() ) + return pEditView->MouseButtonUp( rMEvt ); + + Point aMousePosWin( pEditView->GetWindow()->PixelToLogic( rMEvt.GetPosPixel() ) ); + if( !pEditView->GetOutputArea().IsInside( aMousePosWin ) ) + return FALSE; + + Pointer aPointer = GetPointer( rMEvt.GetPosPixel() ); + pEditView->GetWindow()->SetPointer( aPointer ); + + return pEditView->MouseButtonUp( rMEvt ); +} + +void OutlinerView::ImpHideDDCursor() +{ + DBG_CHKTHIS(OutlinerView,0); + if ( bDDCursorVisible ) + { + bDDCursorVisible = FALSE; + ImpPaintDDCursor(); + } +} + +void OutlinerView::ImpShowDDCursor() +{ + DBG_CHKTHIS(OutlinerView,0); + if ( !bDDCursorVisible ) + { + bDDCursorVisible = TRUE; + ImpPaintDDCursor(); + } +} + +void OutlinerView::ImpPaintDDCursor() +{ + DBG_CHKTHIS(OutlinerView,0); + + Window* pWindow = pEditView->GetWindow(); + RasterOp eOldOp = pWindow->GetRasterOp(); + pWindow->SetRasterOp( ROP_INVERT ); + + const Color& rOldLineColor = pWindow->GetLineColor(); + pWindow->SetLineColor( Color( COL_BLACK ) ); + + Point aStartPointWin, aEndPointWin; + Rectangle aOutputArWin = pEditView->GetOutputArea(); + Rectangle aVisAreaRef = pEditView->GetVisArea(); + + if( bDDChangingDepth ) + { + aStartPointWin.X() = pHorTabArrDoc[ nDDCurDepth ]; + aStartPointWin.X() += aOutputArWin.Left(); + aStartPointWin.Y() = aOutputArWin.Top(); + aEndPointWin.X() = aStartPointWin.X(); + aEndPointWin.Y() = aOutputArWin.Bottom(); + } + else + { + ULONG nPara = nDDCurPara; + if ( nDDCurPara == LIST_APPEND ) + { + Paragraph* pTemp = pOwner->pParaList->LastVisible(); + nPara = pOwner->pParaList->GetAbsPos( pTemp ); + } + aStartPointWin = pEditView->GetWindowPosTopLeft((USHORT) nPara ); + if ( nDDCurPara == LIST_APPEND ) + { + long nHeight = pOwner->pEditEngine->GetTextHeight((USHORT)nPara ); + aStartPointWin.Y() += nHeight; + } + aStartPointWin.X() = aOutputArWin.Left(); + aEndPointWin.Y() = aStartPointWin.Y(); + aEndPointWin.X() = aOutputArWin.Right(); + } + + pWindow->DrawLine( aStartPointWin, aEndPointWin ); + pWindow->SetLineColor( rOldLineColor ); + pWindow->SetRasterOp( eOldOp ); +} + +// Berechnet, ueber welchem Absatz eingefuegt werden muss + +ULONG OutlinerView::ImpGetInsertionPara( const Point& rPosPixel ) +{ + DBG_CHKTHIS(OutlinerView,0); + ULONG nCurPara = pEditView->GetParagraph( rPosPixel ); + ParagraphList* pParaList = pOwner->pParaList; + + if ( nCurPara == EE_PARA_NOT_FOUND ) + nCurPara = LIST_APPEND; + else + { + Point aPosWin = pEditView->GetWindow()->PixelToLogic( rPosPixel ); + Point aParaPosWin = pEditView->GetWindowPosTopLeft((USHORT)nCurPara); + long nHeightRef = pOwner->pEditEngine->GetTextHeight((USHORT)nCurPara); + long nParaYOffs = aPosWin.Y() - aParaPosWin.Y(); + + if ( nParaYOffs > nHeightRef / 2 ) + { + Paragraph* p = pParaList->GetParagraph( nCurPara ); + p = pParaList->NextVisible( p ); + nCurPara = p ? pParaList->GetAbsPos( p ) : LIST_APPEND; + } + } + return nCurPara; +} + + +void OutlinerView::ImpToggleExpand( Paragraph* pPara ) +{ + DBG_CHKTHIS(OutlinerView,0); + + USHORT nPara = (USHORT) pOwner->pParaList->GetAbsPos( pPara ); + pEditView->SetSelection( ESelection( nPara, 0, nPara, 0 ) ); + ImplExpandOrCollaps( nPara, nPara, !pOwner->pParaList->HasVisibleChilds( pPara ) ); + pEditView->ShowCursor(); +} + + +void OutlinerView::SetOutliner( Outliner* pOutliner ) +{ + DBG_CHKTHIS(OutlinerView,0); + pOwner = pOutliner; + pEditView->SetEditEngine( pOutliner->pEditEngine ); +} + + + +ULONG OutlinerView::Select( Paragraph* pParagraph, BOOL bSelect, + BOOL bWithChilds ) +{ + DBG_CHKTHIS(OutlinerView,0); + + ULONG nPara = pOwner->pParaList->GetAbsPos( pParagraph ); + USHORT nEnd = 0; + if ( bSelect ) + nEnd = 0xffff; + + ULONG nChildCount = 0; + if ( bWithChilds ) + nChildCount = pOwner->pParaList->GetChildCount( pParagraph ); + + ESelection aSel( (USHORT)nPara, 0,(USHORT)(nPara+nChildCount), nEnd ); + pEditView->SetSelection( aSel ); + return nChildCount+1; +} + + +void OutlinerView::SetAttribs( const SfxItemSet& rAttrs ) +{ + DBG_CHKTHIS(OutlinerView,0); + + BOOL bUpdate = pOwner->pEditEngine->GetUpdateMode(); + pOwner->pEditEngine->SetUpdateMode( FALSE ); + + if( !pOwner->IsInUndo() && pOwner->IsUndoEnabled() ) + pOwner->UndoActionStart( OLUNDO_ATTR ); + + ParaRange aSel = ImpGetSelectedParagraphs( FALSE ); + + pEditView->SetAttribs( rAttrs ); + + // Bullet-Texte aktualisieren + for( USHORT nPara= aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + pOwner->ImplCheckNumBulletItem( nPara ); + pOwner->ImplCalcBulletText( nPara, FALSE, FALSE ); + + if( !pOwner->IsInUndo() && pOwner->IsUndoEnabled() ) + pOwner->InsertUndo( new OutlinerUndoCheckPara( pOwner, nPara ) ); + } + + if( !pOwner->IsInUndo() && pOwner->IsUndoEnabled() ) + pOwner->UndoActionEnd( OLUNDO_ATTR ); + + pEditView->SetEditEngineUpdateMode( bUpdate ); +} + +ParaRange OutlinerView::ImpGetSelectedParagraphs( BOOL bIncludeHiddenChilds ) +{ + DBG_CHKTHIS( OutlinerView, 0 ); + + ESelection aSel = pEditView->GetSelection(); + ParaRange aParas( aSel.nStartPara, aSel.nEndPara ); + aParas.Adjust(); + + // unsichtbare Childs des letzten Parents in Selektion mit aufnehmen + if ( bIncludeHiddenChilds ) + { + Paragraph* pLast = pOwner->pParaList->GetParagraph( aParas.nEndPara ); + if ( pOwner->pParaList->HasHiddenChilds( pLast ) ) + aParas.nEndPara = + sal::static_int_cast< USHORT >( + aParas.nEndPara + + pOwner->pParaList->GetChildCount( pLast ) ); + } + return aParas; +} + +// MT: Name sollte mal geaendert werden! +void OutlinerView::AdjustDepth( short nDX ) +{ + Indent( nDX ); +} + +void OutlinerView::Indent( short nDiff ) +{ + DBG_CHKTHIS( OutlinerView, 0 ); + + if( !nDiff || ( ( nDiff > 0 ) && ImpCalcSelectedPages( TRUE ) && !pOwner->ImpCanIndentSelectedPages( this ) ) ) + return; + + const bool bOutlinerView = pOwner->pEditEngine->GetControlWord() & EE_CNTRL_OUTLINER; + BOOL bUpdate = pOwner->pEditEngine->GetUpdateMode(); + pOwner->pEditEngine->SetUpdateMode( FALSE ); + + BOOL bUndo = !pOwner->IsInUndo() && pOwner->IsUndoEnabled(); + + if( bUndo ) + pOwner->UndoActionStart( OLUNDO_DEPTH ); + + sal_Int16 nMinDepth = -1; // Optimierung: Nicht unnoetig viele Absatze neu berechnen + + ParaRange aSel = ImpGetSelectedParagraphs( TRUE ); + for ( USHORT nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + + sal_Int16 nOldDepth = pPara->GetDepth(); + sal_Int16 nNewDepth = nOldDepth + nDiff; + + if( bOutlinerView && nPara ) + { + const bool bPage = pPara->HasFlag(PARAFLAG_ISPAGE); + if( (bPage && (nDiff == +1)) || (!bPage && (nDiff == -1) && (nOldDepth <= 0)) ) + { + // App benachrichtigen + pOwner->nDepthChangedHdlPrevDepth = (sal_Int16)nOldDepth; + pOwner->mnDepthChangeHdlPrevFlags = pPara->nFlags; + pOwner->pHdlParagraph = pPara; + + if( bPage ) + pPara->RemoveFlag( PARAFLAG_ISPAGE ); + else + pPara->SetFlag( PARAFLAG_ISPAGE ); + + pOwner->DepthChangedHdl(); + pOwner->pEditEngine->QuickMarkInvalid( ESelection( nPara, 0, nPara, 0 ) ); + + if( bUndo ) + pOwner->InsertUndo( new OutlinerUndoChangeParaFlags( pOwner, nPara, pOwner->mnDepthChangeHdlPrevFlags, pPara->nFlags ) ); + + continue; + } + } + + // do not switch off numeration with tab + if( (nOldDepth == 0) && (nNewDepth == -1) ) + continue; + + // do not indent if there is no numeration enabled + if( nOldDepth == -1 ) + continue; + + if ( nNewDepth < pOwner->nMinDepth ) + nNewDepth = pOwner->nMinDepth; + if ( nNewDepth > pOwner->nMaxDepth ) + nNewDepth = pOwner->nMaxDepth; + + if( nOldDepth < nMinDepth ) + nMinDepth = nOldDepth; + if( nNewDepth < nMinDepth ) + nMinDepth = nNewDepth; + + if( nOldDepth != nNewDepth ) + { + if ( ( nPara == aSel.nStartPara ) && aSel.nStartPara && ( pOwner->ImplGetOutlinerMode() != OUTLINERMODE_TEXTOBJECT )) + { + // Sonderfall: Der Vorgaenger eines eingerueckten Absatzes ist + // unsichtbar und steht jetzt auf der gleichen Ebene wie der + // sichtbare Absatz. In diesem Fall wird der naechste sichtbare + // Absatz gesucht und aufgeplustert. +#ifdef DBG_UTIL + Paragraph* _pPara = pOwner->pParaList->GetParagraph( aSel.nStartPara ); + DBG_ASSERT(_pPara->IsVisible(),"Selected Paragraph invisible ?!"); +#endif + Paragraph* pPrev= pOwner->pParaList->GetParagraph( aSel.nStartPara-1 ); + + if( !pPrev->IsVisible() && ( pPrev->GetDepth() == nNewDepth ) ) + { + // Vorgaenger ist eingeklappt und steht auf gleicher Ebene + // => naechsten sichtbaren Absatz suchen und expandieren + pPrev = pOwner->pParaList->GetParent( pPrev ); + while( !pPrev->IsVisible() ) + pPrev = pOwner->pParaList->GetParent( pPrev ); + + pOwner->Expand( pPrev ); + pOwner->InvalidateBullet( pPrev, pOwner->pParaList->GetAbsPos( pPrev ) ); + } + } + + pOwner->nDepthChangedHdlPrevDepth = (sal_Int16)nOldDepth; + pOwner->mnDepthChangeHdlPrevFlags = pPara->nFlags; + pOwner->pHdlParagraph = pPara; + + pOwner->ImplInitDepth( nPara, nNewDepth, TRUE, FALSE ); + pOwner->ImplCalcBulletText( nPara, FALSE, FALSE ); + + if ( pOwner->ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) + pOwner->ImplSetLevelDependendStyleSheet( nPara ); + + // App benachrichtigen + pOwner->DepthChangedHdl(); + } + else + { + // Needs at least a repaint... + pOwner->pEditEngine->QuickMarkInvalid( ESelection( nPara, 0, nPara, 0 ) ); + } + } + + // MT 19.08.99: War mal fuer Optimierung (outliner.cxx#1.193), + // hat aber zu zuviel Wartungsaufwand / doppelten Funktionen gefuehrt + // und zu wenig gebracht: + // pOwner->ImpSetBulletTextsFrom( aSel.nStartPara+1, nMinDepth ); + // Wird jetzt direkt in Schleife mit ImplCalcBulletText() erledigt. + // Jetzt fehlen nur noch die folgenden Ansaetze, die davon betroffen sind. + USHORT nParas = (USHORT)pOwner->pParaList->GetParagraphCount(); + for ( USHORT n = aSel.nEndPara+1; n < nParas; n++ ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( n ); + if ( pPara->GetDepth() < nMinDepth ) + break; + pOwner->ImplCalcBulletText( n, FALSE, FALSE ); + } + + if ( bUpdate ) + { + pEditView->SetEditEngineUpdateMode( TRUE ); + pEditView->ShowCursor(); + } + + if( bUndo ) + pOwner->UndoActionEnd( OLUNDO_DEPTH ); +} + +BOOL OutlinerView::AdjustHeight( long nDY ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->MoveParagraphs( nDY ); + return TRUE; // remove return value... +} + +void OutlinerView::AdjustDepth( Paragraph* pPara, short nDX, BOOL bWithChilds) +{ + DBG_CHKTHIS(OutlinerView,0); + ULONG nStartPara = pOwner->pParaList->GetAbsPos( pPara ); + ULONG nEndPara = nStartPara; + if ( bWithChilds ) + nEndPara += pOwner->pParaList->GetChildCount( pPara ); + ESelection aSel((USHORT)nStartPara, 0,(USHORT)nEndPara, 0xffff ); + pEditView->SetSelection( aSel ); + AdjustDepth( nDX ); +} + +void OutlinerView::AdjustHeight( Paragraph* pPara, long nDY, BOOL bWithChilds ) +{ + DBG_CHKTHIS(OutlinerView,0); + ULONG nStartPara = pOwner->pParaList->GetAbsPos( pPara ); + ULONG nEndPara = nStartPara; + if ( bWithChilds ) + nEndPara += pOwner->pParaList->GetChildCount( pPara ); + ESelection aSel( (USHORT)nStartPara, 0, (USHORT)nEndPara, 0xffff ); + pEditView->SetSelection( aSel ); + AdjustHeight( nDY ); +} + + +Rectangle OutlinerView::GetVisArea() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetVisArea(); +} + + +Point OutlinerView::ImpGetDocPos( const Point& rPosPixel ) +{ + DBG_CHKTHIS(OutlinerView,0); + Rectangle aOutArWin = GetOutputArea(); + // Position in der OutputArea berechnen + Point aCurPosDoc( rPosPixel ); + aCurPosDoc = pEditView->GetWindow()->PixelToLogic( aCurPosDoc ); + aCurPosDoc -= aOutArWin.TopLeft(); + aCurPosDoc += pEditView->GetVisArea().TopLeft(); + return aCurPosDoc; +} + +// MT 05/00: Wofuer dies ImpXXXScroll, sollte das nicht die EditEngine machen??? + +void OutlinerView::ImpDragScroll( const Point& rPosPix ) +{ + DBG_CHKTHIS(OutlinerView,0); + Point aPosWin = pEditView->GetWindow()->PixelToLogic( rPosPix ); + Rectangle aOutputArWin = pEditView->GetOutputArea(); + if ( aPosWin.X() <= aOutputArWin.Left() + nDDScrollLRBorderWidthWin) + ImpScrollLeft(); + else if( aPosWin.X() >= aOutputArWin.Right()- nDDScrollLRBorderWidthWin) + ImpScrollRight(); + else if( aPosWin.Y() <= aOutputArWin.Top() + nDDScrollTBBorderWidthWin) + ImpScrollUp(); + else if(aPosWin.Y() >= aOutputArWin.Bottom() - nDDScrollTBBorderWidthWin) + ImpScrollDown(); +} + + +void OutlinerView::ImpScrollLeft() +{ + DBG_CHKTHIS(OutlinerView,0); + Rectangle aVisArea( pEditView->GetVisArea() ); + long nMaxScrollOffs = aVisArea.Left(); + if ( !nMaxScrollOffs ) + return; + long nScrollOffsRef = (aVisArea.GetWidth() * OL_SCROLL_HOROFFSET) / 100; + if ( !nScrollOffsRef ) + nScrollOffsRef = 1; + if ( nScrollOffsRef > nMaxScrollOffs ) + nScrollOffsRef = nMaxScrollOffs; + + ImpHideDDCursor(); + Scroll( -nScrollOffsRef, 0 ); + + EditStatus aScrollStat; + aScrollStat.GetStatusWord() = EE_STAT_HSCROLL; + pOwner->pEditEngine->GetStatusEventHdl().Call( &aScrollStat ); +} + + +void OutlinerView::ImpScrollRight() +{ + DBG_CHKTHIS(OutlinerView,0); + Rectangle aVisArea( pEditView->GetVisArea() ); + long nMaxScrollOffs = pOwner->pEditEngine->GetPaperSize().Width() - + aVisArea.Right(); + if ( !nMaxScrollOffs ) + return; + long nScrollOffsRef = (aVisArea.GetWidth() * OL_SCROLL_HOROFFSET) / 100; + if ( !nScrollOffsRef ) + nScrollOffsRef = 1; + if ( nScrollOffsRef > nMaxScrollOffs ) + nScrollOffsRef = nMaxScrollOffs; + + ImpHideDDCursor(); + Scroll( nScrollOffsRef, 0 ); + + EditStatus aScrollStat; + aScrollStat.GetStatusWord() = EE_STAT_HSCROLL; + pOwner->pEditEngine->GetStatusEventHdl().Call( &aScrollStat ); +} + + +void OutlinerView::ImpScrollDown() +{ + DBG_CHKTHIS(OutlinerView,0); + Rectangle aVisArea( pEditView->GetVisArea() ); + Size aDocSize( 0, (long)pOwner->pEditEngine->GetTextHeight() ); + + long nMaxScrollOffs = aDocSize.Height(); + nMaxScrollOffs -= aVisArea.Top(); + nMaxScrollOffs -= aVisArea.GetHeight(); + if ( !nMaxScrollOffs ) + return; + + long nScrollOffsRef = (aVisArea.GetHeight() * OL_SCROLL_VEROFFSET) / 100; + + if ( nScrollOffsRef > nMaxScrollOffs ) + nScrollOffsRef = nMaxScrollOffs; + if ( !nScrollOffsRef ) + nScrollOffsRef = 1; + + ImpHideDDCursor(); + Scroll( 0, -nScrollOffsRef ); + + EditStatus aScrollStat; + aScrollStat.GetStatusWord() = EE_STAT_VSCROLL; + pOwner->pEditEngine->GetStatusEventHdl().Call( &aScrollStat ); +} + + +void OutlinerView::ImpScrollUp() +{ + DBG_CHKTHIS(OutlinerView,0); + Rectangle aVisArea( pEditView->GetVisArea() ); + long nMaxScrollOffs = aVisArea.Top(); + if ( !nMaxScrollOffs ) + return; + long nScrollOffsRef = (aVisArea.GetHeight() * OL_SCROLL_VEROFFSET) / 100; + + + if ( nScrollOffsRef > nMaxScrollOffs ) + nScrollOffsRef = nMaxScrollOffs; + if ( !nScrollOffsRef ) + nScrollOffsRef = 1; + + ImpHideDDCursor(); + Scroll( 0, nScrollOffsRef ); + + EditStatus aScrollStat; + aScrollStat.GetStatusWord() = EE_STAT_VSCROLL; + pOwner->pEditEngine->GetStatusEventHdl().Call( &aScrollStat ); +} + + +void OutlinerView::Expand() +{ + DBG_CHKTHIS( OutlinerView, 0 ); + ParaRange aParas = ImpGetSelectedParagraphs( FALSE ); + ImplExpandOrCollaps( aParas.nStartPara, aParas.nEndPara, TRUE ); +} + + +void OutlinerView::Collapse() +{ + DBG_CHKTHIS( OutlinerView, 0 ); + ParaRange aParas = ImpGetSelectedParagraphs( FALSE ); + ImplExpandOrCollaps( aParas.nStartPara, aParas.nEndPara, FALSE ); +} + + +void OutlinerView::ExpandAll() +{ + DBG_CHKTHIS( OutlinerView, 0 ); + ImplExpandOrCollaps( 0, (USHORT)(pOwner->pParaList->GetParagraphCount()-1), TRUE ); +} + + +void OutlinerView::CollapseAll() +{ + DBG_CHKTHIS(OutlinerView,0); + ImplExpandOrCollaps( 0, (USHORT)(pOwner->pParaList->GetParagraphCount()-1), FALSE ); +} + +void OutlinerView::ImplExpandOrCollaps( USHORT nStartPara, USHORT nEndPara, BOOL bExpand ) +{ + DBG_CHKTHIS( OutlinerView, 0 ); + + BOOL bUpdate = pOwner->GetUpdateMode(); + pOwner->SetUpdateMode( FALSE ); + + BOOL bUndo = !pOwner->IsInUndo() && pOwner->IsUndoEnabled(); + if( bUndo ) + pOwner->UndoActionStart( bExpand ? OLUNDO_EXPAND : OLUNDO_COLLAPSE ); + + for ( USHORT nPara = nStartPara; nPara <= nEndPara; nPara++ ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + BOOL bDone = bExpand ? pOwner->Expand( pPara ) : pOwner->Collapse( pPara ); + if( bDone ) + { + // Der Strich unter dem Absatz muss verschwinden... + pOwner->pEditEngine->QuickMarkToBeRepainted( nPara ); + } + } + + if( bUndo ) + pOwner->UndoActionEnd( bExpand ? OLUNDO_EXPAND : OLUNDO_COLLAPSE ); + + if ( bUpdate ) + { + pOwner->SetUpdateMode( TRUE ); + pEditView->ShowCursor(); + } +} + + +void OutlinerView::Expand( Paragraph* pPara) +{ + DBG_CHKTHIS(OutlinerView,0); + pOwner->Expand( pPara ); +} + + +void OutlinerView::Collapse( Paragraph* pPara) +{ + DBG_CHKTHIS(OutlinerView,0); + pOwner->Collapse( pPara ); +} + +void OutlinerView::InsertText( const OutlinerParaObject& rParaObj ) +{ + // MT: Wie Paste, nur EditView::Insert, statt EditView::Paste. + // Eigentlich nicht ganz richtig, das evtl. Einrueckungen + // korrigiert werden muessen, aber das kommt spaeter durch ein + // allgemeingueltiges Import. + // Dann wird im Inserted gleich ermittelt, was fr eine Einrueckebene + // Moegliche Struktur: + // pImportInfo mit DestPara, DestPos, nFormat, pParaObj... + // Evtl. Problematisch: + // EditEngine, RTF => Absplittung des Bereichs, spaeter + // zusammenfuehrung + + DBG_CHKTHIS(OutlinerView,0); + + if ( ImpCalcSelectedPages( FALSE ) && !pOwner->ImpCanDeleteSelectedPages( this ) ) + return; + + pOwner->UndoActionStart( OLUNDO_INSERT ); + + pOwner->pEditEngine->SetUpdateMode( FALSE ); + ULONG nStart, nParaCount; + nParaCount = pOwner->pEditEngine->GetParagraphCount(); + USHORT nSize = ImpInitPaste( nStart ); + pEditView->InsertText( rParaObj.GetTextObject() ); + ImpPasted( nStart, nParaCount, nSize); + pEditView->SetEditEngineUpdateMode( TRUE ); + + pOwner->UndoActionEnd( OLUNDO_INSERT ); + + pEditView->ShowCursor( TRUE, TRUE ); +} + + + +void OutlinerView::Cut() +{ + DBG_CHKTHIS(OutlinerView,0); + if ( !ImpCalcSelectedPages( FALSE ) || pOwner->ImpCanDeleteSelectedPages( this ) ) + pEditView->Cut(); +} + +void OutlinerView::Paste() +{ + DBG_CHKTHIS(OutlinerView,0); + PasteSpecial(); // HACK(SD ruft nicht PasteSpecial auf) +} + +void OutlinerView::PasteSpecial() +{ + DBG_CHKTHIS(OutlinerView,0); + if ( !ImpCalcSelectedPages( FALSE ) || pOwner->ImpCanDeleteSelectedPages( this ) ) + { + pOwner->UndoActionStart( OLUNDO_INSERT ); + + pOwner->pEditEngine->SetUpdateMode( FALSE ); + pOwner->bPasting = TRUE; + pEditView->PasteSpecial(); + + if ( pOwner->ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) + { + const USHORT nParaCount = pOwner->pEditEngine->GetParagraphCount(); + + for( USHORT nPara = 0; nPara < nParaCount; nPara++ ) + pOwner->ImplSetLevelDependendStyleSheet( nPara ); + } + + pEditView->SetEditEngineUpdateMode( TRUE ); + pOwner->UndoActionEnd( OLUNDO_INSERT ); + pEditView->ShowCursor( TRUE, TRUE ); + } +} + +List* OutlinerView::CreateSelectionList() +{ + DBG_CHKTHIS( OutlinerView, 0 ); + + ParaRange aParas = ImpGetSelectedParagraphs( TRUE ); + List* pSelList = new List; + for ( USHORT nPara = aParas.nStartPara; nPara <= aParas.nEndPara; nPara++ ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + pSelList->Insert( pPara, LIST_APPEND ); + } + return pSelList; +} + +SfxStyleSheet* OutlinerView::GetStyleSheet() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetStyleSheet(); +} + +void OutlinerView::SetStyleSheet( SfxStyleSheet* pStyle ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetStyleSheet( pStyle ); + + ParaRange aSel = ImpGetSelectedParagraphs( TRUE ); + for( USHORT nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + pOwner->ImplCheckNumBulletItem( nPara ); + pOwner->ImplCalcBulletText( nPara, FALSE, FALSE ); + } +} + +Pointer OutlinerView::GetPointer( const Point& rPosPixel ) +{ + DBG_CHKTHIS(OutlinerView,0); + + MouseTarget eTarget; + ImpCheckMousePos( rPosPixel, eTarget ); + + PointerStyle ePointerStyle = POINTER_ARROW; + if ( eTarget == MouseText ) + { + ePointerStyle = GetOutliner()->IsVertical() ? POINTER_TEXT_VERTICAL : POINTER_TEXT; + } + else if ( eTarget == MouseHypertext ) + { + ePointerStyle = POINTER_REFHAND; + } + else if ( eTarget == MouseBullet ) + { + ePointerStyle = POINTER_MOVE; + } + + return Pointer( ePointerStyle ); +} + + +USHORT OutlinerView::ImpInitPaste( ULONG& rStart ) +{ + DBG_CHKTHIS(OutlinerView,0); + pOwner->bPasting = TRUE; + ESelection aSelection( pEditView->GetSelection() ); + aSelection.Adjust(); + rStart = aSelection.nStartPara; + USHORT nSize = aSelection.nEndPara - aSelection.nStartPara + 1; + return nSize; +} + + +void OutlinerView::ImpPasted( ULONG nStart, ULONG nPrevParaCount, USHORT nSize) +{ + DBG_CHKTHIS(OutlinerView,0); + pOwner->bPasting = FALSE; + ULONG nCurParaCount = (ULONG)pOwner->pEditEngine->GetParagraphCount(); + if( nCurParaCount < nPrevParaCount ) + nSize = sal::static_int_cast< USHORT >( + nSize - ( nPrevParaCount - nCurParaCount ) ); + else + nSize = sal::static_int_cast< USHORT >( + nSize + ( nCurParaCount - nPrevParaCount ) ); + pOwner->ImpTextPasted( nStart, nSize ); +} + + +void OutlinerView::Command( const CommandEvent& rCEvt ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->Command( rCEvt ); +} + + +void OutlinerView::SelectRange( ULONG nFirst, USHORT nCount ) +{ + DBG_CHKTHIS(OutlinerView,0); + ULONG nLast = nFirst+nCount; + nCount = (USHORT)pOwner->pParaList->GetParagraphCount(); + if( nLast <= nCount ) + nLast = nCount - 1; + ESelection aSel( (USHORT)nFirst, 0, (USHORT)nLast, 0xffff ); + pEditView->SetSelection( aSel ); +} + + +USHORT OutlinerView::ImpCalcSelectedPages( BOOL bIncludeFirstSelected ) +{ + DBG_CHKTHIS(OutlinerView,0); + + ESelection aSel( pEditView->GetSelection() ); + aSel.Adjust(); + + USHORT nPages = 0; + USHORT nFirstPage = 0xFFFF; + USHORT nStartPara = aSel.nStartPara; + if ( !bIncludeFirstSelected ) + nStartPara++; // alle nach StartPara kommenden Absaetze werden geloescht + for ( USHORT nPara = nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + DBG_ASSERT(pPara, "ImpCalcSelectedPages: ungueltige Selection? "); + if( pPara->HasFlag(PARAFLAG_ISPAGE) ) + { + nPages++; + if( nFirstPage == 0xFFFF ) + nFirstPage = nPara; + } + } + + if( nPages ) + { + pOwner->nDepthChangedHdlPrevDepth = nPages; + pOwner->pHdlParagraph = 0; + pOwner->mnFirstSelPage = nFirstPage; + } + + return nPages; +} + + +void OutlinerView::ToggleBullets() +{ + pOwner->UndoActionStart( OLUNDO_DEPTH ); + + ESelection aSel( pEditView->GetSelection() ); + aSel.Adjust(); + + const bool bUpdate = pOwner->pEditEngine->GetUpdateMode(); + pOwner->pEditEngine->SetUpdateMode( FALSE ); + + sal_Int16 nDepth = -2; + + for ( USHORT nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + DBG_ASSERT(pPara, "OutlinerView::ToggleBullets(), illegal selection?"); + + if( pPara ) + { + if( nDepth == -2 ) + nDepth = (pOwner->GetDepth(nPara) == -1) ? 0 : -1; + + pOwner->SetDepth( pPara, nDepth ); + + if( nDepth == -1 ) + { + const SfxItemSet& rAttrs = pOwner->GetParaAttribs( nPara ); + if(rAttrs.GetItemState( EE_PARA_BULLETSTATE ) == SFX_ITEM_SET) + { + SfxItemSet aAttrs(rAttrs); + aAttrs.ClearItem( EE_PARA_BULLETSTATE ); + pOwner->SetParaAttribs( nPara, aAttrs ); + } + } + } + } + + // --> OD 2009-03-10 #i100014# + // It is not a good idea to substract 1 from a count and cast the result + // to USHORT without check, if the count is 0. + USHORT nParaCount = (USHORT) (pOwner->pParaList->GetParagraphCount()); + // <-- + pOwner->ImplCheckParagraphs( aSel.nStartPara, nParaCount ); + pOwner->pEditEngine->QuickMarkInvalid( ESelection( aSel.nStartPara, 0, nParaCount, 0 ) ); + + pOwner->pEditEngine->SetUpdateMode( bUpdate ); + + pOwner->UndoActionEnd( OLUNDO_DEPTH ); +} + +void OutlinerView::EnableBullets() +{ + pOwner->UndoActionStart( OLUNDO_DEPTH ); + + ESelection aSel( pEditView->GetSelection() ); + aSel.Adjust(); + + const bool bUpdate = pOwner->pEditEngine->GetUpdateMode(); + pOwner->pEditEngine->SetUpdateMode( FALSE ); + + for ( USHORT nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + DBG_ASSERT(pPara, "OutlinerView::ToggleBullets(), illegal selection?"); + + if( pPara && (pOwner->GetDepth(nPara) == -1) ) + { + pOwner->SetDepth( pPara, 0 ); + } + } + + // --> OD 2009-03-10 #i100014# + // It is not a good idea to substract 1 from a count and cast the result + // to USHORT without check, if the count is 0. + USHORT nParaCount = (USHORT) (pOwner->pParaList->GetParagraphCount()); + // <-- + pOwner->ImplCheckParagraphs( aSel.nStartPara, nParaCount ); + pOwner->pEditEngine->QuickMarkInvalid( ESelection( aSel.nStartPara, 0, nParaCount, 0 ) ); + + pOwner->pEditEngine->SetUpdateMode( bUpdate ); + + pOwner->UndoActionEnd( OLUNDO_DEPTH ); +} + + +void OutlinerView::RemoveAttribsKeepLanguages( BOOL bRemoveParaAttribs ) +{ + RemoveAttribs( bRemoveParaAttribs, 0, TRUE /*keep language attribs*/ ); +} + +void OutlinerView::RemoveAttribs( BOOL bRemoveParaAttribs, USHORT nWhich, BOOL bKeepLanguages ) +{ + DBG_CHKTHIS(OutlinerView,0); + BOOL bUpdate = pOwner->GetUpdateMode(); + pOwner->SetUpdateMode( FALSE ); + pOwner->UndoActionStart( OLUNDO_ATTR ); + if (bKeepLanguages) + pEditView->RemoveAttribsKeepLanguages( bRemoveParaAttribs ); + else + pEditView->RemoveAttribs( bRemoveParaAttribs, nWhich ); + if ( bRemoveParaAttribs ) + { + // Ueber alle Absaetze, und Einrueckung und Level einstellen + ESelection aSel = pEditView->GetSelection(); + aSel.Adjust(); + for ( USHORT nPara = aSel.nStartPara; nPara <= aSel.nEndPara; nPara++ ) + { + Paragraph* pPara = pOwner->pParaList->GetParagraph( nPara ); + pOwner->ImplInitDepth( nPara, pPara->GetDepth(), FALSE, FALSE ); + } + } + pOwner->UndoActionEnd( OLUNDO_ATTR ); + pOwner->SetUpdateMode( bUpdate ); +} + + + +// ===================================================================== +// ====================== Einfache Durchreicher ======================= +// ====================================================================== + + +void OutlinerView::InsertText( const XubString& rNew, BOOL bSelect ) +{ + DBG_CHKTHIS(OutlinerView,0); + if( pOwner->bFirstParaIsEmpty ) + pOwner->Insert( String() ); + pEditView->InsertText( rNew, bSelect ); +} + +void OutlinerView::SetVisArea( const Rectangle& rRec ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetVisArea( rRec ); +} + + +void OutlinerView::SetSelection( const ESelection& rSel ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetSelection( rSel ); +} + +void OutlinerView::SetReadOnly( BOOL bReadOnly ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetReadOnly( bReadOnly ); +} + +BOOL OutlinerView::IsReadOnly() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->IsReadOnly(); +} + +BOOL OutlinerView::HasSelection() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->HasSelection(); +} + + +void OutlinerView::ShowCursor( BOOL bGotoCursor ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->ShowCursor( bGotoCursor ); +} + + +void OutlinerView::HideCursor() +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->HideCursor(); +} + + +void OutlinerView::SetWindow( Window* pWin ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetWindow( pWin ); +} + + +Window* OutlinerView::GetWindow() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetWindow(); +} + + +void OutlinerView::SetOutputArea( const Rectangle& rRect ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetOutputArea( rRect ); +} + + +Rectangle OutlinerView::GetOutputArea() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetOutputArea(); +} + + +XubString OutlinerView::GetSelected() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetSelected(); +} + + +void OutlinerView::RemoveCharAttribs( ULONG nPara, USHORT nWhich) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->RemoveCharAttribs( (USHORT)nPara, nWhich); +} + + +void OutlinerView::CompleteAutoCorrect() +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->CompleteAutoCorrect(); +} + + +EESpellState OutlinerView::StartSpeller( BOOL bMultiDoc ) +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->StartSpeller( bMultiDoc ); +} + + +EESpellState OutlinerView::StartThesaurus() +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->StartThesaurus(); +} + + +void OutlinerView::StartTextConversion( + LanguageType nSrcLang, LanguageType nDestLang, const Font *pDestFont, + INT32 nOptions, BOOL bIsInteractive, BOOL bMultipleDoc ) +{ + DBG_CHKTHIS(OutlinerView,0); + if ( + (LANGUAGE_KOREAN == nSrcLang && LANGUAGE_KOREAN == nDestLang) || + (LANGUAGE_CHINESE_SIMPLIFIED == nSrcLang && LANGUAGE_CHINESE_TRADITIONAL == nDestLang) || + (LANGUAGE_CHINESE_TRADITIONAL == nSrcLang && LANGUAGE_CHINESE_SIMPLIFIED == nDestLang) + ) + { + pEditView->StartTextConversion( nSrcLang, nDestLang, pDestFont, nOptions, bIsInteractive, bMultipleDoc ); + } + else + { + DBG_ERROR( "unexpected language" ); + } +} + + +USHORT OutlinerView::StartSearchAndReplace( const SvxSearchItem& rSearchItem ) +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->StartSearchAndReplace( rSearchItem ); +} + +void OutlinerView::TransliterateText( sal_Int32 nTransliterationMode ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->TransliterateText( nTransliterationMode ); +} + + + +ESelection OutlinerView::GetSelection() +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetSelection(); +} + + +void OutlinerView::Scroll( long nHorzScroll, long nVertScroll ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->Scroll( nHorzScroll, nVertScroll ); +} + + +void OutlinerView::SetControlWord( ULONG nWord ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetControlWord( nWord ); +} + + +ULONG OutlinerView::GetControlWord() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetControlWord(); +} + + +void OutlinerView::SetAnchorMode( EVAnchorMode eMode ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetAnchorMode( eMode ); +} + + +EVAnchorMode OutlinerView::GetAnchorMode() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetAnchorMode(); +} + + +void OutlinerView::Undo() +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->Undo(); +} + + +void OutlinerView::Redo() +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->Redo(); +} + + +void OutlinerView::EnablePaste( BOOL bEnable ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->EnablePaste( bEnable ); +} + + +void OutlinerView::Copy() +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->Copy(); +} + + +void OutlinerView::InsertField( const SvxFieldItem& rFld ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->InsertField( rFld ); +} + + +const SvxFieldItem* OutlinerView::GetFieldUnderMousePointer() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetFieldUnderMousePointer(); +} + + +const SvxFieldItem* OutlinerView::GetFieldUnderMousePointer( USHORT& nPara, USHORT& nPos ) const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetFieldUnderMousePointer( nPara, nPos ); +} + + +const SvxFieldItem* OutlinerView::GetFieldAtSelection() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetFieldAtSelection(); +} + +void OutlinerView::SetInvalidateMore( USHORT nPixel ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetInvalidateMore( nPixel ); +} + + +USHORT OutlinerView::GetInvalidateMore() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetInvalidateMore(); +} + + +BOOL OutlinerView::IsCursorAtWrongSpelledWord( BOOL bMarkIfWrong ) +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->IsCursorAtWrongSpelledWord( bMarkIfWrong ); +} + + +BOOL OutlinerView::IsWrongSpelledWordAtPos( const Point& rPosPixel, BOOL bMarkIfWrong ) +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->IsWrongSpelledWordAtPos( rPosPixel, bMarkIfWrong ); +} + + +void OutlinerView::SpellIgnoreWord() +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SpellIgnoreWord(); +} + + +void OutlinerView::ExecuteSpellPopup( const Point& rPosPixel, Link* pStartDlg ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->ExecuteSpellPopup( rPosPixel, pStartDlg ); +} + +ULONG OutlinerView::Read( SvStream& rInput, const String& rBaseURL, EETextFormat eFormat, BOOL bSelect, SvKeyValueIterator* pHTTPHeaderAttrs ) +{ + DBG_CHKTHIS(OutlinerView,0); + USHORT nOldParaCount = pEditView->GetEditEngine()->GetParagraphCount(); + ESelection aOldSel = pEditView->GetSelection(); + aOldSel.Adjust(); + + ULONG nRet = pEditView->Read( rInput, rBaseURL, eFormat, bSelect, pHTTPHeaderAttrs ); + + // MT 08/00: Hier sollte eigentlich das gleiche wie in PasteSpecial passieren! + // Mal anpassen, wenn dieses ImplInitPaste und ImpPasted-Geraffel ueberarbeitet ist. + + long nParaDiff = pEditView->GetEditEngine()->GetParagraphCount() - nOldParaCount; + USHORT nChangesStart = aOldSel.nStartPara; + USHORT nChangesEnd = sal::static_int_cast< USHORT >(nChangesStart + nParaDiff + (aOldSel.nEndPara-aOldSel.nStartPara)); + + for ( USHORT n = nChangesStart; n <= nChangesEnd; n++ ) + { + if ( eFormat == EE_FORMAT_BIN ) + { + USHORT nDepth = 0; + const SfxItemSet& rAttrs = pOwner->GetParaAttribs( n ); + const SfxInt16Item& rLevel = (const SfxInt16Item&) rAttrs.Get( EE_PARA_OUTLLEVEL ); + nDepth = rLevel.GetValue(); + pOwner->ImplInitDepth( n, nDepth, FALSE ); + } + + if ( pOwner->ImplGetOutlinerMode() == OUTLINERMODE_OUTLINEOBJECT ) + pOwner->ImplSetLevelDependendStyleSheet( n ); + } + + if ( eFormat != EE_FORMAT_BIN ) + { + pOwner->ImpFilterIndents( nChangesStart, nChangesEnd ); + } + + return nRet; +} + +ULONG OutlinerView::Write( SvStream& rOutput, EETextFormat eFormat ) +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->Write( rOutput, eFormat ); +} + +void OutlinerView::SetBackgroundColor( const Color& rColor ) +{ + DBG_CHKTHIS(OutlinerView,0); + pEditView->SetBackgroundColor( rColor ); +} + + +Color OutlinerView::GetBackgroundColor() +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetBackgroundColor(); +} + +SfxItemSet OutlinerView::GetAttribs() +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetAttribs(); +} + +USHORT OutlinerView::GetSelectedScriptType() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetSelectedScriptType(); +} + +String OutlinerView::GetSurroundingText() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetSurroundingText(); +} + +Selection OutlinerView::GetSurroundingTextSelection() const +{ + DBG_CHKTHIS(OutlinerView,0); + return pEditView->GetSurroundingTextSelection(); +} diff --git a/editeng/source/outliner/paralist.cxx b/editeng/source/outliner/paralist.cxx new file mode 100644 index 000000000000..97bf3c6e013d --- /dev/null +++ b/editeng/source/outliner/paralist.cxx @@ -0,0 +1,290 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: paralist.cxx,v $ + * $Revision: 1.11.6.3 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <paralist.hxx> +#include <editeng/outliner.hxx> // nur wegen Paragraph, muss geaendert werden! +#include <editeng/numdef.hxx> + +DBG_NAME(Paragraph) + +ParagraphData::ParagraphData() +: nDepth( -1 ) +, mnNumberingStartValue( -1 ) +, mbParaIsNumberingRestart( sal_False ) +{ +} + +ParagraphData::ParagraphData( const ParagraphData& r ) +: nDepth( r.nDepth ) +, mnNumberingStartValue( r.mnNumberingStartValue ) +, mbParaIsNumberingRestart( r.mbParaIsNumberingRestart ) +{ +} + +ParagraphData& ParagraphData::operator=( const ParagraphData& r) +{ + nDepth = r.nDepth; + mnNumberingStartValue = r.mnNumberingStartValue; + mbParaIsNumberingRestart = r.mbParaIsNumberingRestart; + return *this; +} + +bool ParagraphData::operator==(const ParagraphData& rCandidate) const +{ + return (nDepth == rCandidate.nDepth + && mnNumberingStartValue == rCandidate.mnNumberingStartValue + && mbParaIsNumberingRestart == rCandidate.mbParaIsNumberingRestart); +} + +Paragraph::Paragraph( sal_Int16 nDDepth ) +: aBulSize( -1, -1) +{ + DBG_CTOR( Paragraph, 0 ); + + DBG_ASSERT( ( nDDepth >= -1 ) && ( nDDepth < SVX_MAX_NUM ), "Paragraph-CTOR: nDepth invalid!" ); + + nDepth = nDDepth; + nFlags = 0; + bVisible = TRUE; +} + +Paragraph::Paragraph( const Paragraph& rPara ) +: ParagraphData( rPara ) +, aBulText( rPara.aBulText ) +, aBulSize( rPara.aBulSize ) +{ + DBG_CTOR( Paragraph, 0 ); + + nDepth = rPara.nDepth; + nFlags = rPara.nFlags; + bVisible = rPara.bVisible; +} + +Paragraph::Paragraph( const ParagraphData& rData ) +: nFlags( 0 ) +, aBulSize( -1, -1) +, bVisible( TRUE ) +{ + DBG_CTOR( Paragraph, 0 ); + + nDepth = rData.nDepth; + mnNumberingStartValue = rData.mnNumberingStartValue; + mbParaIsNumberingRestart = rData.mbParaIsNumberingRestart; +} + +Paragraph::~Paragraph() +{ + DBG_DTOR( Paragraph, 0 ); +} + +void Paragraph::SetNumberingStartValue( sal_Int16 nNumberingStartValue ) +{ + mnNumberingStartValue = nNumberingStartValue; + if( mnNumberingStartValue != -1 ) + mbParaIsNumberingRestart = true; +} + +void Paragraph::SetParaIsNumberingRestart( sal_Bool bParaIsNumberingRestart ) +{ + mbParaIsNumberingRestart = bParaIsNumberingRestart; + if( !mbParaIsNumberingRestart ) + mnNumberingStartValue = -1; +} + +void ParagraphList::Clear( BOOL bDestroyParagraphs ) +{ + if ( bDestroyParagraphs ) + { + for ( ULONG n = GetParagraphCount(); n; ) + { + Paragraph* pPara = GetParagraph( --n ); + delete pPara; + } + } + List::Clear(); +} + +void ParagraphList::MoveParagraphs( ULONG nStart, ULONG nDest, ULONG _nCount ) +{ + if ( ( nDest < nStart ) || ( nDest >= ( nStart + _nCount ) ) ) + { + ULONG n; + ParagraphList aParas; + for ( n = 0; n < _nCount; n++ ) + { + Paragraph* pPara = GetParagraph( nStart ); + aParas.Insert( pPara, LIST_APPEND ); + Remove( nStart ); + } + + if ( nDest > nStart ) + nDest -= _nCount; + + for ( n = 0; n < _nCount; n++ ) + { + Paragraph* pPara = aParas.GetParagraph( n ); + Insert( pPara, nDest++ ); + } + } + else + { + DBG_ERROR( "MoveParagraphs: Invalid Parameters" ); + } +} + +Paragraph* ParagraphList::NextVisible( Paragraph* pPara ) const +{ + ULONG n = GetAbsPos( pPara ); + + Paragraph* p = GetParagraph( ++n ); + while ( p && !p->IsVisible() ) + p = GetParagraph( ++n ); + + return p; +} + +Paragraph* ParagraphList::PrevVisible( Paragraph* pPara ) const +{ + ULONG n = GetAbsPos( pPara ); + + Paragraph* p = n ? GetParagraph( --n ) : NULL; + while ( p && !p->IsVisible() ) + p = n ? GetParagraph( --n ) : NULL; + + return p; +} + +Paragraph* ParagraphList::LastVisible() const +{ + ULONG n = GetParagraphCount(); + + Paragraph* p = n ? GetParagraph( --n ) : NULL; + while ( p && !p->IsVisible() ) + p = n ? GetParagraph( --n ) : NULL; + + return p; +} + +BOOL ParagraphList::HasChilds( Paragraph* pParagraph ) const +{ + ULONG n = GetAbsPos( pParagraph ); + Paragraph* pNext = GetParagraph( ++n ); + return ( pNext && ( pNext->GetDepth() > pParagraph->GetDepth() ) ) ? TRUE : FALSE; +} + +BOOL ParagraphList::HasHiddenChilds( Paragraph* pParagraph ) const +{ + ULONG n = GetAbsPos( pParagraph ); + Paragraph* pNext = GetParagraph( ++n ); + return ( pNext && ( pNext->GetDepth() > pParagraph->GetDepth() ) && !pNext->IsVisible() ) ? TRUE : FALSE; +} + +BOOL ParagraphList::HasVisibleChilds( Paragraph* pParagraph ) const +{ + ULONG n = GetAbsPos( pParagraph ); + Paragraph* pNext = GetParagraph( ++n ); + return ( pNext && ( pNext->GetDepth() > pParagraph->GetDepth() ) && pNext->IsVisible() ) ? TRUE : FALSE; +} + +ULONG ParagraphList::GetChildCount( Paragraph* pParent ) const +{ + ULONG nChildCount = 0; + ULONG n = GetAbsPos( pParent ); + Paragraph* pPara = GetParagraph( ++n ); + while ( pPara && ( pPara->GetDepth() > pParent->GetDepth() ) ) + { + nChildCount++; + pPara = GetParagraph( ++n ); + } + return nChildCount; +} + +Paragraph* ParagraphList::GetParent( Paragraph* pParagraph /*, USHORT& rRelPos */ ) const +{ + /* rRelPos = 0 */; + ULONG n = GetAbsPos( pParagraph ); + Paragraph* pPrev = GetParagraph( --n ); + while ( pPrev && ( pPrev->GetDepth() >= pParagraph->GetDepth() ) ) + { +// if ( pPrev->GetDepth() == pParagraph->GetDepth() ) +// rRelPos++; + pPrev = GetParagraph( --n ); + } + + return pPrev; +} + +void ParagraphList::Expand( Paragraph* pParent ) +{ + ULONG nChildCount = GetChildCount( pParent ); + ULONG nPos = GetAbsPos( pParent ); + + for ( ULONG n = 1; n <= nChildCount; n++ ) + { + Paragraph* pPara = GetParagraph( nPos+n ); + if ( !( pPara->IsVisible() ) ) + { + pPara->bVisible = TRUE; + aVisibleStateChangedHdl.Call( pPara ); + } + } +} + +void ParagraphList::Collapse( Paragraph* pParent ) +{ + ULONG nChildCount = GetChildCount( pParent ); + ULONG nPos = GetAbsPos( pParent ); + + for ( ULONG n = 1; n <= nChildCount; n++ ) + { + Paragraph* pPara = GetParagraph( nPos+n ); + if ( pPara->IsVisible() ) + { + pPara->bVisible = FALSE; + aVisibleStateChangedHdl.Call( pPara ); + } + } +} + +ULONG ParagraphList::GetVisPos( Paragraph* pPara ) +{ + ULONG nVisPos = 0; + ULONG nPos = GetAbsPos( pPara ); + for ( ULONG n = 0; n < nPos; n++ ) + { + Paragraph* _pPara = GetParagraph( n ); + if ( _pPara->IsVisible() ) + nVisPos++; + } + return nVisPos; +} diff --git a/editeng/source/outliner/paralist.hxx b/editeng/source/outliner/paralist.hxx new file mode 100644 index 000000000000..91901c3815e6 --- /dev/null +++ b/editeng/source/outliner/paralist.hxx @@ -0,0 +1,74 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: paralist.hxx,v $ + * $Revision: 1.4 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _PARALIST_HXX +#define _PARALIST_HXX + +class Paragraph; + +#include <tools/list.hxx> +#include <tools/link.hxx> + +class ParagraphList : private List +{ +private: + Link aVisibleStateChangedHdl; + +public: + void Clear( BOOL bDestroyParagraphs ); + + ULONG GetParagraphCount() const { return List::Count(); } + Paragraph* GetParagraph( ULONG nPos ) const { return (Paragraph*)List::GetObject( nPos ); } + + ULONG GetAbsPos( Paragraph* pParent ) const { return List::GetPos( pParent ); } + ULONG GetVisPos( Paragraph* pParagraph ); + + void Insert( Paragraph* pPara, ULONG nAbsPos = LIST_APPEND ) { List::Insert( pPara, nAbsPos ); } + void Remove( ULONG nPara ) { List::Remove( nPara ); } + void MoveParagraphs( ULONG nStart, ULONG nDest, ULONG nCount ); + + Paragraph* NextVisible( Paragraph* ) const; + Paragraph* PrevVisible( Paragraph* ) const; + Paragraph* LastVisible() const; + + Paragraph* GetParent( Paragraph* pParagraph /*, USHORT& rRelPos */ ) const; + BOOL HasChilds( Paragraph* pParagraph ) const; + BOOL HasHiddenChilds( Paragraph* pParagraph ) const; + BOOL HasVisibleChilds( Paragraph* pParagraph ) const; + ULONG GetChildCount( Paragraph* pParagraph ) const; + + void Expand( Paragraph* pParent ); + void Collapse( Paragraph* pParent ); + + void SetVisibleStateChangedHdl( const Link& rLink ) { aVisibleStateChangedHdl = rLink; } + Link GetVisibleStateChangedHdl() const { return aVisibleStateChangedHdl; } +}; + +#endif diff --git a/editeng/source/rtf/makefile.mk b/editeng/source/rtf/makefile.mk new file mode 100644 index 000000000000..b633d5c08879 --- /dev/null +++ b/editeng/source/rtf/makefile.mk @@ -0,0 +1,55 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.5 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=editeng +TARGET=rtf + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +EXCEPTIONSFILES= \ + $(SLO)$/svxrtf.obj + +SLOFILES= \ + $(EXCEPTIONSFILES) \ + $(SLO)$/rtfitem.obj \ + $(SLO)$/rtfgrf.obj + +# ========================================================================== + +.INCLUDE : target.mk + diff --git a/editeng/source/rtf/rtfgrf.cxx b/editeng/source/rtf/rtfgrf.cxx new file mode 100644 index 000000000000..5903090205f0 --- /dev/null +++ b/editeng/source/rtf/rtfgrf.cxx @@ -0,0 +1,561 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: rtfgrf.cxx,v $ + * $Revision: 1.13 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ +#include <osl/endian.h> +#include <tools/cachestr.hxx> +#include <vcl/graph.hxx> +#include <vcl/svapp.hxx> +#include <svtools/rtfkeywd.hxx> +#include <svtools/rtftoken.h> +#include <svtools/filter.hxx> + +#include <editeng/svxrtf.hxx> + + +#ifndef DBG_UTIL +#undef DEBUG_JP +#endif + +#ifdef DEBUG_JP + +#include <tools/fsys.hxx> + +class GrfWindow : public WorkWindow +{ + Graphic aGrf; +public: + GrfWindow( const Graphic& rGrf ); + virtual void Paint( const Rectangle& rRect ); +}; + +GrfWindow::GrfWindow( const Graphic& rGrf ) + : WorkWindow( NULL ), + aGrf( rGrf ) +{ + SetPosSizePixel( Point( 100, 0 ), Size( 300, 300 )); + Show(); + Invalidate(); + Update(); +} + +void GrfWindow::Paint( const Rectangle& ) +{ + aGrf.Draw( this, Point(0,0), GetSizePixel() ); +} +#endif + +static BYTE __FAR_DATA aPal1[ 2 * 4 ] = { + 0x00, 0x00, 0x00, 0x00, // Schwarz + 0xFF, 0xFF, 0xFF, 0x00 // Weiss +}; + +static BYTE __FAR_DATA aPal4[ 16 * 4 ] = { + 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, + 0x80, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, + 0x00, 0x80, 0x80, 0x00, + 0x80, 0x80, 0x80, 0x00, + 0xC0, 0xC0, 0xC0, 0x00, + 0xFF, 0x00, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0xFF, 0x00, + 0xFF, 0xFF, 0xFF, 0x00 +}; + +static BYTE __FAR_DATA aPal8[ 256 * 4 ] = +{ +0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, +0x80, 0x92, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x80, 0x00, 0xAA, 0x00, +0x00, 0x92, 0xAA, 0x00, 0xC1, 0xC1, 0xC1, 0x00, 0xC9, 0xC9, 0xC9, 0x00, +0xAA, 0xDB, 0xFF, 0x00, 0x00, 0x49, 0xAA, 0x00, 0x00, 0x49, 0xFF, 0x00, +0x00, 0x6D, 0x00, 0x00, 0x00, 0x6D, 0x55, 0x00, 0x00, 0x6D, 0xAA, 0x00, +0x00, 0x6D, 0xFF, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x92, 0x55, 0x00, +0x00, 0x24, 0xAA, 0x00, 0x00, 0x92, 0xFF, 0x00, 0x00, 0xB6, 0x00, 0x00, +0x00, 0xB6, 0x55, 0x00, 0x00, 0xB6, 0xAA, 0x00, 0x00, 0xB6, 0xFF, 0x00, +0x00, 0xDB, 0x00, 0x00, 0x00, 0xDB, 0x55, 0x00, 0x00, 0xDB, 0xAA, 0x00, +0x00, 0xDB, 0xFF, 0x00, 0xFF, 0xDB, 0xAA, 0x00, 0x00, 0xFF, 0x55, 0x00, +0x00, 0xFF, 0xAA, 0x00, 0xFF, 0xFF, 0xAA, 0x00, 0x2B, 0x00, 0x00, 0x00, +0x2B, 0x00, 0x55, 0x00, 0x2B, 0x00, 0xAA, 0x00, 0x2B, 0x00, 0xFF, 0x00, +0x2B, 0x24, 0x00, 0x00, 0x2B, 0x24, 0x55, 0x00, 0x2B, 0x24, 0xAA, 0x00, +0x2B, 0x24, 0xFF, 0x00, 0x2B, 0x49, 0x00, 0x00, 0x2B, 0x49, 0x55, 0x00, +0x2B, 0x49, 0xAA, 0x00, 0x2B, 0x49, 0xFF, 0x00, 0x2B, 0x6D, 0x00, 0x00, +0x2B, 0x6D, 0x55, 0x00, 0x2B, 0x6D, 0xAA, 0x00, 0x2B, 0x6D, 0xFF, 0x00, +0x2B, 0x92, 0x00, 0x00, 0x2B, 0x92, 0x55, 0x00, 0x2B, 0x92, 0xAA, 0x00, +0x2B, 0x92, 0xFF, 0x00, 0x2B, 0xB6, 0x00, 0x00, 0x2B, 0xB6, 0x55, 0x00, +0x2B, 0xB6, 0xAA, 0x00, 0x2B, 0xB6, 0xFF, 0x00, 0x2B, 0xDB, 0x00, 0x00, +0x2B, 0xDB, 0x55, 0x00, 0x2B, 0xDB, 0xAA, 0x00, 0x2B, 0xDB, 0xFF, 0x00, +0x2B, 0xFF, 0x00, 0x00, 0x2B, 0xFF, 0x55, 0x00, 0x2B, 0xFF, 0xAA, 0x00, +0x2B, 0xFF, 0xFF, 0x00, 0x55, 0x00, 0x00, 0x00, 0x55, 0x00, 0x55, 0x00, +0x55, 0x00, 0xAA, 0x00, 0x55, 0x00, 0xFF, 0x00, 0x55, 0x24, 0x00, 0x00, +0x55, 0x24, 0x55, 0x00, 0x55, 0x24, 0xAA, 0x00, 0x55, 0x24, 0xFF, 0x00, +0x55, 0x49, 0x00, 0x00, 0x55, 0x49, 0x55, 0x00, 0x55, 0x49, 0xAA, 0x00, +0x55, 0x49, 0xFF, 0x00, 0x55, 0x6D, 0x00, 0x00, 0x55, 0x6D, 0x55, 0x00, +0x55, 0x6D, 0xAA, 0x00, 0x55, 0x6D, 0xFF, 0x00, 0x55, 0x92, 0x00, 0x00, +0x55, 0x92, 0x55, 0x00, 0x55, 0x92, 0xAA, 0x00, 0x55, 0x92, 0xFF, 0x00, +0x55, 0xB6, 0x00, 0x00, 0x55, 0xB6, 0x55, 0x00, 0x55, 0xB6, 0xAA, 0x00, +0x55, 0xB6, 0xFF, 0x00, 0x55, 0xDB, 0x00, 0x00, 0x55, 0xDB, 0x55, 0x00, +0x55, 0xDB, 0xAA, 0x00, 0x55, 0xDB, 0xFF, 0x00, 0x55, 0xFF, 0x00, 0x00, +0x55, 0xFF, 0x55, 0x00, 0x55, 0xFF, 0xAA, 0x00, 0x55, 0xFF, 0xFF, 0x00, +0x00, 0x00, 0x55, 0x00, 0x80, 0x00, 0x55, 0x00, 0x00, 0x24, 0x55, 0x00, +0x80, 0x00, 0xFF, 0x00, 0x80, 0x24, 0x00, 0x00, 0x80, 0x24, 0x55, 0x00, +0x80, 0x24, 0xAA, 0x00, 0x80, 0x24, 0xFF, 0x00, 0x80, 0x49, 0x00, 0x00, +0x80, 0x49, 0x55, 0x00, 0x80, 0x49, 0xAA, 0x00, 0x80, 0x49, 0xFF, 0x00, +0x80, 0x6D, 0x00, 0x00, 0x80, 0x6D, 0x55, 0x00, 0x80, 0x6D, 0xAA, 0x00, +0x80, 0x6D, 0xFF, 0x00, 0x08, 0x08, 0x08, 0x00, 0x0F, 0x0F, 0x0F, 0x00, +0x17, 0x17, 0x17, 0x00, 0x1F, 0x1F, 0x1F, 0x00, 0x27, 0x27, 0x27, 0x00, +0x2E, 0x2E, 0x2E, 0x00, 0x36, 0x36, 0x36, 0x00, 0x3E, 0x3E, 0x3E, 0x00, +0x46, 0x46, 0x46, 0x00, 0x4D, 0x4D, 0x4D, 0x00, 0x55, 0x55, 0x55, 0x00, +0x5D, 0x5D, 0x5D, 0x00, 0x64, 0x64, 0x64, 0x00, 0x6C, 0x6C, 0x6C, 0x00, +0x74, 0x74, 0x74, 0x00, 0x7C, 0x7C, 0x7C, 0x00, 0xFF, 0xDB, 0x00, 0x00, +0x8B, 0x8B, 0x8B, 0x00, 0x93, 0x93, 0x93, 0x00, 0x9B, 0x9B, 0x9B, 0x00, +0xFF, 0xB6, 0xFF, 0x00, 0xAA, 0xAA, 0xAA, 0x00, 0xB2, 0xB2, 0xB2, 0x00, +0xB9, 0xB9, 0xB9, 0x00, 0x00, 0x24, 0xFF, 0x00, 0x00, 0x49, 0x00, 0x00, +0xD1, 0xD1, 0xD1, 0x00, 0xD8, 0xD8, 0xD8, 0x00, 0xE0, 0xE0, 0xE0, 0x00, +0xE8, 0xE8, 0xE8, 0x00, 0xF0, 0xF0, 0xF0, 0x00, 0xFF, 0xB6, 0xAA, 0x00, +0xFF, 0xDB, 0xFF, 0x00, 0x80, 0x92, 0x55, 0x00, 0x80, 0x92, 0xAA, 0x00, +0x80, 0x92, 0xFF, 0x00, 0x80, 0xB6, 0x00, 0x00, 0x80, 0xB6, 0x55, 0x00, +0x80, 0xB6, 0xAA, 0x00, 0x80, 0xB6, 0xFF, 0x00, 0x80, 0xDB, 0x00, 0x00, +0x80, 0xDB, 0x55, 0x00, 0x80, 0xDB, 0xAA, 0x00, 0x80, 0xDB, 0xFF, 0x00, +0x80, 0xFF, 0x00, 0x00, 0x80, 0xFF, 0x55, 0x00, 0x80, 0xFF, 0xAA, 0x00, +0x80, 0xFF, 0xFF, 0x00, 0xAA, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x55, 0x00, +0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xFF, 0x00, 0xAA, 0x24, 0x00, 0x00, +0xAA, 0x24, 0x55, 0x00, 0xAA, 0x24, 0xAA, 0x00, 0xAA, 0x24, 0xFF, 0x00, +0xAA, 0x49, 0x00, 0x00, 0xAA, 0x49, 0x55, 0x00, 0xAA, 0x49, 0xAA, 0x00, +0xAA, 0x49, 0xFF, 0x00, 0xAA, 0x6D, 0x00, 0x00, 0xAA, 0x6D, 0x55, 0x00, +0xAA, 0x6D, 0xAA, 0x00, 0xAA, 0x6D, 0xFF, 0x00, 0xAA, 0x92, 0x00, 0x00, +0xAA, 0x92, 0x55, 0x00, 0xAA, 0x92, 0xAA, 0x00, 0xAA, 0x92, 0xFF, 0x00, +0xAA, 0xB6, 0x00, 0x00, 0xAA, 0xB6, 0x55, 0x00, 0xAA, 0xB6, 0xAA, 0x00, +0xAA, 0xB6, 0xFF, 0x00, 0xAA, 0xDB, 0x00, 0x00, 0xAA, 0xDB, 0x55, 0x00, +0xAA, 0xDB, 0xAA, 0x00, 0x00, 0x49, 0x55, 0x00, 0xAA, 0xFF, 0x00, 0x00, +0xAA, 0xFF, 0x55, 0x00, 0xAA, 0xFF, 0xAA, 0x00, 0xAA, 0xFF, 0xFF, 0x00, +0xD5, 0x00, 0x00, 0x00, 0xD5, 0x00, 0x55, 0x00, 0xD5, 0x00, 0xAA, 0x00, +0xD5, 0x00, 0xFF, 0x00, 0xD5, 0x24, 0x00, 0x00, 0xD5, 0x24, 0x55, 0x00, +0xD5, 0x24, 0xAA, 0x00, 0xD5, 0x24, 0xFF, 0x00, 0xD5, 0x49, 0x00, 0x00, +0xD5, 0x49, 0x55, 0x00, 0xD5, 0x49, 0xAA, 0x00, 0xD5, 0x49, 0xFF, 0x00, +0xD5, 0x6D, 0x00, 0x00, 0xD5, 0x6D, 0x55, 0x00, 0xD5, 0x6D, 0xAA, 0x00, +0xD5, 0x6D, 0xFF, 0x00, 0xD5, 0x92, 0x00, 0x00, 0xD5, 0x92, 0x55, 0x00, +0xD5, 0x92, 0xAA, 0x00, 0xD5, 0x92, 0xFF, 0x00, 0xD5, 0xB6, 0x00, 0x00, +0xD5, 0xB6, 0x55, 0x00, 0xD5, 0xB6, 0xAA, 0x00, 0xD5, 0xB6, 0xFF, 0x00, +0xD5, 0xDB, 0x00, 0x00, 0xD5, 0xDB, 0x55, 0x00, 0xD5, 0xDB, 0xAA, 0x00, +0xD5, 0xDB, 0xFF, 0x00, 0xD5, 0xFF, 0x00, 0x00, 0xD5, 0xFF, 0x55, 0x00, +0xD5, 0xFF, 0xAA, 0x00, 0xD5, 0xFF, 0xFF, 0x00, 0xFF, 0xDB, 0x55, 0x00, +0xFF, 0x00, 0x55, 0x00, 0xFF, 0x00, 0xAA, 0x00, 0xFF, 0xFF, 0x55, 0x00, +0xFF, 0x24, 0x00, 0x00, 0xFF, 0x24, 0x55, 0x00, 0xFF, 0x24, 0xAA, 0x00, +0xFF, 0x24, 0xFF, 0x00, 0xFF, 0x49, 0x00, 0x00, 0xFF, 0x49, 0x55, 0x00, +0xFF, 0x49, 0xAA, 0x00, 0xFF, 0x49, 0xFF, 0x00, 0xFF, 0x6D, 0x00, 0x00, +0xFF, 0x6D, 0x55, 0x00, 0xFF, 0x6D, 0xAA, 0x00, 0xFF, 0x6D, 0xFF, 0x00, +0xFF, 0x92, 0x00, 0x00, 0xFF, 0x92, 0x55, 0x00, 0xFF, 0x92, 0xAA, 0x00, +0xFF, 0x92, 0xFF, 0x00, 0xFF, 0xB6, 0x00, 0x00, 0xFF, 0xB6, 0x55, 0x00, +0xF7, 0xF7, 0xF7, 0x00, 0xA2, 0xA2, 0xA2, 0x00, 0x83, 0x83, 0x83, 0x00, +0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, +0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, +0xFF, 0xFF, 0xFF, 0x00 +}; + + +/* */ + + +inline long SwapLong( long n ) +{ +#ifndef OSL_LITENDIAN + return SWAPLONG( n ); +#else + return n; +#endif +} + +inline short SwapShort( short n ) +{ +#ifndef OSL_LITENDIAN + return SWAPSHORT( n ); +#else + return n; +#endif +} + + +static void WriteBMPHeader( SvStream& rStream, + const SvxRTFPictureType& rPicType ) +{ + ULONG n4Width = rPicType.nWidth; + ULONG n4Height = rPicType.nHeight; + USHORT n4ColBits = rPicType.nBitsPerPixel; + + USHORT nColors = (1 << n4ColBits); // Anzahl der Farben ( 1, 16, 256 ) + USHORT nWdtOut = rPicType.nWidthBytes; + if( !nWdtOut ) + nWdtOut = (USHORT)((( n4Width * n4ColBits + 31 ) / 32 ) * 4 ); + + long nOffset = 14 + 40; // BMP_FILE_HD_SIZ + sizeof(*pBmpInfo); + if( 256 >= nColors ) + nOffset += nColors * 4; + long nSize = nOffset + nWdtOut * n4Height; + rStream << "BM" // = "BM" + << SwapLong(nSize) // Filesize in Bytes + << SwapShort(0) // Reserviert + << SwapShort(0) // Reserviert + << SwapLong(nOffset); // Offset? + + rStream << SwapLong(40) // sizeof( BmpInfo ) + << SwapLong(n4Width) + << SwapLong(n4Height) + << (USHORT)1 + << n4ColBits + << SwapLong(0) + << SwapLong(0) + << SwapLong( rPicType.nGoalWidth + ? rPicType.nGoalWidth * 1000L / 254L + : 0 ) // DPI in Pixel per Meter + << SwapLong( rPicType.nGoalHeight + ? rPicType.nGoalHeight * 1000L / 254L // dito + : 0 ) + << SwapLong(0) + << SwapLong(0); + + + switch( rPicType.nBitsPerPixel ) + { + case 1: rStream.Write( aPal1, sizeof( aPal1 )); break; + case 4: rStream.Write( aPal4, sizeof( aPal4 )); break; + case 8: rStream.Write( aPal8, sizeof( aPal8 )); break; + } +} + +/* */ + + // wandel die ASCII-HexCodes in binaere Zeichen um. Werden + // ungueltige Daten gefunden (Zeichen ausser 0-9|a-f|A-F, so + // wird USHRT_MAX returnt, ansonsten die Anzahl der umgewandelten Ze. +xub_StrLen SvxRTFParser::HexToBin( String& rToken ) +{ + // dann mache aus den Hex-Werten mal "Binare Daten" + // (missbrauche den String als temp Buffer) + if( rToken.Len() & 1 ) // ungerade Anzahl, mit 0 auffuellen + rToken += '0'; + + xub_StrLen n, nLen; + sal_Unicode nVal; + BOOL bValidData = TRUE; + const sal_Unicode* pStr = rToken.GetBufferAccess(); + sal_Char* pData = (sal_Char*)pStr; + for( n = 0, nLen = rToken.Len(); n < nLen; ++n, ++pStr ) + { + if( ((nVal = *pStr) >= '0') && ( nVal <= '9') ) + nVal -= '0'; + else if( (nVal >= 'A') && (nVal <= 'F') ) + nVal -= 'A' - 10; + else if( (nVal >= 'a') && (nVal <= 'f') ) + nVal -= 'a' - 10; + else + { + DBG_ASSERT( !this, "ungueltiger Hex-Wert" ); + bValidData = FALSE; + break; + } + + if( n & 1 ) + *(pData++) |= nVal & 0x0f; + else + *(pData) = sal::static_int_cast< char >( ( nVal << 4 ) & 0xf0 ); + } + // the len div 2, because 2 character are one byte + return bValidData ? nLen / 2 : STRING_NOTFOUND; +} + +BOOL SvxRTFParser::ReadBmpData( Graphic& rGrf, SvxRTFPictureType& rPicType ) +{ + // die alten Daten loeschen + rGrf.Clear(); +// ULONG nBmpSize = 0; + + rtl_TextEncoding eOldEnc = GetSrcEncoding(); + SetSrcEncoding( RTL_TEXTENCODING_MS_1252 ); + + const sal_Char* pFilterNm = 0; + SvCacheStream* pTmpFile = 0; + + int nToken = 0; + bool bValidBmp = true, bFirstTextToken = true; + int _nOpenBrakets = 1, // die erste wurde schon vorher erkannt !! + nValidDataBraket = 1; + + if( RTF_SHPPICT == GetStackPtr(0)->nTokenId ) + ++nValidDataBraket; + + while( _nOpenBrakets && IsParserWorking() && bValidBmp ) + { + nToken = GetNextToken(); + USHORT nVal = USHORT( nTokenValue ); + switch( nToken ) + { + case '}': --_nOpenBrakets; break; + case '{': + { + if( RTF_IGNOREFLAG != GetNextToken() ) + nToken = SkipToken( -1 ); + else if( RTF_UNKNOWNCONTROL != GetNextToken() ) + nToken = SkipToken( -2 ); + else + { + // gleich herausfiltern + ReadUnknownData(); + nToken = GetNextToken(); + if( '}' != nToken ) + eState = SVPAR_ERROR; + break; + } + ++_nOpenBrakets; + } + break; + + case RTF_MACPICT: + { + rPicType.eStyle = SvxRTFPictureType::MAC_QUICKDRAW; + // Mac-Pict bekommt einen leeren Header voran + pTmpFile = new SvCacheStream; + ByteString aStr; + aStr.Fill( 512, '\0' ); + pTmpFile->Write( aStr.GetBuffer(), aStr.Len() ); + pFilterNm = "PCT"; + } + break; + + case RTF_EMFBLIP: + case RTF_WMETAFILE: + case RTF_PNGBLIP: + case RTF_JPEGBLIP: + case RTF_WBITMAP: + case RTF_OSMETAFILE: + case RTF_DIBITMAP: + { + switch( nToken ) + { + case RTF_EMFBLIP: + rPicType.eStyle = SvxRTFPictureType::ENHANCED_MF; + pFilterNm = "EMF"; + break; + case RTF_WMETAFILE: + rPicType.eStyle = SvxRTFPictureType::WIN_METAFILE; + pFilterNm = "WMF"; + break; + case RTF_PNGBLIP: + rPicType.eStyle = SvxRTFPictureType::RTF_PNG; + pFilterNm = "PNG"; + break; + case RTF_JPEGBLIP: + rPicType.eStyle = SvxRTFPictureType::RTF_JPG; + pFilterNm = "JPG"; + break; + + case RTF_WBITMAP: + rPicType.eStyle = SvxRTFPictureType::RTF_BITMAP; + break; + case RTF_OSMETAFILE: + rPicType.eStyle = SvxRTFPictureType::OS2_METAFILE; + break; + case RTF_DIBITMAP: + rPicType.eStyle = SvxRTFPictureType::RTF_DI_BMP; + break; + } + + rPicType.nType = nVal; + pTmpFile = new SvCacheStream; + } + break; + + case RTF_PICW: rPicType.nWidth = nVal; break; + case RTF_PICH: rPicType.nHeight = nVal; break; + case RTF_WBMBITSPIXEL: rPicType.nBitsPerPixel = nVal; break; + case RTF_WBMPLANES: rPicType.nPlanes = nVal; break; + case RTF_WBMWIDTHBYTES: rPicType.nWidthBytes = nVal; break; + case RTF_PICWGOAL: rPicType.nGoalWidth = nVal; break; + case RTF_PICHGOAL: rPicType.nGoalHeight = nVal; break; + case RTF_BIN: + rPicType.nMode = SvxRTFPictureType::BINARY_MODE; + rPicType.uPicLen = nTokenValue; + if (rPicType.uPicLen) + { + ULONG nPos = rStrm.Tell(); + nPos = nPos; + rStrm.SeekRel(-1); + sal_uInt8 aData[4096]; + ULONG nSize = sizeof(aData); + + while (rPicType.uPicLen > 0) + { + if (rPicType.uPicLen < nSize) + nSize = rPicType.uPicLen; + + rStrm.Read(aData, nSize); + pTmpFile->Write(aData, nSize); + rPicType.uPicLen -= nSize; + } + nNextCh = GetNextChar(); + bValidBmp = !pTmpFile->GetError(); + nPos = rStrm.Tell(); + nPos = nPos; + } + break; + case RTF_PICSCALEX: rPicType.nScalX = nVal; break; + case RTF_PICSCALEY: rPicType.nScalY = nVal; break; + case RTF_PICSCALED: break; + + case RTF_PICCROPT: rPicType.nCropT = (short)nTokenValue; break; + case RTF_PICCROPB: rPicType.nCropB = (short)nTokenValue; break; + case RTF_PICCROPL: rPicType.nCropL = (short)nTokenValue; break; + case RTF_PICCROPR: rPicType.nCropR = (short)nTokenValue; break; + + case RTF_TEXTTOKEN: + // JP 26.06.98: Bug #51719# - nur TextToken auf 1. Ebene + // auswerten. Alle anderen sind irgendwelche + // nicht auszuwertende Daten + if( nValidDataBraket != _nOpenBrakets ) + break; + + if( bFirstTextToken ) + { + switch( rPicType.eStyle ) + { + case SvxRTFPictureType::RTF_BITMAP: + // erstmal die Header und Info-Struktur schreiben + if( pTmpFile ) + ::WriteBMPHeader( *pTmpFile, rPicType ); + break; + default: + break; + } + bFirstTextToken = FALSE; + } + + if( pTmpFile && SvxRTFPictureType::HEX_MODE == rPicType.nMode ) + { + xub_StrLen nTokenLen = HexToBin( aToken ); + if( STRING_NOTFOUND == nTokenLen ) + bValidBmp = FALSE; + else + { + pTmpFile->Write( (sal_Char*)aToken.GetBuffer(), + nTokenLen ); + bValidBmp = 0 == pTmpFile->GetError(); + } + } + break; + } + } + + if (pTmpFile) + { + //#i20775# + if (pTmpFile->Tell() == 0) + bValidBmp = false; + + if( bValidBmp ) + { + GraphicFilter* pGF = GraphicFilter::GetGraphicFilter(); + USHORT nImportFilter = GRFILTER_FORMAT_DONTKNOW; + + if( pFilterNm ) + { + String sTmp; + for( USHORT n = pGF->GetImportFormatCount(); n; ) + { + sTmp = pGF->GetImportFormatShortName( --n ); + if( sTmp.EqualsAscii( pFilterNm )) + { + nImportFilter = n; + break; + } + } + } + + String sTmpStr; + pTmpFile->Seek( STREAM_SEEK_TO_BEGIN ); + bValidBmp = 0 == pGF->ImportGraphic( rGrf, sTmpStr, *pTmpFile, + nImportFilter ); + } + delete pTmpFile; + } + + if( !bValidBmp ) + { + rGrf.Clear(); + //TODO If nToken were not initialized to 0 above, it would potentially + // be used uninitialized here (if IsParserWorking() is false at the + // start of the while loop above): + if( '}' != nToken ) + SkipGroup(); + } + else + { + switch( rPicType.eStyle ) + { +//?? ENHANCED_MF, // in den Pict.Daten steht ein Enhanced-Metafile + case SvxRTFPictureType::RTF_PNG: + case SvxRTFPictureType::RTF_JPG: + { + const MapMode aMap( MAP_100TH_MM ); + Size aSize( rGrf.GetPrefSize() ); + if( MAP_PIXEL == rGrf.GetPrefMapMode().GetMapUnit() ) + aSize = Application::GetDefaultDevice()->PixelToLogic( + aSize, aMap ); + else + aSize = OutputDevice::LogicToLogic( aSize, + rGrf.GetPrefMapMode(), aMap ); + rPicType.nWidth = sal::static_int_cast< USHORT >(aSize.Width()); + rPicType.nHeight = sal::static_int_cast< USHORT >( + aSize.Height()); + } + break; + default: + break; + } + +#ifdef DEBUG_JP + new GrfWindow( rGrf ); +#endif + } + SetSrcEncoding( eOldEnc ); + + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet + return bValidBmp; +} + +/* vi:set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/editeng/source/rtf/rtfitem.cxx b/editeng/source/rtf/rtfitem.cxx new file mode 100644 index 000000000000..a8e3d4b3d25e --- /dev/null +++ b/editeng/source/rtf/rtfitem.cxx @@ -0,0 +1,2104 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: rtfitem.cxx,v $ + * $Revision: 1.35.212.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ + +#include <editeng/flstitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fwdtitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/shdditem.hxx> +#include <editeng/akrnitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/cntritem.hxx> +#include <editeng/prszitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/cscoitem.hxx> +#include <editeng/kernitem.hxx> +#include <editeng/cmapitem.hxx> +#include <editeng/escpitem.hxx> +#include <editeng/langitem.hxx> +#include <editeng/nlbkitem.hxx> +#include <editeng/nhypitem.hxx> +#include <editeng/lcolitem.hxx> +#include <editeng/blnkitem.hxx> +#include <editeng/emphitem.hxx> +#include <editeng/twolinesitem.hxx> +#include <editeng/pbinitem.hxx> +#include <editeng/sizeitem.hxx> +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/prntitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/protitem.hxx> +#include <editeng/shaditem.hxx> +#include <editeng/boxitem.hxx> +#include <editeng/brkitem.hxx> +#include <editeng/keepitem.hxx> +#include <editeng/bolnitem.hxx> +#include <editeng/brshitem.hxx> +#include <editeng/lspcitem.hxx> +#include <editeng/adjitem.hxx> +#include <editeng/orphitem.hxx> +#include <editeng/widwitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/pmdlitem.hxx> +#include <editeng/spltitem.hxx> +#include <editeng/hyznitem.hxx> +#include <editeng/charscaleitem.hxx> +#include <editeng/charrotateitem.hxx> +#include <editeng/charreliefitem.hxx> +#include <editeng/paravertalignitem.hxx> +#include <editeng/forbiddenruleitem.hxx> +#include <editeng/hngpnctitem.hxx> +#include <editeng/scriptspaceitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/charhiddenitem.hxx> + +#include <svtools/rtftoken.h> +#include <svl/itempool.hxx> +#include <svl/itemiter.hxx> + +#include <editeng/svxrtf.hxx> +#include <editeng/editids.hrc> + +#define BRACELEFT '{' +#define BRACERIGHT '}' + + +// einige Hilfs-Funktionen +// char +inline const SvxEscapementItem& GetEscapement(const SfxItemSet& rSet,USHORT nId,BOOL bInP=TRUE) + { return (const SvxEscapementItem&)rSet.Get( nId,bInP); } +inline const SvxLineSpacingItem& GetLineSpacing(const SfxItemSet& rSet,USHORT nId,BOOL bInP=TRUE) + { return (const SvxLineSpacingItem&)rSet.Get( nId,bInP); } +// frm +inline const SvxLRSpaceItem& GetLRSpace(const SfxItemSet& rSet,USHORT nId,BOOL bInP=TRUE) + { return (const SvxLRSpaceItem&)rSet.Get( nId,bInP); } +inline const SvxULSpaceItem& GetULSpace(const SfxItemSet& rSet,USHORT nId,BOOL bInP=TRUE) + { return (const SvxULSpaceItem&)rSet.Get( nId,bInP); } + +#define PARDID ((RTFPardAttrMapIds*)aPardMap.GetData()) +#define PLAINID ((RTFPlainAttrMapIds*)aPlainMap.GetData()) + +void SvxRTFParser::SetScriptAttr( RTF_CharTypeDef eType, SfxItemSet& rSet, + SfxPoolItem& rItem ) +{ + const USHORT *pNormal = 0, *pCJK = 0, *pCTL = 0; + const RTFPlainAttrMapIds* pIds = (RTFPlainAttrMapIds*)aPlainMap.GetData(); + switch( rItem.Which() ) + { + case SID_ATTR_CHAR_FONT: + pNormal = &pIds->nFont; + pCJK = &pIds->nCJKFont; + pCTL = &pIds->nCTLFont; + break; + + case SID_ATTR_CHAR_FONTHEIGHT: + pNormal = &pIds->nFontHeight; + pCJK = &pIds->nCJKFontHeight; + pCTL = &pIds->nCTLFontHeight; + break; + + case SID_ATTR_CHAR_POSTURE: + pNormal = &pIds->nPosture; + pCJK = &pIds->nCJKPosture; + pCTL = &pIds->nCTLPosture; + break; + + case SID_ATTR_CHAR_WEIGHT: + pNormal = &pIds->nWeight; + pCJK = &pIds->nCJKWeight; + pCTL = &pIds->nCTLWeight; + break; + + case SID_ATTR_CHAR_LANGUAGE: + pNormal = &pIds->nLanguage; + pCJK = &pIds->nCJKLanguage; + pCTL = &pIds->nCTLLanguage; + break; + + case 0: + // it exist no WhichId - don't set this item + break; + + default: + rSet.Put( rItem ); + break; + } + + + if( DOUBLEBYTE_CHARTYPE == eType ) + { + if( bIsLeftToRightDef && *pCJK ) + { + rItem.SetWhich( *pCJK ); + rSet.Put( rItem ); + } + } + else if( !bIsLeftToRightDef ) + { + if( *pCTL ) + { + rItem.SetWhich( *pCTL ); + rSet.Put( rItem ); + } + } + else + { + if( LOW_CHARTYPE == eType ) + { + if( *pNormal ) + { + rItem.SetWhich( *pNormal ); + rSet.Put( rItem ); + } + } + else if( HIGH_CHARTYPE == eType ) + { + if( *pCTL ) + { + rItem.SetWhich( *pCTL ); + rSet.Put( rItem ); + } + } + else + { + if( *pCJK ) + { + rItem.SetWhich( *pCJK ); + rSet.Put( rItem ); + } + if( *pCTL ) + { + rItem.SetWhich( *pCTL ); + rSet.Put( rItem ); + } + if( *pNormal ) + { + rItem.SetWhich( *pNormal ); + rSet.Put( rItem ); + } + } + } +} + +// -------------------- + +void SvxRTFParser::ReadAttr( int nToken, SfxItemSet* pSet ) +{ + DBG_ASSERT( pSet, "Es muss ein SfxItemSet uebergeben werden!" ); + int bFirstToken = TRUE, bWeiter = TRUE; + USHORT nStyleNo = 0; // default + FontUnderline eUnderline; + FontUnderline eOverline; + FontEmphasisMark eEmphasis; + bPardTokenRead = FALSE; + RTF_CharTypeDef eCharType = NOTDEF_CHARTYPE; + USHORT nFontAlign; + + int bChkStkPos = !bNewGroup && aAttrStack.Top(); + + while( bWeiter && IsParserWorking() ) // solange bekannte Attribute erkannt werden + { + switch( nToken ) + { + case RTF_PARD: + RTFPardPlain( TRUE, &pSet ); + ResetPard(); + nStyleNo = 0; + bPardTokenRead = TRUE; + break; + + case RTF_PLAIN: + RTFPardPlain( FALSE, &pSet ); + break; + + default: + do { // middle checked loop + if( !bChkStkPos ) + break; + + SvxRTFItemStackType* pAkt = aAttrStack.Top(); + if( !pAkt || (pAkt->pSttNd->GetIdx() == pInsPos->GetNodeIdx() && + pAkt->nSttCnt == pInsPos->GetCntIdx() )) + break; + + int nLastToken = GetStackPtr(-1)->nTokenId; + if( RTF_PARD == nLastToken || RTF_PLAIN == nLastToken ) + break; + + if( pAkt->aAttrSet.Count() || pAkt->pChildList || + pAkt->nStyleNo ) + { + // eine neue Gruppe aufmachen + SvxRTFItemStackType* pNew = new SvxRTFItemStackType( + *pAkt, *pInsPos, TRUE ); + pNew->SetRTFDefaults( GetRTFDefaults() ); + + // alle bis hierher gueltigen Attribute "setzen" + AttrGroupEnd(); + pAkt = aAttrStack.Top(); // can be changed after AttrGroupEnd! + pNew->aAttrSet.SetParent( pAkt ? &pAkt->aAttrSet : 0 ); + + aAttrStack.Push( pNew ); + pAkt = pNew; + } + else + // diesen Eintrag als neuen weiterbenutzen + pAkt->SetStartPos( *pInsPos ); + + pSet = &pAkt->aAttrSet; + } while( FALSE ); + + switch( nToken ) + { + case RTF_INTBL: + case RTF_PAGEBB: + case RTF_SBYS: + case RTF_CS: + case RTF_LS: + case RTF_ILVL: + UnknownAttrToken( nToken, pSet ); + break; + + case RTF_S: + if( bIsInReadStyleTab ) + { + if( !bFirstToken ) + SkipToken( -1 ); + bWeiter = FALSE; + } + else + { + nStyleNo = -1 == nTokenValue ? 0 : USHORT(nTokenValue); + // setze am akt. auf dem AttrStack stehenden Style die + // StyleNummer + SvxRTFItemStackType* pAkt = aAttrStack.Top(); + if( !pAkt ) + break; + + pAkt->nStyleNo = USHORT( nStyleNo ); + +#if 0 +// JP 05.09.95: zuruecksetzen der Style-Attribute fuehrt nur zu Problemen. +// Es muss reichen, wenn das ueber pard/plain erfolgt +// ansonsten Bugdoc 15304.rtf - nach nur "\pard" falscher Font !! + + SvxRTFStyleType* pStyle = aStyleTbl.Get( pAkt->nStyleNo ); + if( pStyle && pStyle->aAttrSet.Count() ) + { + //JP 07.07.95: + // alle Attribute, die in der Vorlage gesetzt werden + // auf defaults setzen. In RTF werden die Attribute + // der Vorlage danach ja wiederholt. + // WICHTIG: Attribute die in der Vorlage definiert + // sind, werden zurueckgesetzt !!!! + // pAkt->aAttrSet.Put( pStyle->aAttrSet ); + + SfxItemIter aIter( pStyle->aAttrSet ); + SfxItemPool* pPool = pStyle->aAttrSet.GetPool(); + USHORT nWh = aIter.GetCurItem()->Which(); + while( TRUE ) + { + pAkt->aAttrSet.Put( pPool->GetDefaultItem( nWh )); + if( aIter.IsAtEnd() ) + break; + nWh = aIter.NextItem()->Which(); + } + } +#endif + } + break; + + case RTF_KEEP: + if( PARDID->nSplit ) + { + pSet->Put( SvxFmtSplitItem( FALSE, PARDID->nSplit )); + } + break; + + case RTF_KEEPN: + if( PARDID->nKeep ) + { + pSet->Put( SvxFmtKeepItem( TRUE, PARDID->nKeep )); + } + break; + + case RTF_LEVEL: + if( PARDID->nOutlineLvl ) + { + pSet->Put( SfxUInt16Item( PARDID->nOutlineLvl, + (UINT16)nTokenValue )); + } + break; + + case RTF_QL: + if( PARDID->nAdjust ) + { + pSet->Put( SvxAdjustItem( SVX_ADJUST_LEFT, PARDID->nAdjust )); + } + break; + case RTF_QR: + if( PARDID->nAdjust ) + { + pSet->Put( SvxAdjustItem( SVX_ADJUST_RIGHT, PARDID->nAdjust )); + } + break; + case RTF_QJ: + if( PARDID->nAdjust ) + { + pSet->Put( SvxAdjustItem( SVX_ADJUST_BLOCK, PARDID->nAdjust )); + } + break; + case RTF_QC: + if( PARDID->nAdjust ) + { + pSet->Put( SvxAdjustItem( SVX_ADJUST_CENTER, PARDID->nAdjust )); + } + break; + + case RTF_FI: + if( PARDID->nLRSpace ) + { + SvxLRSpaceItem aLR( GetLRSpace(*pSet, PARDID->nLRSpace )); + USHORT nSz = 0; + if( -1 != nTokenValue ) + { + if( IsCalcValue() ) + CalcValue(); + nSz = USHORT(nTokenValue); + } + aLR.SetTxtFirstLineOfst( nSz ); + pSet->Put( aLR ); + } + break; + + case RTF_LI: + case RTF_LIN: + if( PARDID->nLRSpace ) + { + SvxLRSpaceItem aLR( GetLRSpace(*pSet, PARDID->nLRSpace )); + USHORT nSz = 0; + if( 0 < nTokenValue ) + { + if( IsCalcValue() ) + CalcValue(); + nSz = USHORT(nTokenValue); + } + aLR.SetTxtLeft( nSz ); + pSet->Put( aLR ); + } + break; + + case RTF_RI: + case RTF_RIN: + if( PARDID->nLRSpace ) + { + SvxLRSpaceItem aLR( GetLRSpace(*pSet, PARDID->nLRSpace )); + USHORT nSz = 0; + if( 0 < nTokenValue ) + { + if( IsCalcValue() ) + CalcValue(); + nSz = USHORT(nTokenValue); + } + aLR.SetRight( nSz ); + pSet->Put( aLR ); + } + break; + + case RTF_SB: + if( PARDID->nULSpace ) + { + SvxULSpaceItem aUL( GetULSpace(*pSet, PARDID->nULSpace )); + USHORT nSz = 0; + if( 0 < nTokenValue ) + { + if( IsCalcValue() ) + CalcValue(); + nSz = USHORT(nTokenValue); + } + aUL.SetUpper( nSz ); + pSet->Put( aUL ); + } + break; + + case RTF_SA: + if( PARDID->nULSpace ) + { + SvxULSpaceItem aUL( GetULSpace(*pSet, PARDID->nULSpace )); + USHORT nSz = 0; + if( 0 < nTokenValue ) + { + if( IsCalcValue() ) + CalcValue(); + nSz = USHORT(nTokenValue); + } + aUL.SetLower( nSz ); + pSet->Put( aUL ); + } + break; + + case RTF_SLMULT: + if( PARDID->nLinespacing && 1 == nTokenValue ) + { + // dann wird auf mehrzeilig umgeschaltet! + SvxLineSpacingItem aLSpace( GetLineSpacing( *pSet, + PARDID->nLinespacing, FALSE )); + + // wieviel bekommt man aus dem LineHeight Wert heraus + + // Proportionale-Groesse: + // D.H. das Verhaeltnis ergibt sich aus ( n / 240 ) Twips + + nTokenValue = 240; + if( IsCalcValue() ) + CalcValue(); + + nTokenValue = short( 100L * aLSpace.GetLineHeight() + / long( nTokenValue ) ); + + if( nTokenValue > 200 ) // Datenwert fuer PropLnSp + nTokenValue = 200; // ist ein BYTE !!! + + aLSpace.SetPropLineSpace( (const BYTE)nTokenValue ); + aLSpace.GetLineSpaceRule() = SVX_LINE_SPACE_AUTO; + + pSet->Put( aLSpace ); + } + break; + + case RTF_SL: + if( PARDID->nLinespacing ) + { + // errechne das Verhaeltnis aus dem default Font zu der + // Size Angabe. Der Abstand besteht aus der Zeilenhoehe + // (100%) und dem Leerraum ueber der Zeile (20%). + SvxLineSpacingItem aLSpace(0, PARDID->nLinespacing); + + nTokenValue = !bTokenHasValue ? 0 : nTokenValue; + if (1000 == nTokenValue ) + nTokenValue = 240; + + SvxLineSpace eLnSpc; + if (nTokenValue < 0) + { + eLnSpc = SVX_LINE_SPACE_FIX; + nTokenValue = -nTokenValue; + } + else if (nTokenValue == 0) + { + //if \sl0 is used, the line spacing is automatically + //determined + eLnSpc = SVX_LINE_SPACE_AUTO; + } + else + eLnSpc = SVX_LINE_SPACE_MIN; + + if (IsCalcValue()) + CalcValue(); + + if (eLnSpc != SVX_LINE_SPACE_AUTO) + aLSpace.SetLineHeight( (const USHORT)nTokenValue ); + + aLSpace.GetLineSpaceRule() = eLnSpc; + pSet->Put(aLSpace); + } + break; + + case RTF_NOCWRAP: + if( PARDID->nForbRule ) + { + pSet->Put( SvxForbiddenRuleItem( FALSE, + PARDID->nForbRule )); + } + break; + case RTF_NOOVERFLOW: + if( PARDID->nHangPunct ) + { + pSet->Put( SvxHangingPunctuationItem( FALSE, + PARDID->nHangPunct )); + } + break; + + case RTF_ASPALPHA: + if( PARDID->nScriptSpace ) + { + pSet->Put( SvxScriptSpaceItem( TRUE, + PARDID->nScriptSpace )); + } + break; + + case RTF_FAFIXED: + case RTF_FAAUTO: nFontAlign = SvxParaVertAlignItem::AUTOMATIC; + goto SET_FONTALIGNMENT; + case RTF_FAHANG: nFontAlign = SvxParaVertAlignItem::TOP; + goto SET_FONTALIGNMENT; + case RTF_FAVAR: nFontAlign = SvxParaVertAlignItem::BOTTOM; + goto SET_FONTALIGNMENT; + case RTF_FACENTER: nFontAlign = SvxParaVertAlignItem::CENTER; + goto SET_FONTALIGNMENT; + case RTF_FAROMAN: nFontAlign = SvxParaVertAlignItem::BASELINE; + goto SET_FONTALIGNMENT; +SET_FONTALIGNMENT: + if( PARDID->nFontAlign ) + { + pSet->Put( SvxParaVertAlignItem( nFontAlign, + PARDID->nFontAlign )); + } + break; + +/* */ + case RTF_B: + case RTF_AB: + if( IsAttrSttPos() ) // nicht im Textfluss ? + { + + SvxWeightItem aTmpItem( + nTokenValue ? WEIGHT_BOLD : WEIGHT_NORMAL, + SID_ATTR_CHAR_WEIGHT ); + SetScriptAttr( eCharType, *pSet, aTmpItem); + } + break; + + case RTF_CAPS: + case RTF_SCAPS: + if( PLAINID->nCaseMap && + IsAttrSttPos() ) // nicht im Textfluss ? + { + SvxCaseMap eCaseMap; + if( !nTokenValue ) + eCaseMap = SVX_CASEMAP_NOT_MAPPED; + else if( RTF_CAPS == nToken ) + eCaseMap = SVX_CASEMAP_VERSALIEN; + else + eCaseMap = SVX_CASEMAP_KAPITAELCHEN; + + pSet->Put( SvxCaseMapItem( eCaseMap, PLAINID->nCaseMap )); + } + break; + + case RTF_DN: + case RTF_SUB: + if( PLAINID->nEscapement ) + { + const USHORT nEsc = PLAINID->nEscapement; + if( -1 == nTokenValue || RTF_SUB == nToken ) + nTokenValue = 6; + if( IsCalcValue() ) + CalcValue(); + const SvxEscapementItem& rOld = GetEscapement( *pSet, nEsc, FALSE ); + short nEs; + BYTE nProp; + if( DFLT_ESC_AUTO_SUPER == rOld.GetEsc() ) + { + nEs = DFLT_ESC_AUTO_SUB; + nProp = rOld.GetProp(); + } + else + { + nEs = (short)-nTokenValue; + nProp = (nToken == RTF_SUB) ? DFLT_ESC_PROP : 100; + } + pSet->Put( SvxEscapementItem( nEs, nProp, nEsc )); + } + break; + + case RTF_NOSUPERSUB: + if( PLAINID->nEscapement ) + { + const USHORT nEsc = PLAINID->nEscapement; + pSet->Put( SvxEscapementItem( nEsc )); + } + break; + + case RTF_EXPND: + if( PLAINID->nKering ) + { + if( -1 == nTokenValue ) + nTokenValue = 0; + else + nTokenValue *= 5; + if( IsCalcValue() ) + CalcValue(); + pSet->Put( SvxKerningItem( (short)nTokenValue, PLAINID->nKering )); + } + break; + + case RTF_KERNING: + if( PLAINID->nAutoKerning ) + { + if( -1 == nTokenValue ) + nTokenValue = 0; + else + nTokenValue *= 10; + if( IsCalcValue() ) + CalcValue(); + pSet->Put( SvxAutoKernItem( 0 != nTokenValue, + PLAINID->nAutoKerning )); + } + break; + + case RTF_EXPNDTW: + if( PLAINID->nKering ) + { + if( -1 == nTokenValue ) + nTokenValue = 0; + if( IsCalcValue() ) + CalcValue(); + pSet->Put( SvxKerningItem( (short)nTokenValue, PLAINID->nKering )); + } + break; + + case RTF_F: + case RTF_AF: + { + const Font& rSVFont = GetFont( USHORT(nTokenValue) ); + SvxFontItem aTmpItem( rSVFont.GetFamily(), + rSVFont.GetName(), rSVFont.GetStyleName(), + rSVFont.GetPitch(), rSVFont.GetCharSet(), + SID_ATTR_CHAR_FONT ); + SetScriptAttr( eCharType, *pSet, aTmpItem ); + if( RTF_F == nToken ) + { + SetEncoding( rSVFont.GetCharSet() ); + RereadLookahead(); + } + } + break; + + case RTF_FS: + case RTF_AFS: + { + if( -1 == nTokenValue ) + nTokenValue = 240; + else + nTokenValue *= 10; +// #i66167# +// for the SwRTFParser 'IsCalcValue' will be false and for the EditRTFParser +// the converiosn takes now place in EditRTFParser since for other reasons +// the wrong MapUnit might still be use there +// if( IsCalcValue() ) +// CalcValue(); + SvxFontHeightItem aTmpItem( + (const USHORT)nTokenValue, 100, + SID_ATTR_CHAR_FONTHEIGHT ); + SetScriptAttr( eCharType, *pSet, aTmpItem ); + } + break; + + case RTF_I: + case RTF_AI: + if( IsAttrSttPos() ) // nicht im Textfluss ? + { + SvxPostureItem aTmpItem( + nTokenValue ? ITALIC_NORMAL : ITALIC_NONE, + SID_ATTR_CHAR_POSTURE ); + SetScriptAttr( eCharType, *pSet, aTmpItem ); + } + break; + + case RTF_OUTL: + if( PLAINID->nContour && + IsAttrSttPos() ) // nicht im Textfluss ? + { + pSet->Put( SvxContourItem( nTokenValue ? TRUE : FALSE, + PLAINID->nContour )); + } + break; + + case RTF_SHAD: + if( PLAINID->nShadowed && + IsAttrSttPos() ) // nicht im Textfluss ? + { + pSet->Put( SvxShadowedItem( nTokenValue ? TRUE : FALSE, + PLAINID->nShadowed )); + } + break; + + case RTF_STRIKE: + if( PLAINID->nCrossedOut && + IsAttrSttPos() ) // nicht im Textfluss ? + { + pSet->Put( SvxCrossedOutItem( + nTokenValue ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, + PLAINID->nCrossedOut )); + } + break; + + case RTF_STRIKED: + if( PLAINID->nCrossedOut ) // nicht im Textfluss ? + { + pSet->Put( SvxCrossedOutItem( + nTokenValue ? STRIKEOUT_DOUBLE : STRIKEOUT_NONE, + PLAINID->nCrossedOut )); + } + break; + + case RTF_UL: + if( !IsAttrSttPos() ) + break; + eUnderline = nTokenValue ? UNDERLINE_SINGLE : UNDERLINE_NONE; + goto ATTR_SETUNDERLINE; + + case RTF_ULD: + eUnderline = UNDERLINE_DOTTED; + goto ATTR_SETUNDERLINE; + case RTF_ULDASH: + eUnderline = UNDERLINE_DASH; + goto ATTR_SETUNDERLINE; + case RTF_ULDASHD: + eUnderline = UNDERLINE_DASHDOT; + goto ATTR_SETUNDERLINE; + case RTF_ULDASHDD: + eUnderline = UNDERLINE_DASHDOTDOT; + goto ATTR_SETUNDERLINE; + case RTF_ULDB: + eUnderline = UNDERLINE_DOUBLE; + goto ATTR_SETUNDERLINE; + case RTF_ULNONE: + eUnderline = UNDERLINE_NONE; + goto ATTR_SETUNDERLINE; + case RTF_ULTH: + eUnderline = UNDERLINE_BOLD; + goto ATTR_SETUNDERLINE; + case RTF_ULWAVE: + eUnderline = UNDERLINE_WAVE; + goto ATTR_SETUNDERLINE; + case RTF_ULTHD: + eUnderline = UNDERLINE_BOLDDOTTED; + goto ATTR_SETUNDERLINE; + case RTF_ULTHDASH: + eUnderline = UNDERLINE_BOLDDASH; + goto ATTR_SETUNDERLINE; + case RTF_ULLDASH: + eUnderline = UNDERLINE_LONGDASH; + goto ATTR_SETUNDERLINE; + case RTF_ULTHLDASH: + eUnderline = UNDERLINE_BOLDLONGDASH; + goto ATTR_SETUNDERLINE; + case RTF_ULTHDASHD: + eUnderline = UNDERLINE_BOLDDASHDOT; + goto ATTR_SETUNDERLINE; + case RTF_ULTHDASHDD: + eUnderline = UNDERLINE_BOLDDASHDOTDOT; + goto ATTR_SETUNDERLINE; + case RTF_ULHWAVE: + eUnderline = UNDERLINE_BOLDWAVE; + goto ATTR_SETUNDERLINE; + case RTF_ULULDBWAVE: + eUnderline = UNDERLINE_DOUBLEWAVE; + goto ATTR_SETUNDERLINE; + + case RTF_ULW: + eUnderline = UNDERLINE_SINGLE; + + if( PLAINID->nWordlineMode ) + { + pSet->Put( SvxWordLineModeItem( TRUE, PLAINID->nWordlineMode )); + } + goto ATTR_SETUNDERLINE; + +ATTR_SETUNDERLINE: + if( PLAINID->nUnderline ) + { + pSet->Put( SvxUnderlineItem( eUnderline, PLAINID->nUnderline )); + } + break; + + case RTF_ULC: + if( PLAINID->nUnderline ) + { + SvxUnderlineItem aUL( UNDERLINE_SINGLE, PLAINID->nUnderline ); + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pSet->GetItemState( + PLAINID->nUnderline, FALSE, &pItem ) ) + { + // is switched off ? + if( UNDERLINE_NONE == + ((SvxUnderlineItem*)pItem)->GetLineStyle() ) + break; + aUL = *(SvxUnderlineItem*)pItem; + } + else + aUL = (const SvxUnderlineItem&)pSet->Get( PLAINID->nUnderline, FALSE ); + + if( UNDERLINE_NONE == aUL.GetLineStyle() ) + aUL.SetLineStyle( UNDERLINE_SINGLE ); + aUL.SetColor( GetColor( USHORT(nTokenValue) )); + pSet->Put( aUL ); + } + break; + + case RTF_OL: + if( !IsAttrSttPos() ) + break; + eOverline = nTokenValue ? UNDERLINE_SINGLE : UNDERLINE_NONE; + goto ATTR_SETOVERLINE; + + case RTF_OLD: + eOverline = UNDERLINE_DOTTED; + goto ATTR_SETOVERLINE; + case RTF_OLDASH: + eOverline = UNDERLINE_DASH; + goto ATTR_SETOVERLINE; + case RTF_OLDASHD: + eOverline = UNDERLINE_DASHDOT; + goto ATTR_SETOVERLINE; + case RTF_OLDASHDD: + eOverline = UNDERLINE_DASHDOTDOT; + goto ATTR_SETOVERLINE; + case RTF_OLDB: + eOverline = UNDERLINE_DOUBLE; + goto ATTR_SETOVERLINE; + case RTF_OLNONE: + eOverline = UNDERLINE_NONE; + goto ATTR_SETOVERLINE; + case RTF_OLTH: + eOverline = UNDERLINE_BOLD; + goto ATTR_SETOVERLINE; + case RTF_OLWAVE: + eOverline = UNDERLINE_WAVE; + goto ATTR_SETOVERLINE; + case RTF_OLTHD: + eOverline = UNDERLINE_BOLDDOTTED; + goto ATTR_SETOVERLINE; + case RTF_OLTHDASH: + eOverline = UNDERLINE_BOLDDASH; + goto ATTR_SETOVERLINE; + case RTF_OLLDASH: + eOverline = UNDERLINE_LONGDASH; + goto ATTR_SETOVERLINE; + case RTF_OLTHLDASH: + eOverline = UNDERLINE_BOLDLONGDASH; + goto ATTR_SETOVERLINE; + case RTF_OLTHDASHD: + eOverline = UNDERLINE_BOLDDASHDOT; + goto ATTR_SETOVERLINE; + case RTF_OLTHDASHDD: + eOverline = UNDERLINE_BOLDDASHDOTDOT; + goto ATTR_SETOVERLINE; + case RTF_OLHWAVE: + eOverline = UNDERLINE_BOLDWAVE; + goto ATTR_SETOVERLINE; + case RTF_OLOLDBWAVE: + eOverline = UNDERLINE_DOUBLEWAVE; + goto ATTR_SETOVERLINE; + + case RTF_OLW: + eOverline = UNDERLINE_SINGLE; + + if( PLAINID->nWordlineMode ) + { + pSet->Put( SvxWordLineModeItem( TRUE, PLAINID->nWordlineMode )); + } + goto ATTR_SETOVERLINE; + +ATTR_SETOVERLINE: + if( PLAINID->nUnderline ) + { + pSet->Put( SvxOverlineItem( eOverline, PLAINID->nOverline )); + } + break; + + case RTF_OLC: + if( PLAINID->nOverline ) + { + SvxOverlineItem aOL( UNDERLINE_SINGLE, PLAINID->nOverline ); + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == pSet->GetItemState( + PLAINID->nOverline, FALSE, &pItem ) ) + { + // is switched off ? + if( UNDERLINE_NONE == + ((SvxOverlineItem*)pItem)->GetLineStyle() ) + break; + aOL = *(SvxOverlineItem*)pItem; + } + else + aOL = (const SvxOverlineItem&)pSet->Get( PLAINID->nUnderline, FALSE ); + + if( UNDERLINE_NONE == aOL.GetLineStyle() ) + aOL.SetLineStyle( UNDERLINE_SINGLE ); + aOL.SetColor( GetColor( USHORT(nTokenValue) )); + pSet->Put( aOL ); + } + break; + + case RTF_UP: + case RTF_SUPER: + if( PLAINID->nEscapement ) + { + const USHORT nEsc = PLAINID->nEscapement; + if( -1 == nTokenValue || RTF_SUPER == nToken ) + nTokenValue = 6; + if( IsCalcValue() ) + CalcValue(); + const SvxEscapementItem& rOld = GetEscapement( *pSet, nEsc, FALSE ); + short nEs; + BYTE nProp; + if( DFLT_ESC_AUTO_SUB == rOld.GetEsc() ) + { + nEs = DFLT_ESC_AUTO_SUPER; + nProp = rOld.GetProp(); + } + else + { + nEs = (short)nTokenValue; + nProp = (nToken == RTF_SUPER) ? DFLT_ESC_PROP : 100; + } + pSet->Put( SvxEscapementItem( nEs, nProp, nEsc )); + } + break; + + case RTF_CF: + if( PLAINID->nColor ) + { + pSet->Put( SvxColorItem( GetColor( USHORT(nTokenValue) ), + PLAINID->nColor )); + } + break; +#if 0 + //#i12501# While cb is clearly documented in the rtf spec, word + //doesn't accept it at all + case RTF_CB: + if( PLAINID->nBgColor ) + { + pSet->Put( SvxBrushItem( GetColor( USHORT(nTokenValue) ), + PLAINID->nBgColor )); + } + break; +#endif + case RTF_LANG: + if( PLAINID->nLanguage ) + { + pSet->Put( SvxLanguageItem( (LanguageType)nTokenValue, + PLAINID->nLanguage )); + } + break; + + case RTF_LANGFE: + if( PLAINID->nCJKLanguage ) + { + pSet->Put( SvxLanguageItem( (LanguageType)nTokenValue, + PLAINID->nCJKLanguage )); + } + break; + case RTF_ALANG: + { + SvxLanguageItem aTmpItem( (LanguageType)nTokenValue, + SID_ATTR_CHAR_LANGUAGE ); + SetScriptAttr( eCharType, *pSet, aTmpItem ); + } + break; + + case RTF_RTLCH: + bIsLeftToRightDef = FALSE; + break; + case RTF_LTRCH: + bIsLeftToRightDef = TRUE; + break; + case RTF_RTLPAR: + if (PARDID->nDirection) + { + pSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_RIGHT_TOP, + PARDID->nDirection)); + } + break; + case RTF_LTRPAR: + if (PARDID->nDirection) + { + pSet->Put(SvxFrameDirectionItem(FRMDIR_HORI_LEFT_TOP, + PARDID->nDirection)); + } + break; + case RTF_LOCH: eCharType = LOW_CHARTYPE; break; + case RTF_HICH: eCharType = HIGH_CHARTYPE; break; + case RTF_DBCH: eCharType = DOUBLEBYTE_CHARTYPE; break; + + + case RTF_ACCNONE: + eEmphasis = EMPHASISMARK_NONE; + goto ATTR_SETEMPHASIS; + case RTF_ACCDOT: + eEmphasis = EMPHASISMARK_DOTS_ABOVE; + goto ATTR_SETEMPHASIS; + + case RTF_ACCCOMMA: + eEmphasis = EMPHASISMARK_SIDE_DOTS; +ATTR_SETEMPHASIS: + if( PLAINID->nEmphasis ) + { + pSet->Put( SvxEmphasisMarkItem( eEmphasis, + PLAINID->nEmphasis )); + } + break; + + case RTF_TWOINONE: + if( PLAINID->nTwoLines ) + { + sal_Unicode cStt, cEnd; + switch ( nTokenValue ) + { + case 1: cStt = '(', cEnd = ')'; break; + case 2: cStt = '[', cEnd = ']'; break; + case 3: cStt = '<', cEnd = '>'; break; + case 4: cStt = '{', cEnd = '}'; break; + default: cStt = 0, cEnd = 0; break; + } + + pSet->Put( SvxTwoLinesItem( TRUE, cStt, cEnd, + PLAINID->nTwoLines )); + } + break; + + case RTF_CHARSCALEX : + if (PLAINID->nCharScaleX) + { + //i21372 + if (nTokenValue < 1 || nTokenValue > 600) + nTokenValue = 100; + pSet->Put( SvxCharScaleWidthItem( USHORT(nTokenValue), + PLAINID->nCharScaleX )); + } + break; + + case RTF_HORZVERT: + if( PLAINID->nHorzVert ) + { + // RTF knows only 90deg + pSet->Put( SvxCharRotateItem( 900, 1 == nTokenValue, + PLAINID->nHorzVert )); + } + break; + + case RTF_EMBO: + if (PLAINID->nRelief) + { + pSet->Put(SvxCharReliefItem(RELIEF_EMBOSSED, + PLAINID->nRelief)); + } + break; + case RTF_IMPR: + if (PLAINID->nRelief) + { + pSet->Put(SvxCharReliefItem(RELIEF_ENGRAVED, + PLAINID->nRelief)); + } + break; + case RTF_V: + if (PLAINID->nHidden) + { + pSet->Put(SvxCharHiddenItem(nTokenValue != 0, + PLAINID->nHidden)); + } + break; + case RTF_CHBGFDIAG: + case RTF_CHBGDKVERT: + case RTF_CHBGDKHORIZ: + case RTF_CHBGVERT: + case RTF_CHBGHORIZ: + case RTF_CHBGDKFDIAG: + case RTF_CHBGDCROSS: + case RTF_CHBGCROSS: + case RTF_CHBGBDIAG: + case RTF_CHBGDKDCROSS: + case RTF_CHBGDKCROSS: + case RTF_CHBGDKBDIAG: + case RTF_CHCBPAT: + case RTF_CHCFPAT: + case RTF_CHSHDNG: + if( PLAINID->nBgColor ) + ReadBackgroundAttr( nToken, *pSet ); + break; + + +/* */ + + case BRACELEFT: + { + // teste auf Swg-Interne Tokens + bool bHandled = false; + short nSkip = 0; + if( RTF_IGNOREFLAG != GetNextToken()) + nSkip = -1; + else if( (nToken = GetNextToken() ) & RTF_SWGDEFS ) + { + bHandled = true; + switch( nToken ) + { + case RTF_PGDSCNO: + case RTF_PGBRK: + case RTF_SOUTLVL: + UnknownAttrToken( nToken, pSet ); + // ueberlese die schliessende Klammer + break; + + case RTF_SWG_ESCPROP: + { + // prozentuale Veraenderung speichern ! + BYTE nProp = BYTE( nTokenValue / 100 ); + short nEsc = 0; + if( 1 == ( nTokenValue % 100 )) + // Erkennung unseres AutoFlags! + nEsc = DFLT_ESC_AUTO_SUPER; + + if( PLAINID->nEscapement ) + pSet->Put( SvxEscapementItem( nEsc, nProp, + PLAINID->nEscapement )); + } + break; + + case RTF_HYPHEN: + { + SvxHyphenZoneItem aHypenZone( + (nTokenValue & 1) ? TRUE : FALSE, + PARDID->nHyphenzone ); + aHypenZone.SetPageEnd( + (nTokenValue & 2) ? TRUE : FALSE ); + + if( PARDID->nHyphenzone && + RTF_HYPHLEAD == GetNextToken() && + RTF_HYPHTRAIL == GetNextToken() && + RTF_HYPHMAX == GetNextToken() ) + { + aHypenZone.GetMinLead() = + BYTE(GetStackPtr( -2 )->nTokenValue); + aHypenZone.GetMinTrail() = + BYTE(GetStackPtr( -1 )->nTokenValue); + aHypenZone.GetMaxHyphens() = + BYTE(nTokenValue); + + pSet->Put( aHypenZone ); + } + else + SkipGroup(); // ans Ende der Gruppe + } + break; + + case RTF_SHADOW: + { + int bSkip = TRUE; + do { // middle check loop + SvxShadowLocation eSL = SvxShadowLocation( nTokenValue ); + if( RTF_SHDW_DIST != GetNextToken() ) + break; + USHORT nDist = USHORT( nTokenValue ); + + if( RTF_SHDW_STYLE != GetNextToken() ) + break; + //! (pb) class Brush removed -> obsolete + //! BrushStyle eStyle = BrushStyle( nTokenValue ); + + if( RTF_SHDW_COL != GetNextToken() ) + break; + USHORT nCol = USHORT( nTokenValue ); + + if( RTF_SHDW_FCOL != GetNextToken() ) + break; +// USHORT nFillCol = USHORT( nTokenValue ); + + Color aColor = GetColor( nCol ); + + if( PARDID->nShadow ) + pSet->Put( SvxShadowItem( PARDID->nShadow, + &aColor, nDist, eSL ) ); + + bSkip = FALSE; + } while( FALSE ); + + if( bSkip ) + SkipGroup(); // ans Ende der Gruppe + } + break; + + default: + bHandled = false; + if( (nToken & ~(0xff | RTF_SWGDEFS)) == RTF_TABSTOPDEF ) + { + nToken = SkipToken( -2 ); + ReadTabAttr( nToken, *pSet ); + + /* + cmc: #i76140, he who consumed the { must consume the } + We rewound to a state of { being the current + token so it is our responsibility to consume the } + token if we consumed the {. We will not have consumed + the { if it belonged to our caller, i.e. if the { we + are handling is the "firsttoken" passed to us then + the *caller* must consume it, not us. Otherwise *we* + should consume it. + */ + if (nToken == BRACELEFT && !bFirstToken) + { + nToken = GetNextToken(); + DBG_ASSERT( nToken == BRACERIGHT, + "} did not follow { as expected\n"); + } + } + else if( (nToken & ~(0xff| RTF_SWGDEFS)) == RTF_BRDRDEF) + { + nToken = SkipToken( -2 ); + ReadBorderAttr( nToken, *pSet ); + } + else // also kein Attribut mehr + nSkip = -2; + break; + } + +#if 1 + /* + cmc: #i4727# / #i12713# Who owns this closing bracket? + If we read the opening one, we must read this one, if + other is counting the brackets so as to push/pop off + the correct environment then we will have pushed a new + environment for the start { of this, but will not see + the } and so is out of sync for the rest of the + document. + */ + if (bHandled && !bFirstToken) + GetNextToken(); +#endif + } + else + nSkip = -2; + + if( nSkip ) // alles voellig unbekannt + { + if (!bFirstToken) + --nSkip; // BRACELEFT: ist das naechste Token + SkipToken( nSkip ); + bWeiter = FALSE; + } + } + break; + default: + if( (nToken & ~0xff ) == RTF_TABSTOPDEF ) + ReadTabAttr( nToken, *pSet ); + else if( (nToken & ~0xff ) == RTF_BRDRDEF ) + ReadBorderAttr( nToken, *pSet ); + else if( (nToken & ~0xff ) == RTF_SHADINGDEF ) + ReadBackgroundAttr( nToken, *pSet ); + else + { + // kenne das Token nicht also das Token "in den Parser zurueck" + if( !bFirstToken ) + SkipToken( -1 ); + bWeiter = FALSE; + } + } + } + if( bWeiter ) + { + nToken = GetNextToken(); + } + bFirstToken = FALSE; + } + +/* + // teste Attribute gegen ihre Styles + if( IsChkStyleAttr() && pSet->Count() && !pInsPos->GetCntIdx() ) + { + SvxRTFStyleType* pStyle = aStyleTbl.Get( nStyleNo ); + if( pStyle && pStyle->aAttrSet.Count() ) + { + // alle Attribute, die schon vom Style definiert sind, aus dem + // akt. Set entfernen + const SfxPoolItem* pItem; + SfxItemIter aIter( *pSet ); + USHORT nWhich = aIter.GetCurItem()->Which(); + while( TRUE ) + { + if( SFX_ITEM_SET == pStyle->aAttrSet.GetItemState( + nWhich, FALSE, &pItem ) && *pItem == *aIter.GetCurItem()) + pSet->ClearItem( nWhich ); // loeschen + + if( aIter.IsAtEnd() ) + break; + nWhich = aIter.NextItem()->Which(); + } + } + } +*/ +} + +void SvxRTFParser::ReadTabAttr( int nToken, SfxItemSet& rSet ) +{ + bool bMethodOwnsToken = false; // #i52542# patch from cmc. +// dann lese doch mal alle TabStops ein + SvxTabStop aTabStop; + SvxTabStopItem aAttr( 0, 0, SVX_TAB_ADJUST_DEFAULT, PARDID->nTabStop ); + int bWeiter = TRUE; + do { + switch( nToken ) + { + case RTF_TB: // BarTab ??? + case RTF_TX: + { + if( IsCalcValue() ) + CalcValue(); + aTabStop.GetTabPos() = nTokenValue; + aAttr.Insert( aTabStop ); + aTabStop = SvxTabStop(); // alle Werte default + } + break; + + case RTF_TQL: + aTabStop.GetAdjustment() = SVX_TAB_ADJUST_LEFT; + break; + case RTF_TQR: + aTabStop.GetAdjustment() = SVX_TAB_ADJUST_RIGHT; + break; + case RTF_TQC: + aTabStop.GetAdjustment() = SVX_TAB_ADJUST_CENTER; + break; + case RTF_TQDEC: + aTabStop.GetAdjustment() = SVX_TAB_ADJUST_DECIMAL; + break; + + case RTF_TLDOT: aTabStop.GetFill() = '.'; break; + case RTF_TLHYPH: aTabStop.GetFill() = ' '; break; + case RTF_TLUL: aTabStop.GetFill() = '_'; break; + case RTF_TLTH: aTabStop.GetFill() = '-'; break; + case RTF_TLEQ: aTabStop.GetFill() = '='; break; + + case BRACELEFT: + { + // Swg - Kontrol BRACELEFT RTF_IGNOREFLAG RTF_TLSWG BRACERIGHT + short nSkip = 0; + if( RTF_IGNOREFLAG != GetNextToken() ) + nSkip = -1; + else if( RTF_TLSWG != ( nToken = GetNextToken() )) + nSkip = -2; + else + { + aTabStop.GetDecimal() = BYTE(nTokenValue & 0xff); + aTabStop.GetFill() = BYTE((nTokenValue >> 8) & 0xff); + // ueberlese noch die schliessende Klammer + if (bMethodOwnsToken) + GetNextToken(); + } + if( nSkip ) + { + SkipToken( nSkip ); // Ignore wieder zurueck + bWeiter = FALSE; + } + } + break; + + default: + bWeiter = FALSE; + } + if( bWeiter ) + { + nToken = GetNextToken(); + bMethodOwnsToken = true; + } + } while( bWeiter ); + + // mit Defaults aufuellen fehlt noch !!! + rSet.Put( aAttr ); + SkipToken( -1 ); +} + +static void SetBorderLine( int nBorderTyp, SvxBoxItem& rItem, + const SvxBorderLine& rBorder ) +{ + switch( nBorderTyp ) + { + case RTF_BOX: // alle Stufen durchlaufen + + case RTF_BRDRT: + rItem.SetLine( &rBorder, BOX_LINE_TOP ); + if( RTF_BOX != nBorderTyp ) + return; + + case RTF_BRDRB: + rItem.SetLine( &rBorder, BOX_LINE_BOTTOM ); + if( RTF_BOX != nBorderTyp ) + return; + + case RTF_BRDRL: + rItem.SetLine( &rBorder, BOX_LINE_LEFT ); + if( RTF_BOX != nBorderTyp ) + return; + + case RTF_BRDRR: + rItem.SetLine( &rBorder, BOX_LINE_RIGHT ); + if( RTF_BOX != nBorderTyp ) + return; + } +} + +void SvxRTFParser::ReadBorderAttr( int nToken, SfxItemSet& rSet, + int bTableDef ) +{ + // dann lese doch mal das BoderAttribut ein + SvxBoxItem aAttr( PARDID->nBox ); + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == rSet.GetItemState( PARDID->nBox, FALSE, &pItem ) ) + aAttr = *(SvxBoxItem*)pItem; + + SvxBorderLine aBrd( 0, DEF_LINE_WIDTH_0, 0, 0 ); // einfache Linien + int bWeiter = TRUE, nBorderTyp = 0; + + do { + switch( nToken ) + { + case RTF_BOX: + case RTF_BRDRT: + case RTF_BRDRB: + case RTF_BRDRL: + case RTF_BRDRR: + nBorderTyp = nToken; + goto SETBORDER; + + case RTF_CLBRDRT: + if( !bTableDef ) + break; + nBorderTyp = RTF_BRDRT; + goto SETBORDER; + case RTF_CLBRDRB: + if( !bTableDef ) + break; + nBorderTyp = RTF_BRDRB; + goto SETBORDER; + case RTF_CLBRDRL: + if( !bTableDef ) + break; + nBorderTyp = RTF_BRDRL; + goto SETBORDER; + case RTF_CLBRDRR: + if( !bTableDef ) + break; + nBorderTyp = RTF_BRDRR; + goto SETBORDER; + +SETBORDER: + { + // auf defaults setzen + aBrd.SetOutWidth( DEF_LINE_WIDTH_0 ); + aBrd.SetInWidth( 0 ); + aBrd.SetDistance( 0 ); + aBrd.SetColor( Color( COL_BLACK ) ); + } + break; + + +// werden noch nicht ausgewertet + case RTF_BRSP: + { + switch( nBorderTyp ) + { + case RTF_BRDRB: + aAttr.SetDistance( (USHORT)nTokenValue, BOX_LINE_BOTTOM ); + break; + + case RTF_BRDRT: + aAttr.SetDistance( (USHORT)nTokenValue, BOX_LINE_TOP ); + break; + + case RTF_BRDRL: + aAttr.SetDistance( (USHORT)nTokenValue, BOX_LINE_LEFT ); + break; + + case RTF_BRDRR: + aAttr.SetDistance( (USHORT)nTokenValue, BOX_LINE_RIGHT ); + break; + + case RTF_BOX: + aAttr.SetDistance( (USHORT)nTokenValue ); + break; + } + } + break; + +case RTF_BRDRBTW: +case RTF_BRDRBAR: break; + + + case RTF_BRDRCF: + { + aBrd.SetColor( GetColor( USHORT(nTokenValue) ) ); + SetBorderLine( nBorderTyp, aAttr, aBrd ); + } + break; + + case RTF_BRDRTH: + aBrd.SetOutWidth( DEF_LINE_WIDTH_1 ); + aBrd.SetInWidth( 0 ); + aBrd.SetDistance( 0 ); + goto SETBORDERLINE; + + case RTF_BRDRDB: + aBrd.SetOutWidth( DEF_DOUBLE_LINE0_OUT ); + aBrd.SetInWidth( DEF_DOUBLE_LINE0_IN ); + aBrd.SetDistance( DEF_DOUBLE_LINE0_DIST ); + goto SETBORDERLINE; + + case RTF_BRDRSH: + // schattierte Box + { + rSet.Put( SvxShadowItem( PARDID->nShadow, (Color*) 0, 60 /*3pt*/, + SVX_SHADOW_BOTTOMRIGHT ) ); + } + break; + + case RTF_BRDRW: + if( -1 != nTokenValue ) + { + // sollte es eine "dicke" Linie sein ? + if( DEF_LINE_WIDTH_0 != aBrd.GetOutWidth() ) + nTokenValue *= 2; + + // eine Doppelline? + if( aBrd.GetInWidth() ) + { + // WinWord - Werte an StarOffice anpassen + if( nTokenValue < DEF_LINE_WIDTH_1 - (DEF_LINE_WIDTH_1/10)) + { + aBrd.SetOutWidth( DEF_DOUBLE_LINE0_OUT ); + aBrd.SetInWidth( DEF_DOUBLE_LINE0_IN ); + aBrd.SetDistance( DEF_DOUBLE_LINE0_DIST ); + } + else + if( nTokenValue < DEF_LINE_WIDTH_2 - (DEF_LINE_WIDTH_2/10)) + { + aBrd.SetOutWidth( DEF_DOUBLE_LINE1_OUT ); + aBrd.SetInWidth( DEF_DOUBLE_LINE1_IN ); + aBrd.SetDistance( DEF_DOUBLE_LINE1_DIST ); + } + else + { + aBrd.SetOutWidth( DEF_DOUBLE_LINE2_OUT ); + aBrd.SetInWidth( DEF_DOUBLE_LINE2_IN ); + aBrd.SetDistance( DEF_DOUBLE_LINE2_DIST ); + } + } + else + { + // WinWord - Werte an StarOffice anpassen + if( nTokenValue < DEF_LINE_WIDTH_1 - (DEF_LINE_WIDTH_1/10)) + aBrd.SetOutWidth( DEF_LINE_WIDTH_0 ); + else + if( nTokenValue < DEF_LINE_WIDTH_2 - (DEF_LINE_WIDTH_2/10)) + aBrd.SetOutWidth( DEF_LINE_WIDTH_1 ); + else + if( nTokenValue < DEF_LINE_WIDTH_3 - (DEF_LINE_WIDTH_3/10)) + aBrd.SetOutWidth( DEF_LINE_WIDTH_2 ); + else + if( nTokenValue < DEF_LINE_WIDTH_4 ) + aBrd.SetOutWidth( DEF_LINE_WIDTH_3 ); + else + aBrd.SetOutWidth( DEF_LINE_WIDTH_4 ); + } + } + goto SETBORDERLINE; + + case RTF_BRDRS: + case RTF_BRDRDOT: + case RTF_BRDRHAIR: + case RTF_BRDRDASH: +SETBORDERLINE: + SetBorderLine( nBorderTyp, aAttr, aBrd ); + break; + + case BRACELEFT: + { + short nSkip = 0; + if( RTF_IGNOREFLAG != GetNextToken() ) + nSkip = -1; + else + { + int bSwgControl = TRUE, bFirstToken = TRUE; + nToken = GetNextToken(); + do { + switch( nToken ) + { + case RTF_BRDBOX: + aAttr.SetDistance( USHORT(nTokenValue) ); + break; + + case RTF_BRDRT: + case RTF_BRDRB: + case RTF_BRDRR: + case RTF_BRDRL: + nBorderTyp = nToken; + bFirstToken = FALSE; + if( RTF_BRDLINE_COL != GetNextToken() ) + { + bSwgControl = FALSE; + break; + } + aBrd.SetColor( GetColor( USHORT(nTokenValue) )); + + if( RTF_BRDLINE_IN != GetNextToken() ) + { + bSwgControl = FALSE; + break; + } + aBrd.SetInWidth( USHORT(nTokenValue)); + + if( RTF_BRDLINE_OUT != GetNextToken() ) + { + bSwgControl = FALSE; + break; + } + aBrd.SetOutWidth( USHORT(nTokenValue)); + + if( RTF_BRDLINE_DIST != GetNextToken() ) + { + bSwgControl = FALSE; + break; + } + aBrd.SetDistance( USHORT(nTokenValue)); + SetBorderLine( nBorderTyp, aAttr, aBrd ); + break; + + default: + bSwgControl = FALSE; + break; + } + + if( bSwgControl ) + { + nToken = GetNextToken(); + bFirstToken = FALSE; + } + } while( bSwgControl ); + + // Ende der Swg-Gruppe + // -> lese noch die schliessende Klammer + if( BRACERIGHT == nToken ) + ; + else if( !bFirstToken ) + { + // es ist ein Parser-Fehler, springe zum + // Ende der Gruppe + SkipGroup(); + // schliessende BRACERIGHT ueberspringen + GetNextToken(); + } + else + nSkip = -2; + } + + if( nSkip ) + { + SkipToken( nSkip ); // Ignore wieder zurueck + bWeiter = FALSE; + } + } + break; + + default: + bWeiter = (nToken & ~(0xff| RTF_SWGDEFS)) == RTF_BRDRDEF; + } + if( bWeiter ) + nToken = GetNextToken(); + } while( bWeiter ); + rSet.Put( aAttr ); + SkipToken( -1 ); +} + +inline ULONG CalcShading( ULONG nColor, ULONG nFillColor, BYTE nShading ) +{ + nColor = (nColor * nShading) / 100; + nFillColor = (nFillColor * ( 100 - nShading )) / 100; + return nColor + nFillColor; +} + +void SvxRTFParser::ReadBackgroundAttr( int nToken, SfxItemSet& rSet, + int bTableDef ) +{ + // dann lese doch mal das BoderAttribut ein + int bWeiter = TRUE; + USHORT nColor = USHRT_MAX, nFillColor = USHRT_MAX; + BYTE nFillValue = 0; + + USHORT nWh = ( nToken & ~0xff ) == RTF_CHRFMT + ? PLAINID->nBgColor + : PARDID->nBrush; + + do { + switch( nToken ) + { + case RTF_CLCBPAT: + case RTF_CHCBPAT: + case RTF_CBPAT: + nFillColor = USHORT( nTokenValue ); + break; + + case RTF_CLCFPAT: + case RTF_CHCFPAT: + case RTF_CFPAT: + nColor = USHORT( nTokenValue ); + break; + + case RTF_CLSHDNG: + case RTF_CHSHDNG: + case RTF_SHADING: + nFillValue = (BYTE)( nTokenValue / 100 ); + break; + + case RTF_CLBGDKHOR: + case RTF_CHBGDKHORIZ: + case RTF_BGDKHORIZ: + case RTF_CLBGDKVERT: + case RTF_CHBGDKVERT: + case RTF_BGDKVERT: + case RTF_CLBGDKBDIAG: + case RTF_CHBGDKBDIAG: + case RTF_BGDKBDIAG: + case RTF_CLBGDKFDIAG: + case RTF_CHBGDKFDIAG: + case RTF_BGDKFDIAG: + case RTF_CLBGDKCROSS: + case RTF_CHBGDKCROSS: + case RTF_BGDKCROSS: + case RTF_CLBGDKDCROSS: + case RTF_CHBGDKDCROSS: + case RTF_BGDKDCROSS: + // dark -> 60% + nFillValue = 60; + break; + + case RTF_CLBGHORIZ: + case RTF_CHBGHORIZ: + case RTF_BGHORIZ: + case RTF_CLBGVERT: + case RTF_CHBGVERT: + case RTF_BGVERT: + case RTF_CLBGBDIAG: + case RTF_CHBGBDIAG: + case RTF_BGBDIAG: + case RTF_CLBGFDIAG: + case RTF_CHBGFDIAG: + case RTF_BGFDIAG: + case RTF_CLBGCROSS: + case RTF_CHBGCROSS: + case RTF_BGCROSS: + case RTF_CLBGDCROSS: + case RTF_CHBGDCROSS: + case RTF_BGDCROSS: + // light -> 20% + nFillValue = 20; + break; + + default: + if( bTableDef ) + bWeiter = (nToken & ~(0xff | RTF_TABLEDEF) ) == RTF_SHADINGDEF; + else + bWeiter = (nToken & ~0xff) == RTF_SHADINGDEF; + } + if( bWeiter ) + nToken = GetNextToken(); + } while( bWeiter ); + + Color aCol( COL_WHITE ), aFCol; + if( !nFillValue ) + { + // es wurde nur eine von beiden Farben angegeben oder kein BrushTyp + if( USHRT_MAX != nFillColor ) + { + nFillValue = 100; + aCol = GetColor( nFillColor ); + } + else if( USHRT_MAX != nColor ) + aFCol = GetColor( nColor ); + } + else + { + if( USHRT_MAX != nColor ) + aCol = GetColor( nColor ); + else + aCol = Color( COL_BLACK ); + + if( USHRT_MAX != nFillColor ) + aFCol = GetColor( nFillColor ); + else + aFCol = Color( COL_WHITE ); + } + + Color aColor; + if( 0 == nFillValue || 100 == nFillValue ) + aColor = aCol; + else + aColor = Color( + (BYTE)CalcShading( aCol.GetRed(), aFCol.GetRed(), nFillValue ), + (BYTE)CalcShading( aCol.GetGreen(), aFCol.GetGreen(), nFillValue ), + (BYTE)CalcShading( aCol.GetBlue(), aFCol.GetBlue(), nFillValue ) ); + + rSet.Put( SvxBrushItem( aColor, nWh ) ); + SkipToken( -1 ); +} + + +// pard / plain abarbeiten +void SvxRTFParser::RTFPardPlain( int bPard, SfxItemSet** ppSet ) +{ + if( !bNewGroup && aAttrStack.Top() ) // nicht am Anfang einer neuen Gruppe + { + SvxRTFItemStackType* pAkt = aAttrStack.Top(); + + int nLastToken = GetStackPtr(-1)->nTokenId; + int bNewStkEntry = TRUE; + if( RTF_PARD != nLastToken && + RTF_PLAIN != nLastToken && + BRACELEFT != nLastToken ) + { + if( pAkt->aAttrSet.Count() || pAkt->pChildList || pAkt->nStyleNo ) + { + // eine neue Gruppe aufmachen + SvxRTFItemStackType* pNew = new SvxRTFItemStackType( *pAkt, *pInsPos, TRUE ); + pNew->SetRTFDefaults( GetRTFDefaults() ); + + // alle bis hierher gueltigen Attribute "setzen" + AttrGroupEnd(); + pAkt = aAttrStack.Top(); // can be changed after AttrGroupEnd! + pNew->aAttrSet.SetParent( pAkt ? &pAkt->aAttrSet : 0 ); + aAttrStack.Push( pNew ); + pAkt = pNew; + } + else + { + // diesen Eintrag als neuen weiterbenutzen + pAkt->SetStartPos( *pInsPos ); + bNewStkEntry = FALSE; + } + } + + // jetzt noch alle auf default zuruecksetzen + if( bNewStkEntry && + ( pAkt->aAttrSet.GetParent() || pAkt->aAttrSet.Count() )) + { + const SfxPoolItem *pItem, *pDef; + const USHORT* pPtr; + USHORT nCnt; + const SfxItemSet* pDfltSet = &GetRTFDefaults(); + if( bPard ) + { + pAkt->nStyleNo = 0; + pPtr = aPardMap.GetData(); + nCnt = aPardMap.Count(); + } + else + { + pPtr = aPlainMap.GetData(); + nCnt = aPlainMap.Count(); + } + + for( USHORT n = 0; n < nCnt; ++n, ++pPtr ) + { + // Item gesetzt und unterschiedlich -> das Pooldefault setzen + //JP 06.04.98: bei Items die nur SlotItems sind, darf nicht + // auf das Default zugefriffen werden. Diese + // werden gecleart + if( !*pPtr ) + ; + else if( SFX_WHICH_MAX < *pPtr ) + pAkt->aAttrSet.ClearItem( *pPtr ); + else if( IsChkStyleAttr() ) + pAkt->aAttrSet.Put( pDfltSet->Get( *pPtr ) ); + else if( !pAkt->aAttrSet.GetParent() ) + { + if( SFX_ITEM_SET == + pDfltSet->GetItemState( *pPtr, FALSE, &pDef )) + pAkt->aAttrSet.Put( *pDef ); + else + pAkt->aAttrSet.ClearItem( *pPtr ); + } + else if( SFX_ITEM_SET == pAkt->aAttrSet.GetParent()-> + GetItemState( *pPtr, TRUE, &pItem ) && + *( pDef = &pDfltSet->Get( *pPtr )) != *pItem ) + pAkt->aAttrSet.Put( *pDef ); + else + { + if( SFX_ITEM_SET == + pDfltSet->GetItemState( *pPtr, FALSE, &pDef )) + pAkt->aAttrSet.Put( *pDef ); + else + pAkt->aAttrSet.ClearItem( *pPtr ); + } + } + } + else if( bPard ) + pAkt->nStyleNo = 0; // Style-Nummer zuruecksetzen + + *ppSet = &pAkt->aAttrSet; + + if (!bPard) + { + //Once we have a default font, then any text without a font specifier is + //in the default font, and thus has the default font charset, otherwise + //we can fall back to the ansicpg set codeset + if (nDfltFont != -1) + { + const Font& rSVFont = GetFont(USHORT(nDfltFont)); + SetEncoding(rSVFont.GetCharSet()); + } + else + SetEncoding(GetCodeSet()); + } + } +} + +void SvxRTFParser::SetDefault( int nToken, int nValue ) +{ + if( !bNewDoc ) + return; + + SfxItemSet aTmp( *pAttrPool, aWhichMap.GetData() ); + BOOL bOldFlag = bIsLeftToRightDef; + bIsLeftToRightDef = TRUE; + switch( nToken ) + { + case RTF_ADEFF: bIsLeftToRightDef = FALSE; // no break! + case RTF_DEFF: + { + if( -1 == nValue ) + nValue = 0; + const Font& rSVFont = GetFont( USHORT(nValue) ); + SvxFontItem aTmpItem( + rSVFont.GetFamily(), rSVFont.GetName(), + rSVFont.GetStyleName(), rSVFont.GetPitch(), + rSVFont.GetCharSet(), SID_ATTR_CHAR_FONT ); + SetScriptAttr( NOTDEF_CHARTYPE, aTmp, aTmpItem ); + } + break; + + case RTF_ADEFLANG: bIsLeftToRightDef = FALSE; // no break! + case RTF_DEFLANG: + // default Language merken + if( -1 != nValue ) + { + SvxLanguageItem aTmpItem( (const LanguageType)nValue, + SID_ATTR_CHAR_LANGUAGE ); + SetScriptAttr( NOTDEF_CHARTYPE, aTmp, aTmpItem ); + } + break; + + case RTF_DEFTAB: + if( PARDID->nTabStop ) + { + // RTF definiert 720 twips als default + bIsSetDfltTab = TRUE; + if( -1 == nValue || !nValue ) + nValue = 720; + + // wer keine Twips haben moechte ... + if( IsCalcValue() ) + { + nTokenValue = nValue; + CalcValue(); + nValue = nTokenValue; + } +#if 1 + /* + cmc: + This stuff looks a little hairy indeed, this should be totally + unnecessary where default tabstops are understood. Just make one + tabstop and stick the value in there, the first one is all that + matters. + + e.g. + + SvxTabStopItem aNewTab(1, USHORT(nValue), SVX_TAB_ADJUST_DEFAULT, + PARDID->nTabStop); + ((SvxTabStop&)aNewTab[0]).GetAdjustment() = SVX_TAB_ADJUST_DEFAULT; + + + It must exist as a foul hack to support somebody that does not + have a true concept of default tabstops by making a tabsetting + result from the default tabstop, creating a lot of them all at + the default locations to give the effect of the first real + default tabstop being in use just in case the receiving + application doesn't do that for itself. + */ +#endif + + // Verhaeltnis der def. TabWidth / Tabs errechnen und + // enstsprechend die neue Anzahl errechnen. +/*-----------------14.12.94 19:32------------------- + ?? wie kommt man auf die 13 ?? +--------------------------------------------------*/ + USHORT nAnzTabs = (SVX_TAB_DEFDIST * 13 ) / USHORT(nValue); + /* + cmc, make sure we have at least one, or all hell breaks loose in + everybodies exporters, #i8247# + */ + if (nAnzTabs < 1) + nAnzTabs = 1; + + // wir wollen Defaulttabs + SvxTabStopItem aNewTab( nAnzTabs, USHORT(nValue), + SVX_TAB_ADJUST_DEFAULT, PARDID->nTabStop ); + while( nAnzTabs ) + ((SvxTabStop&)aNewTab[ --nAnzTabs ]).GetAdjustment() = SVX_TAB_ADJUST_DEFAULT; + + pAttrPool->SetPoolDefaultItem( aNewTab ); + } + break; + } + bIsLeftToRightDef = bOldFlag; + + if( aTmp.Count() ) + { + SfxItemIter aIter( aTmp ); + const SfxPoolItem* pItem = aIter.GetCurItem(); + while( TRUE ) + { + pAttrPool->SetPoolDefaultItem( *pItem ); + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + } +} + +// default: keine Umrechnung, alles bei Twips lassen. +void SvxRTFParser::CalcValue() +{ +} + + // fuer Tokens, die im ReadAttr nicht ausgewertet werden +void SvxRTFParser::UnknownAttrToken( int, SfxItemSet* ) +{ +} + +/* vi:set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/editeng/source/rtf/segincr.asm b/editeng/source/rtf/segincr.asm new file mode 100644 index 000000000000..d90d79dbd8be --- /dev/null +++ b/editeng/source/rtf/segincr.asm @@ -0,0 +1,43 @@ +;************************************************************************* +; +; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +; +; Copyright 2008 by Sun Microsystems, Inc. +; +; OpenOffice.org - a multi-platform office productivity suite +; +; $RCSfile: segincr.asm,v $ +; +; $Revision: 1.6 $ +; +; This file is part of OpenOffice.org. +; +; OpenOffice.org is free software: you can redistribute it and/or modify +; it under the terms of the GNU Lesser General Public License version 3 +; only, as published by the Free Software Foundation. +; +; OpenOffice.org is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU Lesser General Public License version 3 for more details +; (a copy is included in the LICENSE file that accompanied this code). +; +; You should have received a copy of the GNU Lesser General Public License +; version 3 along with OpenOffice.org. If not, see +; <http://www.openoffice.org/license.html> +; for a copy of the LGPLv3 License. +; +;************************************************************************* + +EXTRN __AHINCR:abs + .MODEL LARGE +STARTWS0_SEG SEGMENT WORD PUBLIC 'STARTWS_CODE' + + PUBLIC _SegIncr +_SegIncr PROC + MOV AX, __AHINCR + RET +_SegIncr ENDP + +STARTWS0_SEG ENDS + END diff --git a/editeng/source/rtf/svxrtf.cxx b/editeng/source/rtf/svxrtf.cxx new file mode 100644 index 000000000000..c659abe45a90 --- /dev/null +++ b/editeng/source/rtf/svxrtf.cxx @@ -0,0 +1,1517 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: svxrtf.cxx,v $ + * $Revision: 1.34.212.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ + + +#include <ctype.h> +#include <tools/datetime.hxx> +#include <rtl/tencinfo.h> +#include <svl/itemiter.hxx> +#include <svl/whiter.hxx> +#include <svtools/rtftoken.h> +#include <svl/itempool.hxx> + +#include <comphelper/string.hxx> + +#include <com/sun/star/lang/Locale.hpp> +#include <editeng/scriptspaceitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/svxrtf.hxx> +#include <editeng/editids.hrc> +#include <vcl/svapp.hxx> + +#include <com/sun/star/document/XDocumentProperties.hpp> + + +using namespace ::com::sun::star; + + +SV_IMPL_PTRARR( SvxRTFColorTbl, ColorPtr ) +SV_IMPL_PTRARR( SvxRTFItemStackList, SvxRTFItemStackType* ) + +CharSet lcl_GetDefaultTextEncodingForRTF() +{ + + ::com::sun::star::lang::Locale aLocale; + ::rtl::OUString aLangString; + + aLocale = Application::GetSettings().GetLocale(); + aLangString = aLocale.Language; + + if ( aLangString.equals( ::rtl::OUString::createFromAscii( "ru" ) ) + || aLangString.equals( ::rtl::OUString::createFromAscii( "uk" ) ) ) + return RTL_TEXTENCODING_MS_1251; + if ( aLangString.equals( ::rtl::OUString::createFromAscii( "tr" ) ) ) + return RTL_TEXTENCODING_MS_1254; + else + return RTL_TEXTENCODING_MS_1252; +} + +// -------------- Methoden -------------------- + +SvxRTFParser::SvxRTFParser( SfxItemPool& rPool, SvStream& rIn, + uno::Reference<document::XDocumentProperties> i_xDocProps, + int bReadNewDoc ) + : SvRTFParser( rIn, 5 ), + rStrm(rIn), + aColorTbl( 16, 4 ), + aFontTbl( 16, 4 ), + pInsPos( 0 ), + pAttrPool( &rPool ), + m_xDocProps( i_xDocProps ), + pRTFDefaults( 0 ), + nVersionNo( 0 ) +{ + bNewDoc = bReadNewDoc; + + bChkStyleAttr = bCalcValue = bReadDocInfo = bIsInReadStyleTab = FALSE; + bIsLeftToRightDef = TRUE; + + { + RTFPlainAttrMapIds aTmp( rPool ); + aPlainMap.Insert( (USHORT*)&aTmp, + sizeof( RTFPlainAttrMapIds ) / sizeof(USHORT), 0 ); + } + { + RTFPardAttrMapIds aTmp( rPool ); + aPardMap.Insert( (USHORT*)&aTmp, + sizeof( RTFPardAttrMapIds ) / sizeof(USHORT), 0 ); + } + pDfltFont = new Font; + pDfltColor = new Color; +} + +void SvxRTFParser::EnterEnvironment() +{ +} + +void SvxRTFParser::LeaveEnvironment() +{ +} + +void SvxRTFParser::ResetPard() +{ +} + +SvxRTFParser::~SvxRTFParser() +{ + if( aColorTbl.Count() ) + ClearColorTbl(); + if( aFontTbl.Count() ) + ClearFontTbl(); + if( aStyleTbl.Count() ) + ClearStyleTbl(); + if( aAttrStack.Count() ) + ClearAttrStack(); + + delete pRTFDefaults; + + delete pInsPos; + delete pDfltFont; + delete pDfltColor; +} + +void SvxRTFParser::SetInsPos( const SvxPosition& rNew ) +{ + if( pInsPos ) + delete pInsPos; + pInsPos = rNew.Clone(); +} + +SvParserState SvxRTFParser::CallParser() +{ + DBG_ASSERT( pInsPos, "keine Einfuegeposition" ); + + if( !pInsPos ) + return SVPAR_ERROR; + + if( aColorTbl.Count() ) + ClearColorTbl(); + if( aFontTbl.Count() ) + ClearFontTbl(); + if( aStyleTbl.Count() ) + ClearStyleTbl(); + if( aAttrStack.Count() ) + ClearAttrStack(); + + bIsSetDfltTab = FALSE; + bNewGroup = FALSE; + nDfltFont = 0; + + sBaseURL.Erase(); + + // erzeuge aus den gesetzten WhichIds die richtige WhichId-Tabelle. + BuildWhichTbl(); + + return SvRTFParser::CallParser(); +} + +void SvxRTFParser::Continue( int nToken ) +{ + SvRTFParser::Continue( nToken ); + + if( SVPAR_PENDING != GetStatus() ) + { + SetAllAttrOfStk(); +#if 0 + //Regardless of what "color 0" is, word defaults to auto as the default colour. + //e.g. see #i7713# + if( bNewDoc && ((RTFPlainAttrMapIds*)aPlainMap.GetData())->nColor ) + pAttrPool->SetPoolDefaultItem( SvxColorItem( GetColor( 0 ), + ((RTFPlainAttrMapIds*)aPlainMap.GetData())->nColor )); +#endif + } +} + + +// wird fuer jedes Token gerufen, das in CallParser erkannt wird +void SvxRTFParser::NextToken( int nToken ) +{ + sal_Unicode cCh; + switch( nToken ) + { + case RTF_COLORTBL: ReadColorTable(); break; + case RTF_FONTTBL: ReadFontTable(); break; + case RTF_STYLESHEET: ReadStyleTable(); break; + + case RTF_DEFF: + if( bNewDoc ) + { + if( aFontTbl.Count() ) + // koennen wir sofort setzen + SetDefault( nToken, nTokenValue ); + else + // wird nach einlesen der Fonttabelle gesetzt + nDfltFont = int(nTokenValue); + } + break; + + case RTF_DEFTAB: + case RTF_DEFLANG: + if( bNewDoc ) + SetDefault( nToken, nTokenValue ); + break; + + + case RTF_PICT: ReadBitmapData(); break; + + case RTF_LINE: cCh = '\n'; goto INSINGLECHAR; + case RTF_TAB: cCh = '\t'; goto INSINGLECHAR; + case RTF_SUBENTRYINDEX: cCh = ':'; goto INSINGLECHAR; + + case RTF_EMDASH: cCh = 151; goto INSINGLECHAR; + case RTF_ENDASH: cCh = 150; goto INSINGLECHAR; + case RTF_BULLET: cCh = 149; goto INSINGLECHAR; + case RTF_LQUOTE: cCh = 145; goto INSINGLECHAR; + case RTF_RQUOTE: cCh = 146; goto INSINGLECHAR; + case RTF_LDBLQUOTE: cCh = 147; goto INSINGLECHAR; + case RTF_RDBLQUOTE: cCh = 148; goto INSINGLECHAR; +INSINGLECHAR: + aToken = ByteString::ConvertToUnicode( (sal_Char)cCh, + RTL_TEXTENCODING_MS_1252 ); + + // kein Break, aToken wird als Text gesetzt + case RTF_TEXTTOKEN: + { + InsertText(); + // alle angesammelten Attribute setzen + for( USHORT n = aAttrSetList.Count(); n; ) + { + SvxRTFItemStackType* pStkSet = aAttrSetList[--n]; + SetAttrSet( *pStkSet ); + aAttrSetList.DeleteAndDestroy( n ); + } + } + break; + + + case RTF_PAR: + InsertPara(); + break; + case '{': + if (bNewGroup) // Verschachtelung !! + _GetAttrSet(); + EnterEnvironment(); + bNewGroup = true; + break; + case '}': + if( !bNewGroup ) // leere Gruppe ?? + AttrGroupEnd(); + LeaveEnvironment(); + bNewGroup = false; + break; + case RTF_INFO: +#ifndef SVX_LIGHT + if (bReadDocInfo && bNewDoc && m_xDocProps.is()) + ReadInfo(); + else +#endif + SkipGroup(); + break; + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // erstmal gesamt ueberlesen (muessen alle in einer Gruppe stehen !!) + // Koennen auch ohne dem IGNORE-Flag im RTF-File auftreten; alle Gruppen + // mit IGNORE-Flag werden im default-Zweig ueberlesen. + + case RTF_SWG_PRTDATA: + case RTF_FIELD: + case RTF_ATNID: + case RTF_ANNOTATION: + + case RTF_BKMKSTART: + case RTF_BKMKEND: + case RTF_BKMK_KEY: + case RTF_XE: + case RTF_TC: + case RTF_NEXTFILE: + case RTF_TEMPLATE: +#if 0 + //disabled for #i19718# + case RTF_SHPRSLT: // RTF_SHP fehlt noch !! +#endif + SkipGroup(); + break; + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + case RTF_PGDSCNO: + case RTF_PGBRK: + case RTF_SHADOW: + if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId ) + break; + nToken = SkipToken( -1 ); + if( '{' == GetStackPtr( -1 )->nTokenId ) + nToken = SkipToken( -1 ); + + ReadAttr( nToken, &GetAttrSet() ); + break; + + default: + switch( nToken & ~(0xff | RTF_SWGDEFS) ) + { + case RTF_PARFMT: // hier gibts keine Swg-Defines + ReadAttr( nToken, &GetAttrSet() ); + break; + + case RTF_CHRFMT: + case RTF_BRDRDEF: + case RTF_TABSTOPDEF: + + if( RTF_SWGDEFS & nToken) + { + if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId ) + break; + nToken = SkipToken( -1 ); + if( '{' == GetStackPtr( -1 )->nTokenId ) + { + nToken = SkipToken( -1 ); + } + } + ReadAttr( nToken, &GetAttrSet() ); + break; + default: + { + if( /*( '{' == GetStackPtr( -1 )->nTokenId ) ||*/ + ( RTF_IGNOREFLAG == GetStackPtr( -1 )->nTokenId && + '{' == GetStackPtr( -2 )->nTokenId ) ) + SkipGroup(); + } + break; + } + break; + } +} + +void SvxRTFParser::ReadStyleTable() +{ + int nToken, bSaveChkStyleAttr = bChkStyleAttr; + short nStyleNo = 0; + int _nOpenBrakets = 1; // die erste wurde schon vorher erkannt !! + SvxRTFStyleType* pStyle = new SvxRTFStyleType( *pAttrPool, aWhichMap.GetData() ); + pStyle->aAttrSet.Put( GetRTFDefaults() ); + + bIsInReadStyleTab = TRUE; + bChkStyleAttr = FALSE; // Attribute nicht gegen die Styles checken + + while( _nOpenBrakets && IsParserWorking() ) + { + switch( nToken = GetNextToken() ) + { + case '}': if( --_nOpenBrakets && IsParserWorking() ) + // Style konnte vollstaendig gelesen werden, + // also ist das noch ein stabiler Status + SaveState( RTF_STYLESHEET ); + break; + case '{': + { + if( RTF_IGNOREFLAG != GetNextToken() ) + nToken = SkipToken( -1 ); + else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) && + RTF_PN != nToken ) + nToken = SkipToken( -2 ); + else + { + // gleich herausfiltern + ReadUnknownData(); + nToken = GetNextToken(); + if( '}' != nToken ) + eState = SVPAR_ERROR; + break; + } + ++_nOpenBrakets; + } + break; + + case RTF_SBASEDON: pStyle->nBasedOn = USHORT(nTokenValue); pStyle->bBasedOnIsSet=TRUE; break; + case RTF_SNEXT: pStyle->nNext = USHORT(nTokenValue); break; + case RTF_OUTLINELEVEL: + case RTF_SOUTLVL: pStyle->nOutlineNo = BYTE(nTokenValue); break; + case RTF_S: nStyleNo = (short)nTokenValue; break; + case RTF_CS: nStyleNo = (short)nTokenValue; + pStyle->bIsCharFmt = TRUE; + break; + + case RTF_TEXTTOKEN: + { + pStyle->sName = DelCharAtEnd( aToken, ';' ); + +/* +??? soll man das umsetzen ??? + if( !pStyle->sName.Len() ) + pStyle->sName = "Standard"; +*/ + // sollte die Nummer doppelt vergeben werden ? + if( aStyleTbl.Count() ) + { + SvxRTFStyleType* pOldSt = aStyleTbl.Remove( nStyleNo ); + if( pOldSt ) + delete pOldSt; + } + // alle Daten vom Style vorhanden, also ab in die Tabelle + aStyleTbl.Insert( nStyleNo, pStyle ); + pStyle = new SvxRTFStyleType( *pAttrPool, aWhichMap.GetData() ); + pStyle->aAttrSet.Put( GetRTFDefaults() ); + nStyleNo = 0; + } + break; + default: + switch( nToken & ~(0xff | RTF_SWGDEFS) ) + { + case RTF_PARFMT: // hier gibts keine Swg-Defines + ReadAttr( nToken, &pStyle->aAttrSet ); + break; + + case RTF_CHRFMT: + case RTF_BRDRDEF: + case RTF_TABSTOPDEF: + + if( RTF_SWGDEFS & nToken) + { + if( RTF_IGNOREFLAG != GetStackPtr( -1 )->nTokenId ) + break; + nToken = SkipToken( -1 ); + if( '{' == GetStackPtr( -1 )->nTokenId ) + { + nToken = SkipToken( -1 ); +#if 0 + --_nOpenBrakets; // korrigieren!! +#endif + } + } + ReadAttr( nToken, &pStyle->aAttrSet ); + break; + } + break; + } + } + delete pStyle; // loesche das letze Style + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet + + // Flag wieder auf alten Zustand + bChkStyleAttr = bSaveChkStyleAttr; + bIsInReadStyleTab = FALSE; +} + +void SvxRTFParser::ReadColorTable() +{ + int nToken; + BYTE nRed = 0xff, nGreen = 0xff, nBlue = 0xff; + + while( '}' != ( nToken = GetNextToken() ) && IsParserWorking() ) + { + switch( nToken ) + { + case RTF_RED: nRed = BYTE(nTokenValue); break; + case RTF_GREEN: nGreen = BYTE(nTokenValue); break; + case RTF_BLUE: nBlue = BYTE(nTokenValue); break; + + case RTF_TEXTTOKEN: // oder sollte irgendein Unsin darumstehen? + if( 1 == aToken.Len() + ? aToken.GetChar( 0 ) != ';' + : STRING_NOTFOUND == aToken.Search( ';' ) ) + break; // es muss zumindestens das ';' gefunden werden + + // else kein break !! + + case ';': + if( IsParserWorking() ) + { + // eine Farbe ist Fertig, in die Tabelle eintragen + // versuche die Werte auf SV interne Namen zu mappen + ColorPtr pColor = new Color( nRed, nGreen, nBlue ); + if( !aColorTbl.Count() && + BYTE(-1) == nRed && BYTE(-1) == nGreen && BYTE(-1) == nBlue ) + pColor->SetColor( COL_AUTO ); + aColorTbl.Insert( pColor, aColorTbl.Count() ); + nRed = 0, nGreen = 0, nBlue = 0; + + // Color konnte vollstaendig gelesen werden, + // also ist das noch ein stabiler Status + SaveState( RTF_COLORTBL ); + } + break; + } + } + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet +} + +void SvxRTFParser::ReadFontTable() +{ + int nToken; + int _nOpenBrakets = 1; // die erste wurde schon vorher erkannt !! + Font* pFont = new Font(); + short nFontNo(0), nInsFontNo (0); + String sAltNm, sFntNm; + BOOL bIsAltFntNm = FALSE, bCheckNewFont; + + CharSet nSystemChar = lcl_GetDefaultTextEncodingForRTF(); + pFont->SetCharSet( nSystemChar ); + SetEncoding( nSystemChar ); + + while( _nOpenBrakets && IsParserWorking() ) + { + bCheckNewFont = FALSE; + switch( ( nToken = GetNextToken() )) + { + case '}': + bIsAltFntNm = FALSE; + // Style konnte vollstaendig gelesen werden, + // also ist das noch ein stabiler Status + if( --_nOpenBrakets <= 1 && IsParserWorking() ) + SaveState( RTF_FONTTBL ); + bCheckNewFont = TRUE; + nInsFontNo = nFontNo; + break; + case '{': + if( RTF_IGNOREFLAG != GetNextToken() ) + nToken = SkipToken( -1 ); + // Unknown und alle bekannten nicht ausgewerteten Gruppen + // sofort ueberspringen + else if( RTF_UNKNOWNCONTROL != ( nToken = GetNextToken() ) && + RTF_PANOSE != nToken && RTF_FNAME != nToken && + RTF_FONTEMB != nToken && RTF_FONTFILE != nToken ) + nToken = SkipToken( -2 ); + else + { + // gleich herausfiltern + ReadUnknownData(); + nToken = GetNextToken(); + if( '}' != nToken ) + eState = SVPAR_ERROR; + break; + } + ++_nOpenBrakets; + break; + case RTF_FROMAN: + pFont->SetFamily( FAMILY_ROMAN ); + break; + case RTF_FSWISS: + pFont->SetFamily( FAMILY_SWISS ); + break; + case RTF_FMODERN: + pFont->SetFamily( FAMILY_MODERN ); + break; + case RTF_FSCRIPT: + pFont->SetFamily( FAMILY_SCRIPT ); + break; + case RTF_FDECOR: + pFont->SetFamily( FAMILY_DECORATIVE ); + break; + // bei technischen/symbolischen Font wird der CharSet ungeschaltet!! + case RTF_FTECH: + pFont->SetCharSet( RTL_TEXTENCODING_SYMBOL ); + // deliberate fall through + case RTF_FNIL: + pFont->SetFamily( FAMILY_DONTKNOW ); + break; + case RTF_FCHARSET: + if (-1 != nTokenValue) + { + CharSet nCharSet = rtl_getTextEncodingFromWindowsCharset( + (BYTE)nTokenValue); + pFont->SetCharSet(nCharSet); + //When we're in a font, the fontname is in the font + //charset, except for symbol fonts I believe + if (nCharSet == RTL_TEXTENCODING_SYMBOL) + nCharSet = RTL_TEXTENCODING_DONTKNOW; + SetEncoding(nCharSet); + } + break; + case RTF_FPRQ: + switch( nTokenValue ) + { + case 1: + pFont->SetPitch( PITCH_FIXED ); + break; + case 2: + pFont->SetPitch( PITCH_VARIABLE ); + break; + } + break; + case RTF_F: + bCheckNewFont = TRUE; + nInsFontNo = nFontNo; + nFontNo = (short)nTokenValue; + break; + case RTF_FALT: + bIsAltFntNm = TRUE; + break; + case RTF_TEXTTOKEN: + DelCharAtEnd( aToken, ';' ); + if ( aToken.Len() ) + { + if( bIsAltFntNm ) + sAltNm = aToken; + else + sFntNm = aToken; + } + break; + } + + if( bCheckNewFont && 1 >= _nOpenBrakets && sFntNm.Len() ) // one font is ready + { + // alle Daten vom Font vorhanden, also ab in die Tabelle + if (sAltNm.Len()) + (sFntNm += ';' ) += sAltNm; + + pFont->SetName( sFntNm ); + aFontTbl.Insert( nInsFontNo, pFont ); + pFont = new Font(); + pFont->SetCharSet( nSystemChar ); + sAltNm.Erase(); + sFntNm.Erase(); + } + } + // den letzen muessen wir selbst loeschen + delete pFont; + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet + + // setze den default Font am Doc + if( bNewDoc && IsParserWorking() ) + SetDefault( RTF_DEFF, nDfltFont ); +} + +void SvxRTFParser::ReadBitmapData() +{ + SvRTFParser::ReadBitmapData(); +} + +void SvxRTFParser::ReadOLEData() +{ + SvRTFParser::ReadOLEData(); +} + +String& SvxRTFParser::GetTextToEndGroup( String& rStr ) +{ + rStr.Erase( 0 ); + int _nOpenBrakets = 1, nToken; // die erste wurde schon vorher erkannt !! + + while( _nOpenBrakets && IsParserWorking() ) + { + switch( nToken = GetNextToken() ) + { + case '}': --_nOpenBrakets; break; + case '{': + { + if( RTF_IGNOREFLAG != GetNextToken() ) + nToken = SkipToken( -1 ); + else if( RTF_UNKNOWNCONTROL != GetNextToken() ) + nToken = SkipToken( -2 ); + else + { + // gleich herausfiltern + ReadUnknownData(); + nToken = GetNextToken(); + if( '}' != nToken ) + eState = SVPAR_ERROR; + break; + } + ++_nOpenBrakets; + } + break; + + case RTF_TEXTTOKEN: + rStr += aToken; + break; + } + } + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet + return rStr; +} + +util::DateTime SvxRTFParser::GetDateTimeStamp( ) +{ + util::DateTime aDT; + BOOL bWeiter = TRUE; + int nToken; + while( bWeiter && IsParserWorking() ) + { + switch( nToken = GetNextToken() ) + { + case RTF_YR: aDT.Year = (USHORT)nTokenValue; break; + case RTF_MO: aDT.Month = (USHORT)nTokenValue; break; + case RTF_DY: aDT.Day = (USHORT)nTokenValue; break; + case RTF_HR: aDT.Hours = (USHORT)nTokenValue; break; + case RTF_MIN: aDT.Minutes = (USHORT)nTokenValue; break; + default: + bWeiter = FALSE; + } + } + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet + return aDT; +} + +void SvxRTFParser::ReadInfo( const sal_Char* pChkForVerNo ) +{ +#ifndef SVX_LIGHT + int _nOpenBrakets = 1, nToken; // die erste wurde schon vorher erkannt !! + DBG_ASSERT(m_xDocProps.is(), + "SvxRTFParser::ReadInfo: no DocumentProperties"); + String sStr, sComment; + long nVersNo = 0; + + while( _nOpenBrakets && IsParserWorking() ) + { + switch( nToken = GetNextToken() ) + { + case '}': --_nOpenBrakets; break; + case '{': + { + if( RTF_IGNOREFLAG != GetNextToken() ) + nToken = SkipToken( -1 ); + else if( RTF_UNKNOWNCONTROL != GetNextToken() ) + nToken = SkipToken( -2 ); + else + { + // gleich herausfiltern + ReadUnknownData(); + nToken = GetNextToken(); + if( '}' != nToken ) + eState = SVPAR_ERROR; + break; + } + ++_nOpenBrakets; + } + break; + + case RTF_TITLE: + m_xDocProps->setTitle( GetTextToEndGroup( sStr ) ); + break; + case RTF_SUBJECT: + m_xDocProps->setSubject( GetTextToEndGroup( sStr ) ); + break; + case RTF_AUTHOR: + m_xDocProps->setAuthor( GetTextToEndGroup( sStr ) ); + break; + case RTF_OPERATOR: + m_xDocProps->setModifiedBy( GetTextToEndGroup( sStr ) ); + break; + case RTF_KEYWORDS: + { + ::rtl::OUString sTemp = GetTextToEndGroup( sStr ); + m_xDocProps->setKeywords( + ::comphelper::string::convertCommaSeparated(sTemp) ); + break; + } + case RTF_DOCCOMM: + m_xDocProps->setDescription( GetTextToEndGroup( sStr ) ); + break; + + case RTF_HLINKBASE: + sBaseURL = GetTextToEndGroup( sStr ) ; + break; + + case RTF_CREATIM: + m_xDocProps->setCreationDate( GetDateTimeStamp() ); + break; + + case RTF_REVTIM: + m_xDocProps->setModificationDate( GetDateTimeStamp() ); + break; + + case RTF_PRINTIM: + m_xDocProps->setPrintDate( GetDateTimeStamp() ); + break; + + case RTF_COMMENT: + GetTextToEndGroup( sComment ); + break; + + case RTF_BUPTIM: + SkipGroup(); + break; + + case RTF_VERN: + nVersNo = nTokenValue; + break; + + case RTF_EDMINS: + case RTF_ID: + case RTF_VERSION: + case RTF_NOFPAGES: + case RTF_NOFWORDS: + case RTF_NOFCHARS: + NextToken( nToken ); + break; + +// default: + } + } + + if( pChkForVerNo && + COMPARE_EQUAL == sComment.CompareToAscii( pChkForVerNo )) + nVersionNo = nVersNo; + + SkipToken( -1 ); // die schliesende Klammer wird "oben" ausgewertet +#endif +} + + +void SvxRTFParser::ClearColorTbl() +{ + aColorTbl.DeleteAndDestroy( 0, aColorTbl.Count() ); +} + +void SvxRTFParser::ClearFontTbl() +{ + for( ULONG nCnt = aFontTbl.Count(); nCnt; ) + delete aFontTbl.GetObject( --nCnt ); +} + +void SvxRTFParser::ClearStyleTbl() +{ + for( ULONG nCnt = aStyleTbl.Count(); nCnt; ) + delete aStyleTbl.GetObject( --nCnt ); +} + +void SvxRTFParser::ClearAttrStack() +{ + SvxRTFItemStackType* pTmp; + for( ULONG nCnt = aAttrStack.Count(); nCnt; --nCnt ) + { + pTmp = aAttrStack.Pop(); + delete pTmp; + } +} + +String& SvxRTFParser::DelCharAtEnd( String& rStr, const sal_Unicode cDel ) +{ + if( rStr.Len() && ' ' == rStr.GetChar( 0 )) + rStr.EraseLeadingChars(); + if( rStr.Len() && ' ' == rStr.GetChar( rStr.Len()-1 )) + rStr.EraseTrailingChars(); + if( rStr.Len() && cDel == rStr.GetChar( rStr.Len()-1 )) + rStr.Erase( rStr.Len()-1 ); + return rStr; +} + + +const Font& SvxRTFParser::GetFont( USHORT nId ) +{ + const Font* pFont = aFontTbl.Get( nId ); + if( !pFont ) + { + const SvxFontItem& rDfltFont = (const SvxFontItem&) + pAttrPool->GetDefaultItem( + ((RTFPlainAttrMapIds*)aPlainMap.GetData())->nFont ); + pDfltFont->SetName( rDfltFont.GetStyleName() ); + pDfltFont->SetFamily( rDfltFont.GetFamily() ); + pFont = pDfltFont; + } + return *pFont; +} + +SvxRTFItemStackType* SvxRTFParser::_GetAttrSet( int bCopyAttr ) +{ + SvxRTFItemStackType* pAkt = aAttrStack.Top(); + SvxRTFItemStackType* pNew; + if( pAkt ) + pNew = new SvxRTFItemStackType( *pAkt, *pInsPos, bCopyAttr ); + else + pNew = new SvxRTFItemStackType( *pAttrPool, aWhichMap.GetData(), + *pInsPos ); + pNew->SetRTFDefaults( GetRTFDefaults() ); + + aAttrStack.Push( pNew ); + bNewGroup = FALSE; + return pNew; +} + + +void SvxRTFParser::_ClearStyleAttr( SvxRTFItemStackType& rStkType ) +{ + // check attributes to the attributes of the stylesheet or to + // the default attrs of the document + SfxItemSet &rSet = rStkType.GetAttrSet(); + const SfxItemPool& rPool = *rSet.GetPool(); + const SfxPoolItem* pItem; + SfxWhichIter aIter( rSet ); + + SvxRTFStyleType* pStyle; + if( !IsChkStyleAttr() || + !rStkType.GetAttrSet().Count() || + 0 == ( pStyle = aStyleTbl.Get( rStkType.nStyleNo ) )) + { + for( USHORT nWhich = aIter.GetCurWhich(); nWhich; nWhich = aIter.NextWhich() ) + { + if( SFX_WHICH_MAX > nWhich && + SFX_ITEM_SET == rSet.GetItemState( nWhich, FALSE, &pItem ) && + rPool.GetDefaultItem( nWhich ) == *pItem ) + rSet.ClearItem( nWhich ); // loeschen + } + } + else + { + // alle Attribute, die schon vom Style definiert sind, aus dem + // akt. AttrSet entfernen + SfxItemSet &rStyleSet = pStyle->aAttrSet; + const SfxPoolItem* pSItem; + for( USHORT nWhich = aIter.GetCurWhich(); nWhich; nWhich = aIter.NextWhich() ) + { + if( SFX_ITEM_SET == rStyleSet.GetItemState( nWhich, TRUE, &pSItem )) + { + // JP 22.06.99: im Style und im Set gleich gesetzt -> loeschen + if( SFX_ITEM_SET == rSet.GetItemState( nWhich, FALSE, &pItem ) + && *pItem == *pSItem ) + rSet.ClearItem( nWhich ); // loeschen + } + // Bug 59571 - falls nicht im Style gesetzt und gleich mit + // dem PoolDefault -> auch dann loeschen + else if( SFX_WHICH_MAX > nWhich && + SFX_ITEM_SET == rSet.GetItemState( nWhich, FALSE, &pItem ) && + rPool.GetDefaultItem( nWhich ) == *pItem ) + rSet.ClearItem( nWhich ); // loeschen + } + } +} + +void SvxRTFParser::AttrGroupEnd() // den akt. Bearbeiten, vom Stack loeschen +{ + if( aAttrStack.Count() ) + { + SvxRTFItemStackType *pOld = aAttrStack.Pop(); + SvxRTFItemStackType *pAkt = aAttrStack.Top(); + + do { // middle check loop + ULONG nOldSttNdIdx = pOld->pSttNd->GetIdx(); + if( !pOld->pChildList && + ((!pOld->aAttrSet.Count() && !pOld->nStyleNo ) || + (nOldSttNdIdx == pInsPos->GetNodeIdx() && + pOld->nSttCnt == pInsPos->GetCntIdx() ))) + break; // keine Attribute oder Bereich + + // setze nur die Attribute, die unterschiedlich zum Parent sind + if( pAkt && pOld->aAttrSet.Count() ) + { + SfxItemIter aIter( pOld->aAttrSet ); + const SfxPoolItem* pItem = aIter.GetCurItem(), *pGet; + while( TRUE ) + { + if( SFX_ITEM_SET == pAkt->aAttrSet.GetItemState( + pItem->Which(), FALSE, &pGet ) && + *pItem == *pGet ) + pOld->aAttrSet.ClearItem( pItem->Which() ); + + if( aIter.IsAtEnd() ) + break; + pItem = aIter.NextItem(); + } + + if( !pOld->aAttrSet.Count() && !pOld->pChildList && + !pOld->nStyleNo ) + break; + } + + // setze alle Attribute, die von Start bis hier + // definiert sind. + int bCrsrBack = !pInsPos->GetCntIdx(); + if( bCrsrBack ) + { + // am Absatzanfang ? eine Position zurueck + ULONG nNd = pInsPos->GetNodeIdx(); + MovePos( FALSE ); + // if can not move backward then later dont move forward ! + bCrsrBack = nNd != pInsPos->GetNodeIdx(); + } + + //Bug #46608#: ungueltige Bereiche ignorieren! + if( ( pOld->pSttNd->GetIdx() < pInsPos->GetNodeIdx() || + ( pOld->pSttNd->GetIdx() == pInsPos->GetNodeIdx() && + pOld->nSttCnt <= pInsPos->GetCntIdx() )) +#if 0 +//BUG 68555 - dont test for empty paragraph or any range + && ( nOldSttNdIdx != pInsPos->GetNodeIdx() || + pOld->nSttCnt != pInsPos->GetCntIdx() || + !pOld->nSttCnt ) +#endif + ) + { + if( !bCrsrBack ) + { + // alle pard-Attribute gelten nur bis zum vorherigen + // Absatz !! + if( nOldSttNdIdx == pInsPos->GetNodeIdx() ) + { +#if 0 +//BUG 68555 - dont reset pard attrs, if the group not begins not at start of +// paragraph + // Bereich innerhalb eines Absatzes: + // alle Absatz-Attribute und StyleNo loeschen + // aber nur wenn mitten drin angefangen wurde + if( pOld->nSttCnt ) + { + pOld->nStyleNo = 0; + for( USHORT n = 0; n < aPardMap.Count() && + pOld->aAttrSet.Count(); ++n ) + if( aPardMap[n] ) + pOld->aAttrSet.ClearItem( aPardMap[n] ); + + if( !pOld->aAttrSet.Count() && !pOld->pChildList && + !pOld->nStyleNo ) + break; // auch dieser verlaesst uns jetzt + } +#endif + } + else + { + // jetzt wirds kompliziert: + // - alle Zeichen-Attribute behalten den Bereich, + // - alle Absatz-Attribute bekommen den Bereich + // bis zum vorherigen Absatz + SvxRTFItemStackType* pNew = new SvxRTFItemStackType( + *pOld, *pInsPos, TRUE ); + pNew->aAttrSet.SetParent( pOld->aAttrSet.GetParent() ); + + // loesche aus pNew alle Absatz Attribute + for( USHORT n = 0; n < aPardMap.Count() && + pNew->aAttrSet.Count(); ++n ) + if( aPardMap[n] ) + pNew->aAttrSet.ClearItem( aPardMap[n] ); + pNew->SetRTFDefaults( GetRTFDefaults() ); + + // gab es ueberhaupt welche ? + if( pNew->aAttrSet.Count() == pOld->aAttrSet.Count() ) + delete pNew; // das wars dann + else + { + pNew->nStyleNo = 0; + + // spanne jetzt den richtigen Bereich auf + // pNew von alter + SetEndPrevPara( pOld->pEndNd, pOld->nEndCnt ); + pNew->nSttCnt = 0; + + if( IsChkStyleAttr() ) + { + _ClearStyleAttr( *pOld ); + _ClearStyleAttr( *pNew ); //#i10381#, methinks. + } + + if( pAkt ) + { + pAkt->Add( pOld ); + pAkt->Add( pNew ); + } + else + { + // letzter vom Stack, also zwischenspeichern, bis der + // naechste Text eingelesen wurde. (keine Attribute + // aufspannen!!) + aAttrSetList.Insert( pOld, aAttrSetList.Count() ); + aAttrSetList.Insert( pNew, aAttrSetList.Count() ); + } + pOld = 0; // pOld nicht loeschen + break; // das wars !! + } + } + } + + pOld->pEndNd = pInsPos->MakeNodeIdx(); + pOld->nEndCnt = pInsPos->GetCntIdx(); + +#if 0 + if( IsChkStyleAttr() ) + _ClearStyleAttr( *pOld ); +#else + /* + #i21422# + If the parent (pAkt) sets something e.g. , and the child (pOld) + unsets it and the style both are based on has it unset then + clearing the pOld by looking at the style is clearly a disaster + as the text ends up with pAkts bold and not pOlds no bold, this + should be rethought out. For the moment its safest to just do + the clean if we have no parent, all we suffer is too many + redundant properties. + */ + if (IsChkStyleAttr() && !pAkt) + _ClearStyleAttr( *pOld ); +#endif + + if( pAkt ) + { + pAkt->Add( pOld ); + // split up and create new entry, because it make no sense + // to create a "so long" depend list. Bug 95010 + if( bCrsrBack && 50 < pAkt->pChildList->Count() ) + { + // am Absatzanfang ? eine Position zurueck + MovePos( TRUE ); + bCrsrBack = FALSE; + + // eine neue Gruppe aufmachen + SvxRTFItemStackType* pNew = new SvxRTFItemStackType( + *pAkt, *pInsPos, TRUE ); + pNew->SetRTFDefaults( GetRTFDefaults() ); + + // alle bis hierher gueltigen Attribute "setzen" + AttrGroupEnd(); + pAkt = aAttrStack.Top(); // can be changed after AttrGroupEnd! + pNew->aAttrSet.SetParent( pAkt ? &pAkt->aAttrSet : 0 ); + aAttrStack.Push( pNew ); + pAkt = pNew; + } + } + else + // letzter vom Stack, also zwischenspeichern, bis der + // naechste Text eingelesen wurde. (keine Attribute + // aufspannen!!) + aAttrSetList.Insert( pOld, aAttrSetList.Count() ); + + pOld = 0; + } + + if( bCrsrBack ) + // am Absatzanfang ? eine Position zurueck + MovePos( TRUE ); + + } while( FALSE ); + + if( pOld ) + delete pOld; + + bNewGroup = FALSE; + } +} + +void SvxRTFParser::SetAllAttrOfStk() // end all Attr. and set it into doc +{ + // noch alle Attrbute vom Stack holen !! + while( aAttrStack.Count() ) + AttrGroupEnd(); + + for( USHORT n = aAttrSetList.Count(); n; ) + { + SvxRTFItemStackType* pStkSet = aAttrSetList[--n]; + SetAttrSet( *pStkSet ); + aAttrSetList.DeleteAndDestroy( n ); + } +} + +// setzt alle Attribute, die unterschiedlich zum aktuellen sind +void SvxRTFParser::SetAttrSet( SvxRTFItemStackType &rSet ) +{ + // wurde DefTab nie eingelesen? dann setze auf default + if( !bIsSetDfltTab ) + SetDefault( RTF_DEFTAB, 720 ); + + if( rSet.pChildList ) + rSet.Compress( *this ); + if( rSet.aAttrSet.Count() || rSet.nStyleNo ) + SetAttrInDoc( rSet ); + + // dann mal alle Childs abarbeiten + if( rSet.pChildList ) + for( USHORT n = 0; n < rSet.pChildList->Count(); ++n ) + SetAttrSet( *(*rSet.pChildList)[ n ] ); +} + + // wurde noch kein Text eingefuegt ? (SttPos vom obersten StackEintrag!) +int SvxRTFParser::IsAttrSttPos() +{ + SvxRTFItemStackType* pAkt = aAttrStack.Top(); + return !pAkt || (pAkt->pSttNd->GetIdx() == pInsPos->GetNodeIdx() && + pAkt->nSttCnt == pInsPos->GetCntIdx()); +} + + +void SvxRTFParser::SetAttrInDoc( SvxRTFItemStackType & ) +{ +} + +#ifdef USED +void SvxRTFParser::SaveState( int nToken ) +{ + SvRTFParser::SaveState( nToken ); +} + +void SvxRTFParser::RestoreState() +{ + SvRTFParser::RestoreState(); +} +#endif + +void SvxRTFParser::BuildWhichTbl() +{ + if( aWhichMap.Count() ) + aWhichMap.Remove( 0, aWhichMap.Count() ); + aWhichMap.Insert( (USHORT)0, (USHORT)0 ); + + // Aufbau einer Which-Map 'rWhichMap' aus einem Array von + // 'pWhichIds' von Which-Ids. Es hat die Lange 'nWhichIds'. + // Die Which-Map wird nicht geloescht. + SvParser::BuildWhichTbl( aWhichMap, (USHORT*)aPardMap.GetData(), aPardMap.Count() ); + SvParser::BuildWhichTbl( aWhichMap, (USHORT*)aPlainMap.GetData(), aPlainMap.Count() ); +} + +const SfxItemSet& SvxRTFParser::GetRTFDefaults() +{ + if( !pRTFDefaults ) + { + pRTFDefaults = new SfxItemSet( *pAttrPool, aWhichMap.GetData() ); + USHORT nId; + if( 0 != ( nId = ((RTFPardAttrMapIds*)aPardMap.GetData())->nScriptSpace )) + { + SvxScriptSpaceItem aItem( FALSE, nId ); + if( bNewDoc ) + pAttrPool->SetPoolDefaultItem( aItem ); + else + pRTFDefaults->Put( aItem ); + } + } + return *pRTFDefaults; +} + +/**/ + +SvxRTFStyleType::SvxRTFStyleType( SfxItemPool& rPool, const USHORT* pWhichRange ) + : aAttrSet( rPool, pWhichRange ) +{ + nOutlineNo = BYTE(-1); // nicht gesetzt + nBasedOn = 0; + bBasedOnIsSet = FALSE; //$flr #117411# + nNext = 0; + bIsCharFmt = FALSE; +} + + +SvxRTFItemStackType::SvxRTFItemStackType( + SfxItemPool& rPool, const USHORT* pWhichRange, + const SvxPosition& rPos ) + : aAttrSet( rPool, pWhichRange ), + pChildList( 0 ), + nStyleNo( 0 ) +{ + pSttNd = rPos.MakeNodeIdx(); + nSttCnt = rPos.GetCntIdx(); + pEndNd = pSttNd; + nEndCnt = nSttCnt; +} + +SvxRTFItemStackType::SvxRTFItemStackType( + const SvxRTFItemStackType& rCpy, + const SvxPosition& rPos, + int bCopyAttr ) + : aAttrSet( *rCpy.aAttrSet.GetPool(), rCpy.aAttrSet.GetRanges() ), + pChildList( 0 ), + nStyleNo( rCpy.nStyleNo ) +{ + pSttNd = rPos.MakeNodeIdx(); + nSttCnt = rPos.GetCntIdx(); + pEndNd = pSttNd; + nEndCnt = nSttCnt; + + aAttrSet.SetParent( &rCpy.aAttrSet ); + if( bCopyAttr ) + aAttrSet.Put( rCpy.aAttrSet ); +} + +SvxRTFItemStackType::~SvxRTFItemStackType() +{ + if( pChildList ) + delete pChildList; + if( pSttNd != pEndNd ) + delete pEndNd; + delete pSttNd; +} + +void SvxRTFItemStackType::Add( SvxRTFItemStackType* pIns ) +{ + if( !pChildList ) + pChildList = new SvxRTFItemStackList( 4, 16 ); + pChildList->Insert( pIns, pChildList->Count() ); +} + +#if 0 +//cmc: This is the original. nEndCnt is redundantly assigned to itself, and +//pEndNd can leak if not equal to pSttNd. +void SvxRTFItemStackType::SetStartPos( const SvxPosition& rPos ) +{ + delete pSttNd; + pSttNd = rPos.MakeNodeIdx(); + nSttCnt = rPos.GetCntIdx(); + pEndNd = pSttNd; + nEndCnt = nEndCnt; +} +#else +void SvxRTFItemStackType::SetStartPos( const SvxPosition& rPos ) +{ + if (pSttNd != pEndNd) + delete pEndNd; + delete pSttNd; + pSttNd = rPos.MakeNodeIdx(); + pEndNd = pSttNd; + nSttCnt = rPos.GetCntIdx(); +} +#endif + +void SvxRTFItemStackType::MoveFullNode(const SvxNodeIdx &rOldNode, + const SvxNodeIdx &rNewNode) +{ + bool bSameEndAsStart = (pSttNd == pEndNd) ? true : false; + + if (GetSttNodeIdx() == rOldNode.GetIdx()) + { + delete pSttNd; + pSttNd = rNewNode.Clone(); + if (bSameEndAsStart) + pEndNd = pSttNd; + } + + if (!bSameEndAsStart && GetEndNodeIdx() == rOldNode.GetIdx()) + { + delete pEndNd; + pEndNd = rNewNode.Clone(); + } + + //And the same for all the children + USHORT nCount = pChildList ? pChildList->Count() : 0; + for (USHORT i = 0; i < nCount; ++i) + { + SvxRTFItemStackType* pStk = (*pChildList)[i]; + pStk->MoveFullNode(rOldNode, rNewNode); + } +} + +bool SvxRTFParser::UncompressableStackEntry(const SvxRTFItemStackType &) const +{ + return false; +} + +void SvxRTFItemStackType::Compress( const SvxRTFParser& rParser ) +{ + DBG_ASSERT( pChildList, "es gibt keine ChildListe" ); + + USHORT n; + SvxRTFItemStackType* pTmp = (*pChildList)[0]; + + if( !pTmp->aAttrSet.Count() || + pSttNd->GetIdx() != pTmp->pSttNd->GetIdx() || + nSttCnt != pTmp->nSttCnt ) + return; + + SvxNodeIdx* pLastNd = pTmp->pEndNd; + xub_StrLen nLastCnt = pTmp->nEndCnt; + + SfxItemSet aMrgSet( pTmp->aAttrSet ); + for( n = 1; n < pChildList->Count(); ++n ) + { + pTmp = (*pChildList)[n]; + if( pTmp->pChildList ) + pTmp->Compress( rParser ); + + if( !pTmp->nSttCnt + ? (pLastNd->GetIdx()+1 != pTmp->pSttNd->GetIdx() || + !rParser.IsEndPara( pLastNd, nLastCnt ) ) + : ( pTmp->nSttCnt != nLastCnt || + pLastNd->GetIdx() != pTmp->pSttNd->GetIdx() )) + { + while( ++n < pChildList->Count() ) + if( (pTmp = (*pChildList)[n])->pChildList ) + pTmp->Compress( rParser ); + return; + } + + if (rParser.UncompressableStackEntry(*pTmp)) + return; + + if( n ) + { + // suche alle, die ueber den gesamten Bereich gesetzt sind + SfxItemIter aIter( aMrgSet ); + const SfxPoolItem* pItem; + do { + USHORT nWhich = aIter.GetCurItem()->Which(); + if( SFX_ITEM_SET != pTmp->aAttrSet.GetItemState( nWhich, + FALSE, &pItem ) || *pItem != *aIter.GetCurItem() ) + aMrgSet.ClearItem( nWhich ); + + if( aIter.IsAtEnd() ) + break; + aIter.NextItem(); + } while( TRUE ); + + if( !aMrgSet.Count() ) + return; + } + + pLastNd = pTmp->pEndNd; + nLastCnt = pTmp->nEndCnt; + } + + if( pEndNd->GetIdx() != pLastNd->GetIdx() || nEndCnt != nLastCnt ) + return; + + // es kann zusammengefasst werden + aAttrSet.Put( aMrgSet ); + + for( n = 0; n < pChildList->Count(); ++n ) + { + pTmp = (*pChildList)[n]; + pTmp->aAttrSet.Differentiate( aMrgSet ); + + if( !pTmp->pChildList && !pTmp->aAttrSet.Count() && !pTmp->nStyleNo ) + { + pChildList->Remove( n ); + delete pTmp; + --n; + continue; + } + } + if( !pChildList->Count() ) + { + delete pChildList; + pChildList = 0; + } +} +void SvxRTFItemStackType::SetRTFDefaults( const SfxItemSet& rDefaults ) +{ + if( rDefaults.Count() ) + { + SfxItemIter aIter( rDefaults ); + do { + USHORT nWhich = aIter.GetCurItem()->Which(); + if( SFX_ITEM_SET != aAttrSet.GetItemState( nWhich, FALSE )) + aAttrSet.Put( *aIter.GetCurItem() ); + + if( aIter.IsAtEnd() ) + break; + aIter.NextItem(); + } while( TRUE ); + } +} + +/**/ + +RTFPlainAttrMapIds::RTFPlainAttrMapIds( const SfxItemPool& rPool ) +{ + nCaseMap = rPool.GetTrueWhich( SID_ATTR_CHAR_CASEMAP, FALSE ); + nBgColor = rPool.GetTrueWhich( SID_ATTR_BRUSH_CHAR, FALSE ); + nColor = rPool.GetTrueWhich( SID_ATTR_CHAR_COLOR, FALSE ); + nContour = rPool.GetTrueWhich( SID_ATTR_CHAR_CONTOUR, FALSE ); + nCrossedOut = rPool.GetTrueWhich( SID_ATTR_CHAR_STRIKEOUT, FALSE ); + nEscapement = rPool.GetTrueWhich( SID_ATTR_CHAR_ESCAPEMENT, FALSE ); + nFont = rPool.GetTrueWhich( SID_ATTR_CHAR_FONT, FALSE ); + nFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_FONTHEIGHT, FALSE ); + nKering = rPool.GetTrueWhich( SID_ATTR_CHAR_KERNING, FALSE ); + nLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_LANGUAGE, FALSE ); + nPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_POSTURE, FALSE ); + nShadowed = rPool.GetTrueWhich( SID_ATTR_CHAR_SHADOWED, FALSE ); + nUnderline = rPool.GetTrueWhich( SID_ATTR_CHAR_UNDERLINE, FALSE ); + nOverline = rPool.GetTrueWhich( SID_ATTR_CHAR_OVERLINE, FALSE ); + nWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_WEIGHT, FALSE ); + nWordlineMode = rPool.GetTrueWhich( SID_ATTR_CHAR_WORDLINEMODE, FALSE ); + nAutoKerning = rPool.GetTrueWhich( SID_ATTR_CHAR_AUTOKERN, FALSE ); + + nCJKFont = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_FONT, FALSE ); + nCJKFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_FONTHEIGHT, FALSE ); + nCJKLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_LANGUAGE, FALSE ); + nCJKPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_POSTURE, FALSE ); + nCJKWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_WEIGHT, FALSE ); + nCTLFont = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_FONT, FALSE ); + nCTLFontHeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_FONTHEIGHT, FALSE ); + nCTLLanguage = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_LANGUAGE, FALSE ); + nCTLPosture = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_POSTURE, FALSE ); + nCTLWeight = rPool.GetTrueWhich( SID_ATTR_CHAR_CTL_WEIGHT, FALSE ); + nEmphasis = rPool.GetTrueWhich( SID_ATTR_CHAR_EMPHASISMARK, FALSE ); + nTwoLines = rPool.GetTrueWhich( SID_ATTR_CHAR_TWO_LINES, FALSE ); + nRuby = 0; //rPool.GetTrueWhich( SID_ATTR_CHAR_CJK_RUBY, FALSE ); + nCharScaleX = rPool.GetTrueWhich( SID_ATTR_CHAR_SCALEWIDTH, FALSE ); + nHorzVert = rPool.GetTrueWhich( SID_ATTR_CHAR_ROTATED, FALSE ); + nRelief = rPool.GetTrueWhich( SID_ATTR_CHAR_RELIEF, FALSE ); + nHidden = rPool.GetTrueWhich( SID_ATTR_CHAR_HIDDEN, FALSE ); +} + +RTFPardAttrMapIds ::RTFPardAttrMapIds ( const SfxItemPool& rPool ) +{ + nLinespacing = rPool.GetTrueWhich( SID_ATTR_PARA_LINESPACE, FALSE ); + nAdjust = rPool.GetTrueWhich( SID_ATTR_PARA_ADJUST, FALSE ); + nTabStop = rPool.GetTrueWhich( SID_ATTR_TABSTOP, FALSE ); + nHyphenzone = rPool.GetTrueWhich( SID_ATTR_PARA_HYPHENZONE, FALSE ); + nLRSpace = rPool.GetTrueWhich( SID_ATTR_LRSPACE, FALSE ); + nULSpace = rPool.GetTrueWhich( SID_ATTR_ULSPACE, FALSE ); + nBrush = rPool.GetTrueWhich( SID_ATTR_BRUSH, FALSE ); + nBox = rPool.GetTrueWhich( SID_ATTR_BORDER_OUTER, FALSE ); + nShadow = rPool.GetTrueWhich( SID_ATTR_BORDER_SHADOW, FALSE ); + nOutlineLvl = rPool.GetTrueWhich( SID_ATTR_PARA_OUTLLEVEL, FALSE ); + nSplit = rPool.GetTrueWhich( SID_ATTR_PARA_SPLIT, FALSE ); + nKeep = rPool.GetTrueWhich( SID_ATTR_PARA_KEEP, FALSE ); + nFontAlign = rPool.GetTrueWhich( SID_PARA_VERTALIGN, FALSE ); + nScriptSpace = rPool.GetTrueWhich( SID_ATTR_PARA_SCRIPTSPACE, FALSE ); + nHangPunct = rPool.GetTrueWhich( SID_ATTR_PARA_HANGPUNCTUATION, FALSE ); + nForbRule = rPool.GetTrueWhich( SID_ATTR_PARA_FORBIDDEN_RULES, FALSE ); + nDirection = rPool.GetTrueWhich( SID_ATTR_FRAMEDIRECTION, FALSE ); +} + +/* vi:set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/editeng/source/uno/UnoForbiddenCharsTable.cxx b/editeng/source/uno/UnoForbiddenCharsTable.cxx new file mode 100644 index 000000000000..9b7213c5712b --- /dev/null +++ b/editeng/source/uno/UnoForbiddenCharsTable.cxx @@ -0,0 +1,148 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: UnoForbiddenCharsTable.cxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <editeng/UnoForbiddenCharsTable.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <editeng/unolingu.hxx> // LocalToLanguage, LanguageToLocale + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::i18n; +using namespace ::rtl; +using namespace ::vos; +using namespace ::cppu; + +SvxUnoForbiddenCharsTable::SvxUnoForbiddenCharsTable(ORef<SvxForbiddenCharactersTable> xForbiddenChars) : + mxForbiddenChars( xForbiddenChars ) +{ +} + +SvxUnoForbiddenCharsTable::~SvxUnoForbiddenCharsTable() +{ +} + +void SvxUnoForbiddenCharsTable::onChange() +{ +} + +ForbiddenCharacters SvxUnoForbiddenCharsTable::getForbiddenCharacters( const Locale& rLocale ) + throw(NoSuchElementException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if(!mxForbiddenChars.isValid()) + throw RuntimeException(); + + const LanguageType eLang = SvxLocaleToLanguage( rLocale ); + const ForbiddenCharacters* pForbidden = mxForbiddenChars->GetForbiddenCharacters( eLang, FALSE ); + if(!pForbidden) + throw NoSuchElementException(); + + return *pForbidden; +} + +sal_Bool SvxUnoForbiddenCharsTable::hasForbiddenCharacters( const Locale& rLocale ) + throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if(!mxForbiddenChars.isValid()) + return sal_False; + + const LanguageType eLang = SvxLocaleToLanguage( rLocale ); + const ForbiddenCharacters* pForbidden = mxForbiddenChars->GetForbiddenCharacters( eLang, FALSE ); + + return NULL != pForbidden; +} + +void SvxUnoForbiddenCharsTable::setForbiddenCharacters(const Locale& rLocale, const ForbiddenCharacters& rForbiddenCharacters ) + throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if(!mxForbiddenChars.isValid()) + throw RuntimeException(); + + const LanguageType eLang = SvxLocaleToLanguage( rLocale ); + mxForbiddenChars->SetForbiddenCharacters( eLang, rForbiddenCharacters ); + + onChange(); +} + +void SvxUnoForbiddenCharsTable::removeForbiddenCharacters( const Locale& rLocale ) + throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if(!mxForbiddenChars.isValid()) + throw RuntimeException(); + + const LanguageType eLang = SvxLocaleToLanguage( rLocale ); + mxForbiddenChars->ClearForbiddenCharacters( eLang ); + + onChange(); +} + +// XSupportedLocales +Sequence< Locale > SAL_CALL SvxUnoForbiddenCharsTable::getLocales() + throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + const sal_Int32 nCount = mxForbiddenChars.isValid() ? mxForbiddenChars->Count() : 0; + + Sequence< Locale > aLocales( nCount ); + if( nCount ) + { + Locale* pLocales = aLocales.getArray(); + + for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) + { + const ULONG nLanguage = mxForbiddenChars->GetObjectKey( nIndex ); + SvxLanguageToLocale ( *pLocales++, static_cast < LanguageType > (nLanguage) ); + } + } + + return aLocales; +} + +sal_Bool SAL_CALL SvxUnoForbiddenCharsTable::hasLocale( const Locale& aLocale ) + throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + return hasForbiddenCharacters( aLocale ); +} diff --git a/editeng/source/uno/makefile.mk b/editeng/source/uno/makefile.mk new file mode 100644 index 000000000000..71e2c9b89e2f --- /dev/null +++ b/editeng/source/uno/makefile.mk @@ -0,0 +1,65 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.11 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=editeng +TARGET=uno +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +SLOFILES= \ + $(SLO)$/unonrule.obj \ + $(SLO)$/unoedsrc.obj \ + $(SLO)$/unoedhlp.obj \ + $(SLO)$/unofdesc.obj \ + $(SLO)$/unoviwou.obj \ + $(SLO)$/unofored.obj \ + $(SLO)$/unoforou.obj \ + $(SLO)$/unoipset.obj \ + $(SLO)$/unotext.obj \ + $(SLO)$/unotext2.obj \ + $(SLO)$/unofield.obj \ + $(SLO)$/UnoForbiddenCharsTable.obj \ + $(SLO)$/unopracc.obj \ + $(SLO)$/unoedprx.obj \ + $(SLO)$/unoviwed.obj + +# --- Tagets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/editeng/source/uno/unoedhlp.cxx b/editeng/source/uno/unoedhlp.cxx new file mode 100644 index 000000000000..ecda949ca8d7 --- /dev/null +++ b/editeng/source/uno/unoedhlp.cxx @@ -0,0 +1,200 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unoedhlp.cxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <tools/debug.hxx> + +#include <editeng/unoedhlp.hxx> +#include <editeng/editdata.hxx> +#include <editeng/editeng.hxx> + +//------------------------------------------------------------------------ + +TYPEINIT1( SvxEditSourceHint, TextHint ); + +SvxEditSourceHint::SvxEditSourceHint( ULONG _nId ) : + TextHint( _nId ), + mnStart( 0 ), + mnEnd( 0 ) +{ +} + +SvxEditSourceHint::SvxEditSourceHint( ULONG _nId, ULONG nValue, ULONG nStart, ULONG nEnd ) : + TextHint( _nId, nValue ), + mnStart( nStart), + mnEnd( nEnd ) +{ +} + +ULONG SvxEditSourceHint::GetValue() const +{ + return TextHint::GetValue(); +} + +ULONG SvxEditSourceHint::GetStartValue() const +{ + return mnStart; +} + +ULONG SvxEditSourceHint::GetEndValue() const +{ + return mnEnd; +} + +void SvxEditSourceHint::SetValue( ULONG n ) +{ + TextHint::SetValue( n ); +} + +void SvxEditSourceHint::SetStartValue( ULONG n ) +{ + mnStart = n; +} + +void SvxEditSourceHint::SetEndValue( ULONG n ) +{ + mnEnd = n; +} + +//------------------------------------------------------------------------ + +::std::auto_ptr<SfxHint> SvxEditSourceHelper::EENotification2Hint( EENotify* aNotify ) +{ + if( aNotify ) + { + switch( aNotify->eNotificationType ) + { + case EE_NOTIFY_TEXTMODIFIED: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_MODIFIED, aNotify->nParagraph ) ); + + case EE_NOTIFY_PARAGRAPHINSERTED: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_PARAINSERTED, aNotify->nParagraph ) ); + + case EE_NOTIFY_PARAGRAPHREMOVED: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_PARAREMOVED, aNotify->nParagraph ) ); + + case EE_NOTIFY_PARAGRAPHSMOVED: + return ::std::auto_ptr<SfxHint>( new SvxEditSourceHint( EDITSOURCE_HINT_PARASMOVED, aNotify->nParagraph, aNotify->nParam1, aNotify->nParam2 ) ); + + case EE_NOTIFY_TEXTHEIGHTCHANGED: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_TEXTHEIGHTCHANGED, aNotify->nParagraph ) ); + + case EE_NOTIFY_TEXTVIEWSCROLLED: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_VIEWSCROLLED ) ); + + case EE_NOTIFY_TEXTVIEWSELECTIONCHANGED: + return ::std::auto_ptr<SfxHint>( new SvxEditSourceHint( EDITSOURCE_HINT_SELECTIONCHANGED ) ); + + case EE_NOTIFY_BLOCKNOTIFICATION_START: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_BLOCKNOTIFICATION_START, 0 ) ); + + case EE_NOTIFY_BLOCKNOTIFICATION_END: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_BLOCKNOTIFICATION_END, 0 ) ); + + case EE_NOTIFY_INPUT_START: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_INPUT_START, 0 ) ); + + case EE_NOTIFY_INPUT_END: + return ::std::auto_ptr<SfxHint>( new TextHint( TEXT_HINT_INPUT_END, 0 ) ); + + default: + DBG_ERROR( "SvxEditSourceHelper::EENotification2Hint unknown notification" ); + break; + } + } + + return ::std::auto_ptr<SfxHint>( new SfxHint() ); +} + +sal_Bool SvxEditSourceHelper::GetAttributeRun( USHORT& nStartIndex, USHORT& nEndIndex, const EditEngine& rEE, USHORT nPara, USHORT nIndex ) +{ + EECharAttribArray aCharAttribs; + + rEE.GetCharAttribs( nPara, aCharAttribs ); + + // find closest index in front of nIndex + USHORT nAttr, nCurrIndex; + sal_Int32 nClosestStartIndex; + for( nAttr=0, nClosestStartIndex=0; nAttr<aCharAttribs.Count(); ++nAttr ) + { + nCurrIndex = aCharAttribs[nAttr].nStart; + + if( nCurrIndex > nIndex ) + break; // aCharAttribs array is sorted in increasing order for nStart values + + if( nCurrIndex > nClosestStartIndex ) + { + nClosestStartIndex = nCurrIndex; + } + } + + // find closest index behind of nIndex + sal_Int32 nClosestEndIndex; + for( nAttr=0, nClosestEndIndex=rEE.GetTextLen(nPara); nAttr<aCharAttribs.Count(); ++nAttr ) + { + nCurrIndex = aCharAttribs[nAttr].nEnd; + + if( nCurrIndex > nIndex && + nCurrIndex < nClosestEndIndex ) + { + nClosestEndIndex = nCurrIndex; + } + } + + nStartIndex = static_cast<USHORT>( nClosestStartIndex ); + nEndIndex = static_cast<USHORT>( nClosestEndIndex ); + + return sal_True; +} + +Point SvxEditSourceHelper::EEToUserSpace( const Point& rPoint, const Size& rEESize, bool bIsVertical ) +{ + return bIsVertical ? Point( -rPoint.Y() + rEESize.Height(), rPoint.X() ) : rPoint; +} + +Point SvxEditSourceHelper::UserSpaceToEE( const Point& rPoint, const Size& rEESize, bool bIsVertical ) +{ + return bIsVertical ? Point( rPoint.Y(), -rPoint.X() + rEESize.Height() ) : rPoint; +} + +Rectangle SvxEditSourceHelper::EEToUserSpace( const Rectangle& rRect, const Size& rEESize, bool bIsVertical ) +{ + // #106775# Don't touch rect if not vertical + return bIsVertical ? Rectangle( EEToUserSpace(rRect.BottomLeft(), rEESize, bIsVertical), + EEToUserSpace(rRect.TopRight(), rEESize, bIsVertical) ) : rRect; +} + +Rectangle SvxEditSourceHelper::UserSpaceToEE( const Rectangle& rRect, const Size& rEESize, bool bIsVertical ) +{ + // #106775# Don't touch rect if not vertical + return bIsVertical ? Rectangle( UserSpaceToEE(rRect.TopRight(), rEESize, bIsVertical), + UserSpaceToEE(rRect.BottomLeft(), rEESize, bIsVertical) ) : rRect; +} diff --git a/editeng/source/uno/unoedprx.cxx b/editeng/source/uno/unoedprx.cxx new file mode 100644 index 000000000000..ba6c86226b50 --- /dev/null +++ b/editeng/source/uno/unoedprx.cxx @@ -0,0 +1,1292 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unoedprx.cxx,v $ + * $Revision: 1.22 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +//------------------------------------------------------------------------ +// +// Global header +// +//------------------------------------------------------------------------ + +#include <limits.h> +#include <vector> +#include <algorithm> +#include <vos/mutex.hxx> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> + +//------------------------------------------------------------------------ +// +// Project-local header +// +//------------------------------------------------------------------------ +#include "editeng/unoedprx.hxx" +#include <editeng/unotext.hxx> +#include <editeng/unoedhlp.hxx> +#include <editeng/editdata.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/AccessibleStringWrap.hxx> +#include <editeng/outliner.hxx> + +using namespace ::com::sun::star; + + +class SvxAccessibleTextIndex +{ +public: + SvxAccessibleTextIndex() : + mnPara(0), + mnIndex(0), + mnEEIndex(0), + mnFieldOffset(0), + mnFieldLen(0), + mbInField(sal_False), + mnBulletOffset(0), + mnBulletLen(0), + mbInBullet(sal_False) {}; + ~SvxAccessibleTextIndex() {}; + + // Get/Set current paragraph + void SetParagraph( USHORT nPara ) + { + mnPara = nPara; + } + USHORT GetParagraph() const { return mnPara; } + + /** Set the index in the UAA semantic + + @param nIndex + The index from the UA API (fields and bullets are expanded) + + @param rTF + The text forwarder to use in the calculations + */ + void SetIndex( sal_Int32 nIndex, const SvxTextForwarder& rTF ); + void SetIndex( USHORT nPara, sal_Int32 nIndex, const SvxTextForwarder& rTF ) { SetParagraph(nPara); SetIndex(nIndex, rTF); } + sal_Int32 GetIndex() const { return mnIndex; } + + /** Set the index in the edit engine semantic + + Update the object state to reflect the given index position in + EditEngine/Outliner index values + + @param nEEIndex + The index from the edit engine (fields span exactly one index increment) + + @param rTF + The text forwarder to use in the calculations + */ + void SetEEIndex( USHORT nEEIndex, const SvxTextForwarder& rTF ); + void SetEEIndex( USHORT nPara, USHORT nEEIndex, const SvxTextForwarder& rTF ) { SetParagraph(nPara); SetEEIndex(nEEIndex, rTF); } + USHORT GetEEIndex() const; + + void SetFieldOffset( sal_Int32 nOffset, sal_Int32 nLen ) { mnFieldOffset = nOffset; mnFieldLen = nLen; } + sal_Int32 GetFieldOffset() const { return mnFieldOffset; } + sal_Int32 GetFieldLen() const { return mnFieldLen; } + void AreInField( sal_Bool bInField = sal_True ) { mbInField = bInField; } + sal_Bool InField() const { return mbInField; } + + void SetBulletOffset( sal_Int32 nOffset, sal_Int32 nLen ) { mnBulletOffset = nOffset; mnBulletLen = nLen; } + sal_Int32 GetBulletOffset() const { return mnBulletOffset; } + sal_Int32 GetBulletLen() const { return mnBulletLen; } + void AreInBullet( sal_Bool bInBullet = sal_True ) { mbInBullet = bInBullet; } + sal_Bool InBullet() const { return mbInBullet; } + + /// returns false if the current index contains non-editable text (e.g. bullets) + sal_Bool IsEditable() const; + + /// returns false if the given range is non-editable (e.g. contains bullets or _parts_ of fields) + sal_Bool IsEditableRange( const SvxAccessibleTextIndex& rEnd ) const; + +private: + USHORT mnPara; + sal_Int32 mnIndex; + sal_Int32 mnEEIndex; + sal_Int32 mnFieldOffset; + sal_Int32 mnFieldLen; + sal_Bool mbInField; + sal_Int32 mnBulletOffset; + sal_Int32 mnBulletLen; + sal_Bool mbInBullet; +}; + +ESelection MakeEESelection( const SvxAccessibleTextIndex& rStart, const SvxAccessibleTextIndex& rEnd ) +{ + // deal with field special case: to really get a field contained + // within a selection, the start index must be before or on the + // field, the end index after it. + + // The SvxAccessibleTextIndex.GetEEIndex method gives the index on + // the field, as long the input index is on the field. Thus, + // correction necessary for the end index + + // Therefore, for _ranges_, if part of the field is touched, all + // of the field must be selected + if( rStart.GetParagraph() <= rEnd.GetParagraph() || + (rStart.GetParagraph() == rEnd.GetParagraph() && + rStart.GetEEIndex() <= rEnd.GetEEIndex()) ) + { + if( rEnd.InField() && rEnd.GetFieldOffset() ) + return ESelection( rStart.GetParagraph(), rStart.GetEEIndex(), + rEnd.GetParagraph(), rEnd.GetEEIndex()+1 ); + } + else if( rStart.GetParagraph() > rEnd.GetParagraph() || + (rStart.GetParagraph() == rEnd.GetParagraph() && + rStart.GetEEIndex() > rEnd.GetEEIndex()) ) + { + if( rStart.InField() && rStart.GetFieldOffset() ) + return ESelection( rStart.GetParagraph(), rStart.GetEEIndex()+1, + rEnd.GetParagraph(), rEnd.GetEEIndex() ); + } + + return ESelection( rStart.GetParagraph(), rStart.GetEEIndex(), + rEnd.GetParagraph(), rEnd.GetEEIndex() ); +} + +ESelection MakeEESelection( const SvxAccessibleTextIndex& rIndex ) +{ + return ESelection( rIndex.GetParagraph(), rIndex.GetEEIndex(), + rIndex.GetParagraph(), rIndex.GetEEIndex() + 1 ); +} + +USHORT SvxAccessibleTextIndex::GetEEIndex() const +{ + DBG_ASSERT(mnEEIndex >= 0 && mnEEIndex <= USHRT_MAX, + "SvxAccessibleTextIndex::GetEEIndex: index value overflow"); + + return static_cast< USHORT > (mnEEIndex); +} + +void SvxAccessibleTextIndex::SetEEIndex( USHORT nEEIndex, const SvxTextForwarder& rTF ) +{ + // reset + mnFieldOffset = 0; + mbInField = sal_False; + mnFieldLen = 0; + mnBulletOffset = 0; + mbInBullet = sal_False; + mnBulletLen = 0; + + // set known values + mnEEIndex = nEEIndex; + + // calculate unknowns + USHORT nCurrField, nFieldCount = rTF.GetFieldCount( GetParagraph() ); + + mnIndex = nEEIndex; + + EBulletInfo aBulletInfo = rTF.GetBulletInfo( GetParagraph() ); + + // any text bullets? + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + mnIndex += aBulletInfo.aText.Len(); + } + + for( nCurrField=0; nCurrField < nFieldCount; ++nCurrField ) + { + EFieldInfo aFieldInfo( rTF.GetFieldInfo( GetParagraph(), nCurrField ) ); + + if( aFieldInfo.aPosition.nIndex > nEEIndex ) + break; + + if( aFieldInfo.aPosition.nIndex == nEEIndex ) + { + AreInField(); + break; + } + + // #106010# + mnIndex += ::std::max(aFieldInfo.aCurrentText.Len()-1, 0); + } +} + +void SvxAccessibleTextIndex::SetIndex( sal_Int32 nIndex, const SvxTextForwarder& rTF ) +{ + // reset + mnFieldOffset = 0; + mbInField = sal_False; + mnFieldLen = 0; + mnBulletOffset = 0; + mbInBullet = sal_False; + mnBulletLen = 0; + + // set known values + mnIndex = nIndex; + + // calculate unknowns + USHORT nCurrField, nFieldCount = rTF.GetFieldCount( GetParagraph() ); + + DBG_ASSERT(nIndex >= 0 && nIndex <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + mnEEIndex = nIndex; + + EBulletInfo aBulletInfo = rTF.GetBulletInfo( GetParagraph() ); + + // any text bullets? + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + sal_Int32 nBulletLen = aBulletInfo.aText.Len(); + + if( nIndex < nBulletLen ) + { + AreInBullet(); + SetBulletOffset( nIndex, nBulletLen ); + mnEEIndex = 0; + return; + } + + mnEEIndex = mnEEIndex - nBulletLen; + } + + for( nCurrField=0; nCurrField < nFieldCount; ++nCurrField ) + { + EFieldInfo aFieldInfo( rTF.GetFieldInfo( GetParagraph(), nCurrField ) ); + + // we're before a field + if( aFieldInfo.aPosition.nIndex > mnEEIndex ) + break; + + // #106010# + mnEEIndex -= ::std::max(aFieldInfo.aCurrentText.Len()-1, 0); + + // we're within a field + if( aFieldInfo.aPosition.nIndex >= mnEEIndex ) + { + AreInField(); + SetFieldOffset( ::std::max(aFieldInfo.aCurrentText.Len()-1, 0) - (aFieldInfo.aPosition.nIndex - mnEEIndex), + aFieldInfo.aCurrentText.Len() ); + mnEEIndex = aFieldInfo.aPosition.nIndex ; + break; + } + } +} + +sal_Bool SvxAccessibleTextIndex::IsEditable() const +{ + if( InBullet() || InField() ) + return sal_False; + + return sal_True; +} + +sal_Bool SvxAccessibleTextIndex::IsEditableRange( const SvxAccessibleTextIndex& rEnd ) const +{ + if( GetIndex() > rEnd.GetIndex() ) + return rEnd.IsEditableRange( *this ); + + if( InBullet() || rEnd.InBullet() ) + return sal_False; + + if( InField() && GetFieldOffset() ) + return sal_False; // within field + + if( rEnd.InField() && rEnd.GetFieldOffset() >= rEnd.GetFieldLen() - 1 ) + return sal_False; // within field + + return sal_True; +} + +//--------------------------------------------------------------------------------- + +SvxEditSourceAdapter::SvxEditSourceAdapter() : mbEditSourceValid( sal_False ) +{ +} + +SvxEditSourceAdapter::~SvxEditSourceAdapter() +{ +} + +SvxEditSource* SvxEditSourceAdapter::Clone() const +{ + if( mbEditSourceValid && mpAdaptee.get() ) + { + ::std::auto_ptr< SvxEditSource > pClonedAdaptee( mpAdaptee->Clone() ); + + if( pClonedAdaptee.get() ) + { + SvxEditSourceAdapter* pClone = new SvxEditSourceAdapter(); + + if( pClone ) + { + pClone->SetEditSource( pClonedAdaptee ); + return pClone; + } + } + } + + return NULL; +} + +SvxAccessibleTextAdapter* SvxEditSourceAdapter::GetTextForwarderAdapter() +{ + if( mbEditSourceValid && mpAdaptee.get() ) + { + SvxTextForwarder* pTextForwarder = mpAdaptee->GetTextForwarder(); + + if( pTextForwarder ) + { + maTextAdapter.SetForwarder(*pTextForwarder); + + return &maTextAdapter; + } + } + + return NULL; +} + +SvxTextForwarder* SvxEditSourceAdapter::GetTextForwarder() +{ + return GetTextForwarderAdapter(); +} + +SvxViewForwarder* SvxEditSourceAdapter::GetViewForwarder() +{ + if( mbEditSourceValid && mpAdaptee.get() ) + return mpAdaptee->GetViewForwarder(); + + return NULL; +} + +SvxAccessibleTextEditViewAdapter* SvxEditSourceAdapter::GetEditViewForwarderAdapter( sal_Bool bCreate ) +{ + if( mbEditSourceValid && mpAdaptee.get() ) + { + SvxEditViewForwarder* pEditViewForwarder = mpAdaptee->GetEditViewForwarder(bCreate); + + if( pEditViewForwarder ) + { + SvxAccessibleTextAdapter* pTextAdapter = GetTextForwarderAdapter(); + + if( pTextAdapter ) + { + maEditViewAdapter.SetForwarder(*pEditViewForwarder, *pTextAdapter); + + return &maEditViewAdapter; + } + } + } + + return NULL; +} + +SvxEditViewForwarder* SvxEditSourceAdapter::GetEditViewForwarder( sal_Bool bCreate ) +{ + return GetEditViewForwarderAdapter( bCreate ); +} + +void SvxEditSourceAdapter::UpdateData() +{ + if( mbEditSourceValid && mpAdaptee.get() ) + mpAdaptee->UpdateData(); +} + +SfxBroadcaster& SvxEditSourceAdapter::GetBroadcaster() const +{ + if( mbEditSourceValid && mpAdaptee.get() ) + return mpAdaptee->GetBroadcaster(); + + return maDummyBroadcaster; +} + +void SvxEditSourceAdapter::SetEditSource( ::std::auto_ptr< SvxEditSource > pAdaptee ) +{ + if( pAdaptee.get() ) + { + mpAdaptee = pAdaptee; + mbEditSourceValid = sal_True; + } + else + { + // do a lazy delete (prevents us from deleting the broadcaster + // from within a broadcast in + // AccessibleTextHelper_Impl::Notify) + mbEditSourceValid = sal_False; + } +} + +sal_Bool SvxEditSourceAdapter::IsValid() const +{ + return mbEditSourceValid; +} + + +//-------------------------------------------------------------------------------------- + +SvxAccessibleTextAdapter::SvxAccessibleTextAdapter() : mrTextForwarder( NULL ) +{ +} + +SvxAccessibleTextAdapter::~SvxAccessibleTextAdapter() +{ +} + +USHORT SvxAccessibleTextAdapter::GetParagraphCount() const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetParagraphCount(); +} + +USHORT SvxAccessibleTextAdapter::GetTextLen( USHORT nParagraph ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + aIndex.SetEEIndex( nParagraph, mrTextForwarder->GetTextLen( nParagraph ), *this ); + + return static_cast< USHORT >(aIndex.GetIndex()); +} + +String SvxAccessibleTextAdapter::GetText( const ESelection& rSel ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + // normalize selection + if( rSel.nStartPara > rSel.nEndPara || + (rSel.nStartPara == rSel.nEndPara && rSel.nStartPos > rSel.nEndPos) ) + { + ::std::swap( aStartIndex, aEndIndex ); + } + + String sStr = mrTextForwarder->GetText( MakeEESelection(aStartIndex, aEndIndex) ); + + // trim field text, if necessary + if( aStartIndex.InField() ) + { + DBG_ASSERT(aStartIndex.GetFieldOffset() >= 0 && + aStartIndex.GetFieldOffset() <= USHRT_MAX, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sStr.Erase(0, static_cast< USHORT > (aStartIndex.GetFieldOffset()) ); + } + if( aEndIndex.InField() && aEndIndex.GetFieldOffset() ) + { + DBG_ASSERT(sStr.Len() - (aEndIndex.GetFieldLen() - aEndIndex.GetFieldOffset()) >= 0 && + sStr.Len() - (aEndIndex.GetFieldLen() - aEndIndex.GetFieldOffset()) <= USHRT_MAX, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sStr = sStr.Copy(0, static_cast< USHORT > (sStr.Len() - (aEndIndex.GetFieldLen() - aEndIndex.GetFieldOffset())) ); + } + + EBulletInfo aBulletInfo1 = GetBulletInfo( static_cast< USHORT >(aStartIndex.GetParagraph()) ); + EBulletInfo aBulletInfo2 = GetBulletInfo( static_cast< USHORT >(aEndIndex.GetParagraph()) ); + + if( aStartIndex.InBullet() ) + { + // prepend leading bullet + String sBullet = aBulletInfo1.aText; + + DBG_ASSERT(aStartIndex.GetBulletOffset() >= 0 && + aStartIndex.GetBulletOffset() <= USHRT_MAX, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sBullet.Erase(0, static_cast< USHORT > (aStartIndex.GetBulletOffset()) ); + + sBullet += sStr; + sStr = sBullet; + } + + if( aEndIndex.InBullet() ) + { + // append trailing bullet + sStr += aBulletInfo2.aText;; + + DBG_ASSERT(sStr.Len() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset()) >= 0 && + sStr.Len() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset()) <= USHRT_MAX, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sStr = sStr.Copy(0, static_cast< USHORT > (sStr.Len() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset())) ); + } + else if( aStartIndex.GetParagraph() != aEndIndex.GetParagraph() && + HaveTextBullet( aEndIndex.GetParagraph() ) ) + { + String sBullet = aBulletInfo2.aText; + + DBG_ASSERT(sBullet.Len() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset()) >= 0 && + sBullet.Len() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset()) <= USHRT_MAX, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sBullet = sBullet.Copy(0, static_cast< USHORT > (sBullet.Len() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset())) ); + + // insert bullet + sStr.Insert( sBullet, + static_cast< USHORT > (GetTextLen(aStartIndex.GetParagraph()) - aStartIndex.GetIndex()) ); + } + + return sStr; +} + +SfxItemSet SvxAccessibleTextAdapter::GetAttribs( const ESelection& rSel, BOOL bOnlyHardAttrib ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + return mrTextForwarder->GetAttribs( MakeEESelection(aStartIndex, aEndIndex), + bOnlyHardAttrib ); +} + +SfxItemSet SvxAccessibleTextAdapter::GetParaAttribs( USHORT nPara ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetParaAttribs( nPara ); +} + +void SvxAccessibleTextAdapter::SetParaAttribs( USHORT nPara, const SfxItemSet& rSet ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + mrTextForwarder->SetParaAttribs( nPara, rSet ); +} + +void SvxAccessibleTextAdapter::RemoveAttribs( const ESelection& , sal_Bool , sal_uInt16 ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); +} + +void SvxAccessibleTextAdapter::GetPortions( USHORT nPara, SvUShorts& rList ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + mrTextForwarder->GetPortions( nPara, rList ); +} + +USHORT SvxAccessibleTextAdapter::GetItemState( const ESelection& rSel, USHORT nWhich ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + return mrTextForwarder->GetItemState( MakeEESelection(aStartIndex, aEndIndex), + nWhich ); +} + +USHORT SvxAccessibleTextAdapter::GetItemState( USHORT nPara, USHORT nWhich ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetItemState( nPara, nWhich ); +} + +void SvxAccessibleTextAdapter::QuickInsertText( const String& rText, const ESelection& rSel ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + mrTextForwarder->QuickInsertText( rText, + MakeEESelection(aStartIndex, aEndIndex) ); +} + +void SvxAccessibleTextAdapter::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + mrTextForwarder->QuickInsertField( rFld, + MakeEESelection(aStartIndex, aEndIndex) ); +} + +void SvxAccessibleTextAdapter::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + mrTextForwarder->QuickSetAttribs( rSet, + MakeEESelection(aStartIndex, aEndIndex) ); +} + +void SvxAccessibleTextAdapter::QuickInsertLineBreak( const ESelection& rSel ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + mrTextForwarder->QuickInsertLineBreak( MakeEESelection(aStartIndex, aEndIndex) ); +} + +SfxItemPool* SvxAccessibleTextAdapter::GetPool() const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetPool(); +} + +XubString SvxAccessibleTextAdapter::CalcFieldValue( const SvxFieldItem& rField, USHORT nPara, USHORT nPos, Color*& rpTxtColor, Color*& rpFldColor ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->CalcFieldValue( rField, nPara, nPos, rpTxtColor, rpFldColor ); +} + +BOOL SvxAccessibleTextAdapter::IsValid() const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + if( mrTextForwarder ) + return mrTextForwarder->IsValid(); + else + return sal_False; +} + +LanguageType SvxAccessibleTextAdapter::GetLanguage( USHORT nPara, USHORT nPos ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + + aIndex.SetIndex( nPara, nPos, *this ); + + return mrTextForwarder->GetLanguage( nPara, aIndex.GetEEIndex() ); +} + +USHORT SvxAccessibleTextAdapter::GetFieldCount( USHORT nPara ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetFieldCount( nPara ); +} + +EFieldInfo SvxAccessibleTextAdapter::GetFieldInfo( USHORT nPara, USHORT nField ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetFieldInfo( nPara, nField ); +} + +EBulletInfo SvxAccessibleTextAdapter::GetBulletInfo( USHORT nPara ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetBulletInfo( nPara ); +} + +Rectangle SvxAccessibleTextAdapter::GetCharBounds( USHORT nPara, USHORT nIndex ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + aIndex.SetIndex( nPara, nIndex, *this ); + + // preset if anything goes wrong below + // n-th char in GetParagraphIndex's paragraph + Rectangle aRect = mrTextForwarder->GetCharBounds( nPara, static_cast< USHORT >( aIndex.GetEEIndex() ) ); + + if( aIndex.InBullet() ) + { + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + OutputDevice* pOutDev = GetRefDevice(); + + DBG_ASSERT(pOutDev!=NULL, "SvxAccessibleTextAdapter::GetCharBounds: No ref device"); + + // preset if anything goes wrong below + aRect = aBulletInfo.aBounds; // better than nothing + if( pOutDev ) + { + AccessibleStringWrap aStringWrap( *pOutDev, aBulletInfo.aFont, aBulletInfo.aText ); + + if( aStringWrap.GetCharacterBounds( aIndex.GetBulletOffset(), aRect ) ) + aRect.Move( aBulletInfo.aBounds.Left(), aBulletInfo.aBounds.Top() ); + } + } + else + { + // handle field content manually + if( aIndex.InField() ) + { + OutputDevice* pOutDev = GetRefDevice(); + + DBG_ASSERT(pOutDev!=NULL, "SvxAccessibleTextAdapter::GetCharBounds: No ref device"); + + if( pOutDev ) + { + ESelection aSel = MakeEESelection( aIndex ); + + SvxFont aFont = EditEngine::CreateSvxFontFromItemSet( mrTextForwarder->GetAttribs( aSel ) ); + AccessibleStringWrap aStringWrap( *pOutDev, + aFont, + mrTextForwarder->GetText( aSel ) ); + + Rectangle aStartRect = mrTextForwarder->GetCharBounds( nPara, static_cast< USHORT >( aIndex.GetEEIndex() ) ); + + if( !aStringWrap.GetCharacterBounds( aIndex.GetFieldOffset(), aRect ) ) + aRect = aStartRect; + else + aRect.Move( aStartRect.Left(), aStartRect.Top() ); + } + } + } + + return aRect; +} + +Rectangle SvxAccessibleTextAdapter::GetParaBounds( USHORT nPara ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + // include bullet in para bounding box + Rectangle aRect( mrTextForwarder->GetParaBounds( nPara ) ); + + aRect.Union( aBulletInfo.aBounds ); + + return aRect; + } + + return mrTextForwarder->GetParaBounds( nPara ); +} + +MapMode SvxAccessibleTextAdapter::GetMapMode() const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetMapMode(); +} + +OutputDevice* SvxAccessibleTextAdapter::GetRefDevice() const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetRefDevice(); +} + +sal_Bool SvxAccessibleTextAdapter::GetIndexAtPoint( const Point& rPoint, USHORT& nPara, USHORT& nIndex ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + if( !mrTextForwarder->GetIndexAtPoint( rPoint, nPara, nIndex ) ) + return sal_False; + + SvxAccessibleTextIndex aIndex; + aIndex.SetEEIndex(nPara, nIndex, *this); + + DBG_ASSERT(aIndex.GetIndex() >= 0 && aIndex.GetIndex() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + nIndex = static_cast< USHORT > (aIndex.GetIndex()); + + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + // any text bullets? + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + if( aBulletInfo.aBounds.IsInside( rPoint) ) + { + OutputDevice* pOutDev = GetRefDevice(); + + DBG_ASSERT(pOutDev!=NULL, "SvxAccessibleTextAdapter::GetIndexAtPoint: No ref device"); + + if( !pOutDev ) + return sal_False; + + AccessibleStringWrap aStringWrap( *pOutDev, aBulletInfo.aFont, aBulletInfo.aText ); + + Point aPoint = rPoint; + aPoint.Move( -aBulletInfo.aBounds.Left(), -aBulletInfo.aBounds.Top() ); + + DBG_ASSERT(aStringWrap.GetIndexAtPoint( aPoint ) >= 0 && + aStringWrap.GetIndexAtPoint( aPoint ) <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + nIndex = static_cast< USHORT > (aStringWrap.GetIndexAtPoint( aPoint )); + return sal_True; + } + } + + if( aIndex.InField() ) + { + OutputDevice* pOutDev = GetRefDevice(); + + DBG_ASSERT(pOutDev!=NULL, "SvxAccessibleTextAdapter::GetIndexAtPoint: No ref device"); + + if( !pOutDev ) + return sal_False; + + ESelection aSelection = MakeEESelection( aIndex ); + SvxFont aFont = EditEngine::CreateSvxFontFromItemSet( mrTextForwarder->GetAttribs( aSelection ) ); + AccessibleStringWrap aStringWrap( *pOutDev, + aFont, + mrTextForwarder->GetText( aSelection ) ); + + Rectangle aRect = mrTextForwarder->GetCharBounds( nPara, aIndex.GetEEIndex() ); + Point aPoint = rPoint; + aPoint.Move( -aRect.Left(), -aRect.Top() ); + + DBG_ASSERT(aIndex.GetIndex() + aStringWrap.GetIndexAtPoint( rPoint ) >= 0 && + aIndex.GetIndex() + aStringWrap.GetIndexAtPoint( rPoint ) <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + nIndex = static_cast< USHORT >(aIndex.GetIndex() + aStringWrap.GetIndexAtPoint( aPoint )); + return sal_True; + } + + return sal_True; +} + +sal_Bool SvxAccessibleTextAdapter::GetWordIndices( USHORT nPara, USHORT nIndex, USHORT& nStart, USHORT& nEnd ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + aIndex.SetIndex(nPara, nIndex, *this); + nIndex = aIndex.GetEEIndex(); + + if( aIndex.InBullet() ) + { + DBG_ASSERT(aIndex.GetBulletLen() >= 0 && + aIndex.GetBulletLen() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + // always treat bullet as separate word + nStart = 0; + nEnd = static_cast< USHORT > (aIndex.GetBulletLen()); + + return sal_True; + } + + if( aIndex.InField() ) + { + DBG_ASSERT(aIndex.GetIndex() - aIndex.GetFieldOffset() >= 0 && + aIndex.GetIndex() - aIndex.GetFieldOffset() <= USHRT_MAX && + nStart + aIndex.GetFieldLen() >= 0 && + nStart + aIndex.GetFieldLen() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + // always treat field as separate word + // TODO: to circumvent this, _we_ would have to do the break iterator stuff! + nStart = static_cast< USHORT > (aIndex.GetIndex() - aIndex.GetFieldOffset()); + nEnd = static_cast< USHORT > (nStart + aIndex.GetFieldLen()); + + return sal_True; + } + + if( !mrTextForwarder->GetWordIndices( nPara, nIndex, nStart, nEnd ) ) + return sal_False; + + aIndex.SetEEIndex( nPara, nStart, *this ); + DBG_ASSERT(aIndex.GetIndex() >= 0 && + aIndex.GetIndex() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + nStart = static_cast< USHORT > (aIndex.GetIndex()); + + aIndex.SetEEIndex( nPara, nEnd, *this ); + DBG_ASSERT(aIndex.GetIndex() >= 0 && + aIndex.GetIndex() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + nEnd = static_cast< USHORT > (aIndex.GetIndex()); + + return sal_True; +} + +sal_Bool SvxAccessibleTextAdapter::GetAttributeRun( USHORT& nStartIndex, USHORT& nEndIndex, USHORT nPara, USHORT nIndex ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + aIndex.SetIndex(nPara, nIndex, *this); + nIndex = aIndex.GetEEIndex(); + + if( aIndex.InBullet() ) + { + DBG_ASSERT(aIndex.GetBulletLen() >= 0 && + aIndex.GetBulletLen() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + // always treat bullet as distinct attribute + nStartIndex = 0; + nEndIndex = static_cast< USHORT > (aIndex.GetBulletLen()); + + return sal_True; + } + + if( aIndex.InField() ) + { + DBG_ASSERT(aIndex.GetIndex() - aIndex.GetFieldOffset() >= 0 && + aIndex.GetIndex() - aIndex.GetFieldOffset() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + // always treat field as distinct attribute + nStartIndex = static_cast< USHORT > (aIndex.GetIndex() - aIndex.GetFieldOffset()); + nEndIndex = static_cast< USHORT > (nStartIndex + aIndex.GetFieldLen()); + + return sal_True; + } + + if( !mrTextForwarder->GetAttributeRun( nStartIndex, nEndIndex, nPara, nIndex ) ) + return sal_False; + + aIndex.SetEEIndex( nPara, nStartIndex, *this ); + DBG_ASSERT(aIndex.GetIndex() >= 0 && + aIndex.GetIndex() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + nStartIndex = static_cast< USHORT > (aIndex.GetIndex()); + + aIndex.SetEEIndex( nPara, nEndIndex, *this ); + DBG_ASSERT(aIndex.GetIndex() >= 0 && + aIndex.GetIndex() <= USHRT_MAX, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + nEndIndex = static_cast< USHORT > (aIndex.GetIndex()); + + return sal_True; +} + +USHORT SvxAccessibleTextAdapter::GetLineCount( USHORT nPara ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetLineCount( nPara ); +} + +USHORT SvxAccessibleTextAdapter::GetLineLen( USHORT nPara, USHORT nLine ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + USHORT nCurrLine; + USHORT nCurrIndex, nLastIndex; + for( nCurrLine=0, nCurrIndex=0, nLastIndex=0; nCurrLine<=nLine; ++nCurrLine ) + { + nLastIndex = nCurrIndex; + nCurrIndex = + nCurrIndex + mrTextForwarder->GetLineLen( nPara, nCurrLine ); + } + + aEndIndex.SetEEIndex( nPara, nCurrIndex, *this ); + if( nLine > 0 ) + { + aStartIndex.SetEEIndex( nPara, nLastIndex, *this ); + + return static_cast< USHORT >(aEndIndex.GetIndex() - aStartIndex.GetIndex()); + } + else + return static_cast< USHORT >(aEndIndex.GetIndex()); +} + +void SvxAccessibleTextAdapter::GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nParagraph, USHORT nLine ) const +{ + mrTextForwarder->GetLineBoundaries( rStart, rEnd, nParagraph, nLine ); +} + +USHORT SvxAccessibleTextAdapter::GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const +{ + return mrTextForwarder->GetLineNumberAtIndex( nPara, nIndex ); +} + +sal_Bool SvxAccessibleTextAdapter::Delete( const ESelection& rSel ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + return mrTextForwarder->Delete( MakeEESelection(aStartIndex, aEndIndex ) ); +} + +sal_Bool SvxAccessibleTextAdapter::InsertText( const String& rStr, const ESelection& rSel ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + return mrTextForwarder->InsertText( rStr, MakeEESelection(aStartIndex, aEndIndex) ); +} + +sal_Bool SvxAccessibleTextAdapter::QuickFormatDoc( BOOL bFull ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->QuickFormatDoc( bFull ); +} + +sal_Int16 SvxAccessibleTextAdapter::GetDepth( USHORT nPara ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->GetDepth( nPara ); +} + +sal_Bool SvxAccessibleTextAdapter::SetDepth( USHORT nPara, sal_Int16 nNewDepth ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + return mrTextForwarder->SetDepth( nPara, nNewDepth ); +} + +void SvxAccessibleTextAdapter::SetForwarder( SvxTextForwarder& rForwarder ) +{ + mrTextForwarder = &rForwarder; +} + +sal_Bool SvxAccessibleTextAdapter::HaveImageBullet( USHORT nPara ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType == SVX_NUM_BITMAP ) + { + return sal_True; + } + else + { + return sal_False; + } +} + +sal_Bool SvxAccessibleTextAdapter::HaveTextBullet( USHORT nPara ) const +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + return sal_True; + } + else + { + return sal_False; + } +} + +sal_Bool SvxAccessibleTextAdapter::IsEditable( const ESelection& rSel ) +{ + DBG_ASSERT(mrTextForwarder, "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + // normalize selection + if( rSel.nStartPara > rSel.nEndPara || + (rSel.nStartPara == rSel.nEndPara && rSel.nStartPos > rSel.nEndPos) ) + { + ::std::swap( aStartIndex, aEndIndex ); + } + + return aStartIndex.IsEditableRange( aEndIndex ); +} + +const SfxItemSet * SvxAccessibleTextAdapter::GetEmptyItemSetPtr() +{ + DBG_ERROR( "not implemented" ); + return 0; +} + +void SvxAccessibleTextAdapter::AppendParagraph() +{ + DBG_ERROR( "not implemented" ); +} + +xub_StrLen SvxAccessibleTextAdapter::AppendTextPortion( USHORT, const String &, const SfxItemSet & ) +{ + DBG_ERROR( "not implemented" ); + return 0; +} +void SvxAccessibleTextAdapter::CopyText(const SvxTextForwarder&) +{ + DBG_ERROR( "not implemented" ); +} + + + +//--------------------------------------------------------------------------------------- + +SvxAccessibleTextEditViewAdapter::SvxAccessibleTextEditViewAdapter() +{ +} + +SvxAccessibleTextEditViewAdapter::~SvxAccessibleTextEditViewAdapter() +{ +} + +BOOL SvxAccessibleTextEditViewAdapter::IsValid() const +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + if( mrViewForwarder ) + return mrViewForwarder->IsValid(); + else + return sal_False; +} + +Rectangle SvxAccessibleTextEditViewAdapter::GetVisArea() const +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mrViewForwarder->GetVisArea(); +} + +Point SvxAccessibleTextEditViewAdapter::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mrViewForwarder->LogicToPixel(rPoint, rMapMode); +} + +Point SvxAccessibleTextEditViewAdapter::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mrViewForwarder->PixelToLogic(rPoint, rMapMode); +} + +sal_Bool SvxAccessibleTextEditViewAdapter::GetSelection( ESelection& rSel ) const +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + ESelection aSelection; + + if( !mrViewForwarder->GetSelection( aSelection ) ) + return sal_False; + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetEEIndex( aSelection.nStartPara, aSelection.nStartPos, *mrTextForwarder ); + aEndIndex.SetEEIndex( aSelection.nEndPara, aSelection.nEndPos, *mrTextForwarder ); + + DBG_ASSERT(aStartIndex.GetIndex() >= 0 && aStartIndex.GetIndex() <= USHRT_MAX && + aEndIndex.GetIndex() >= 0 && aEndIndex.GetIndex() <= USHRT_MAX, + "SvxAccessibleTextEditViewAdapter::GetSelection: index value overflow"); + + rSel = ESelection( aStartIndex.GetParagraph(), static_cast< USHORT > (aStartIndex.GetIndex()), + aEndIndex.GetParagraph(), static_cast< USHORT > (aEndIndex.GetIndex()) ); + + return sal_True; +} + +sal_Bool SvxAccessibleTextEditViewAdapter::SetSelection( const ESelection& rSel ) +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *mrTextForwarder ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *mrTextForwarder ); + + return mrViewForwarder->SetSelection( MakeEESelection(aStartIndex, aEndIndex) ); +} + +sal_Bool SvxAccessibleTextEditViewAdapter::Copy() +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mrViewForwarder->Copy(); +} + +sal_Bool SvxAccessibleTextEditViewAdapter::Cut() +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mrViewForwarder->Cut(); +} + +sal_Bool SvxAccessibleTextEditViewAdapter::Paste() +{ + DBG_ASSERT(mrViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mrViewForwarder->Paste(); +} + +void SvxAccessibleTextEditViewAdapter::SetForwarder( SvxEditViewForwarder& rForwarder, + SvxAccessibleTextAdapter& rTextForwarder ) +{ + mrViewForwarder = &rForwarder; + mrTextForwarder = &rTextForwarder; +} + diff --git a/editeng/source/uno/unoedsrc.cxx b/editeng/source/uno/unoedsrc.cxx new file mode 100644 index 000000000000..ea8dab8d7b3c --- /dev/null +++ b/editeng/source/uno/unoedsrc.cxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unoedsrc.cxx,v $ + * $Revision: 1.13 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <svl/brdcst.hxx> + +#include <editeng/unoedsrc.hxx> + + +//------------------------------------------------------------------------ + +void SvxEditSource::addRange( SvxUnoTextRangeBase* ) +{ +} + +//------------------------------------------------------------------------ + +void SvxEditSource::removeRange( SvxUnoTextRangeBase* ) +{ +} + +//------------------------------------------------------------------------ + +const SvxUnoTextRangeBaseList& SvxEditSource::getRanges() const +{ + static SvxUnoTextRangeBaseList gList; + return gList; +} + +//------------------------------------------------------------------------ + +SvxTextForwarder::~SvxTextForwarder() +{ +} + +//------------------------------------------------------------------------ + +SvxViewForwarder::~SvxViewForwarder() +{ +} + +//------------------------------------------------------------------------ + +SvxEditSource::~SvxEditSource() +{ +} + +SvxViewForwarder* SvxEditSource::GetViewForwarder() +{ + return NULL; +} + +SvxEditViewForwarder* SvxEditSource::GetEditViewForwarder( sal_Bool ) +{ + return NULL; +} + +SfxBroadcaster& SvxEditSource::GetBroadcaster() const +{ + DBG_ERROR("SvxEditSource::GetBroadcaster called for implementation missing this feature!"); + + static SfxBroadcaster aBroadcaster; + + return aBroadcaster; +} diff --git a/editeng/source/uno/unofdesc.cxx b/editeng/source/uno/unofdesc.cxx new file mode 100644 index 000000000000..f7d989c1ac4f --- /dev/null +++ b/editeng/source/uno/unofdesc.cxx @@ -0,0 +1,269 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unofdesc.cxx,v $ + * $Revision: 1.7.212.1 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <editeng/eeitem.hxx> +#include <com/sun/star/uno/Any.hxx> + +#ifndef _TOOLKIT_HELPRE_VCLUNOHELPER_HXX_ +#include <toolkit/helper/vclunohelper.hxx> +#endif +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/crsditem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/memberids.hrc> +#include <svl/itempool.hxx> + +#include <editeng/unofdesc.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star; + + +void SvxUnoFontDescriptor::ConvertToFont( const awt::FontDescriptor& rDesc, Font& rFont ) +{ + rFont.SetName( rDesc.Name ); + rFont.SetStyleName( rDesc.StyleName ); + rFont.SetSize( Size( rDesc.Width, rDesc.Height ) ); + rFont.SetFamily( (FontFamily)rDesc.Family ); + rFont.SetCharSet( (CharSet)rDesc.CharSet ); + rFont.SetPitch( (FontPitch)rDesc.Pitch ); + rFont.SetOrientation( (short)(rDesc.Orientation*10) ); + rFont.SetKerning( rDesc.Kerning ); + rFont.SetWeight( VCLUnoHelper::ConvertFontWeight(rDesc.Weight) ); + rFont.SetItalic( (FontItalic)rDesc.Slant ); + rFont.SetUnderline( (FontUnderline)rDesc.Underline ); + rFont.SetStrikeout( (FontStrikeout)rDesc.Strikeout ); + rFont.SetWordLineMode( rDesc.WordLineMode ); +} + +void SvxUnoFontDescriptor::ConvertFromFont( const Font& rFont, awt::FontDescriptor& rDesc ) +{ + rDesc.Name = rFont.GetName(); + rDesc.StyleName = rFont.GetStyleName(); + rDesc.Width = sal::static_int_cast< sal_Int16 >(rFont.GetSize().Width()); + rDesc.Height = sal::static_int_cast< sal_Int16 >(rFont.GetSize().Height()); + rDesc.Family = sal::static_int_cast< sal_Int16 >(rFont.GetFamily()); + rDesc.CharSet = rFont.GetCharSet(); + rDesc.Pitch = sal::static_int_cast< sal_Int16 >(rFont.GetPitch()); + rDesc.Orientation = static_cast< float >(rFont.GetOrientation() / 10); + rDesc.Kerning = rFont.IsKerning(); + rDesc.Weight = VCLUnoHelper::ConvertFontWeight( rFont.GetWeight() ); + rDesc.Slant = (awt::FontSlant)rFont.GetItalic(); + rDesc.Underline = sal::static_int_cast< sal_Int16 >(rFont.GetUnderline()); + rDesc.Strikeout = sal::static_int_cast< sal_Int16 >(rFont.GetStrikeout()); + rDesc.WordLineMode = rFont.IsWordLineMode(); +} + +void SvxUnoFontDescriptor::FillItemSet( const awt::FontDescriptor& rDesc, SfxItemSet& rSet ) +{ + uno::Any aTemp; + + { + SvxFontItem aFontItem( EE_CHAR_FONTINFO ); + aFontItem.GetFamilyName()= rDesc.Name; + aFontItem.GetStyleName() = rDesc.StyleName; + aFontItem.GetFamily() = (FontFamily)rDesc.Family; + aFontItem.GetCharSet() = rDesc.CharSet; + aFontItem.GetPitch() = (FontPitch)rDesc.Pitch; + rSet.Put(aFontItem); + } + + { + SvxFontHeightItem aFontHeightItem( 0, 100, EE_CHAR_FONTHEIGHT ); + aTemp <<= (float)rDesc.Height; + ((SfxPoolItem*)&aFontHeightItem)->PutValue( aTemp, MID_FONTHEIGHT|CONVERT_TWIPS ); + rSet.Put(aFontHeightItem); + } + + { + SvxPostureItem aPostureItem( (FontItalic)0, EE_CHAR_ITALIC ); + aTemp <<= rDesc.Slant; + ((SfxPoolItem*)&aPostureItem)->PutValue( aTemp, MID_POSTURE ); + rSet.Put(aPostureItem); + } + + { + SvxUnderlineItem aUnderlineItem( (FontUnderline)0, EE_CHAR_UNDERLINE ); + aTemp <<= (sal_Int16)rDesc.Underline; + ((SfxPoolItem*)&aUnderlineItem)->PutValue( aTemp, MID_TL_STYLE ); + rSet.Put( aUnderlineItem ); + } + + { + SvxWeightItem aWeightItem( (FontWeight)0, EE_CHAR_WEIGHT ); + aTemp <<= rDesc.Weight; + ((SfxPoolItem*)&aWeightItem)->PutValue( aTemp, MID_WEIGHT ); + rSet.Put( aWeightItem ); + } + + { + SvxCrossedOutItem aCrossedOutItem( (FontStrikeout)0, EE_CHAR_STRIKEOUT ); + aTemp <<= rDesc.Strikeout; + ((SfxPoolItem*)&aCrossedOutItem)->PutValue( aTemp, MID_CROSS_OUT ); + rSet.Put( aCrossedOutItem ); + } + + { + SvxWordLineModeItem aWLMItem( rDesc.WordLineMode, EE_CHAR_WLM ); + rSet.Put( aWLMItem ); + } +} + +void SvxUnoFontDescriptor::FillFromItemSet( const SfxItemSet& rSet, awt::FontDescriptor& rDesc ) +{ + const SfxPoolItem* pItem = NULL; + { + SvxFontItem* pFontItem = (SvxFontItem*)&rSet.Get( EE_CHAR_FONTINFO, TRUE ); + rDesc.Name = pFontItem->GetFamilyName(); + rDesc.StyleName = pFontItem->GetStyleName(); + rDesc.Family = sal::static_int_cast< sal_Int16 >( + pFontItem->GetFamily()); + rDesc.CharSet = pFontItem->GetCharSet(); + rDesc.Pitch = sal::static_int_cast< sal_Int16 >( + pFontItem->GetPitch()); + } + { + pItem = &rSet.Get( EE_CHAR_FONTHEIGHT, TRUE ); + uno::Any aHeight; + if( pItem->QueryValue( aHeight, MID_FONTHEIGHT ) ) + aHeight >>= rDesc.Height; + } + { + pItem = &rSet.Get( EE_CHAR_ITALIC, TRUE ); + uno::Any aFontSlant; + if(pItem->QueryValue( aFontSlant, MID_POSTURE )) + aFontSlant >>= rDesc.Slant; + } + { + pItem = &rSet.Get( EE_CHAR_UNDERLINE, TRUE ); + uno::Any aUnderline; + if(pItem->QueryValue( aUnderline, MID_TL_STYLE )) + aUnderline >>= rDesc.Underline; + } + { + pItem = &rSet.Get( EE_CHAR_WEIGHT, TRUE ); + uno::Any aWeight; + if(pItem->QueryValue( aWeight, MID_WEIGHT )) + aWeight >>= rDesc.Weight; + } + { + pItem = &rSet.Get( EE_CHAR_STRIKEOUT, TRUE ); + uno::Any aStrikeOut; + if(pItem->QueryValue( aStrikeOut, MID_CROSS_OUT )) + aStrikeOut >>= rDesc.Strikeout; + } + { + SvxWordLineModeItem* pWLMItem = (SvxWordLineModeItem*)&rSet.Get( EE_CHAR_WLM, TRUE ); + rDesc.WordLineMode = pWLMItem->GetValue(); + } +} + +#define CheckState( state ) \ + switch( state ) \ + { \ + case SFX_ITEM_DONTCARE: \ + case SFX_ITEM_DISABLED: \ + return beans::PropertyState_AMBIGUOUS_VALUE; \ + case SFX_ITEM_READONLY: \ + case SFX_ITEM_SET: \ + return beans::PropertyState_DIRECT_VALUE; \ + } + +beans::PropertyState SvxUnoFontDescriptor::getPropertyState( const SfxItemSet& rSet ) +{ + CheckState(rSet.GetItemState( EE_CHAR_FONTINFO, FALSE )); + CheckState(rSet.GetItemState( EE_CHAR_FONTHEIGHT, FALSE )); + CheckState(rSet.GetItemState( EE_CHAR_ITALIC, FALSE )); + CheckState(rSet.GetItemState( EE_CHAR_UNDERLINE, FALSE )); + CheckState(rSet.GetItemState( EE_CHAR_WEIGHT, FALSE )); + CheckState(rSet.GetItemState( EE_CHAR_STRIKEOUT, FALSE )); + CheckState(rSet.GetItemState( EE_CHAR_WLM, FALSE )); + + return beans::PropertyState_DEFAULT_VALUE; +} + +void SvxUnoFontDescriptor::setPropertyToDefault( SfxItemSet& rSet ) +{ + rSet.InvalidateItem( EE_CHAR_FONTINFO ); + rSet.InvalidateItem( EE_CHAR_FONTHEIGHT ); + rSet.InvalidateItem( EE_CHAR_ITALIC ); + rSet.InvalidateItem( EE_CHAR_UNDERLINE ); + rSet.InvalidateItem( EE_CHAR_WEIGHT ); + rSet.InvalidateItem( EE_CHAR_STRIKEOUT ); + rSet.InvalidateItem( EE_CHAR_WLM ); +} + +uno::Any SvxUnoFontDescriptor::getPropertyDefault( SfxItemPool* pPool ) +{ + SfxItemSet aSet( *pPool, EE_CHAR_FONTINFO, EE_CHAR_FONTINFO, + EE_CHAR_FONTHEIGHT, EE_CHAR_FONTHEIGHT, + EE_CHAR_ITALIC, EE_CHAR_ITALIC, + EE_CHAR_UNDERLINE, EE_CHAR_UNDERLINE, + EE_CHAR_WEIGHT, EE_CHAR_WEIGHT, + EE_CHAR_STRIKEOUT, EE_CHAR_STRIKEOUT, + EE_CHAR_WLM, EE_CHAR_WLM, 0 ); + + uno::Any aAny; + + if(!pPool->IsWhich(EE_CHAR_FONTINFO)|| + !pPool->IsWhich(EE_CHAR_FONTHEIGHT)|| + !pPool->IsWhich(EE_CHAR_ITALIC)|| + !pPool->IsWhich(EE_CHAR_UNDERLINE)|| + !pPool->IsWhich(EE_CHAR_WEIGHT)|| + !pPool->IsWhich(EE_CHAR_STRIKEOUT)|| + !pPool->IsWhich(EE_CHAR_WLM)) + return aAny; + + aSet.Put(pPool->GetDefaultItem(EE_CHAR_FONTINFO)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_FONTHEIGHT)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_ITALIC)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_UNDERLINE)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_WEIGHT)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_STRIKEOUT)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_WLM)); + + awt::FontDescriptor aDesc; + + FillFromItemSet( aSet, aDesc ); + + aAny <<= aDesc; + + return aAny; +} + + + diff --git a/editeng/source/uno/unofield.cxx b/editeng/source/uno/unofield.cxx new file mode 100644 index 000000000000..36c7f5141176 --- /dev/null +++ b/editeng/source/uno/unofield.cxx @@ -0,0 +1,1183 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unofield.cxx,v $ + * $Revision: 1.31 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/text/FilenameDisplayFormat.hpp> +#include <com/sun/star/lang/NoSupportException.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <vcl/svapp.hxx> +#include <vos/mutex.hxx> + +#include <rtl/uuid.h> +#include <rtl/memory.h> + +#include <editeng/eeitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/measfld.hxx> +#include <editeng/unofield.hxx> +#include <editeng/unotext.hxx> +#include <comphelper/serviceinfohelper.hxx> + +using namespace ::rtl; +using namespace ::vos; +using namespace ::cppu; +using namespace ::com::sun::star; + +#define QUERYINT( xint ) \ + if( rType == ::getCppuType((const uno::Reference< xint >*)0) ) \ + aAny <<= uno::Reference< xint >(this) + + +#define WID_DATE 0 +#define WID_BOOL1 1 +#define WID_BOOL2 2 +#define WID_INT32 3 +#define WID_INT16 4 +#define WID_STRING1 5 +#define WID_STRING2 6 +#define WID_STRING3 7 + +class SvxUnoFieldData_Impl +{ +public: + sal_Bool mbBoolean1; + sal_Bool mbBoolean2; + sal_Int32 mnInt32; + sal_Int16 mnInt16; + OUString msString1; + OUString msString2; + OUString msString3; + util::DateTime maDateTime; + + OUString msPresentation; +}; + +const SfxItemPropertySet* ImplGetFieldItemPropertySet( sal_Int32 mnId ) +{ + static SfxItemPropertyMapEntry aExDateTimeFieldPropertyMap_Impl[] = + { + { MAP_CHAR_LEN("DateTime"), WID_DATE, &::getCppuType((const util::DateTime*)0), 0, 0 }, + { MAP_CHAR_LEN("IsFixed"), WID_BOOL1, &::getBooleanCppuType(), 0, 0 }, + { MAP_CHAR_LEN("IsDate"), WID_BOOL2, &::getBooleanCppuType(), 0, 0 }, + { MAP_CHAR_LEN("NumberFormat"), WID_INT32, &::getCppuType((const sal_Int16*)0), 0, 0 }, + {0,0,0,0,0,0} + }; + static SfxItemPropertySet aExDateTimeFieldPropertySet_Impl(aExDateTimeFieldPropertyMap_Impl); + + static SfxItemPropertyMapEntry aDateTimeFieldPropertyMap_Impl[] = + { + { MAP_CHAR_LEN("IsDate"), WID_BOOL2, &::getBooleanCppuType(), 0, 0 }, + {0,0,0,0,0,0} + }; + static SfxItemPropertySet aDateTimeFieldPropertySet_Impl(aDateTimeFieldPropertyMap_Impl); + + static SfxItemPropertyMapEntry aUrlFieldPropertyMap_Impl[] = + { + + { MAP_CHAR_LEN("Format"), WID_INT16, &::getCppuType((const sal_Int16*)0), 0, 0 }, + { MAP_CHAR_LEN("Representation"), WID_STRING1, &::getCppuType((const OUString*)0), 0, 0 }, + { MAP_CHAR_LEN("TargetFrame"), WID_STRING2, &::getCppuType((const OUString*)0), 0, 0 }, + { MAP_CHAR_LEN("URL"), WID_STRING3, &::getCppuType((const OUString*)0), 0, 0 }, + {0,0,0,0,0,0} + }; + static SfxItemPropertySet aUrlFieldPropertySet_Impl(aUrlFieldPropertyMap_Impl); + + static SfxItemPropertyMapEntry aEmptyPropertyMap_Impl[] = + { + {0,0,0,0,0,0} + }; + static SfxItemPropertySet aEmptyPropertySet_Impl(aEmptyPropertyMap_Impl); + + static SfxItemPropertyMapEntry aExtFileFieldPropertyMap_Impl[] = + { + { MAP_CHAR_LEN("IsFixed"), WID_BOOL1, &::getBooleanCppuType(), 0, 0 }, + { MAP_CHAR_LEN("FileFormat"), WID_INT16, &::getCppuType((const sal_Int16*)0), 0, 0 }, + { MAP_CHAR_LEN("CurrentPresentation"), WID_STRING1,&::getCppuType((const OUString*)0), 0, 0 }, + {0,0,0,0,0,0} + }; + static SfxItemPropertySet aExtFileFieldPropertySet_Impl(aExtFileFieldPropertyMap_Impl); + + static SfxItemPropertyMapEntry aAuthorFieldPropertyMap_Impl[] = + { + { MAP_CHAR_LEN("IsFixed"), WID_BOOL1, &::getBooleanCppuType(), 0, 0 }, + { MAP_CHAR_LEN("CurrentPresentation"), WID_STRING1,&::getCppuType((const OUString*)0), 0, 0 }, + { MAP_CHAR_LEN("Content"), WID_STRING2,&::getCppuType((const OUString*)0), 0, 0 }, + { MAP_CHAR_LEN("AuthorFormat"), WID_INT16, &::getCppuType((const sal_Int16*)0), 0, 0 }, + { MAP_CHAR_LEN("FullName"), WID_BOOL2, &::getBooleanCppuType(), 0, 0 }, + {0,0,0,0,0,0} + }; + static SfxItemPropertySet aAuthorFieldPropertySet_Impl(aAuthorFieldPropertyMap_Impl); + + static SfxItemPropertyMapEntry aMeasureFieldPropertyMap_Impl[] = + { + { MAP_CHAR_LEN("Kind"), WID_INT16, &::getCppuType((const sal_Int16*)0), 0, 0 }, + {0,0,0,0,0,0} + }; + static SfxItemPropertySet aMeasureFieldPropertySet_Impl(aMeasureFieldPropertyMap_Impl); + + switch( mnId ) + { + case ID_EXT_DATEFIELD: + case ID_EXT_TIMEFIELD: + return &aExDateTimeFieldPropertySet_Impl; + case ID_URLFIELD: + return &aUrlFieldPropertySet_Impl; + case ID_DATEFIELD: + case ID_TIMEFIELD: + return &aDateTimeFieldPropertySet_Impl; + case ID_EXT_FILEFIELD: + return &aExtFileFieldPropertySet_Impl; + case ID_AUTHORFIELD: + return &aAuthorFieldPropertySet_Impl; + case ID_MEASUREFIELD: + return &aMeasureFieldPropertySet_Impl; +// case ID_PAGEFIELD: +// case ID_PAGESFIELD: +// case ID_FILEFIELD: +// case ID_TABLEFIELD: +// case ID_HEADERFIELD: +// case ID_FOOTERFIELD: +// case ID_DATETIMEFIELD:: + default: + return &aEmptyPropertySet_Impl; + } +} + +static sal_Char const* aFieldItemNameMap_Impl[] = +{ + "Date", + "URL", + "Page", + "Pages", + "Time", + "File", + "Table", + "ExtTime", + "ExtFile", + "Author", + "Measure", + "ExtDate", + "Header", + "Footer", + "DateTime", + "Unknown" +}; + +/* conversion routines */ + +static sal_Int16 getFileNameDisplayFormat( SvxFileFormat nFormat ) +{ + switch( nFormat ) + { + case SVXFILEFORMAT_NAME_EXT: return text::FilenameDisplayFormat::NAME_AND_EXT; + case SVXFILEFORMAT_FULLPATH: return text::FilenameDisplayFormat::FULL; + case SVXFILEFORMAT_PATH: return text::FilenameDisplayFormat::PATH; +// case SVXFILEFORMAT_NAME: + default: return text::FilenameDisplayFormat::NAME; + } +} + +static SvxFileFormat setFileNameDisplayFormat( sal_Int16 nFormat ) +{ + switch( nFormat ) + { + case text::FilenameDisplayFormat::FULL: return SVXFILEFORMAT_FULLPATH; + case text::FilenameDisplayFormat::PATH: return SVXFILEFORMAT_PATH; + case text::FilenameDisplayFormat::NAME: return SVXFILEFORMAT_NAME; +// case text::FilenameDisplayFormat::NAME_AND_EXT: + default: + return SVXFILEFORMAT_NAME_EXT; + } +} + +static util::DateTime getDate( ULONG nDate ) +{ + util::DateTime aDate; + memset( &aDate, 0, sizeof( util::DateTime ) ); + + Date aTempDate( nDate ); + + aDate.Day = aTempDate.GetDay(); + aDate.Month = aTempDate.GetMonth(); + aDate.Year = aTempDate.GetYear(); + + return aDate; +} + +inline Date setDate( util::DateTime& rDate ) +{ + return Date( rDate.Day, rDate.Month, rDate.Year ); +} + +static util::DateTime getTime( long nTime ) +{ + util::DateTime aTime; + memset( &aTime, 0, sizeof( util::DateTime ) ); + + Time aTempTime( nTime ); + + aTime.HundredthSeconds = aTempTime.Get100Sec(); + aTime.Seconds = aTempTime.GetSec(); + aTime.Minutes = aTempTime.GetMin(); + aTime.Hours = aTempTime.GetHour(); + + return aTime; +} + +inline Time setTime( util::DateTime& rDate ) +{ + return Time( rDate.Hours, rDate.Minutes, rDate.Seconds, rDate.HundredthSeconds ); +} + +// ==================================================================== +// class SvxUnoTextField +// ==================================================================== +UNO3_GETIMPLEMENTATION_IMPL( SvxUnoTextField ); + +SvxUnoTextField::SvxUnoTextField( sal_Int32 nServiceId ) throw() +: OComponentHelper( getMutex() ) +, mpPropSet(NULL) +, mnServiceId(nServiceId) +, mpImpl( new SvxUnoFieldData_Impl ) +{ + mpPropSet = ImplGetFieldItemPropertySet(mnServiceId); + + memset( &(mpImpl->maDateTime), 0, sizeof( util::DateTime ) ); + + switch( nServiceId ) + { + case ID_EXT_DATEFIELD: + case ID_DATEFIELD: + mpImpl->mbBoolean2 = sal_True; + mpImpl->mnInt32 = SVXDATEFORMAT_STDSMALL; + mpImpl->mbBoolean1 = sal_False; + break; + + case ID_EXT_TIMEFIELD: + case ID_TIMEFIELD: + mpImpl->mbBoolean2 = sal_False; + mpImpl->mbBoolean1 = sal_False; + mpImpl->mnInt32 = SVXTIMEFORMAT_STANDARD; + break; + + case ID_URLFIELD: + mpImpl->mnInt16 = SVXURLFORMAT_REPR; + break; + + case ID_EXT_FILEFIELD: + mpImpl->mbBoolean1 = sal_False; + mpImpl->mnInt16 = text::FilenameDisplayFormat::FULL; + break; + + case ID_AUTHORFIELD: + mpImpl->mnInt16 = SVXAUTHORFORMAT_FULLNAME; + mpImpl->mbBoolean1 = sal_False; + mpImpl->mbBoolean2 = sal_True; + break; + + case ID_MEASUREFIELD: + mpImpl->mnInt16 = SDRMEASUREFIELD_VALUE; + break; + + default: + mpImpl->mbBoolean1 = sal_False; + mpImpl->mbBoolean2 = sal_False; + mpImpl->mnInt32 = 0; + mpImpl->mnInt16 = 0; + + } +} + +SvxUnoTextField::SvxUnoTextField( uno::Reference< text::XTextRange > xAnchor, const OUString& rPresentation, const SvxFieldData* pData ) throw() +: OComponentHelper( getMutex() ) +, mxAnchor( xAnchor ) +, mpPropSet(NULL) +, mnServiceId(ID_UNKNOWN) +, mpImpl( new SvxUnoFieldData_Impl ) +{ + DBG_ASSERT(pData, "pFieldData == NULL! [CL]" ); + + mpImpl->msPresentation = rPresentation; + + if(pData) + { + mnServiceId = GetFieldId(pData); + DBG_ASSERT(mnServiceId != ID_UNKNOWN, "unknown SvxFieldData! [CL]"); + if(mnServiceId != ID_UNKNOWN) + { + // extract field properties from data class + switch( mnServiceId ) + { + case ID_DATEFIELD: + case ID_EXT_DATEFIELD: + { + mpImpl->mbBoolean2 = sal_True; + // #i35416# for variable date field, don't use invalid "0000-00-00" date, + // use current date instead + sal_Bool bFixed = ((SvxDateField*)pData)->GetType() == SVXDATETYPE_FIX; + mpImpl->maDateTime = getDate( bFixed ? + ((SvxDateField*)pData)->GetFixDate() : + Date().GetDate() ); + mpImpl->mnInt32 = ((SvxDateField*)pData)->GetFormat(); + mpImpl->mbBoolean1 = bFixed; + } + break; + + case ID_TIMEFIELD: + mpImpl->mbBoolean2 = sal_False; + mpImpl->mbBoolean1 = sal_False; + mpImpl->mnInt32 = SVXTIMEFORMAT_STANDARD; + break; + + case ID_EXT_TIMEFIELD: + mpImpl->mbBoolean2 = sal_False; + mpImpl->maDateTime = getTime( ((SvxExtTimeField*)pData)->GetFixTime() ); + mpImpl->mbBoolean1 = ((SvxExtTimeField*)pData)->GetType() == SVXTIMETYPE_FIX; + mpImpl->mnInt32 = ((SvxExtTimeField*)pData)->GetFormat(); + break; + + case ID_URLFIELD: + mpImpl->msString1 = ((SvxURLField*)pData)->GetRepresentation(); + mpImpl->msString2 = ((SvxURLField*)pData)->GetTargetFrame(); + mpImpl->msString3 = ((SvxURLField*)pData)->GetURL(); + mpImpl->mnInt16 = sal::static_int_cast< sal_Int16 >( + ((SvxURLField*)pData)->GetFormat()); + break; + + case ID_EXT_FILEFIELD: + mpImpl->msString1 = ((SvxExtFileField*)pData)->GetFile(); + mpImpl->mbBoolean1 = ((SvxExtFileField*)pData)->GetType() == SVXFILETYPE_FIX; + mpImpl->mnInt16 = getFileNameDisplayFormat(((SvxExtFileField*)pData)->GetFormat()); + break; + + case ID_AUTHORFIELD: + mpImpl->msString1 = ((SvxAuthorField*)pData)->GetFormatted(); + mpImpl->msString2 = ((SvxAuthorField*)pData)->GetFormatted(); + mpImpl->mnInt16 = sal::static_int_cast< sal_Int16 >( + ((SvxAuthorField*)pData)->GetFormat()); + mpImpl->mbBoolean1 = ((SvxAuthorField*)pData)->GetType() == SVXAUTHORTYPE_FIX; + mpImpl->mbBoolean2 = ((SvxAuthorField*)pData)->GetFormat() != SVXAUTHORFORMAT_SHORTNAME; + break; + + case ID_MEASUREFIELD: + mpImpl->mnInt16 = sal::static_int_cast< sal_Int16 >(((SdrMeasureField*)pData)->GetMeasureFieldKind()); + break; + } + } + } + + mpPropSet = ImplGetFieldItemPropertySet(mnServiceId); +} + +SvxUnoTextField::~SvxUnoTextField() throw() +{ + delete mpImpl; +} + +SvxFieldData* SvxUnoTextField::CreateFieldData() const throw() +{ + SvxFieldData* pData = NULL; + + switch( mnServiceId ) + { + case ID_TIMEFIELD: + case ID_EXT_TIMEFIELD: + case ID_DATEFIELD: + case ID_EXT_DATEFIELD: + { + if( mpImpl->mbBoolean2 ) // IsDate? + { + Date aDate( setDate( mpImpl->maDateTime ) ); + pData = new SvxDateField( aDate, mpImpl->mbBoolean1?SVXDATETYPE_FIX:SVXDATETYPE_VAR ); + if( mpImpl->mnInt32 >= SVXDATEFORMAT_APPDEFAULT && mpImpl->mnInt32 <= SVXDATEFORMAT_F ) + ((SvxDateField*)pData)->SetFormat( (SvxDateFormat)mpImpl->mnInt32 ); + } + else + { + if( mnServiceId != ID_TIMEFIELD && mnServiceId != ID_DATEFIELD ) + { + Time aTime( setTime( mpImpl->maDateTime ) ); + pData = new SvxExtTimeField( aTime, mpImpl->mbBoolean1?SVXTIMETYPE_FIX:SVXTIMETYPE_VAR ); + + if( mpImpl->mnInt32 >= SVXTIMEFORMAT_APPDEFAULT && mpImpl->mnInt32 <= SVXTIMEFORMAT_AM_HMSH ) + ((SvxExtTimeField*)pData)->SetFormat( (SvxTimeFormat)mpImpl->mnInt32 ); + } + else + { + pData = new SvxTimeField(); + } + } + + } + break; + + case ID_URLFIELD: + pData = new SvxURLField( mpImpl->msString3, mpImpl->msString1, mpImpl->msString1.getLength() ? SVXURLFORMAT_REPR : SVXURLFORMAT_URL ); + ((SvxURLField*)pData)->SetTargetFrame( mpImpl->msString2 ); + if( mpImpl->mnInt16 >= SVXURLFORMAT_APPDEFAULT && mpImpl->mnInt16 <= SVXURLFORMAT_REPR ) + ((SvxURLField*)pData)->SetFormat( (SvxURLFormat)mpImpl->mnInt16 ); + break; + + case ID_PAGEFIELD: + pData = new SvxPageField(); + break; + + case ID_PAGESFIELD: + pData = new SvxPagesField(); + break; + + case ID_FILEFIELD: + pData = new SvxFileField(); + break; + + case ID_TABLEFIELD: + pData = new SvxTableField(); + break; + + case ID_EXT_FILEFIELD: + { + // #92009# pass fixed attribute to constructor + pData = new SvxExtFileField( mpImpl->msString1, + mpImpl->mbBoolean1 ? SVXFILETYPE_FIX : SVXFILETYPE_VAR, + setFileNameDisplayFormat(mpImpl->mnInt16 ) ); + break; + } + + case ID_AUTHORFIELD: + { + ::rtl::OUString aContent; + String aFirstName; + String aLastName; + String aEmpty; + + // do we have CurrentPresentation given? + // mimic behaviour of writer, which means: + // prefer CurrentPresentation over Content + // if both are given. + if( mpImpl->msString1.getLength() ) + aContent = mpImpl->msString1; + else + aContent = mpImpl->msString2; + + sal_Int32 nPos = aContent.lastIndexOf( sal_Char(' '), 0 ); + if( nPos > 0 ) + { + aFirstName = aContent.copy( 0, nPos ); + aLastName = aContent.copy( nPos + 1 ); + } + else + { + aLastName = aContent; + } + + // #92009# pass fixed attribute to constructor + pData = new SvxAuthorField( aFirstName, aLastName, aEmpty, + mpImpl->mbBoolean1 ? SVXAUTHORTYPE_FIX : SVXAUTHORTYPE_VAR ); + + if( !mpImpl->mbBoolean2 ) + { + ((SvxAuthorField*)pData)->SetFormat( SVXAUTHORFORMAT_SHORTNAME ); + } + else if( mpImpl->mnInt16 >= SVXAUTHORFORMAT_FULLNAME || mpImpl->mnInt16 <= SVXAUTHORFORMAT_SHORTNAME ) + { + ((SvxAuthorField*)pData)->SetFormat( (SvxAuthorFormat) mpImpl->mnInt16 ); + } + + break; + } + + case ID_MEASUREFIELD: + { + SdrMeasureFieldKind eKind = SDRMEASUREFIELD_VALUE; + if( mpImpl->mnInt16 == (sal_Int16)SDRMEASUREFIELD_UNIT || mpImpl->mnInt16 == (sal_Int16)SDRMEASUREFIELD_ROTA90BLANCS ) + eKind = (SdrMeasureFieldKind) mpImpl->mnInt16; + pData = new SdrMeasureField( eKind); + break; + } + case ID_HEADERFIELD: + pData = new SvxHeaderField(); + break; + case ID_FOOTERFIELD: + pData = new SvxFooterField(); + break; + case ID_DATETIMEFIELD: + pData = new SvxDateTimeField(); + break; + }; + + return pData; +} + +// uno::XInterface +uno::Any SAL_CALL SvxUnoTextField::queryAggregation( const uno::Type & rType ) + throw(uno::RuntimeException) +{ + uno::Any aAny; + + QUERYINT( beans::XPropertySet ); + else QUERYINT( text::XTextContent ); + else QUERYINT( text::XTextField ); + else QUERYINT( lang::XServiceInfo ); + else QUERYINT( lang::XUnoTunnel ); + else + return OComponentHelper::queryAggregation( rType ); + + return aAny; +} + +// XTypeProvider + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextField::getTypes() + throw (uno::RuntimeException) +{ + if( maTypeSequence.getLength() == 0 ) + { + maTypeSequence = OComponentHelper::getTypes(); + sal_Int32 nOldCount = maTypeSequence.getLength(); + + maTypeSequence.realloc( nOldCount + 4 ); // !DANGER! keep this updated + uno::Type* pTypes = &maTypeSequence.getArray()[nOldCount]; + + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextField >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XServiceInfo >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XUnoTunnel >*)0); + } + return maTypeSequence; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextField::getImplementationId() + throw (uno::RuntimeException) +{ + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True ); + } + return aId; +} + +uno::Any SAL_CALL SvxUnoTextField::queryInterface( const uno::Type & rType ) + throw(uno::RuntimeException) +{ + return OComponentHelper::queryInterface(rType); +} + +void SAL_CALL SvxUnoTextField::acquire() throw( ) +{ + OComponentHelper::acquire(); +} + +void SAL_CALL SvxUnoTextField::release() throw( ) +{ + OComponentHelper::release(); +} + +// Interface text::XTextField +OUString SAL_CALL SvxUnoTextField::getPresentation( sal_Bool bShowCommand ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if(bShowCommand) + { + DBG_ASSERT( ((sal_uInt32)mnServiceId) < ID_UNKNOWN, "Unknown field type" ); + return OUString::createFromAscii( aFieldItemNameMap_Impl[(((sal_uInt32)mnServiceId) > ID_UNKNOWN)? ID_UNKNOWN : mnServiceId ] ); + } + else + { + return mpImpl->msPresentation; + } +} + +// Interface text::XTextContent +void SAL_CALL SvxUnoTextField::attach( const uno::Reference< text::XTextRange >& xTextRange ) + throw(lang::IllegalArgumentException, uno::RuntimeException) +{ + SvxUnoTextRangeBase* pRange = SvxUnoTextRange::getImplementation( xTextRange ); + if(pRange == NULL) + throw lang::IllegalArgumentException(); + + SvxFieldData* pData = CreateFieldData(); + if( pData ) + pRange->attachField( pData ); + + delete pData; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextField::getAnchor() + throw(uno::RuntimeException) +{ + return mxAnchor; +} + +// lang::XComponent +void SAL_CALL SvxUnoTextField::dispose() + throw(uno::RuntimeException) +{ + OComponentHelper::dispose(); +} + +void SAL_CALL SvxUnoTextField::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw(uno::RuntimeException) +{ + OComponentHelper::addEventListener(xListener); +} + +void SAL_CALL SvxUnoTextField::removeEventListener( const uno::Reference< lang::XEventListener >& aListener ) + throw(uno::RuntimeException) +{ + OComponentHelper::removeEventListener(aListener); +} + + +// Interface beans::XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL SvxUnoTextField::getPropertySetInfo( ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return mpPropSet->getPropertySetInfo(); +} + +void SAL_CALL SvxUnoTextField::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue ) + throw(beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( mpImpl == NULL ) + throw uno::RuntimeException(); + + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMap()->getByName( aPropertyName ); + if ( !pMap ) + throw beans::UnknownPropertyException(); + + switch( pMap->nWID ) + { + case WID_DATE: + if(aValue >>= mpImpl->maDateTime) + return; + break; + case WID_BOOL1: + if(aValue >>= mpImpl->mbBoolean1) + return; + break; + case WID_BOOL2: + if(aValue >>= mpImpl->mbBoolean2) + return; + break; + case WID_INT16: + if(aValue >>= mpImpl->mnInt16) + return; + break; + case WID_INT32: + if(aValue >>= mpImpl->mnInt32) + return; + break; + case WID_STRING1: + if(aValue >>= mpImpl->msString1) + return; + break; + case WID_STRING2: + if(aValue >>= mpImpl->msString2) + return; + break; + case WID_STRING3: + if(aValue >>= mpImpl->msString3) + return; + break; + } + + throw lang::IllegalArgumentException(); + +/* + case WID_FORMAT: + { + sal_Int32 nFormat; + + switch( mnId ) + { + case ID_DATEFIELD: + { + SvxDateField* pDate = PTR_CAST( SvxDateField, aFieldItem.GetField() ); + if(pDate) + pDate->SetFormat( (SvxDateFormat)nFormat ); + break; + } + case ID_URLFIELD: + { + SvxURLField* pURL = PTR_CAST( SvxURLField, aFieldItem.GetField() ); + if(pURL) + pURL->SetFormat( (SvxURLFormat)nFormat ); + break; + } + case ID_EXT_TIMEFIELD: + { + SvxExtTimeField* pTime = PTR_CAST( SvxExtTimeField, aFieldItem.GetField() ); + if(pTime) + pTime->SetFormat( (SvxTimeFormat)nFormat ); + break; + } + case ID_EXT_FILEFIELD: + { + SvxExtFileField* pFile = PTR_CAST( SvxExtFileField, aFieldItem.GetField() ); + if(pFile) + pFile->SetFormat( (SvxFileFormat)nFormat ); + break; + } + case ID_AUTHORFIELD: + { + SvxAuthorField* pAuthor = PTR_CAST( SvxAuthorField, aFieldItem.GetField() ); + if(pAuthor) + pAuthor->SetFormat( (SvxAuthorFormat)nFormat ); + break; + } + default: + throw beans::UnknownPropertyException(); + } + } + break; + case WID_FIX: + { + if( aValue.hasValue() || aValue.getValueType() != ::getCppuBooleanType() ) + throw lang::IllegalArgumentException(); + sal_Bool bFix( *(sal_Bool*)aValue.getValue() ); + switch( mnId ) + { + case ID_EXT_TIMEFIELD: + { + SvxExtTimeField* pTime = PTR_CAST( SvxExtTimeField, aFieldItem.GetField() ); + if(pTime) + pTime->SetType( (SvxTimeType)bFix?SVXTIMETYPE_FIX:SVXTIMETYPE_VAR ); + break; + } + case ID_DATEFIELD: + { + SvxDateField* pDate = PTR_CAST( SvxDateField, aFieldItem.GetField() ); + if(pDate) + pDate->SetType( (SvxDateType)bFix?SVXDATETYPE_FIX:SVXDATETYPE_VAR ); + break; + } + case ID_EXT_FILEFIELD: + { + SvxExtFileField* pFile = PTR_CAST( SvxExtFileField, aFieldItem.GetField() ); + if(pFile) + pFile->SetType( (SvxFileType)bFix?SVXFILETYPE_FIX:SVXFILETYPE_VAR ); + break; + } + case ID_AUTHORFIELD: + { + SvxAuthorField* pAuthor = PTR_CAST( SvxAuthorField, aFieldItem.GetField() ); + if(pAuthor) + pAuthor->SetType( (SvxAuthorType)bFix?SVXAUTHORTYPE_FIX:SVXAUTHORTYPE_VAR ); + break; + } + default: + throw beans::UnknownPropertyException(); + } + } + break; + case WID_PRES: + case WID_URL: + case WID_TARGET: + { + SvxURLField* pURL = PTR_CAST( SvxURLField, aFieldItem.GetField() ); + if(pURL) + { + OUString aUnoStr; + if(!(aValue >>= aUnoStr)) + throw lang::IllegalArgumentException(); + + switch( pMap->nWID ) + { + case WID_PRES: + pURL->SetRepresentation( aUnoStr ); + break; + case WID_URL: + pURL->SetURL( aUnoStr ); + break; + case WID_TARGET: + pURL->SetTargetFrame( aUnoStr ); + break; + } + } + break; + } + } + + SfxItemSet aSet = pForwarder->GetAttribs( GetSelection() ); + aSet.Put( aFieldItem ); +*/ +} + +uno::Any SAL_CALL SvxUnoTextField::getPropertyValue( const OUString& PropertyName ) + throw(beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + uno::Any aValue; + + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMap()->getByName( PropertyName ); + if ( !pMap ) + throw beans::UnknownPropertyException(); + + switch( pMap->nWID ) + { + case WID_DATE: + aValue <<= mpImpl->maDateTime; + break; + case WID_BOOL1: + aValue <<= mpImpl->mbBoolean1; + break; + case WID_BOOL2: + aValue <<= mpImpl->mbBoolean2; + break; + case WID_INT16: + aValue <<= mpImpl->mnInt16; + break; + case WID_INT32: + aValue <<= mpImpl->mnInt32; + break; + case WID_STRING1: + aValue <<= mpImpl->msString1; + break; + case WID_STRING2: + aValue <<= mpImpl->msString2; + break; + case WID_STRING3: + aValue <<= mpImpl->msString3; + break; + } + + return aValue; + +/* + switch(pMap->nWID) + { + case WID_FORMAT: + switch( mnId ) + { + case ID_DATEFIELD: + { + SvxDateField* pDate = PTR_CAST( SvxDateField, pFieldItem->GetField() ); + if(pDate) + aValue <<= (sal_Int32)pDate->GetFormat(); + break; + } + case ID_URLFIELD: + { + SvxURLField* pURL = PTR_CAST( SvxURLField, pFieldItem->GetField() ); + if(pURL) + aValue <<= (sal_Int32)pURL->GetFormat(); + break; + } + case ID_EXT_TIMEFIELD: + { + SvxExtTimeField* pTime = PTR_CAST( SvxExtTimeField, pFieldItem->GetField() ); + if(pTime) + aValue <<= (sal_Int32)pTime->GetFormat(); + break; + } + case ID_EXT_FILEFIELD: + { + SvxExtFileField* pFile = PTR_CAST( SvxExtFileField, pFieldItem->GetField() ); + if(pFile) + aValue <<= (sal_Int32)pFile->GetFormat(); + break; + } + case ID_AUTHORFIELD: + { + SvxAuthorField* pAuthor = PTR_CAST( SvxAuthorField, pFieldItem->GetField() ); + if(pAuthor) + aValue <<= (sal_Int32)pAuthor->GetFormat(); + break; + } + default: + throw beans::UnknownPropertyException(); + } + break; + case WID_FIX: + { + sal_Bool bFix = sal_False; + switch( mnId ) + { + case ID_EXT_TIMEFIELD: + { + SvxExtTimeField* pTime = PTR_CAST( SvxExtTimeField, pFieldItem->GetField() ); + if(pTime) + bFix = pTime->GetType() == SVXTIMETYPE_FIX; + break; + } + case ID_DATEFIELD: + { + SvxDateField* pDate = PTR_CAST( SvxDateField, pFieldItem->GetField() ); + if(pDate) + bFix = pDate->GetType() == SVXDATETYPE_FIX; + break; + } + case ID_EXT_FILEFIELD: + { + SvxExtFileField* pFile = PTR_CAST( SvxExtFileField, pFieldItem->GetField() ); + if(pFile) + bFix = pFile->GetType() == SVXFILETYPE_FIX; + break; + } + case ID_AUTHORFIELD: + { + SvxAuthorField* pAuthor = PTR_CAST( SvxAuthorField, pFieldItem->GetField() ); + if(pAuthor) + bFix = pAuthor->GetType() == SVXAUTHORTYPE_FIX; + break; + } + default: + throw beans::UnknownPropertyException(); + } + aValue.setValue( &bFix, ::getCppuBooleanType() ); + } + break; + case WID_PRES: + case WID_URL: + case WID_TARGET: + { + SvxURLField* pURL = PTR_CAST( SvxURLField, pFieldItem->GetField() ); + if(pURL) + { + OUString aStr; + switch( pMap->nWID ) + { + case WID_PRES: + aStr = pURL->GetRepresentation(); + break; + case WID_URL: + aStr = pURL->GetURL(); + break; + case WID_TARGET: + aStr = pURL->GetTargetFrame(); + break; + } + aValue <<= aStr; + } + break; + } + case WID_FCOLOR: + case WID_TCOLOR: + { + Color* pFColor = NULL; + Color* pTColor = NULL; + const ESelection aSel = GetSelection(); + + pForwarder->CalcFieldValue( *pFieldItem, aSel.nStartPara, aSel.nStartPos, pTColor, pFColor ); + + if( pMap->nWID == WID_FCOLOR ) + aValue <<= (sal_Int32)pFColor->GetColor(); + else + aValue <<= (sal_Int32)pTColor->GetColor(); + break; + + delete pTColor; + delete pFColor; + } + } + return aValue; +*/ +} + +void SAL_CALL SvxUnoTextField::addPropertyChangeListener( const OUString&, const uno::Reference< beans::XPropertyChangeListener >& ) throw(::com::sun::star::beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) {} +void SAL_CALL SvxUnoTextField::removePropertyChangeListener( const OUString&, const uno::Reference< beans::XPropertyChangeListener >& ) throw(::com::sun::star::beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) {} +void SAL_CALL SvxUnoTextField::addVetoableChangeListener( const OUString&, const uno::Reference< beans::XVetoableChangeListener >& ) throw(::com::sun::star::beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) {} +void SAL_CALL SvxUnoTextField::removeVetoableChangeListener( const OUString&, const uno::Reference< beans::XVetoableChangeListener >& ) throw(::com::sun::star::beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) {} + +// OComponentHelper +void SvxUnoTextField::disposing() +{ + // nothing to do +} + +sal_Int32 SvxUnoTextField::GetFieldId( const SvxFieldData* pFieldData ) const throw() +{ + if( pFieldData->ISA( SvxURLField ) ) + return ID_URLFIELD; + else if( pFieldData->ISA( SvxPageField ) ) + return ID_PAGEFIELD; + else if( pFieldData->ISA( SvxPagesField ) ) + return ID_PAGESFIELD; + else if( pFieldData->ISA( SvxTimeField ) ) + return ID_TIMEFIELD; + else if( pFieldData->ISA( SvxFileField ) ) + return ID_FILEFIELD; + else if( pFieldData->ISA( SvxTableField ) ) + return ID_TABLEFIELD; + else if( pFieldData->ISA( SvxExtTimeField ) ) + return ID_EXT_TIMEFIELD; + else if( pFieldData->ISA( SvxExtFileField ) ) + return ID_EXT_FILEFIELD; + else if( pFieldData->ISA( SvxAuthorField ) ) + return ID_AUTHORFIELD; + else if( pFieldData->ISA( SvxDateField ) ) + return ID_EXT_DATEFIELD; + else if( pFieldData->ISA( SdrMeasureField ) ) + return ID_MEASUREFIELD; + else if( pFieldData->ISA( SvxHeaderField ) ) + return ID_HEADERFIELD; + else if( pFieldData->ISA( SvxFooterField ) ) + return ID_FOOTERFIELD; + else if( pFieldData->ISA( SvxDateTimeField ) ) + return ID_DATETIMEFIELD; + + return ID_UNKNOWN; +} + +// lang::XServiceInfo +OUString SAL_CALL SvxUnoTextField::getImplementationName() throw(uno::RuntimeException) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM("SvxUnoTextField")); +} + +static const sal_Char* pOldServiceNames[] = +{ + "com.sun.star.text.TextField.DateTime", + "com.sun.star.text.TextField.URL", + "com.sun.star.text.TextField.PageNumber", + "com.sun.star.text.TextField.PageCount", + "com.sun.star.text.TextField.DateTime", + "com.sun.star.text.TextField.DocInfo.Title", // SvxFileField is used for title + "com.sun.star.text.TextField.SheetName", + "com.sun.star.text.TextField.DateTime", + "com.sun.star.text.TextField.FileName", + "com.sun.star.text.TextField.Author", + "com.sun.star.text.TextField.Measure", + "com.sun.star.text.TextField.DateTime", + "com.sun.star.presentation.TextField.Header", + "com.sun.star.presentation.TextField.Footer", + "com.sun.star.presentation.TextField.DateTime" +}; + +static const sal_Char* pNewServiceNames[] = +{ + "com.sun.star.text.textfield.DateTime", + "com.sun.star.text.textfield.URL", + "com.sun.star.text.textfield.PageNumber", + "com.sun.star.text.textfield.PageCount", + "com.sun.star.text.textfield.DateTime", + "com.sun.star.text.textfield.docinfo.Title", // SvxFileField is used for title + "com.sun.star.text.textfield.SheetName", + "com.sun.star.text.textfield.DateTime", + "com.sun.star.text.textfield.FileName", + "com.sun.star.text.textfield.Author", + "com.sun.star.text.textfield.Measure", + "com.sun.star.text.textfield.DateTime", + "com.sun.star.presentation.textfield.Header", + "com.sun.star.presentation.textfield.Footer", + "com.sun.star.presentation.textfield.DateTime" +}; + +uno::Sequence< OUString > SAL_CALL SvxUnoTextField::getSupportedServiceNames() + throw(uno::RuntimeException) +{ + uno::Sequence< OUString > aSeq( 4 ); + OUString* pServices = aSeq.getArray(); + pServices[0] = OUString::createFromAscii( pNewServiceNames[mnServiceId] ); + pServices[1] = OUString::createFromAscii( pOldServiceNames[mnServiceId] ); + pServices[2] = OUString::createFromAscii( "com.sun.star.text.TextContent" ), + pServices[3] = OUString::createFromAscii( "com.sun.star.text.TextField" ); + + return aSeq; +} + +sal_Bool SAL_CALL SvxUnoTextField::supportsService( const OUString& ServiceName ) throw( uno::RuntimeException ) +{ + return comphelper::ServiceInfoHelper::supportsService( ServiceName, getSupportedServiceNames() ); +} + +uno::Reference< uno::XInterface > SAL_CALL SvxUnoTextCreateTextField( const ::rtl::OUString& ServiceSpecifier ) throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) +{ + uno::Reference< uno::XInterface > xRet; + + const OUString aTextFieldPrexit( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.textfield.") ); + + // #i93308# up to OOo 3.2 we used this wrong namespace name with the capital T & F. This is + // fixed since OOo 3.2 but for compatibility we will still provide support for the wrong notation. + const OUString aTextFieldPrexit2( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.TextField.") ); + + if( (ServiceSpecifier.compareTo( aTextFieldPrexit, aTextFieldPrexit.getLength() ) == 0) || + (ServiceSpecifier.compareTo( aTextFieldPrexit2, aTextFieldPrexit2.getLength() ) == 0) ) + { + OUString aFieldType( ServiceSpecifier.copy( aTextFieldPrexit.getLength() ) ); + + sal_Int32 nId = ID_UNKNOWN; + + if( aFieldType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("DateTime") ) ) + { + nId = ID_DATEFIELD; + } + else if( aFieldType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("URL") ) ) + { + nId = ID_URLFIELD; + } + else if( aFieldType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("PageNumber") ) ) + { + nId = ID_PAGEFIELD; + } + else if( aFieldType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("PageCount") ) ) + { + nId = ID_PAGESFIELD; + } + else if( aFieldType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("SheetName") ) ) + { + nId = ID_TABLEFIELD; + } + else if( aFieldType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("FileName") ) ) + { + nId = ID_EXT_FILEFIELD; + } + else if (aFieldType.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("docinfo.Title") ) || + aFieldType.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("DocInfo.Title") ) ) + { + nId = ID_FILEFIELD; + } + else if( aFieldType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Author") ) ) + { + nId = ID_AUTHORFIELD; + } + else if( aFieldType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Measure") ) ) + { + nId = ID_MEASUREFIELD; + } + + if( nId != ID_UNKNOWN ) + xRet = (::cppu::OWeakObject * )new SvxUnoTextField( nId ); + } + + return xRet; +} diff --git a/editeng/source/uno/unofored.cxx b/editeng/source/uno/unofored.cxx new file mode 100644 index 000000000000..64a31d4e4a40 --- /dev/null +++ b/editeng/source/uno/unofored.cxx @@ -0,0 +1,555 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unofored.cxx,v $ + * $Revision: 1.31 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <algorithm> +#include <editeng/eeitem.hxx> +#include <com/sun/star/i18n/WordType.hpp> + +#include <svl/itemset.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editview.hxx> +#include <editeng/unoedhlp.hxx> +#include <editeng/editdata.hxx> +#include <editeng/outliner.hxx> +#include <editeng/editobj.hxx> // nur fuer die GetText-Kruecke + +#include <editeng/unofored.hxx> + +using namespace ::com::sun::star; + +//------------------------------------------------------------------------ + +SvxEditEngineForwarder::SvxEditEngineForwarder( EditEngine& rEngine ) : + rEditEngine( rEngine ) +{ +} + +SvxEditEngineForwarder::~SvxEditEngineForwarder() +{ + // die EditEngine muss ggf. von aussen geloescht werden +} + +USHORT SvxEditEngineForwarder::GetParagraphCount() const +{ + return rEditEngine.GetParagraphCount(); +} + +USHORT SvxEditEngineForwarder::GetTextLen( USHORT nParagraph ) const +{ + return rEditEngine.GetTextLen( nParagraph ); +} + +String SvxEditEngineForwarder::GetText( const ESelection& rSel ) const +{ + String aRet = rEditEngine.GetText( rSel, LINEEND_LF ); + aRet.ConvertLineEnd(); + return aRet; +} + +SfxItemSet SvxEditEngineForwarder::GetAttribs( const ESelection& rSel, BOOL bOnlyHardAttrib ) const +{ + if( rSel.nStartPara == rSel.nEndPara ) + { + sal_uInt8 nFlags = 0; + switch( bOnlyHardAttrib ) + { + case EditEngineAttribs_All: + nFlags = GETATTRIBS_ALL; + break; + case EditEngineAttribs_HardAndPara: + nFlags = GETATTRIBS_PARAATTRIBS|GETATTRIBS_CHARATTRIBS; + break; + case EditEngineAttribs_OnlyHard: + nFlags = GETATTRIBS_CHARATTRIBS; + break; + default: + DBG_ERROR("unknown flags for SvxOutlinerForwarder::GetAttribs"); + } + + return rEditEngine.GetAttribs( rSel.nStartPara, rSel.nStartPos, rSel.nEndPos, nFlags ); + } + else + { + return rEditEngine.GetAttribs( rSel, bOnlyHardAttrib ); + } +} + +SfxItemSet SvxEditEngineForwarder::GetParaAttribs( USHORT nPara ) const +{ + SfxItemSet aSet( rEditEngine.GetParaAttribs( nPara ) ); + + USHORT nWhich = EE_PARA_START; + while( nWhich <= EE_PARA_END ) + { + if( aSet.GetItemState( nWhich, TRUE ) != SFX_ITEM_ON ) + { + if( rEditEngine.HasParaAttrib( nPara, nWhich ) ) + aSet.Put( rEditEngine.GetParaAttrib( nPara, nWhich ) ); + } + nWhich++; + } + + return aSet; +} + +void SvxEditEngineForwarder::SetParaAttribs( USHORT nPara, const SfxItemSet& rSet ) +{ + rEditEngine.SetParaAttribs( nPara, rSet ); +} + +void SvxEditEngineForwarder::RemoveAttribs( const ESelection& rSelection, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich ) +{ + rEditEngine.RemoveAttribs( rSelection, bRemoveParaAttribs, nWhich ); +} + +SfxItemPool* SvxEditEngineForwarder::GetPool() const +{ + return rEditEngine.GetEmptyItemSet().GetPool(); +} + +void SvxEditEngineForwarder::GetPortions( USHORT nPara, SvUShorts& rList ) const +{ + rEditEngine.GetPortions( nPara, rList ); +} + +void SvxEditEngineForwarder::QuickInsertText( const String& rText, const ESelection& rSel ) +{ + rEditEngine.QuickInsertText( rText, rSel ); +} + +void SvxEditEngineForwarder::QuickInsertLineBreak( const ESelection& rSel ) +{ + rEditEngine.QuickInsertLineBreak( rSel ); +} + +void SvxEditEngineForwarder::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + rEditEngine.QuickInsertField( rFld, rSel ); +} + +void SvxEditEngineForwarder::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + rEditEngine.QuickSetAttribs( rSet, rSel ); +} + +BOOL SvxEditEngineForwarder::IsValid() const +{ + // cannot reliably query EditEngine state + // while in the middle of an update + return rEditEngine.GetUpdateMode(); +} + +XubString SvxEditEngineForwarder::CalcFieldValue( const SvxFieldItem& rField, USHORT nPara, USHORT nPos, Color*& rpTxtColor, Color*& rpFldColor ) +{ + return rEditEngine.CalcFieldValue( rField, nPara, nPos, rpTxtColor, rpFldColor ); +} + +USHORT GetSvxEditEngineItemState( EditEngine& rEditEngine, const ESelection& rSel, USHORT nWhich ) +{ + EECharAttribArray aAttribs; + + const SfxPoolItem* pLastItem = NULL; + + SfxItemState eState = SFX_ITEM_DEFAULT; + + // check all paragraphs inside the selection + for( USHORT nPara = rSel.nStartPara; nPara <= rSel.nEndPara; nPara++ ) + { + SfxItemState eParaState = SFX_ITEM_DEFAULT; + + // calculate start and endpos for this paragraph + USHORT nPos = 0; + if( rSel.nStartPara == nPara ) + nPos = rSel.nStartPos; + + USHORT nEndPos = rSel.nEndPos; + if( rSel.nEndPara != nPara ) + nEndPos = rEditEngine.GetTextLen( nPara ); + + + // get list of char attribs + rEditEngine.GetCharAttribs( nPara, aAttribs ); + + BOOL bEmpty = TRUE; // we found no item inside the selektion of this paragraph + BOOL bGaps = FALSE; // we found items but theire gaps between them + USHORT nLastEnd = nPos; + + const SfxPoolItem* pParaItem = NULL; + + for( USHORT nAttrib = 0; nAttrib < aAttribs.Count(); nAttrib++ ) + { + struct EECharAttrib aAttrib = aAttribs.GetObject( nAttrib ); + DBG_ASSERT( aAttrib.pAttr, "GetCharAttribs gives corrupt data" ); + + const sal_Bool bEmptyPortion = aAttrib.nStart == aAttrib.nEnd; + if( (!bEmptyPortion && (aAttrib.nStart >= nEndPos)) || (bEmptyPortion && (aAttrib.nStart > nEndPos)) ) + break; // break if we are already behind our selektion + + if( (!bEmptyPortion && (aAttrib.nEnd <= nPos)) || (bEmptyPortion && (aAttrib.nEnd < nPos)) ) + continue; // or if the attribute ends before our selektion + + if( aAttrib.pAttr->Which() != nWhich ) + continue; // skip if is not the searched item + + // if we already found an item + if( pParaItem ) + { + // ... and its different to this one than the state is dont care + if( *pParaItem != *aAttrib.pAttr ) + return SFX_ITEM_DONTCARE; + } + else + { + pParaItem = aAttrib.pAttr; + } + + if( bEmpty ) + bEmpty = FALSE; + + if( !bGaps && aAttrib.nStart > nLastEnd ) + bGaps = TRUE; + + nLastEnd = aAttrib.nEnd; + } + + if( !bEmpty && !bGaps && nLastEnd < ( nEndPos - 1 ) ) + bGaps = TRUE; +/* + // since we have no portion with our item or if there were gaps + if( bEmpty || bGaps ) + { + // we need to check the paragraph item + const SfxItemSet& rParaSet = rEditEngine.GetParaAttribs( nPara ); + if( rParaSet.GetItemState( nWhich ) == SFX_ITEM_SET ) + { + eState = SFX_ITEM_SET; + // get item from the paragraph + const SfxPoolItem* pTempItem = rParaSet.GetItem( nWhich ); + if( pParaItem ) + { + if( *pParaItem != *pTempItem ) + return SFX_ITEM_DONTCARE; + } + else + { + pParaItem = pTempItem; + } + + // set if theres no last item or if its the same + eParaState = SFX_ITEM_SET; + } + else if( bEmpty ) + { + eParaState = SFX_ITEM_DEFAULT; + } + else if( bGaps ) + { + // gaps and item not set in paragraph, thats a dont care + return SFX_ITEM_DONTCARE; + } + } + else + { + eParaState = SFX_ITEM_SET; + } +*/ + if( bEmpty ) + eParaState = SFX_ITEM_DEFAULT; + else if( bGaps ) + eParaState = SFX_ITEM_DONTCARE; + else + eParaState = SFX_ITEM_SET; + + // if we already found an item check if we found the same + if( pLastItem ) + { + if( (pParaItem == NULL) || (*pLastItem != *pParaItem) ) + return SFX_ITEM_DONTCARE; + } + else + { + pLastItem = pParaItem; + eState = eParaState; + } + } + + return eState; +} + +USHORT SvxEditEngineForwarder::GetItemState( const ESelection& rSel, USHORT nWhich ) const +{ + return GetSvxEditEngineItemState( rEditEngine, rSel, nWhich ); +} + +USHORT SvxEditEngineForwarder::GetItemState( USHORT nPara, USHORT nWhich ) const +{ + const SfxItemSet& rSet = rEditEngine.GetParaAttribs( nPara ); + return rSet.GetItemState( nWhich ); +} + +LanguageType SvxEditEngineForwarder::GetLanguage( USHORT nPara, USHORT nIndex ) const +{ + return rEditEngine.GetLanguage(nPara, nIndex); +} + +USHORT SvxEditEngineForwarder::GetFieldCount( USHORT nPara ) const +{ + return rEditEngine.GetFieldCount(nPara); +} + +EFieldInfo SvxEditEngineForwarder::GetFieldInfo( USHORT nPara, USHORT nField ) const +{ + return rEditEngine.GetFieldInfo( nPara, nField ); +} + +EBulletInfo SvxEditEngineForwarder::GetBulletInfo( USHORT ) const +{ + return EBulletInfo(); +} + +Rectangle SvxEditEngineForwarder::GetCharBounds( USHORT nPara, USHORT nIndex ) const +{ + // #101701# + // EditEngine's 'internal' methods like GetCharacterBounds() + // don't rotate for vertical text. + Size aSize( rEditEngine.CalcTextWidth(), rEditEngine.GetTextHeight() ); + ::std::swap( aSize.Width(), aSize.Height() ); + bool bIsVertical( rEditEngine.IsVertical() == TRUE ); + + // #108900# Handle virtual position one-past-the end of the string + if( nIndex >= rEditEngine.GetTextLen(nPara) ) + { + Rectangle aLast; + + if( nIndex ) + { + // use last character, if possible + aLast = rEditEngine.GetCharacterBounds( EPosition(nPara, nIndex-1) ); + + // move at end of this last character, make one pixel wide + aLast.Move( aLast.Right() - aLast.Left(), 0 ); + aLast.SetSize( Size(1, aLast.GetHeight()) ); + + // take care for CTL + aLast = SvxEditSourceHelper::EEToUserSpace( aLast, aSize, bIsVertical ); + } + else + { + // #109864# Bounds must lie within the paragraph + aLast = GetParaBounds( nPara ); + + // #109151# Don't use paragraph height, but line height + // instead. aLast is already CTL-correct + if( bIsVertical) + aLast.SetSize( Size( rEditEngine.GetLineHeight(nPara,0), 1 ) ); + else + aLast.SetSize( Size( 1, rEditEngine.GetLineHeight(nPara,0) ) ); + } + + return aLast; + } + else + { + return SvxEditSourceHelper::EEToUserSpace( rEditEngine.GetCharacterBounds( EPosition(nPara, nIndex) ), + aSize, bIsVertical ); + } +} + +Rectangle SvxEditEngineForwarder::GetParaBounds( USHORT nPara ) const +{ + const Point aPnt = rEditEngine.GetDocPosTopLeft( nPara ); + ULONG nWidth; + ULONG nHeight; + ULONG nTextWidth; + + if( rEditEngine.IsVertical() ) + { + // #101701# + // Hargl. EditEngine's 'external' methods return the rotated + // dimensions, 'internal' methods like GetTextHeight( n ) + // don't rotate. + nWidth = rEditEngine.GetTextHeight( nPara ); + nHeight = rEditEngine.GetTextHeight(); + nTextWidth = rEditEngine.GetTextHeight(); + + return Rectangle( nTextWidth - aPnt.Y() - nWidth, 0, nTextWidth - aPnt.Y(), nHeight ); + } + else + { + nWidth = rEditEngine.CalcTextWidth(); + nHeight = rEditEngine.GetTextHeight( nPara ); + + return Rectangle( 0, aPnt.Y(), nWidth, aPnt.Y() + nHeight ); + } +} + +MapMode SvxEditEngineForwarder::GetMapMode() const +{ + return rEditEngine.GetRefMapMode(); +} + +OutputDevice* SvxEditEngineForwarder::GetRefDevice() const +{ + return rEditEngine.GetRefDevice(); +} + +sal_Bool SvxEditEngineForwarder::GetIndexAtPoint( const Point& rPos, USHORT& nPara, USHORT& nIndex ) const +{ + // #101701# + Size aSize( rEditEngine.CalcTextWidth(), rEditEngine.GetTextHeight() ); + ::std::swap( aSize.Width(), aSize.Height() ); + Point aEEPos( SvxEditSourceHelper::UserSpaceToEE( rPos, + aSize, + rEditEngine.IsVertical() == TRUE )); + + EPosition aDocPos = rEditEngine.FindDocPosition( aEEPos ); + + nPara = aDocPos.nPara; + nIndex = aDocPos.nIndex; + + return sal_True; +} + +sal_Bool SvxEditEngineForwarder::GetWordIndices( USHORT nPara, USHORT nIndex, USHORT& nStart, USHORT& nEnd ) const +{ + ESelection aRes = rEditEngine.GetWord( ESelection(nPara, nIndex, nPara, nIndex), com::sun::star::i18n::WordType::DICTIONARY_WORD ); + + if( aRes.nStartPara == nPara && + aRes.nStartPara == aRes.nEndPara ) + { + nStart = aRes.nStartPos; + nEnd = aRes.nEndPos; + + return sal_True; + } + + return sal_False; +} + +sal_Bool SvxEditEngineForwarder::GetAttributeRun( USHORT& nStartIndex, USHORT& nEndIndex, USHORT nPara, USHORT nIndex ) const +{ + return SvxEditSourceHelper::GetAttributeRun( nStartIndex, nEndIndex, rEditEngine, nPara, nIndex ); +} + +USHORT SvxEditEngineForwarder::GetLineCount( USHORT nPara ) const +{ + return rEditEngine.GetLineCount(nPara); +} + +USHORT SvxEditEngineForwarder::GetLineLen( USHORT nPara, USHORT nLine ) const +{ + return rEditEngine.GetLineLen(nPara, nLine); +} + +void SvxEditEngineForwarder::GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nPara, USHORT nLine ) const +{ + rEditEngine.GetLineBoundaries(rStart, rEnd, nPara, nLine); +} + +USHORT SvxEditEngineForwarder::GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const +{ + return rEditEngine.GetLineNumberAtIndex(nPara, nIndex); +} + + +sal_Bool SvxEditEngineForwarder::QuickFormatDoc( BOOL ) +{ + rEditEngine.QuickFormatDoc(); + + return sal_True; +} + +sal_Bool SvxEditEngineForwarder::Delete( const ESelection& rSelection ) +{ + rEditEngine.QuickDelete( rSelection ); + rEditEngine.QuickFormatDoc(); + + return sal_True; +} + +sal_Bool SvxEditEngineForwarder::InsertText( const String& rStr, const ESelection& rSelection ) +{ + rEditEngine.QuickInsertText( rStr, rSelection ); + rEditEngine.QuickFormatDoc(); + + return sal_True; +} + +sal_Int16 SvxEditEngineForwarder::GetDepth( USHORT ) const +{ + // EditEngine does not support outline depth + return -1; +} + +sal_Bool SvxEditEngineForwarder::SetDepth( USHORT, sal_Int16 nNewDepth ) +{ + // EditEngine does not support outline depth + return nNewDepth == -1 ? sal_True : sal_False; +} + +const SfxItemSet * SvxEditEngineForwarder::GetEmptyItemSetPtr() +{ + return &rEditEngine.GetEmptyItemSet(); +} + +void SvxEditEngineForwarder::AppendParagraph() +{ + rEditEngine.InsertParagraph( rEditEngine.GetParagraphCount(), String::EmptyString() ); +} + +xub_StrLen SvxEditEngineForwarder::AppendTextPortion( USHORT nPara, const String &rText, const SfxItemSet & /*rSet*/ ) +{ + xub_StrLen nLen = 0; + + USHORT nParaCount = rEditEngine.GetParagraphCount(); + DBG_ASSERT( nPara < nParaCount, "paragraph index out of bounds" ); + if (/*0 <= nPara && */nPara < nParaCount) + { + nLen = rEditEngine.GetTextLen( nPara ); + rEditEngine.QuickInsertText( rText, ESelection( nPara, nLen, nPara, nLen ) ); + } + + return nLen; +} + +void SvxEditEngineForwarder::CopyText(const SvxTextForwarder& rSource) +{ + const SvxEditEngineForwarder* pSourceForwarder = dynamic_cast< const SvxEditEngineForwarder* >( &rSource ); + if( !pSourceForwarder ) + return; + EditTextObject* pNewTextObject = pSourceForwarder->rEditEngine.CreateTextObject(); + rEditEngine.SetText( *pNewTextObject ); + delete pNewTextObject; +} + +//------------------------------------------------------------------------ diff --git a/editeng/source/uno/unoforou.cxx b/editeng/source/uno/unoforou.cxx new file mode 100644 index 000000000000..b33153583d31 --- /dev/null +++ b/editeng/source/uno/unoforou.cxx @@ -0,0 +1,613 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unoforou.cxx,v $ + * $Revision: 1.36 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#include <algorithm> +#include <svl/style.hxx> +#include <com/sun/star/i18n/WordType.hpp> + +#include <svl/itemset.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editdata.hxx> +#include <editeng/outliner.hxx> +#include <editeng/unoedhlp.hxx> +#include <svl/poolitem.hxx> +#include <vcl/wrkwin.hxx> +#include <editeng/eeitem.hxx> + +#include <editeng/unoforou.hxx> +#include <editeng/unofored.hxx> +#include <editeng/outlobj.hxx> + +using namespace ::com::sun::star; + +//------------------------------------------------------------------------ + +SvxOutlinerForwarder::SvxOutlinerForwarder( Outliner& rOutl, BOOL bOutlText /* = FALSE */ ) : + rOutliner( rOutl ), + bOutlinerText( bOutlText ), + mpAttribsCache( NULL ), + mpParaAttribsCache( NULL ), + mnParaAttribsCache( 0 ) +{ +} + +SvxOutlinerForwarder::~SvxOutlinerForwarder() +{ + flushCache(); +} + +USHORT SvxOutlinerForwarder::GetParagraphCount() const +{ + return (USHORT)rOutliner.GetParagraphCount(); +} + +USHORT SvxOutlinerForwarder::GetTextLen( USHORT nParagraph ) const +{ + return rOutliner.GetEditEngine().GetTextLen( nParagraph ); +} + +String SvxOutlinerForwarder::GetText( const ESelection& rSel ) const +{ + //! GetText(ESelection) sollte es wohl auch mal am Outliner geben + // solange den Hack fuer die EditEngine uebernehmen: + EditEngine* pEditEngine = (EditEngine*)&rOutliner.GetEditEngine(); + return pEditEngine->GetText( rSel, LINEEND_LF ); +} + +static SfxItemSet ImplOutlinerForwarderGetAttribs( const ESelection& rSel, BOOL bOnlyHardAttrib, EditEngine& rEditEngine ) +{ + if( rSel.nStartPara == rSel.nEndPara ) + { + sal_uInt8 nFlags = 0; + + switch( bOnlyHardAttrib ) + { + case EditEngineAttribs_All: + nFlags = GETATTRIBS_ALL; + break; + case EditEngineAttribs_HardAndPara: + nFlags = GETATTRIBS_PARAATTRIBS|GETATTRIBS_CHARATTRIBS; + break; + case EditEngineAttribs_OnlyHard: + nFlags = GETATTRIBS_CHARATTRIBS; + break; + default: + DBG_ERROR("unknown flags for SvxOutlinerForwarder::GetAttribs"); + } + return rEditEngine.GetAttribs( rSel.nStartPara, rSel.nStartPos, rSel.nEndPos, nFlags ); + } + else + { + return rEditEngine.GetAttribs( rSel, bOnlyHardAttrib ); + } +} + +SfxItemSet SvxOutlinerForwarder::GetAttribs( const ESelection& rSel, BOOL bOnlyHardAttrib ) const +{ + if( mpAttribsCache && ( 0 == bOnlyHardAttrib ) ) + { + // have we the correct set in cache? + if( ((SvxOutlinerForwarder*)this)->maAttribCacheSelection.IsEqual(rSel) ) + { + // yes! just return the cache + return *mpAttribsCache; + } + else + { + // no, we need delete the old cache + delete mpAttribsCache; + mpAttribsCache = NULL; + } + } + + //! gibt's das nicht am Outliner ??? + //! und warum ist GetAttribs an der EditEngine nicht const? + EditEngine& rEditEngine = (EditEngine&)rOutliner.GetEditEngine(); + + SfxItemSet aSet( ImplOutlinerForwarderGetAttribs( rSel, bOnlyHardAttrib, rEditEngine ) ); + + if( 0 == bOnlyHardAttrib ) + { + mpAttribsCache = new SfxItemSet( aSet ); + maAttribCacheSelection = rSel; + } + + SfxStyleSheet* pStyle = rEditEngine.GetStyleSheet( rSel.nStartPara ); + if( pStyle ) + aSet.SetParent( &(pStyle->GetItemSet() ) ); + + return aSet; +} + +SfxItemSet SvxOutlinerForwarder::GetParaAttribs( USHORT nPara ) const +{ + if( mpParaAttribsCache ) + { + // have we the correct set in cache? + if( nPara == mnParaAttribsCache ) + { + // yes! just return the cache + return *mpParaAttribsCache; + } + else + { + // no, we need delete the old cache + delete mpParaAttribsCache; + mpParaAttribsCache = NULL; + } + } + + mpParaAttribsCache = new SfxItemSet( rOutliner.GetParaAttribs( nPara ) ); + mnParaAttribsCache = nPara; + + EditEngine& rEditEngine = (EditEngine&)rOutliner.GetEditEngine(); + + SfxStyleSheet* pStyle = rEditEngine.GetStyleSheet( nPara ); + if( pStyle ) + mpParaAttribsCache->SetParent( &(pStyle->GetItemSet() ) ); + + return *mpParaAttribsCache; +} + +void SvxOutlinerForwarder::SetParaAttribs( USHORT nPara, const SfxItemSet& rSet ) +{ + flushCache(); + + const SfxItemSet* pOldParent = rSet.GetParent(); + if( pOldParent ) + ((SfxItemSet*)&rSet)->SetParent( NULL ); + + rOutliner.SetParaAttribs( nPara, rSet ); + + if( pOldParent ) + ((SfxItemSet*)&rSet)->SetParent( pOldParent ); +} + +void SvxOutlinerForwarder::RemoveAttribs( const ESelection& rSelection, sal_Bool bRemoveParaAttribs, sal_uInt16 nWhich ) +{ + rOutliner.RemoveAttribs( rSelection, bRemoveParaAttribs, nWhich ); +} + +SfxItemPool* SvxOutlinerForwarder::GetPool() const +{ + return rOutliner.GetEmptyItemSet().GetPool(); +} + +void SvxOutlinerForwarder::GetPortions( USHORT nPara, SvUShorts& rList ) const +{ + ((EditEngine&)rOutliner.GetEditEngine()).GetPortions( nPara, rList ); +} + +void SvxOutlinerForwarder::QuickInsertText( const String& rText, const ESelection& rSel ) +{ + flushCache(); + if( rText.Len() == 0 ) + { + rOutliner.QuickDelete( rSel ); + } + else + { + rOutliner.QuickInsertText( rText, rSel ); + } +} + +void SvxOutlinerForwarder::QuickInsertLineBreak( const ESelection& rSel ) +{ + flushCache(); + rOutliner.QuickInsertLineBreak( rSel ); +} + +void SvxOutlinerForwarder::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + flushCache(); + rOutliner.QuickInsertField( rFld, rSel ); +} + +void SvxOutlinerForwarder::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + flushCache(); + rOutliner.QuickSetAttribs( rSet, rSel ); +} + +XubString SvxOutlinerForwarder::CalcFieldValue( const SvxFieldItem& rField, USHORT nPara, USHORT nPos, Color*& rpTxtColor, Color*& rpFldColor ) +{ + return rOutliner.CalcFieldValue( rField, nPara, nPos, rpTxtColor, rpFldColor ); +} + +BOOL SvxOutlinerForwarder::IsValid() const +{ + // cannot reliably query outliner state + // while in the middle of an update + return rOutliner.GetUpdateMode(); +} + +extern USHORT GetSvxEditEngineItemState( EditEngine& rEditEngine, const ESelection& rSel, USHORT nWhich ); + +USHORT SvxOutlinerForwarder::GetItemState( const ESelection& rSel, USHORT nWhich ) const +{ + return GetSvxEditEngineItemState( (EditEngine&)rOutliner.GetEditEngine(), rSel, nWhich ); +} + +USHORT SvxOutlinerForwarder::GetItemState( USHORT nPara, USHORT nWhich ) const +{ + const SfxItemSet& rSet = rOutliner.GetParaAttribs( nPara ); + return rSet.GetItemState( nWhich ); +} + + +void SvxOutlinerForwarder::flushCache() +{ + if( mpAttribsCache ) + { + delete mpAttribsCache; + mpAttribsCache = NULL; + } + + if( mpParaAttribsCache ) + { + delete mpParaAttribsCache; + mpParaAttribsCache = NULL; + } +} + +LanguageType SvxOutlinerForwarder::GetLanguage( USHORT nPara, USHORT nIndex ) const +{ + return rOutliner.GetLanguage(nPara, nIndex); +} + +USHORT SvxOutlinerForwarder::GetFieldCount( USHORT nPara ) const +{ + return rOutliner.GetEditEngine().GetFieldCount(nPara); +} + +EFieldInfo SvxOutlinerForwarder::GetFieldInfo( USHORT nPara, USHORT nField ) const +{ + return rOutliner.GetEditEngine().GetFieldInfo( nPara, nField ); +} + +EBulletInfo SvxOutlinerForwarder::GetBulletInfo( USHORT nPara ) const +{ + return rOutliner.GetBulletInfo( nPara ); +} + +Rectangle SvxOutlinerForwarder::GetCharBounds( USHORT nPara, USHORT nIndex ) const +{ + // #101701# + // EditEngine's 'internal' methods like GetCharacterBounds() + // don't rotate for vertical text. + Size aSize( rOutliner.CalcTextSize() ); + ::std::swap( aSize.Width(), aSize.Height() ); + bool bIsVertical( rOutliner.IsVertical() == TRUE ); + + // #108900# Handle virtual position one-past-the end of the string + if( nIndex >= GetTextLen(nPara) ) + { + Rectangle aLast; + + if( nIndex ) + { + // use last character, if possible + aLast = rOutliner.GetEditEngine().GetCharacterBounds( EPosition(nPara, nIndex-1) ); + + // move at end of this last character, make one pixel wide + aLast.Move( aLast.Right() - aLast.Left(), 0 ); + aLast.SetSize( Size(1, aLast.GetHeight()) ); + + // take care for CTL + aLast = SvxEditSourceHelper::EEToUserSpace( aLast, aSize, bIsVertical ); + } + else + { + // #109864# Bounds must lie within the paragraph + aLast = GetParaBounds( nPara ); + + // #109151# Don't use paragraph height, but line height + // instead. aLast is already CTL-correct + if( bIsVertical) + aLast.SetSize( Size( rOutliner.GetLineHeight(nPara,0), 1 ) ); + else + aLast.SetSize( Size( 1, rOutliner.GetLineHeight(nPara,0) ) ); + } + + return aLast; + } + else + { + return SvxEditSourceHelper::EEToUserSpace( rOutliner.GetEditEngine().GetCharacterBounds( EPosition(nPara, nIndex) ), + aSize, bIsVertical ); + } +} + +Rectangle SvxOutlinerForwarder::GetParaBounds( USHORT nPara ) const +{ + Point aPnt = rOutliner.GetDocPosTopLeft( nPara ); + Size aSize = rOutliner.CalcTextSize(); + + if( rOutliner.IsVertical() ) + { + // #101701# + // Hargl. Outliner's 'external' methods return the rotated + // dimensions, 'internal' methods like GetTextHeight( n ) + // don't rotate. + ULONG nWidth = rOutliner.GetTextHeight( nPara ); + + return Rectangle( aSize.Width() - aPnt.Y() - nWidth, 0, aSize.Width() - aPnt.Y(), aSize.Height() ); + } + else + { + ULONG nHeight = rOutliner.GetTextHeight( nPara ); + + return Rectangle( 0, aPnt.Y(), aSize.Width(), aPnt.Y() + nHeight ); + } +} + +MapMode SvxOutlinerForwarder::GetMapMode() const +{ + return rOutliner.GetRefMapMode(); +} + +OutputDevice* SvxOutlinerForwarder::GetRefDevice() const +{ + return rOutliner.GetRefDevice(); +} + +sal_Bool SvxOutlinerForwarder::GetIndexAtPoint( const Point& rPos, USHORT& nPara, USHORT& nIndex ) const +{ + // #101701# + Size aSize( rOutliner.CalcTextSize() ); + ::std::swap( aSize.Width(), aSize.Height() ); + Point aEEPos( SvxEditSourceHelper::UserSpaceToEE( rPos, + aSize, + rOutliner.IsVertical() == TRUE )); + + EPosition aDocPos = rOutliner.GetEditEngine().FindDocPosition( aEEPos ); + + nPara = aDocPos.nPara; + nIndex = aDocPos.nIndex; + + return sal_True; +} + +sal_Bool SvxOutlinerForwarder::GetWordIndices( USHORT nPara, USHORT nIndex, USHORT& nStart, USHORT& nEnd ) const +{ + ESelection aRes = rOutliner.GetEditEngine().GetWord( ESelection(nPara, nIndex, nPara, nIndex), com::sun::star::i18n::WordType::DICTIONARY_WORD ); + + if( aRes.nStartPara == nPara && + aRes.nStartPara == aRes.nEndPara ) + { + nStart = aRes.nStartPos; + nEnd = aRes.nEndPos; + + return sal_True; + } + + return sal_False; +} + +sal_Bool SvxOutlinerForwarder::GetAttributeRun( USHORT& nStartIndex, USHORT& nEndIndex, USHORT nPara, USHORT nIndex ) const +{ + return SvxEditSourceHelper::GetAttributeRun( nStartIndex, nEndIndex, rOutliner.GetEditEngine(), nPara, nIndex ); +} + +USHORT SvxOutlinerForwarder::GetLineCount( USHORT nPara ) const +{ + return static_cast < USHORT >( rOutliner.GetLineCount(nPara) ); +} + +USHORT SvxOutlinerForwarder::GetLineLen( USHORT nPara, USHORT nLine ) const +{ + return rOutliner.GetLineLen(nPara, nLine); +} + +void SvxOutlinerForwarder::GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT nPara, USHORT nLine ) const +{ + return rOutliner.GetEditEngine().GetLineBoundaries( rStart, rEnd, nPara, nLine ); +} + +USHORT SvxOutlinerForwarder::GetLineNumberAtIndex( USHORT nPara, USHORT nIndex ) const +{ + return rOutliner.GetEditEngine().GetLineNumberAtIndex( nPara, nIndex ); +} + +sal_Bool SvxOutlinerForwarder::QuickFormatDoc( BOOL ) +{ + rOutliner.QuickFormatDoc(); + + return sal_True; +} + +sal_Bool SvxOutlinerForwarder::Delete( const ESelection& rSelection ) +{ + flushCache(); + rOutliner.QuickDelete( rSelection ); + rOutliner.QuickFormatDoc(); + + return sal_True; +} + +sal_Bool SvxOutlinerForwarder::InsertText( const String& rStr, const ESelection& rSelection ) +{ + flushCache(); + rOutliner.QuickInsertText( rStr, rSelection ); + rOutliner.QuickFormatDoc(); + + return sal_True; +} + +sal_Int16 SvxOutlinerForwarder::GetDepth( USHORT nPara ) const +{ + DBG_ASSERT( nPara < GetParagraphCount(), "SvxOutlinerForwarder::GetDepth: Invalid paragraph index"); + + Paragraph* pPara = rOutliner.GetParagraph( nPara ); + + sal_Int16 nLevel = -1; + + if( pPara ) + nLevel = rOutliner.GetDepth( nPara ); + + return nLevel; +} + +sal_Bool SvxOutlinerForwarder::SetDepth( USHORT nPara, sal_Int16 nNewDepth ) +{ + DBG_ASSERT( nPara < GetParagraphCount(), "SvxOutlinerForwarder::SetDepth: Invalid paragraph index"); + + if( (nNewDepth >= -1) && (nNewDepth <= 9) && (nPara < GetParagraphCount()) ) + { + Paragraph* pPara = rOutliner.GetParagraph( nPara ); + if( pPara ) + { + rOutliner.SetDepth( pPara, nNewDepth ); + +// const bool bOutlinerText = pSdrObject && (pSdrObject->GetObjInventor() == SdrInventor) && (pSdrObject->GetObjIdentifier() == OBJ_OUTLINETEXT); + if( bOutlinerText ) + rOutliner.SetLevelDependendStyleSheet( nPara ); + + return sal_True; + } + } + + return sal_False; +} + +sal_Int16 SvxOutlinerForwarder::GetNumberingStartValue( sal_uInt16 nPara ) +{ + if( nPara < GetParagraphCount() ) + { + return rOutliner.GetNumberingStartValue( nPara ); + } + else + { + DBG_ERROR( "SvxOutlinerForwarder::GetNumberingStartValue)(), Invalid paragraph index"); + return -1; + } +} + +void SvxOutlinerForwarder::SetNumberingStartValue( sal_uInt16 nPara, sal_Int16 nNumberingStartValue ) +{ + if( nPara < GetParagraphCount() ) + { + rOutliner.SetNumberingStartValue( nPara, nNumberingStartValue ); + } + else + { + DBG_ERROR( "SvxOutlinerForwarder::SetNumberingStartValue)(), Invalid paragraph index"); + } +} + +sal_Bool SvxOutlinerForwarder::IsParaIsNumberingRestart( sal_uInt16 nPara ) +{ + if( nPara < GetParagraphCount() ) + { + return rOutliner.IsParaIsNumberingRestart( nPara ); + } + else + { + DBG_ERROR( "SvxOutlinerForwarder::IsParaIsNumberingRestart)(), Invalid paragraph index"); + return sal_False; + } +} + +void SvxOutlinerForwarder::SetParaIsNumberingRestart( sal_uInt16 nPara, sal_Bool bParaIsNumberingRestart ) +{ + if( nPara < GetParagraphCount() ) + { + rOutliner.SetParaIsNumberingRestart( nPara, bParaIsNumberingRestart ); + } + else + { + DBG_ERROR( "SvxOutlinerForwarder::SetParaIsNumberingRestart)(), Invalid paragraph index"); + } +} + +const SfxItemSet * SvxOutlinerForwarder::GetEmptyItemSetPtr() +{ + EditEngine& rEditEngine = const_cast< EditEngine& >( rOutliner.GetEditEngine() ); + return &rEditEngine.GetEmptyItemSet(); +} + +void SvxOutlinerForwarder::AppendParagraph() +{ + EditEngine& rEditEngine = const_cast< EditEngine& >( rOutliner.GetEditEngine() ); + rEditEngine.InsertParagraph( rEditEngine.GetParagraphCount(), String::EmptyString() ); +} + +xub_StrLen SvxOutlinerForwarder::AppendTextPortion( USHORT nPara, const String &rText, const SfxItemSet & /*rSet*/ ) +{ + xub_StrLen nLen = 0; + + EditEngine& rEditEngine = const_cast< EditEngine& >( rOutliner.GetEditEngine() ); + USHORT nParaCount = rEditEngine.GetParagraphCount(); + DBG_ASSERT( nPara < nParaCount, "paragraph index out of bounds" ); + if (/*0 <= nPara && */nPara < nParaCount) + { + nLen = rEditEngine.GetTextLen( nPara ); + rEditEngine.QuickInsertText( rText, ESelection( nPara, nLen, nPara, nLen ) ); + } + + return nLen; +} + +void SvxOutlinerForwarder::CopyText(const SvxTextForwarder& rSource) +{ + const SvxOutlinerForwarder* pSourceForwarder = dynamic_cast< const SvxOutlinerForwarder* >( &rSource ); + if( !pSourceForwarder ) + return; + OutlinerParaObject* pNewOutlinerParaObject = pSourceForwarder->rOutliner.CreateParaObject(); + rOutliner.SetText( *pNewOutlinerParaObject ); + delete pNewOutlinerParaObject; +} + +//------------------------------------------------------------------------ + + +sal_Int16 SvxTextForwarder::GetNumberingStartValue( sal_uInt16 ) +{ + return -1; +} + +void SvxTextForwarder::SetNumberingStartValue( sal_uInt16, sal_Int16 ) +{ +} + +sal_Bool SvxTextForwarder::IsParaIsNumberingRestart( sal_uInt16 ) +{ + return sal_False; +} + +void SvxTextForwarder::SetParaIsNumberingRestart( sal_uInt16, sal_Bool ) +{ +} + +//------------------------------------------------------------------------ + diff --git a/editeng/source/uno/unoipset.cxx b/editeng/source/uno/unoipset.cxx new file mode 100644 index 000000000000..fd3a8d674264 --- /dev/null +++ b/editeng/source/uno/unoipset.cxx @@ -0,0 +1,394 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unoipset.cxx,v $ + * $Revision: 1.28 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <com/sun/star/beans/XPropertySet.hpp> +#include <svl/eitem.hxx> +#include <tools/list.hxx> + +#include <hash_map> +#include <vector> +#include <svl/itemprop.hxx> + +#include <editeng/unoipset.hxx> +#include <editeng/editids.hrc> +#include <editeng/editeng.hxx> +#include <svl/itempool.hxx> +#include <algorithm> + +using namespace ::com::sun::star; +using namespace ::rtl; + +//---------------------------------------------------------------------- + +struct SfxItemPropertyMapEntryHash +{ + size_t operator()(const SfxItemPropertyMapEntry* pMap) const { return (size_t)pMap; } +}; + +//---------------------------------------------------------------------- + +struct SvxIDPropertyCombine +{ + sal_uInt16 nWID; + uno::Any aAny; +}; + +DECLARE_LIST( SvxIDPropertyCombineList, SvxIDPropertyCombine * ) + +SvxItemPropertySet::SvxItemPropertySet( const SfxItemPropertyMapEntry* pMap, SfxItemPool& rItemPool, sal_Bool bConvertTwips ) +: m_aPropertyMap( pMap ), + _pMap(pMap), mbConvertTwips(bConvertTwips), mrItemPool( rItemPool ) +{ + pCombiList = NULL; +} + +//---------------------------------------------------------------------- +SvxItemPropertySet::~SvxItemPropertySet() +{ +/* + if(pItemPool) + delete pItemPool; + pItemPool = NULL; +*/ + + if(pCombiList) + delete pCombiList; + pCombiList = NULL; +} + +//---------------------------------------------------------------------- +uno::Any* SvxItemPropertySet::GetUsrAnyForID(sal_uInt16 nWID) const +{ + if(pCombiList && pCombiList->Count()) + { + SvxIDPropertyCombine* pActual = pCombiList->First(); + while(pActual) + { + if(pActual->nWID == nWID) + return &pActual->aAny; + pActual = pCombiList->Next(); + + } + } + return NULL; +} + +//---------------------------------------------------------------------- +void SvxItemPropertySet::AddUsrAnyForID(const uno::Any& rAny, sal_uInt16 nWID) +{ + if(!pCombiList) + pCombiList = new SvxIDPropertyCombineList(); + + SvxIDPropertyCombine* pNew = new SvxIDPropertyCombine; + pNew->nWID = nWID; + pNew->aAny = rAny; + pCombiList->Insert(pNew); +} + +sal_Bool SvxUnoCheckForPositiveValue( const uno::Any& rVal ) +{ + sal_Bool bConvert = sal_True; // the default is that all metric items must be converted + sal_Int32 nValue = 0; + if( rVal >>= nValue ) + bConvert = (nValue > 0); + return bConvert; +} + + +//---------------------------------------------------------------------- +uno::Any SvxItemPropertySet::getPropertyValue( const SfxItemPropertySimpleEntry* pMap, const SfxItemSet& rSet, bool bSearchInParent, bool bDontConvertNegativeValues ) const +{ + uno::Any aVal; + if(!pMap || !pMap->nWID) + return aVal; + + const SfxPoolItem* pItem = 0; + SfxItemPool* pPool = rSet.GetPool(); + rSet.GetItemState( pMap->nWID, bSearchInParent, &pItem ); + if( NULL == pItem && pPool ) + pItem = &(pPool->GetDefaultItem( pMap->nWID )); + + const SfxMapUnit eMapUnit = pPool ? pPool->GetMetric((USHORT)pMap->nWID) : SFX_MAPUNIT_100TH_MM; + BYTE nMemberId = pMap->nMemberId & (~SFX_METRIC_ITEM); + if( eMapUnit == SFX_MAPUNIT_100TH_MM ) + nMemberId &= (~CONVERT_TWIPS); + + if(pItem) + { + pItem->QueryValue( aVal, nMemberId ); + if( pMap->nMemberId & SFX_METRIC_ITEM ) + { + if( eMapUnit != SFX_MAPUNIT_100TH_MM ) + { + if ( !bDontConvertNegativeValues || SvxUnoCheckForPositiveValue( aVal ) ) + SvxUnoConvertToMM( eMapUnit, aVal ); + } + } + else if ( pMap->pType->getTypeClass() == uno::TypeClass_ENUM && + aVal.getValueType() == ::getCppuType((const sal_Int32*)0) ) + { + // convert typeless SfxEnumItem to enum type + sal_Int32 nEnum; + aVal >>= nEnum; + aVal.setValue( &nEnum, *pMap->pType ); + } + } + else + { + DBG_ERROR( "No SfxPoolItem found for property!" ); + } + + return aVal; +} + +//---------------------------------------------------------------------- +void SvxItemPropertySet::setPropertyValue( const SfxItemPropertySimpleEntry* pMap, const uno::Any& rVal, SfxItemSet& rSet, bool bDontConvertNegativeValues ) const +{ + if(!pMap || !pMap->nWID) + return; + + // item holen + const SfxPoolItem* pItem = 0; + SfxPoolItem *pNewItem = 0; + SfxItemState eState = rSet.GetItemState( pMap->nWID, sal_True, &pItem ); + SfxItemPool* pPool = rSet.GetPool(); + + // UnoAny in item-Wert stecken + if(eState < SFX_ITEM_DEFAULT || pItem == NULL) + { + if( pPool == NULL ) + { + DBG_ERROR( "No default item and no pool?" ); + return; + } + + pItem = &pPool->GetDefaultItem( pMap->nWID ); + } + + DBG_ASSERT( pItem, "Got no default for item!" ); + if( pItem ) + { + uno::Any aValue( rVal ); + + const SfxMapUnit eMapUnit = pPool ? pPool->GetMetric((USHORT)pMap->nWID) : SFX_MAPUNIT_100TH_MM; + + // check for needed metric translation + if( (pMap->nMemberId & SFX_METRIC_ITEM) && eMapUnit != SFX_MAPUNIT_100TH_MM ) + { + if ( !bDontConvertNegativeValues || SvxUnoCheckForPositiveValue( aValue ) ) + SvxUnoConvertFromMM( eMapUnit, aValue ); + } + + pNewItem = pItem->Clone(); + + BYTE nMemberId = pMap->nMemberId & (~SFX_METRIC_ITEM); + if( eMapUnit == SFX_MAPUNIT_100TH_MM ) + nMemberId &= (~CONVERT_TWIPS); + + if( pNewItem->PutValue( aValue, nMemberId ) ) + { + // neues item in itemset setzen + rSet.Put( *pNewItem, pMap->nWID ); + } + delete pNewItem; + } +} + +//---------------------------------------------------------------------- +uno::Any SvxItemPropertySet::getPropertyValue( const SfxItemPropertySimpleEntry* pMap ) const +{ + // Schon ein Wert eingetragen? Dann schnell fertig + uno::Any* pUsrAny = GetUsrAnyForID(pMap->nWID); + if(pUsrAny) + return *pUsrAny; + + // Noch kein UsrAny gemerkt, generiere Default-Eintrag und gib + // diesen zurueck + + const SfxMapUnit eMapUnit = mrItemPool.GetMetric((USHORT)pMap->nWID); + BYTE nMemberId = pMap->nMemberId & (~SFX_METRIC_ITEM); + if( eMapUnit == SFX_MAPUNIT_100TH_MM ) + nMemberId &= (~CONVERT_TWIPS); + + uno::Any aVal; + SfxItemSet aSet( mrItemPool, pMap->nWID, pMap->nWID); + + if( (pMap->nWID < OWN_ATTR_VALUE_START) && (pMap->nWID > OWN_ATTR_VALUE_END ) ) + { + // Default aus ItemPool holen + if(mrItemPool.IsWhich(pMap->nWID)) + aSet.Put(mrItemPool.GetDefaultItem(pMap->nWID)); + } + + if(aSet.Count()) + { + const SfxPoolItem* pItem = NULL; + SfxItemState eState = aSet.GetItemState( pMap->nWID, sal_True, &pItem ); + if(eState >= SFX_ITEM_DEFAULT && pItem) + { + pItem->QueryValue( aVal, nMemberId ); + ((SvxItemPropertySet*)this)->AddUsrAnyForID(aVal, pMap->nWID); + } + } + + if( pMap->nMemberId & SFX_METRIC_ITEM ) + { + // check for needed metric translation + if(pMap->nMemberId & SFX_METRIC_ITEM && eMapUnit != SFX_MAPUNIT_100TH_MM) + { + SvxUnoConvertToMM( eMapUnit, aVal ); + } + } + + if ( pMap->pType->getTypeClass() == uno::TypeClass_ENUM && + aVal.getValueType() == ::getCppuType((const sal_Int32*)0) ) + { + sal_Int32 nEnum; + aVal >>= nEnum; + + aVal.setValue( &nEnum, *pMap->pType ); + } + + return aVal; +} + +//---------------------------------------------------------------------- + +void SvxItemPropertySet::setPropertyValue( const SfxItemPropertySimpleEntry* pMap, const uno::Any& rVal ) const +{ + uno::Any* pUsrAny = GetUsrAnyForID(pMap->nWID); + if(!pUsrAny) + ((SvxItemPropertySet*)this)->AddUsrAnyForID(rVal, pMap->nWID); + else + *pUsrAny = rVal; +} + +//---------------------------------------------------------------------- + +const SfxItemPropertySimpleEntry* SvxItemPropertySet::getPropertyMapEntry(const OUString &rName) const +{ + return m_aPropertyMap.getByName( rName ); + } + +//---------------------------------------------------------------------- + +uno::Reference< beans::XPropertySetInfo > SvxItemPropertySet::getPropertySetInfo() const +{ + if( !m_xInfo.is() ) + m_xInfo = new SfxItemPropertySetInfo( &m_aPropertyMap ); + return m_xInfo; +} + +//---------------------------------------------------------------------- + +#ifndef TWIPS_TO_MM +#define TWIPS_TO_MM(val) ((val * 127 + 36) / 72) +#endif +#ifndef MM_TO_TWIPS +#define MM_TO_TWIPS(val) ((val * 72 + 63) / 127) +#endif + +/** converts the given any with a metric to 100th/mm if needed */ +void SvxUnoConvertToMM( const SfxMapUnit eSourceMapUnit, uno::Any & rMetric ) throw() +{ + // map the metric of the itempool to 100th mm + switch(eSourceMapUnit) + { + case SFX_MAPUNIT_TWIP : + { + switch( rMetric.getValueTypeClass() ) + { + case uno::TypeClass_BYTE: + rMetric <<= (sal_Int8)(TWIPS_TO_MM(*(sal_Int8*)rMetric.getValue())); + break; + case uno::TypeClass_SHORT: + rMetric <<= (sal_Int16)(TWIPS_TO_MM(*(sal_Int16*)rMetric.getValue())); + break; + case uno::TypeClass_UNSIGNED_SHORT: + rMetric <<= (sal_uInt16)(TWIPS_TO_MM(*(sal_uInt16*)rMetric.getValue())); + break; + case uno::TypeClass_LONG: + rMetric <<= (sal_Int32)(TWIPS_TO_MM(*(sal_Int32*)rMetric.getValue())); + break; + case uno::TypeClass_UNSIGNED_LONG: + rMetric <<= (sal_uInt32)(TWIPS_TO_MM(*(sal_uInt32*)rMetric.getValue())); + break; + default: + DBG_ERROR("AW: Missing unit translation to 100th mm!"); + } + break; + } + default: + { + DBG_ERROR("AW: Missing unit translation to 100th mm!"); + } + } +} + +//---------------------------------------------------------------------- + +/** converts the given any with a metric from 100th/mm to the given metric if needed */ +void SvxUnoConvertFromMM( const SfxMapUnit eDestinationMapUnit, uno::Any & rMetric ) throw() +{ + switch(eDestinationMapUnit) + { + case SFX_MAPUNIT_TWIP : + { + switch( rMetric.getValueTypeClass() ) + { + case uno::TypeClass_BYTE: + rMetric <<= (sal_Int8)(MM_TO_TWIPS(*(sal_Int8*)rMetric.getValue())); + break; + case uno::TypeClass_SHORT: + rMetric <<= (sal_Int16)(MM_TO_TWIPS(*(sal_Int16*)rMetric.getValue())); + break; + case uno::TypeClass_UNSIGNED_SHORT: + rMetric <<= (sal_uInt16)(MM_TO_TWIPS(*(sal_uInt16*)rMetric.getValue())); + break; + case uno::TypeClass_LONG: + rMetric <<= (sal_Int32)(MM_TO_TWIPS(*(sal_Int32*)rMetric.getValue())); + break; + case uno::TypeClass_UNSIGNED_LONG: + rMetric <<= (sal_uInt32)(MM_TO_TWIPS(*(sal_uInt32*)rMetric.getValue())); + break; + default: + DBG_ERROR("AW: Missing unit translation to 100th mm!"); + } + break; + } + default: + { + DBG_ERROR("AW: Missing unit translation to PoolMetrics!"); + } + } +} + diff --git a/editeng/source/uno/unonrule.cxx b/editeng/source/uno/unonrule.cxx new file mode 100644 index 000000000000..f3a1f5066e25 --- /dev/null +++ b/editeng/source/uno/unonrule.cxx @@ -0,0 +1,618 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unonrule.cxx,v $ + * $Revision: 1.26 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +#define PROPERTY_NONE 0 + +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/awt/XBitmap.hpp> + +#include <vcl/svapp.hxx> +#include <vos/mutex.hxx> +#include <vcl/graph.hxx> +#include <svtools/grfmgr.hxx> +#include <toolkit/unohlp.hxx> +#include <rtl/uuid.h> +#include <rtl/memory.h> + +#include <editeng/brshitem.hxx> +#include <editeng/unoprnms.hxx> +#include <editeng/numitem.hxx> +#include <editeng/eeitem.hxx> +#include <editeng/unotext.hxx> +#include <editeng/numitem.hxx> +#include <editeng/unofdesc.hxx> +#include <editeng/unonrule.hxx> +#include <editeng/editids.hrc> + +using ::rtl::OUString; +using ::com::sun::star::util::XCloneable; +using ::com::sun::star::ucb::XAnyCompare; + + +using namespace ::vos; +using namespace ::std; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; + +const SvxAdjust aUnoToSvxAdjust[] = +{ + SVX_ADJUST_LEFT, + SVX_ADJUST_RIGHT, + SVX_ADJUST_CENTER, + SVX_ADJUST_LEFT, + SVX_ADJUST_LEFT, + SVX_ADJUST_LEFT, + SVX_ADJUST_BLOCK +}; + +const unsigned short aSvxToUnoAdjust[] = +{ + text::HoriOrientation::LEFT, + text::HoriOrientation::RIGHT, + text::HoriOrientation::FULL, + text::HoriOrientation::CENTER, + text::HoriOrientation::FULL, + text::HoriOrientation::LEFT +}; + +SvxAdjust ConvertUnoAdjust( unsigned short nAdjust ) +{ + DBG_ASSERT( nAdjust <= 7, "Enum hat sich geaendert! [CL]" ); + return aUnoToSvxAdjust[nAdjust]; +} + +unsigned short ConvertUnoAdjust( SvxAdjust eAdjust ) +{ + DBG_ASSERT( eAdjust <= 6, "Enum hat sich geaendert! [CL]" ); + return aSvxToUnoAdjust[eAdjust]; +} + +/****************************************************************** + * SvxUnoNumberingRules + ******************************************************************/ + +UNO3_GETIMPLEMENTATION_IMPL( SvxUnoNumberingRules ); + +SvxUnoNumberingRules::SvxUnoNumberingRules( const SvxNumRule& rRule ) throw() +: maRule( rRule ) +{ +} + +SvxUnoNumberingRules::~SvxUnoNumberingRules() throw() +{ +} + +//XIndexReplace +void SAL_CALL SvxUnoNumberingRules::replaceByIndex( sal_Int32 Index, const uno::Any& Element ) + throw( IllegalArgumentException, IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( Index < 0 || Index >= maRule.GetLevelCount() ) + throw IndexOutOfBoundsException(); + + Sequence< beans::PropertyValue > aSeq; + + if( !( Element >>= aSeq) ) + throw IllegalArgumentException(); + setNumberingRuleByIndex( aSeq, Index ); +} + +// XIndexAccess +sal_Int32 SAL_CALL SvxUnoNumberingRules::getCount() throw( RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + return maRule.GetLevelCount(); +} + +Any SAL_CALL SvxUnoNumberingRules::getByIndex( sal_Int32 Index ) + throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( Index < 0 || Index >= maRule.GetLevelCount() ) + throw IndexOutOfBoundsException(); + + return Any( getNumberingRuleByIndex(Index) ); +} + +//XElementAccess +Type SAL_CALL SvxUnoNumberingRules::getElementType() + throw( RuntimeException ) +{ + return ::getCppuType(( const Sequence< beans::PropertyValue >*)0); +} + +sal_Bool SAL_CALL SvxUnoNumberingRules::hasElements() throw( RuntimeException ) +{ + return sal_True; +} + +// XAnyCompare +sal_Int16 SAL_CALL SvxUnoNumberingRules::compare( const Any& rAny1, const Any& rAny2 ) throw(RuntimeException) +{ + return SvxUnoNumberingRules::Compare( rAny1, rAny2 ); +} + +// XCloneable +Reference< XCloneable > SAL_CALL SvxUnoNumberingRules::createClone( ) throw (RuntimeException) +{ + return new SvxUnoNumberingRules(maRule); +} + +// XServiceInfo +sal_Char pSvxUnoNumberingRulesService[sizeof("com.sun.star.text.NumberingRules")] = "com.sun.star.text.NumberingRules"; + +OUString SAL_CALL SvxUnoNumberingRules::getImplementationName( ) throw(RuntimeException) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "SvxUnoNumberingRules" ) ); +} + +sal_Bool SAL_CALL SvxUnoNumberingRules::supportsService( const OUString& ServiceName ) throw(RuntimeException) +{ + return ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( pSvxUnoNumberingRulesService ) ); +} + +Sequence< OUString > SAL_CALL SvxUnoNumberingRules::getSupportedServiceNames( ) throw(RuntimeException) +{ + OUString aService( RTL_CONSTASCII_USTRINGPARAM( pSvxUnoNumberingRulesService ) ); + Sequence< OUString > aSeq( &aService, 1 ); + return aSeq; +} + +Sequence<beans::PropertyValue> SvxUnoNumberingRules::getNumberingRuleByIndex( sal_Int32 nIndex) const throw() +{ + // NumberingRule aRule; + const SvxNumberFormat& rFmt = maRule.GetLevel((sal_uInt16) nIndex); + sal_uInt16 nIdx = 0; + + const int nProps = 15; + beans::PropertyValue* pArray = new beans::PropertyValue[nProps]; + + Any aVal; + { + aVal <<= rFmt.GetNumberingType(); + beans::PropertyValue aAlignProp( OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_NUMBERINGTYPE)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aAlignProp; + } + + { + SvxAdjust eAdj = rFmt.GetNumAdjust(); + aVal <<= ConvertUnoAdjust(eAdj); + pArray[nIdx++] = beans::PropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_ADJUST)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + } + + { + aVal <<= OUString(rFmt.GetPrefix()); + beans::PropertyValue aPrefixProp( OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_PREFIX)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aPrefixProp; + } + + { + aVal <<= OUString(rFmt.GetSuffix()); + beans::PropertyValue aSuffixProp( OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_SUFFIX)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aSuffixProp; + } + + { + sal_Unicode nCode = rFmt.GetBulletChar(); + OUString aStr( &nCode, 1 ); + aVal <<= aStr; + beans::PropertyValue aBulletProp( OUString(RTL_CONSTASCII_USTRINGPARAM("BulletChar")), -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aBulletProp; + } + + if( rFmt.GetBulletFont() ) + { + awt::FontDescriptor aDesc; + SvxUnoFontDescriptor::ConvertFromFont( *rFmt.GetBulletFont(), aDesc ); + aVal.setValue(&aDesc, ::getCppuType((const awt::FontDescriptor*)0)); + pArray[nIdx++] = beans::PropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_BULLET_FONT)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + } + + { + const SvxBrushItem* pBrush = rFmt.GetBrush(); + if(pBrush && pBrush->GetGraphicObject()) + { + const GraphicObject* pGrafObj = pBrush->GetGraphicObject(); + OUString aURL( RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_GRAPHOBJ_URLPREFIX)); + aURL += OUString::createFromAscii( pGrafObj->GetUniqueID().GetBuffer() ); + + aVal <<= aURL; + const beans::PropertyValue aGraphicProp( OUString(RTL_CONSTASCII_USTRINGPARAM("GraphicURL")), -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aGraphicProp; + } + } + + { + const Size aSize( rFmt.GetGraphicSize() ); + const awt::Size aUnoSize( aSize.Width(), aSize.Height() ); + aVal <<= aUnoSize; + const beans::PropertyValue aGraphicSizeProp(OUString(RTL_CONSTASCII_USTRINGPARAM("GraphicSize")), -1, aVal, beans::PropertyState_DIRECT_VALUE ); + pArray[nIdx++] = aGraphicSizeProp; + } + + aVal <<= (sal_Int16)rFmt.GetStart(); + pArray[nIdx++] = beans::PropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_START_WITH)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + + aVal <<= (sal_Int32)rFmt.GetAbsLSpace(); + pArray[nIdx++] = beans::PropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_LEFT_MARGIN)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + + aVal <<= (sal_Int32)rFmt.GetFirstLineOffset(); + pArray[nIdx++] = beans::PropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_FIRST_LINE_OFFSET)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + + pArray[nIdx++] = beans::PropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("SymbolTextDistance")), -1, aVal, beans::PropertyState_DIRECT_VALUE); + + aVal <<= (sal_Int32)rFmt.GetBulletColor().GetColor(); + pArray[nIdx++] = beans::PropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_BULLET_COLOR)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + + aVal <<= (sal_Int16)rFmt.GetBulletRelSize(); + pArray[nIdx++] = beans::PropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_NAME_NRULE_BULLET_RELSIZE)), -1, aVal, beans::PropertyState_DIRECT_VALUE); + + DBG_ASSERT( nIdx <= nProps, "FixMe: Array uebergelaufen!!!! [CL]" ); + Sequence< beans::PropertyValue> aSeq(pArray, nIdx); + + delete [] pArray; + return aSeq; +} + +void SvxUnoNumberingRules::setNumberingRuleByIndex( const Sequence< beans::PropertyValue >& rProperties, sal_Int32 nIndex) + throw( RuntimeException, IllegalArgumentException ) +{ + SvxNumberFormat aFmt(maRule.GetLevel( (sal_uInt16)nIndex )); + const beans::PropertyValue* pPropArray = rProperties.getConstArray(); + for(int i = 0; i < rProperties.getLength(); i++) + { + const beans::PropertyValue& rProp = pPropArray[i]; + const OUString& rPropName = rProp.Name; + const Any& aVal = rProp.Value; + + if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_NUMBERINGTYPE))) + { + sal_Int16 nSet = sal_Int16(); + aVal >>= nSet; + + switch(nSet) + { + case SVX_NUM_BITMAP: + case SVX_NUM_CHAR_SPECIAL: + case SVX_NUM_ROMAN_UPPER: + case SVX_NUM_ROMAN_LOWER: + case SVX_NUM_CHARS_UPPER_LETTER: + case SVX_NUM_CHARS_LOWER_LETTER: + case SVX_NUM_ARABIC: + case SVX_NUM_NUMBER_NONE: + case SVX_NUM_CHARS_UPPER_LETTER_N: + case SVX_NUM_CHARS_LOWER_LETTER_N: + aFmt.SetNumberingType(nSet); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_PREFIX))) + { + OUString aPrefix; + if( aVal >>= aPrefix ) + { + aFmt.SetPrefix(aPrefix); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_SUFFIX))) + { + OUString aSuffix; + if( aVal >>= aSuffix ) + { + aFmt.SetSuffix(aSuffix); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_BULLETID))) + { + sal_Int16 nSet = sal_Int16(); + if( aVal >>= nSet ) + { + if(nSet < 0x100) + { + aFmt.SetBulletChar(nSet); + continue; + } + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("BulletChar"))) + { + OUString aStr; + if( aVal >>= aStr ) + { + if(aStr.getLength()) + { + aFmt.SetBulletChar(aStr[0]); + } + else + { + aFmt.SetBulletChar(0); + } + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_ADJUST))) + { + sal_Int16 nAdjust = sal_Int16(); + if( aVal >>= nAdjust ) + { + aFmt.SetNumAdjust(ConvertUnoAdjust( (unsigned short)nAdjust )); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_BULLET_FONT))) + { + awt::FontDescriptor aDesc; + if( aVal >>= aDesc ) + { + Font aFont; + SvxUnoFontDescriptor::ConvertToFont( aDesc, aFont ); + aFmt.SetBulletFont(&aFont); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("Graphic"))) + { + Reference< awt::XBitmap > xBmp; + if( aVal >>= xBmp ) + { + Graphic aGraf( VCLUnoHelper::GetBitmap( xBmp ) ); + SvxBrushItem aBrushItem(aGraf, GPOS_AREA, SID_ATTR_BRUSH); + aFmt.SetGraphicBrush( &aBrushItem ); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("GraphicURL"))) + { + OUString aURL; + if( aVal >>= aURL ) + { + GraphicObject aGrafObj( GraphicObject::CreateGraphicObjectFromURL( aURL ) ); + SvxBrushItem aBrushItem( aGrafObj, GPOS_AREA, SID_ATTR_BRUSH ); + aFmt.SetGraphicBrush( &aBrushItem ); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("GraphicSize"))) + { + awt::Size aUnoSize; + if( aVal >>= aUnoSize ) + { + aFmt.SetGraphicSize( Size( aUnoSize.Width, aUnoSize.Height ) ); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_START_WITH))) + { + sal_Int16 nStart = sal_Int16(); + if( aVal >>= nStart ) + { + aFmt.SetStart( nStart ); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_LEFT_MARGIN))) + { + sal_Int32 nMargin = 0; + if( aVal >>= nMargin ) + { + aFmt.SetAbsLSpace((sal_uInt16)nMargin); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_FIRST_LINE_OFFSET))) + { + sal_Int32 nMargin = 0; + if( aVal >>= nMargin ) + { + aFmt.SetFirstLineOffset((sal_uInt16)nMargin); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("SymbolTextDistance"))) + { + sal_Int32 nTextDistance = 0; + if( aVal >>= nTextDistance ) + { + aFmt.SetCharTextDistance((sal_uInt16)nTextDistance); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_BULLET_COLOR))) + { + sal_Int32 nColor = 0; + if( aVal >>= nColor ) + { + aFmt.SetBulletColor( (Color) nColor ); + continue; + } + } + else if(rPropName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(UNO_NAME_NRULE_BULLET_RELSIZE))) + { + sal_Int16 nSize = sal_Int16(); + if( aVal >>= nSize ) + { + aFmt.SetBulletRelSize( (short)nSize ); + continue; + } + } + else + { + continue; + } + + throw IllegalArgumentException(); + } + + // check that we always have a brush item for bitmap numbering + if( aFmt.GetNumberingType() == SVX_NUM_BITMAP ) + { + if( NULL == aFmt.GetBrush() ) + { + GraphicObject aGrafObj; + SvxBrushItem aBrushItem( aGrafObj, GPOS_AREA, SID_ATTR_BRUSH ); + aFmt.SetGraphicBrush( &aBrushItem ); + } + } + maRule.SetLevel( (sal_uInt16)nIndex, aFmt ); +} + +/////////////////////////////////////////////////////////////////////// + +const SvxNumRule& SvxGetNumRule( Reference< XIndexReplace > xRule ) throw( IllegalArgumentException ) +{ + SvxUnoNumberingRules* pRule = SvxUnoNumberingRules::getImplementation( xRule ); + if( pRule == NULL ) + throw IllegalArgumentException(); + + return pRule->getNumRule(); +} + +bool SvxGetNumRule( Reference< XIndexReplace > xRule, SvxNumRule& rNumRule ) +{ + SvxUnoNumberingRules* pRule = SvxUnoNumberingRules::getImplementation( xRule ); + if( pRule ) + { + rNumRule = pRule->getNumRule(); + } + else if( xRule.is() ) + { + try + { + pRule = new SvxUnoNumberingRules( rNumRule ); + + Reference< XIndexReplace > xDestRule( pRule ); + + const sal_Int32 nCount = min( xRule->getCount(), xDestRule->getCount() ); + sal_Int32 nLevel; + for( nLevel = 0; nLevel < nCount; nLevel++ ) + { + xDestRule->replaceByIndex( nLevel, xRule->getByIndex( nLevel ) ); + } + + rNumRule = pRule->getNumRule(); + } + catch( Exception& ) + { + return false; + } + } + else + { + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////// +com::sun::star::uno::Reference< com::sun::star::container::XIndexReplace > SvxCreateNumRule( const SvxNumRule* pRule ) throw() +{ + DBG_ASSERT( pRule, "No default SvxNumRule!" ); + if( pRule ) + { + return new SvxUnoNumberingRules( *pRule ); + } + else + { + SvxNumRule aDefaultRule( NUM_BULLET_REL_SIZE|NUM_BULLET_COLOR|NUM_CHAR_TEXT_DISTANCE, 10 , FALSE); + return new SvxUnoNumberingRules( aDefaultRule ); + } +} + + +/////////////////////////////////////////////////////////////////////// + +class SvxUnoNumberingRulesCompare : public ::cppu::WeakAggImplHelper1< XAnyCompare > +{ +public: + virtual sal_Int16 SAL_CALL compare( const Any& Any1, const Any& Any2 ) throw(RuntimeException); +}; + +sal_Int16 SAL_CALL SvxUnoNumberingRulesCompare::compare( const Any& Any1, const Any& Any2 ) throw(RuntimeException) +{ + return SvxUnoNumberingRules::Compare( Any1, Any2 ); +} + +sal_Int16 SvxUnoNumberingRules::Compare( const Any& Any1, const Any& Any2 ) +{ + Reference< XIndexReplace > x1( Any1, UNO_QUERY ), x2( Any2, UNO_QUERY ); + if( x1.is() && x2.is() ) + { + if( x1.get() == x2.get() ) + return 0; + + SvxUnoNumberingRules* pRule1 = SvxUnoNumberingRules::getImplementation( x1 ); + if( pRule1 ) + { + SvxUnoNumberingRules* pRule2 = SvxUnoNumberingRules::getImplementation( x2 ); + if( pRule2 ) + { + const SvxNumRule& rRule1 = pRule1->getNumRule(); + const SvxNumRule& rRule2 = pRule2->getNumRule(); + + const USHORT nLevelCount1 = rRule1.GetLevelCount(); + const USHORT nLevelCount2 = rRule2.GetLevelCount(); + + if( nLevelCount1 == 0 || nLevelCount2 == 0 ) + return -1; + + for( USHORT i = 0; (i < nLevelCount1) && (i < nLevelCount2); i++ ) + { + if( rRule1.GetLevel(i) != rRule2.GetLevel(i) ) + return -1; + } + return 0; + } + } + } + + return -1; +} + +Reference< XAnyCompare > SvxCreateNumRuleCompare() throw() +{ + return new SvxUnoNumberingRulesCompare(); +} + +::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexReplace > SvxCreateNumRule() throw() +{ + SvxNumRule aTempRule( 0, 10, false ); + return SvxCreateNumRule( &aTempRule ); +} diff --git a/editeng/source/uno/unopracc.cxx b/editeng/source/uno/unopracc.cxx new file mode 100644 index 000000000000..ea9d5f822ce5 --- /dev/null +++ b/editeng/source/uno/unopracc.cxx @@ -0,0 +1,174 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unopracc.cxx,v $ + * $Revision: 1.6 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +//------------------------------------------------------------------------ +// +// Global header +// +//------------------------------------------------------------------------ +#include <vos/mutex.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <cppuhelper/weakref.hxx> +#include <com/sun/star/lang/XComponent.hpp> +#include <cppuhelper/typeprovider.hxx> + + +//------------------------------------------------------------------------ +// +// Project-local header +// +//------------------------------------------------------------------------ + +#include <editeng/unopracc.hxx> +#include <editeng/unoedsrc.hxx> + +using namespace ::com::sun::star; + +//------------------------------------------------------------------------ +// +// SvxAccessibleTextPropertySet implementation +// +//------------------------------------------------------------------------ + +SvxAccessibleTextPropertySet::SvxAccessibleTextPropertySet( const SvxEditSource* pEditSrc, const SvxItemPropertySet* pPropSet ) + : SvxUnoTextRangeBase( pEditSrc, pPropSet ) +{ +} + +SvxAccessibleTextPropertySet::~SvxAccessibleTextPropertySet() throw() +{ +} + +uno::Reference< text::XText > SAL_CALL SvxAccessibleTextPropertySet::getText() throw (uno::RuntimeException) +{ + // TODO (empty?) + return uno::Reference< text::XText > (); +} + +uno::Any SAL_CALL SvxAccessibleTextPropertySet::queryAggregation( const uno::Type & ) throw(uno::RuntimeException) +{ + // TODO (empty?) + return uno::Any(); +} + +uno::Any SAL_CALL SvxAccessibleTextPropertySet::queryInterface( const uno::Type & rType ) + throw(uno::RuntimeException) +{ + return OWeakObject::queryInterface(rType); +} + +void SAL_CALL SvxAccessibleTextPropertySet::acquire() + throw() +{ + OWeakObject::acquire(); +} + +void SAL_CALL SvxAccessibleTextPropertySet::release() + throw() +{ + OWeakObject::release(); +} + +// XTypeProvider +uno::Sequence< uno::Type > SAL_CALL SvxAccessibleTextPropertySet::getTypes() throw ( uno::RuntimeException ) +{ + static ::cppu::OTypeCollection* pTypeCollection = NULL ; + + // double-checked locking pattern. + if ( pTypeCollection == NULL ) + { + osl::MutexGuard aGuard( osl::Mutex::getGlobalMutex() ) ; + + // Control these pointer again ... it can be, that another instance will be faster then these! + if ( pTypeCollection == NULL ) + { + // Create a static typecollection ... + static ::cppu::OTypeCollection aTypeCollection( + ::getCppuType( static_cast< const uno::Reference< beans::XPropertySet >* > (0) ), + ::getCppuType( static_cast< const uno::Reference< beans::XMultiPropertySet >* > (0) ), + ::getCppuType( static_cast< const uno::Reference< beans::XPropertyState >* > (0) ), + ::getCppuType( static_cast< const uno::Reference< lang::XServiceInfo >* > (0) ), + ::getCppuType( static_cast< const uno::Reference< lang::XTypeProvider >* > (0) ) ); + + // ... and set his address to static pointer! + pTypeCollection = &aTypeCollection ; + } + } + + return pTypeCollection->getTypes() ; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxAccessibleTextPropertySet::getImplementationId() + throw (uno::RuntimeException) +{ + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid( reinterpret_cast< sal_uInt8* > (aId.getArray()), 0, sal_True ); + } + return aId; +} + +// XServiceInfo +::rtl::OUString SAL_CALL SAL_CALL SvxAccessibleTextPropertySet::getImplementationName (void) throw (uno::RuntimeException) +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("SvxAccessibleTextPropertySet")); +} + +sal_Bool SAL_CALL SvxAccessibleTextPropertySet::supportsService (const ::rtl::OUString& sServiceName) throw (uno::RuntimeException) +{ + // Iterate over all supported service names and return true if on of them + // matches the given name. + uno::Sequence< ::rtl::OUString> aSupportedServices ( + getSupportedServiceNames ()); + for (int i=0; i<aSupportedServices.getLength(); i++) + if (sServiceName == aSupportedServices[i]) + return sal_True; + return sal_False; +} + +uno::Sequence< ::rtl::OUString> SAL_CALL SvxAccessibleTextPropertySet::getSupportedServiceNames (void) throw (uno::RuntimeException) +{ + // TODO + return SvxUnoTextRangeBase::getSupportedServiceNames(); +} + +// XServiceName +::rtl::OUString SAL_CALL SvxAccessibleTextPropertySet::getServiceName() throw (uno::RuntimeException) +{ + return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.beans.PropertyValue")); +} + + diff --git a/editeng/source/uno/unotext.cxx b/editeng/source/uno/unotext.cxx new file mode 100644 index 000000000000..82c51a440394 --- /dev/null +++ b/editeng/source/uno/unotext.cxx @@ -0,0 +1,2720 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unotext.cxx,v $ + * $Revision: 1.66 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <vcl/svapp.hxx> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/XTextField.hdl> +#include <vos/mutex.hxx> +#include <svl/itemset.hxx> +#include <svl/itempool.hxx> +#include <svl/intitem.hxx> +#include <svl/eitem.hxx> +#include <rtl/uuid.h> +#include <rtl/memory.h> + +#include <editeng/fontitem.hxx> +#include <editeng/tstpitem.hxx> +#include <editeng/unoprnms.hxx> +#include <editeng/unotext.hxx> +#include <editeng/unoedsrc.hxx> +#include <editeng/unonrule.hxx> +#include <editeng/unofdesc.hxx> +#include <editeng/unofield.hxx> +#include <editeng/flditem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/outliner.hxx> +#include <editeng/unoipset.hxx> +#include <comphelper/serviceinfohelper.hxx> + +using namespace ::rtl; +using namespace ::vos; +using namespace ::cppu; +using namespace ::com::sun::star; + +#define QUERYINT( xint ) \ + if( rType == ::getCppuType((const uno::Reference< xint >*)0) ) \ + return uno::makeAny(uno::Reference< xint >(this)) + +const SvxItemPropertySet* ImplGetSvxUnoOutlinerTextCursorSvxPropertySet() +{ + static SvxItemPropertySet aTextCursorSvxPropertySet( ImplGetSvxUnoOutlinerTextCursorPropertyMap(), EditEngine::GetGlobalItemPool() ); + return &aTextCursorSvxPropertySet; +} + +const SfxItemPropertyMapEntry* ImplGetSvxTextPortionPropertyMap() +{ + // Propertymap fuer einen Outliner Text + static const SfxItemPropertyMapEntry aSvxTextPortionPropertyMap[] = + { + SVX_UNOEDIT_CHAR_PROPERTIES, + SVX_UNOEDIT_FONT_PROPERTIES, + SVX_UNOEDIT_OUTLINER_PROPERTIES, + SVX_UNOEDIT_PARA_PROPERTIES, + {MAP_CHAR_LEN("TextField"), EE_FEATURE_FIELD, &::getCppuType((const uno::Reference< text::XTextField >*)0), beans::PropertyAttribute::READONLY, 0 }, + {MAP_CHAR_LEN("TextPortionType"), WID_PORTIONTYPE, &::getCppuType((const ::rtl::OUString*)0), beans::PropertyAttribute::READONLY, 0 }, + {MAP_CHAR_LEN("TextUserDefinedAttributes"), EE_CHAR_XMLATTRIBS, &::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >*)0) , 0, 0}, + {MAP_CHAR_LEN("ParaUserDefinedAttributes"), EE_PARA_XMLATTRIBS, &::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >*)0) , 0, 0}, + {0,0,0,0,0,0} + }; + return aSvxTextPortionPropertyMap; +} +const SvxItemPropertySet* ImplGetSvxTextPortionSvxPropertySet() +{ + static SvxItemPropertySet aSvxTextPortionPropertySet( ImplGetSvxTextPortionPropertyMap(), EditEngine::GetGlobalItemPool() ); + return &aSvxTextPortionPropertySet; +} + +const SfxItemPropertySet* ImplGetSvxTextPortionSfxPropertySet() +{ + static SfxItemPropertySet aSvxTextPortionSfxPropertySet( ImplGetSvxTextPortionPropertyMap() ); + return &aSvxTextPortionSfxPropertySet; +} + +const SfxItemPropertyMapEntry* ImplGetSvxUnoOutlinerTextCursorPropertyMap() +{ + // Propertymap fuer einen Outliner Text + static const SfxItemPropertyMapEntry aSvxUnoOutlinerTextCursorPropertyMap[] = + { + SVX_UNOEDIT_CHAR_PROPERTIES, + SVX_UNOEDIT_FONT_PROPERTIES, + SVX_UNOEDIT_OUTLINER_PROPERTIES, + SVX_UNOEDIT_PARA_PROPERTIES, + {MAP_CHAR_LEN("TextUserDefinedAttributes"), EE_CHAR_XMLATTRIBS, &::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >*)0) , 0, 0}, + {MAP_CHAR_LEN("ParaUserDefinedAttributes"), EE_PARA_XMLATTRIBS, &::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >*)0) , 0, 0}, + {0,0,0,0,0,0} + }; + + return aSvxUnoOutlinerTextCursorPropertyMap; +} +const SfxItemPropertySet* ImplGetSvxUnoOutlinerTextCursorSfxPropertySet() +{ + static SfxItemPropertySet aTextCursorSfxPropertySet( ImplGetSvxUnoOutlinerTextCursorPropertyMap() ); + return &aTextCursorSfxPropertySet; +} + +// ==================================================================== +// helper fuer Item/Property Konvertierung +// ==================================================================== + +void GetSelection( struct ESelection& rSel, SvxTextForwarder* pForwarder ) throw() +{ + DBG_ASSERT( pForwarder, "I need a valid SvxTextForwarder!" ); + if( pForwarder ) + { + sal_Int16 nParaCount = pForwarder->GetParagraphCount(); + if(nParaCount>0) + nParaCount--; + + rSel = ESelection( 0,0, nParaCount, pForwarder->GetTextLen( nParaCount )); + } +} + +void CheckSelection( struct ESelection& rSel, SvxTextForwarder* pForwarder ) throw() +{ + DBG_ASSERT( pForwarder, "I need a valid SvxTextForwarder!" ); + if( pForwarder ) + { + if( rSel.nStartPara == 0xffff ) + { + ::GetSelection( rSel, pForwarder ); + } + else + { + ESelection aMaxSelection; + GetSelection( aMaxSelection, pForwarder ); + + // check start position + if( rSel.nStartPara < aMaxSelection.nStartPara ) + { + rSel.nStartPara = aMaxSelection.nStartPara; + rSel.nStartPos = aMaxSelection.nStartPos; + } + else if( rSel.nStartPara > aMaxSelection.nEndPara ) + { + rSel.nStartPara = aMaxSelection.nEndPara; + rSel.nStartPos = aMaxSelection.nEndPos; + } + else if( rSel.nStartPos > pForwarder->GetTextLen( rSel.nStartPara ) ) + { + rSel.nStartPos = pForwarder->GetTextLen( rSel.nStartPara ); + } + + // check end position + if( rSel.nEndPara < aMaxSelection.nStartPara ) + { + rSel.nEndPara = aMaxSelection.nStartPara; + rSel.nEndPos = aMaxSelection.nStartPos; + } + else if( rSel.nEndPara > aMaxSelection.nEndPara ) + { + rSel.nEndPara = aMaxSelection.nEndPara; + rSel.nEndPos = aMaxSelection.nEndPos; + } + else if( rSel.nEndPos > pForwarder->GetTextLen( rSel.nEndPara ) ) + { + rSel.nEndPos = pForwarder->GetTextLen( rSel.nEndPara ); + } + } + } +} + +// ==================================================================== +// class SvxUnoTextRangeBase +// ==================================================================== + +#ifdef DEBUG +class check_me +{ +public: + check_me() : mnAllocNum(0) {}; + ~check_me(); + + void add( SvxUnoTextRangeBase* pRange ); + void remove( SvxUnoTextRangeBase* pRange ); + + std::list< std::pair< sal_uInt32, SvxUnoTextRangeBase* > > maRanges; + sal_uInt32 mnAllocNum; +}; + +void check_me::add( SvxUnoTextRangeBase* pRange ) +{ + maRanges.push_back( std::pair< sal_uInt32, SvxUnoTextRangeBase* >( mnAllocNum++, pRange ) ); +} + +void check_me::remove( SvxUnoTextRangeBase* pRange ) +{ + std::list< std::pair< sal_uInt32, SvxUnoTextRangeBase* > >::iterator aIter; + for( aIter = maRanges.begin(); aIter != maRanges.end(); aIter++ ) + { + if( pRange == (*aIter).second ) + { + maRanges.erase( aIter ); + break; + } + } +} + +check_me::~check_me() +{ + if( !maRanges.empty() ) + { + DBG_ERROR("living text range detected!"); + std::list< std::pair< sal_uInt32, SvxUnoTextRangeBase* > >::iterator aIter; + for( aIter = maRanges.begin(); aIter != maRanges.end(); aIter++ ) + { + sal_Int32 nAllocNum; + SvxUnoTextRangeBase* pRange; + nAllocNum = (*aIter).first; + pRange = (*aIter).second; + } + } +} + +static check_me gNumRanges; +#endif + +UNO3_GETIMPLEMENTATION_IMPL( SvxUnoTextRangeBase ); + +SvxUnoTextRangeBase::SvxUnoTextRangeBase( const SvxItemPropertySet* _pSet ) throw() +: mpEditSource(NULL) , mpPropSet(_pSet) +{ +#ifdef DEBUG + gNumRanges.add(this); +#endif +} + +SvxUnoTextRangeBase::SvxUnoTextRangeBase( const SvxEditSource* pSource, const SvxItemPropertySet* _pSet ) throw() +: mpPropSet(_pSet) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + DBG_ASSERT(pSource,"SvxUnoTextRangeBase: I need a valid SvxEditSource!"); + + mpEditSource = pSource->Clone(); + ESelection aSelection; + ::GetSelection( aSelection, mpEditSource->GetTextForwarder() ); + SetSelection( aSelection ); + + if( mpEditSource ) + mpEditSource->addRange( this ); +#ifdef DEBUG + gNumRanges.add(this); +#endif +} + +SvxUnoTextRangeBase::SvxUnoTextRangeBase( const SvxUnoTextRangeBase& rRange ) throw() +: text::XTextRange() +, beans::XPropertySet() +, beans::XMultiPropertySet() +, beans::XMultiPropertyStates() +, beans::XPropertyState() +, lang::XServiceInfo() +, text::XTextRangeCompare() +, lang::XUnoTunnel() +, mpPropSet(rRange.getPropertySet()) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + mpEditSource = rRange.mpEditSource ? rRange.mpEditSource->Clone() : NULL; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + maSelection = rRange.maSelection; + CheckSelection( maSelection, pForwarder ); + } + + if( mpEditSource ) + mpEditSource->addRange( this ); + +#ifdef DEBUG + gNumRanges.add(this); +#endif +} + +SvxUnoTextRangeBase::~SvxUnoTextRangeBase() throw() +{ +#ifdef DEBUG + gNumRanges.remove(this); +#endif + + if( mpEditSource ) + mpEditSource->removeRange( this ); + + delete mpEditSource; +} + +void SvxUnoTextRangeBase::SetEditSource( SvxEditSource* pSource ) throw() +{ + DBG_ASSERT(pSource,"SvxUnoTextRangeBase: I need a valid SvxEditSource!"); + DBG_ASSERT(mpEditSource==NULL,"SvxUnoTextRangeBase::SetEditSource called while SvxEditSource already set" ); + + mpEditSource = pSource; + + maSelection.nStartPara = 0xffff; + + if( mpEditSource ) + mpEditSource->addRange( this ); +} + +/** puts a field item with a copy of the given FieldData into the itemset + corresponding with this range */ +void SvxUnoTextRangeBase::attachField( const SvxFieldData* pData ) throw() +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( pData ) + { + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + SvxFieldItem aField( *pData, EE_FEATURE_FIELD ); + pForwarder->QuickInsertField( aField, maSelection ); + } + } +} + +void SvxUnoTextRangeBase::SetSelection( const ESelection& rSelection ) throw() +{ + OGuard aGuard( Application::GetSolarMutex() ); + + maSelection = rSelection; + CheckSelection( maSelection, mpEditSource->GetTextForwarder() ); +} + +// Interface XTextRange ( XText ) + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextRangeBase::getStart(void) + throw( uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + uno::Reference< text::XTextRange > xRange; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + + CheckSelection( maSelection, pForwarder ); + + SvxUnoTextBase* pText = SvxUnoTextBase::getImplementation( getText() ); + + if(pText == NULL) + throw uno::RuntimeException(); + + SvxUnoTextRange* pRange = new SvxUnoTextRange( *pText ); + xRange = pRange; + + ESelection aNewSel = maSelection; + aNewSel.nEndPara = aNewSel.nStartPara; + aNewSel.nEndPos = aNewSel.nStartPos; + pRange->SetSelection( aNewSel ); + } + + return xRange; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextRangeBase::getEnd(void) + throw( uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + uno::Reference< text::XTextRange > xRet; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + SvxUnoTextBase* pText = SvxUnoTextBase::getImplementation( getText() ); + + if(pText == NULL) + throw uno::RuntimeException(); + + SvxUnoTextRange* pNew = new SvxUnoTextRange( *pText ); + xRet = pNew; + + ESelection aNewSel = maSelection; + aNewSel.nStartPara = aNewSel.nEndPara; + aNewSel.nStartPos = aNewSel.nEndPos; + pNew->SetSelection( aNewSel ); + } + return xRet; +} + +OUString SAL_CALL SvxUnoTextRangeBase::getString(void) + throw( uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + return pForwarder->GetText( maSelection ); + } + else + { + const OUString aEmpty; + return aEmpty; + } +} + +void SAL_CALL SvxUnoTextRangeBase::setString(const OUString& aString) + throw( uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + String aConverted( aString ); + aConverted.ConvertLineEnd( LINEEND_LF ); // Zeilenenden nur einfach zaehlen + + pForwarder->QuickInsertText( aConverted, maSelection ); + mpEditSource->UpdateData(); + + // Selektion anpassen + //! Wenn die EditEngine bei QuickInsertText die Selektion zurueckgeben wuerde, + //! waer's einfacher... + CollapseToStart(); + + sal_uInt16 nLen = aConverted.Len(); + if (nLen) + GoRight( nLen, sal_True ); + } +} + +// Interface beans::XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL SvxUnoTextRangeBase::getPropertySetInfo(void) + throw( uno::RuntimeException ) +{ + return mpPropSet->getPropertySetInfo(); +} + +void SAL_CALL SvxUnoTextRangeBase::setPropertyValue(const OUString& PropertyName, const uno::Any& aValue) + throw( beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException ) +{ + _setPropertyValue( PropertyName, aValue, -1 ); +} + +void SAL_CALL SvxUnoTextRangeBase::_setPropertyValue( const OUString& PropertyName, const uno::Any& aValue, sal_Int32 nPara ) + throw( beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + + CheckSelection( maSelection, pForwarder ); + + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName ); + if ( pMap ) + { + ESelection aSel( GetSelection() ); + sal_Bool bParaAttrib = (pMap->nWID >= EE_PARA_START) && ( pMap->nWID <= EE_PARA_END ); + + if( nPara == -1 && !bParaAttrib ) + { + SfxItemSet aOldSet( pForwarder->GetAttribs( aSel ) ); + // we have a selection and no para attribute + SfxItemSet aNewSet( *aOldSet.GetPool(), aOldSet.GetRanges() ); + + setPropertyValue( pMap, aValue, maSelection, aOldSet, aNewSet ); + + + pForwarder->QuickSetAttribs( aNewSet, GetSelection() ); + } + else + { + sal_Int32 nEndPara; + + if( nPara == -1 ) + { + nPara = aSel.nStartPara; + nEndPara = aSel.nEndPara; + } + else + { + // only one paragraph + nEndPara = nPara; + } + + while( nPara <= nEndPara ) + { + // we have a paragraph + SfxItemSet aSet( pForwarder->GetParaAttribs( (USHORT)nPara ) ); + setPropertyValue( pMap, aValue, maSelection, aSet, aSet ); + pForwarder->SetParaAttribs( (USHORT)nPara, aSet ); + nPara++; + } + } + + GetEditSource()->UpdateData(); + return; + } + } + + throw beans::UnknownPropertyException(); +} + +void SvxUnoTextRangeBase::setPropertyValue( const SfxItemPropertySimpleEntry* pMap, const uno::Any& rValue, const ESelection& rSelection, const SfxItemSet& rOldSet, SfxItemSet& rNewSet ) throw( beans::UnknownPropertyException, lang::IllegalArgumentException ) +{ + if(!SetPropertyValueHelper( rOldSet, pMap, rValue, rNewSet, &rSelection, GetEditSource() )) + { + // Fuer Teile von zusammengesetzten Items mit mehreren Properties (z.B. Hintergrund) + // muss vorher das alte Item aus dem Dokument geholt werden + rNewSet.Put(rOldSet.Get(pMap->nWID)); // altes Item in neuen Set + mpPropSet->setPropertyValue(pMap, rValue, rNewSet, false ); + } +} + +sal_Bool SvxUnoTextRangeBase::SetPropertyValueHelper( const SfxItemSet&, const SfxItemPropertySimpleEntry* pMap, const uno::Any& aValue, SfxItemSet& rNewSet, const ESelection* pSelection /* = NULL */, SvxEditSource* pEditSource /* = NULL*/ ) throw( uno::RuntimeException ) +{ + switch( pMap->nWID ) + { + case WID_FONTDESC: + { + awt::FontDescriptor aDesc; + if(aValue >>= aDesc) + { + SvxUnoFontDescriptor::FillItemSet( aDesc, rNewSet ); + return sal_True; + } + } + break; + + case EE_PARA_NUMBULLET: + { + uno::Reference< container::XIndexReplace > xRule; + if( !aValue.hasValue() || ((aValue >>= xRule) && !xRule.is()) ) + return sal_True; + + return sal_False; + } + + case WID_NUMLEVEL: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : NULL; + if(pForwarder && pSelection) + { + sal_Int16 nLevel = sal_Int16(); + if( aValue >>= nLevel ) + { + // #101004# Call interface method instead of unsafe cast + if(! pForwarder->SetDepth( pSelection->nStartPara, nLevel ) ) + throw lang::IllegalArgumentException(); + + return sal_True; + } + } + } + break; + case WID_NUMBERINGSTARTVALUE: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : NULL; + if(pForwarder && pSelection) + { + sal_Int16 nStartValue = -1; + if( aValue >>= nStartValue ) + { + pForwarder->SetNumberingStartValue( pSelection->nStartPara, nStartValue ); + return sal_True; + } + } + } + break; + case WID_PARAISNUMBERINGRESTART: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : NULL; + if(pForwarder && pSelection) + { + sal_Bool bParaIsNumberingRestart = sal_False; + if( aValue >>= bParaIsNumberingRestart ) + { + pForwarder->SetParaIsNumberingRestart( pSelection->nStartPara, bParaIsNumberingRestart ); + return sal_True; + } + } + } + break; + case EE_PARA_BULLETSTATE: + { + sal_Bool bBullet = sal_True; + if( aValue >>= bBullet ) + { + SfxBoolItem aItem( EE_PARA_BULLETSTATE, bBullet ); + rNewSet.Put(aItem); + return sal_True; + } + } + break; + + default: + return sal_False; + } + + throw lang::IllegalArgumentException(); +} + +uno::Any SAL_CALL SvxUnoTextRangeBase::getPropertyValue(const OUString& PropertyName) + throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException ) +{ + return _getPropertyValue( PropertyName, -1 ); +} + +uno::Any SAL_CALL SvxUnoTextRangeBase::_getPropertyValue(const OUString& PropertyName, sal_Int32 nPara ) + throw( beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + uno::Any aAny; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName ); + if( pMap ) + { + SfxItemSet* pAttribs = NULL; + if( nPara != -1 ) + pAttribs = pForwarder->GetParaAttribs( (USHORT)nPara ).Clone(); + else + pAttribs = pForwarder->GetAttribs( GetSelection() ).Clone(); + + // Dontcare durch Default ersetzen, damit man immer eine Reflection hat + pAttribs->ClearInvalidItems(); + + getPropertyValue( pMap, aAny, *pAttribs ); + + delete pAttribs; + return aAny; + } + } + + throw beans::UnknownPropertyException(); +} + +void SvxUnoTextRangeBase::getPropertyValue( const SfxItemPropertySimpleEntry* pMap, uno::Any& rAny, const SfxItemSet& rSet ) throw( beans::UnknownPropertyException ) +{ + switch( pMap->nWID ) + { + case EE_FEATURE_FIELD: + if ( rSet.GetItemState( EE_FEATURE_FIELD, sal_False ) == SFX_ITEM_SET ) + { + SvxFieldItem* pItem = (SvxFieldItem*)rSet.GetItem( EE_FEATURE_FIELD ); + const SvxFieldData* pData = pItem->GetField(); + uno::Reference< text::XTextRange > xAnchor( this ); + + // get presentation string for field + Color* pTColor = NULL; + Color* pFColor = NULL; + + SvxTextForwarder* pForwarder = mpEditSource->GetTextForwarder(); + OUString aPresentation( pForwarder->CalcFieldValue( SvxFieldItem(*pData, EE_FEATURE_FIELD), maSelection.nStartPara, maSelection.nStartPos, pTColor, pFColor ) ); + + delete pTColor; + delete pFColor; + + uno::Reference< text::XTextField > xField( new SvxUnoTextField( xAnchor, aPresentation, pData ) ); + rAny <<= xField; + } + break; + + case WID_PORTIONTYPE: + if ( rSet.GetItemState( EE_FEATURE_FIELD, sal_False ) == SFX_ITEM_SET ) + { + OUString aType( RTL_CONSTASCII_USTRINGPARAM("TextField") ); + rAny <<= aType; + } + else + { + OUString aType( RTL_CONSTASCII_USTRINGPARAM("Text") ); + rAny <<= aType; + } + break; + + default: + if(!GetPropertyValueHelper( *((SfxItemSet*)(&rSet)), pMap, rAny, &maSelection, GetEditSource() )) + rAny = mpPropSet->getPropertyValue(pMap, rSet, true, false ); + } +} + +sal_Bool SvxUnoTextRangeBase::GetPropertyValueHelper( SfxItemSet& rSet, const SfxItemPropertySimpleEntry* pMap, uno::Any& aAny, const ESelection* pSelection /* = NULL */, SvxEditSource* pEditSource /* = NULL */ ) + throw( uno::RuntimeException ) +{ + switch( pMap->nWID ) + { + case WID_FONTDESC: + { + awt::FontDescriptor aDesc; + SvxUnoFontDescriptor::FillFromItemSet( rSet, aDesc ); + aAny <<= aDesc; + } + break; + + case EE_PARA_NUMBULLET: + { + if((rSet.GetItemState( EE_PARA_NUMBULLET, sal_True ) & (SFX_ITEM_SET|SFX_ITEM_DEFAULT)) == 0) + throw uno::RuntimeException(); + + SvxNumBulletItem* pBulletItem = (SvxNumBulletItem*)rSet.GetItem( EE_PARA_NUMBULLET, sal_True ); + + if( pBulletItem == NULL ) + throw uno::RuntimeException(); + + aAny <<= SvxCreateNumRule( pBulletItem->GetNumRule() ); + } + break; + + case WID_NUMLEVEL: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : NULL; + if(pForwarder && pSelection) + { + sal_Int16 nLevel = pForwarder->GetDepth( pSelection->nStartPara ); + if( nLevel >= 0 ) + aAny <<= nLevel; + } + } + break; + case WID_NUMBERINGSTARTVALUE: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : NULL; + if(pForwarder && pSelection) + aAny <<= pForwarder->GetNumberingStartValue( pSelection->nStartPara ); + } + break; + case WID_PARAISNUMBERINGRESTART: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : NULL; + if(pForwarder && pSelection) + aAny <<= pForwarder->IsParaIsNumberingRestart( pSelection->nStartPara ); + } + break; + + case EE_PARA_BULLETSTATE: + { + sal_Bool bState = sal_False; + if( rSet.GetItemState( EE_PARA_BULLETSTATE, sal_True ) & (SFX_ITEM_SET|SFX_ITEM_DEFAULT)) + { + SfxBoolItem* pItem = (SfxBoolItem*)rSet.GetItem( EE_PARA_BULLETSTATE, sal_True ); + bState = pItem->GetValue() ? sal_True : sal_False; + } + + aAny <<= bState; + } + break; + default: + + return sal_False; + } + + return sal_True; +} + +// wird (noch) nicht unterstuetzt +void SAL_CALL SvxUnoTextRangeBase::addPropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) throw(beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) {} +void SAL_CALL SvxUnoTextRangeBase::removePropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) throw(beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) {} +void SAL_CALL SvxUnoTextRangeBase::addVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) throw(beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) {} +void SAL_CALL SvxUnoTextRangeBase::removeVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) throw(beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) {} + +// XMultiPropertySet +void SAL_CALL SvxUnoTextRangeBase::setPropertyValues( const uno::Sequence< ::rtl::OUString >& aPropertyNames, const uno::Sequence< uno::Any >& aValues ) throw (beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + _setPropertyValues( aPropertyNames, aValues, -1 ); +} + +void SAL_CALL SvxUnoTextRangeBase::_setPropertyValues( const uno::Sequence< ::rtl::OUString >& aPropertyNames, const uno::Sequence< uno::Any >& aValues, sal_Int32 nPara ) throw (beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + ESelection aSel( GetSelection() ); + + const OUString* pPropertyNames = aPropertyNames.getConstArray(); + const uno::Any* pValues = aValues.getConstArray(); + sal_Int32 nCount = aPropertyNames.getLength(); + + sal_Int32 nEndPara = nPara; + sal_Int32 nTempPara = nPara; + + if( nTempPara == -1 ) + { + nTempPara = aSel.nStartPara; + nEndPara = aSel.nEndPara; + } + + SfxItemSet* pOldAttrSet = NULL; + SfxItemSet* pNewAttrSet = NULL; + + SfxItemSet* pOldParaSet = NULL; + SfxItemSet* pNewParaSet = NULL; + + for( ; nCount; nCount--, pPropertyNames++, pValues++ ) + { + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry( *pPropertyNames ); + + if( pMap ) + { + sal_Bool bParaAttrib = (pMap->nWID >= EE_PARA_START) && ( pMap->nWID <= EE_PARA_END ); + + if( (nPara == -1) && !bParaAttrib ) + { + if( NULL == pNewAttrSet ) + { + const SfxItemSet aSet( pForwarder->GetAttribs( aSel ) ); + pOldAttrSet = new SfxItemSet( aSet ); + pNewAttrSet = new SfxItemSet( *pOldAttrSet->GetPool(), pOldAttrSet->GetRanges() ); + } + + setPropertyValue( pMap, *pValues, GetSelection(), *pOldAttrSet, *pNewAttrSet ); + + if( pMap->nWID >= EE_ITEMS_START && pMap->nWID <= EE_ITEMS_END ) + { + const SfxPoolItem* pItem; + if( pNewAttrSet->GetItemState( pMap->nWID, sal_True, &pItem ) == SFX_ITEM_SET ) + { + pOldAttrSet->Put( *pItem ); + } + } + } + else + { + if( NULL == pNewParaSet ) + { + const SfxItemSet aSet( pForwarder->GetParaAttribs( (USHORT)nTempPara ) ); + pOldParaSet = new SfxItemSet( aSet ); + pNewParaSet = new SfxItemSet( *pOldParaSet->GetPool(), pOldParaSet->GetRanges() ); + } + + setPropertyValue( pMap, *pValues, GetSelection(), *pOldParaSet, *pNewParaSet ); + + if( pMap->nWID >= EE_ITEMS_START && pMap->nWID <= EE_ITEMS_END ) + { + const SfxPoolItem* pItem; + if( pNewParaSet->GetItemState( pMap->nWID, sal_True, &pItem ) == SFX_ITEM_SET ) + { + pOldParaSet->Put( *pItem ); + } + } + + } + } + } + + sal_Bool bNeedsUpdate = sal_False; + + if( pNewParaSet ) + { + if( pNewParaSet->Count() ) + { + while( nTempPara <= nEndPara ) + { + SfxItemSet aSet( pForwarder->GetParaAttribs( (USHORT)nTempPara ) ); + aSet.Put( *pNewParaSet ); + pForwarder->SetParaAttribs( (USHORT)nTempPara, aSet ); + nTempPara++; + } + bNeedsUpdate = sal_True; + } + + delete pNewParaSet; + delete pOldParaSet; + } + + if( pNewAttrSet ) + { + if( pNewAttrSet->Count() ) + { + pForwarder->QuickSetAttribs( *pNewAttrSet, GetSelection() ); + bNeedsUpdate = sal_True; + } + delete pNewAttrSet; + delete pOldAttrSet; + + } + + if( bNeedsUpdate ) + GetEditSource()->UpdateData(); + } +} + +uno::Sequence< uno::Any > SAL_CALL SvxUnoTextRangeBase::getPropertyValues( const uno::Sequence< ::rtl::OUString >& aPropertyNames ) throw (uno::RuntimeException) +{ + return _getPropertyValues( aPropertyNames, -1 ); +} + +uno::Sequence< uno::Any > SAL_CALL SvxUnoTextRangeBase::_getPropertyValues( const uno::Sequence< ::rtl::OUString >& aPropertyNames, sal_Int32 nPara ) throw (uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + sal_Int32 nCount = aPropertyNames.getLength(); + + + uno::Sequence< uno::Any > aValues( nCount ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + SfxItemSet* pAttribs = NULL; + if( nPara != -1 ) + pAttribs = pForwarder->GetParaAttribs( (USHORT)nPara ).Clone(); + else + pAttribs = pForwarder->GetAttribs( GetSelection() ).Clone(); + + pAttribs->ClearInvalidItems(); + + const OUString* pPropertyNames = aPropertyNames.getConstArray(); + uno::Any* pValues = aValues.getArray(); + + for( ; nCount; nCount--, pPropertyNames++, pValues++ ) + { + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry( *pPropertyNames ); + if( pMap ) + { + getPropertyValue( pMap, *pValues, *pAttribs ); + } + } + + delete pAttribs; + + } + + return aValues; +} + +void SAL_CALL SvxUnoTextRangeBase::addPropertiesChangeListener( const uno::Sequence< ::rtl::OUString >& , const uno::Reference< beans::XPropertiesChangeListener >& ) throw (uno::RuntimeException) +{ +} + +void SAL_CALL SvxUnoTextRangeBase::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& ) throw (uno::RuntimeException) +{ +} + +void SAL_CALL SvxUnoTextRangeBase::firePropertiesChangeEvent( const uno::Sequence< ::rtl::OUString >& , const uno::Reference< beans::XPropertiesChangeListener >& ) throw (uno::RuntimeException) +{ +} + +// beans::XPropertyState +beans::PropertyState SAL_CALL SvxUnoTextRangeBase::getPropertyState( const OUString& PropertyName ) + throw(beans::UnknownPropertyException, uno::RuntimeException) +{ + return _getPropertyState( PropertyName, -1 ); +} + +static sal_uInt16 aSvxUnoFontDescriptorWhichMap[] = { EE_CHAR_FONTINFO, EE_CHAR_FONTHEIGHT, EE_CHAR_ITALIC, + EE_CHAR_UNDERLINE, EE_CHAR_WEIGHT, EE_CHAR_STRIKEOUT, + EE_CHAR_WLM, 0 }; + +beans::PropertyState SAL_CALL SvxUnoTextRangeBase::_getPropertyState(const SfxItemPropertySimpleEntry* pMap, sal_Int32 nPara) + throw( beans::UnknownPropertyException, uno::RuntimeException ) +{ + if ( pMap ) + { + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + SfxItemState eItemState = SFX_ITEM_UNKNOWN; + sal_uInt16 nWID = 0; + + switch( pMap->nWID ) + { + case WID_FONTDESC: + { + sal_uInt16* pWhichId = aSvxUnoFontDescriptorWhichMap; + SfxItemState eTempItemState; + while( *pWhichId ) + { + if(nPara != -1) + eTempItemState = pForwarder->GetItemState( (USHORT)nPara, *pWhichId ); + else + eTempItemState = pForwarder->GetItemState( GetSelection(), *pWhichId ); + + switch( eTempItemState ) + { + case SFX_ITEM_DISABLED: + case SFX_ITEM_DONTCARE: + eItemState = SFX_ITEM_DONTCARE; + break; + + case SFX_ITEM_DEFAULT: + if( eItemState != SFX_ITEM_DEFAULT ) + { + if( eItemState == SFX_ITEM_UNKNOWN ) + eItemState = SFX_ITEM_DEFAULT; + } + break; + + case SFX_ITEM_READONLY: + case SFX_ITEM_SET: + if( eItemState != SFX_ITEM_SET ) + { + if( eItemState == SFX_ITEM_UNKNOWN ) + eItemState = SFX_ITEM_SET; + } + break; + default: + throw beans::UnknownPropertyException(); + } + + pWhichId++; + } + } + break; + + case WID_NUMLEVEL: + case WID_NUMBERINGSTARTVALUE: + case WID_PARAISNUMBERINGRESTART: + eItemState = SFX_ITEM_SET; + break; + + default: + nWID = pMap->nWID; + } + + if( nWID != 0 ) + { + if( nPara != -1 ) + eItemState = pForwarder->GetItemState( (USHORT)nPara, nWID ); + else + eItemState = pForwarder->GetItemState( GetSelection(), nWID ); + } + + switch( eItemState ) + { + case SFX_ITEM_DONTCARE: + case SFX_ITEM_DISABLED: + return beans::PropertyState_AMBIGUOUS_VALUE; + case SFX_ITEM_READONLY: + case SFX_ITEM_SET: + return beans::PropertyState_DIRECT_VALUE; + case SFX_ITEM_DEFAULT: + return beans::PropertyState_DEFAULT_VALUE; +// case SFX_ITEM_UNKNOWN: + } + } + } + throw beans::UnknownPropertyException(); +} + +beans::PropertyState SAL_CALL SvxUnoTextRangeBase::_getPropertyState(const OUString& PropertyName, sal_Int32 nPara /* = -1 */) + throw( beans::UnknownPropertyException, uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + return _getPropertyState( mpPropSet->getPropertyMapEntry( PropertyName ), nPara); +} + +uno::Sequence< beans::PropertyState > SAL_CALL SvxUnoTextRangeBase::getPropertyStates( const uno::Sequence< OUString >& aPropertyName ) + throw(beans::UnknownPropertyException, uno::RuntimeException) +{ + return _getPropertyStates( aPropertyName, -1 ); +} + +uno::Sequence< beans::PropertyState > SvxUnoTextRangeBase::_getPropertyStates(const uno::Sequence< OUString >& PropertyName, sal_Int32 nPara /* = -1 */) + throw( beans::UnknownPropertyException, uno::RuntimeException ) +{ + const sal_Int32 nCount = PropertyName.getLength(); + const OUString* pNames = PropertyName.getConstArray(); + + uno::Sequence< beans::PropertyState > aRet( nCount ); + beans::PropertyState* pState = aRet.getArray(); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + SfxItemSet* pSet = NULL; + if( nPara != -1 ) + { + pSet = new SfxItemSet( pForwarder->GetParaAttribs( (USHORT)nPara ) ); + } + else + { + ESelection aSel( GetSelection() ); + CheckSelection( aSel, pForwarder ); + pSet = new SfxItemSet( pForwarder->GetAttribs( aSel, EditEngineAttribs_OnlyHard ) ); + } + + sal_Bool bUnknownPropertyFound = sal_False; + for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++ ) + { + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry( *pNames++ ); + if( NULL == pMap ) + { + bUnknownPropertyFound = sal_True; + break; + } + bUnknownPropertyFound = !_getOnePropertyStates(pSet, pMap, *pState++); + } + + delete pSet; + + if( bUnknownPropertyFound ) + throw beans::UnknownPropertyException(); + } + + return aRet; +} + +sal_Bool SvxUnoTextRangeBase::_getOnePropertyStates(const SfxItemSet* pSet, const SfxItemPropertySimpleEntry* pMap, beans::PropertyState& rState) +{ + sal_Bool bUnknownPropertyFound = sal_False; + if(pSet && pMap) + { + SfxItemState eItemState = SFX_ITEM_UNKNOWN; + sal_uInt16 nWID = 0; + + switch( pMap->nWID ) + { + case WID_FONTDESC: + { + sal_uInt16* pWhichId = aSvxUnoFontDescriptorWhichMap; + SfxItemState eTempItemState; + while( *pWhichId ) + { + eTempItemState = pSet->GetItemState( *pWhichId ); + + switch( eTempItemState ) + { + case SFX_ITEM_DISABLED: + case SFX_ITEM_DONTCARE: + eItemState = SFX_ITEM_DONTCARE; + break; + + case SFX_ITEM_DEFAULT: + if( eItemState != SFX_ITEM_DEFAULT ) + { + if( eItemState == SFX_ITEM_UNKNOWN ) + eItemState = SFX_ITEM_DEFAULT; + } + break; + + case SFX_ITEM_READONLY: + case SFX_ITEM_SET: + if( eItemState != SFX_ITEM_SET ) + { + if( eItemState == SFX_ITEM_UNKNOWN ) + eItemState = SFX_ITEM_SET; + } + break; + default: + bUnknownPropertyFound = sal_True; + break; + } + + pWhichId++; + } + } + break; + + case WID_NUMLEVEL: + case WID_NUMBERINGSTARTVALUE: + case WID_PARAISNUMBERINGRESTART: + eItemState = SFX_ITEM_SET; + break; + + default: + nWID = pMap->nWID; + } + + if( bUnknownPropertyFound ) + return !bUnknownPropertyFound; + + if( nWID != 0 ) + eItemState = pSet->GetItemState( nWID, sal_False ); + + switch( eItemState ) + { + case SFX_ITEM_READONLY: + case SFX_ITEM_SET: + rState = beans::PropertyState_DIRECT_VALUE; + break; + case SFX_ITEM_DEFAULT: + rState = beans::PropertyState_DEFAULT_VALUE; + break; +// case SFX_ITEM_UNKNOWN: +// case SFX_ITEM_DONTCARE: +// case SFX_ITEM_DISABLED: + default: + rState = beans::PropertyState_AMBIGUOUS_VALUE; + } + } + return !bUnknownPropertyFound; +} + +void SAL_CALL SvxUnoTextRangeBase::setPropertyToDefault( const OUString& PropertyName ) + throw(beans::UnknownPropertyException, uno::RuntimeException) +{ + _setPropertyToDefault( PropertyName, -1 ); +} + +void SvxUnoTextRangeBase::_setPropertyToDefault(const OUString& PropertyName, sal_Int32 nPara /* = -1 */) + throw( beans::UnknownPropertyException, uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + + if( pForwarder ) + { + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry( PropertyName ); + if ( pMap ) + { + CheckSelection( maSelection, mpEditSource->GetTextForwarder() ); + _setPropertyToDefault( pForwarder, pMap, nPara ); + return; + } + } + + throw beans::UnknownPropertyException(); +} + +void SvxUnoTextRangeBase::_setPropertyToDefault(SvxTextForwarder* pForwarder, const SfxItemPropertySimpleEntry* pMap, sal_Int32 nPara ) + throw( beans::UnknownPropertyException, uno::RuntimeException ) +{ + do + { + SfxItemSet aSet( *pForwarder->GetPool(), TRUE ); + + if( pMap->nWID == WID_FONTDESC ) + { + SvxUnoFontDescriptor::setPropertyToDefault( aSet ); + } + else if( pMap->nWID == WID_NUMLEVEL ) + { + // #101004# Call interface method instead of unsafe cast + pForwarder->SetDepth( maSelection.nStartPara, -1 ); + return; + } + else if( pMap->nWID == WID_NUMBERINGSTARTVALUE ) + { + pForwarder->SetNumberingStartValue( maSelection.nStartPara, -1 ); + } + else if( pMap->nWID == WID_PARAISNUMBERINGRESTART ) + { + pForwarder->SetParaIsNumberingRestart( maSelection.nStartPara, sal_False ); + } + else + { + aSet.InvalidateItem( pMap->nWID ); + } + + if(nPara != -1) + pForwarder->SetParaAttribs( (USHORT)nPara, aSet ); + else + pForwarder->QuickSetAttribs( aSet, GetSelection() ); + + GetEditSource()->UpdateData(); + + return; + } + while(0); +} + +uno::Any SAL_CALL SvxUnoTextRangeBase::getPropertyDefault( const OUString& aPropertyName ) + throw(beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry( aPropertyName ); + if( pMap ) + { + SfxItemPool* pPool = pForwarder->GetPool(); + + switch( pMap->nWID ) + { + case WID_FONTDESC: + return SvxUnoFontDescriptor::getPropertyDefault( pPool ); + + case WID_NUMLEVEL: + { + uno::Any aAny; + return aAny; + } + + case WID_NUMBERINGSTARTVALUE: + return uno::Any( (sal_Int16)-1 ); + + case WID_PARAISNUMBERINGRESTART: + return uno::Any( (sal_Bool)sal_False ); + + default: + { + // Default aus ItemPool holen + if(pPool->IsWhich(pMap->nWID)) + { + SfxItemSet aSet( *pPool, pMap->nWID, pMap->nWID); + aSet.Put(pPool->GetDefaultItem(pMap->nWID)); + return mpPropSet->getPropertyValue(pMap, aSet, true, false ); + } + } + } + } + } + throw beans::UnknownPropertyException(); +} + +// beans::XMultiPropertyStates +void SAL_CALL SvxUnoTextRangeBase::setAllPropertiesToDefault( ) throw (uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + + if( pForwarder ) + { + PropertyEntryVector_t aEntries = mpPropSet->getPropertyMap()->getPropertyEntries(); + PropertyEntryVector_t::const_iterator aIt = aEntries.begin(); + while( aIt != aEntries.end() ) + { + _setPropertyToDefault( pForwarder, &(*aIt), -1 ); + ++aIt; + } + } +} + +void SAL_CALL SvxUnoTextRangeBase::setPropertiesToDefault( const uno::Sequence< OUString >& aPropertyNames ) throw (beans::UnknownPropertyException, uno::RuntimeException) +{ + sal_Int32 nCount = aPropertyNames.getLength(); + for( const OUString* pName = aPropertyNames.getConstArray(); nCount; pName++, nCount-- ) + { + setPropertyToDefault( *pName ); + } +} + +uno::Sequence< uno::Any > SAL_CALL SvxUnoTextRangeBase::getPropertyDefaults( const uno::Sequence< OUString >& aPropertyNames ) throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + sal_Int32 nCount = aPropertyNames.getLength(); + uno::Sequence< uno::Any > ret( nCount ); + uno::Any* pDefaults = ret.getArray(); + + for( const OUString* pName = aPropertyNames.getConstArray(); nCount; pName++, nCount--, pDefaults++ ) + { + *pDefaults = getPropertyDefault( *pName ); + } + + return ret; +} + +// internal +void SvxUnoTextRangeBase::CollapseToStart(void) throw() +{ + CheckSelection( maSelection, mpEditSource->GetTextForwarder() ); + + maSelection.nEndPara = maSelection.nStartPara; + maSelection.nEndPos = maSelection.nStartPos; +} + +void SvxUnoTextRangeBase::CollapseToEnd(void) throw() +{ + CheckSelection( maSelection, mpEditSource->GetTextForwarder() ); + + maSelection.nStartPara = maSelection.nEndPara; + maSelection.nStartPos = maSelection.nEndPos; +} + +sal_Bool SvxUnoTextRangeBase::IsCollapsed(void) throw() +{ + CheckSelection( maSelection, mpEditSource->GetTextForwarder() ); + + return ( maSelection.nStartPara == maSelection.nEndPara && + maSelection.nStartPos == maSelection.nEndPos ); +} + +sal_Bool SvxUnoTextRangeBase::GoLeft(sal_Int16 nCount, sal_Bool Expand) throw() +{ + CheckSelection( maSelection, mpEditSource->GetTextForwarder() ); + + // #75098# use end position, as in Writer (start is anchor, end is cursor) + sal_uInt16 nNewPos = maSelection.nEndPos; + sal_uInt16 nNewPar = maSelection.nEndPara; + + sal_Bool bOk = sal_True; + SvxTextForwarder* pForwarder = NULL; + while ( nCount > nNewPos && bOk ) + { + if ( nNewPar == 0 ) + bOk = sal_False; + else + { + if ( !pForwarder ) + pForwarder = mpEditSource->GetTextForwarder(); // erst hier, wenn's noetig ist... + + --nNewPar; + nCount -= nNewPos + 1; + nNewPos = pForwarder->GetTextLen( nNewPar ); + } + } + + if ( bOk ) + { + nNewPos = nNewPos - nCount; + maSelection.nStartPara = nNewPar; + maSelection.nStartPos = nNewPos; + } + + if (!Expand) + CollapseToStart(); + + return bOk; +} + +sal_Bool SvxUnoTextRangeBase::GoRight(sal_Int16 nCount, sal_Bool Expand) throw() +{ + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + + sal_uInt16 nNewPos = maSelection.nEndPos + nCount; //! Ueberlauf ??? + sal_uInt16 nNewPar = maSelection.nEndPara; + + sal_Bool bOk = sal_True; + sal_uInt16 nParCount = pForwarder->GetParagraphCount(); + sal_uInt16 nThisLen = pForwarder->GetTextLen( nNewPar ); + while ( nNewPos > nThisLen && bOk ) + { + if ( nNewPar + 1 >= nParCount ) + bOk = sal_False; + else + { + nNewPos -= nThisLen+1; + ++nNewPar; + nThisLen = pForwarder->GetTextLen( nNewPar ); + } + } + + if (bOk) + { + maSelection.nEndPara = nNewPar; + maSelection.nEndPos = nNewPos; + } + + if (!Expand) + CollapseToEnd(); + + return bOk; + } + return sal_False; +} + +void SvxUnoTextRangeBase::GotoStart(sal_Bool Expand) throw() +{ + maSelection.nStartPara = 0; + maSelection.nStartPos = 0; + + if (!Expand) + CollapseToStart(); +} + +void SvxUnoTextRangeBase::GotoEnd(sal_Bool Expand) throw() +{ + CheckSelection( maSelection, mpEditSource->GetTextForwarder() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : NULL; + if( pForwarder ) + { + + sal_uInt16 nPar = pForwarder->GetParagraphCount(); + if (nPar) + --nPar; + + maSelection.nEndPara = nPar; + maSelection.nEndPos = pForwarder->GetTextLen( nPar ); + + if (!Expand) + CollapseToEnd(); + } +} + +// lang::XServiceInfo +sal_Bool SAL_CALL SvxUnoTextRangeBase::supportsService( const OUString& ServiceName ) + throw(uno::RuntimeException) +{ + return comphelper::ServiceInfoHelper::supportsService( ServiceName, getSupportedServiceNames() ); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextRangeBase::getSupportedServiceNames() + throw(uno::RuntimeException) +{ + return getSupportedServiceNames_Static(); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextRangeBase::getSupportedServiceNames_Static() + SAL_THROW(()) +{ + uno::Sequence< OUString > aSeq; + comphelper::ServiceInfoHelper::addToSequence( aSeq, 3, "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.CharacterPropertiesAsian"); + return aSeq; +} + +// XTextRangeCompare +sal_Int16 SAL_CALL SvxUnoTextRangeBase::compareRegionStarts( const uno::Reference< text::XTextRange >& xR1, const uno::Reference< text::XTextRange >& xR2 ) throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + SvxUnoTextRangeBase* pR1 = SvxUnoTextRangeBase::getImplementation( xR1 ); + SvxUnoTextRangeBase* pR2 = SvxUnoTextRangeBase::getImplementation( xR2 ); + + if( (pR1 == 0) || (pR2 == 0) ) + throw lang::IllegalArgumentException(); + + const ESelection& r1 = pR1->maSelection; + const ESelection& r2 = pR2->maSelection; + + if( r1.nStartPara == r2.nStartPara ) + { + if( r1.nStartPos == r2.nStartPos ) + return 0; + else + return r1.nStartPos < r2.nStartPos ? 1 : -1; + } + else + { + return r1.nStartPara < r2.nStartPara ? 1 : -1; + } +} + +sal_Int16 SAL_CALL SvxUnoTextRangeBase::compareRegionEnds( const uno::Reference< text::XTextRange >& xR1, const uno::Reference< text::XTextRange >& xR2 ) throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + SvxUnoTextRangeBase* pR1 = SvxUnoTextRangeBase::getImplementation( xR1 ); + SvxUnoTextRangeBase* pR2 = SvxUnoTextRangeBase::getImplementation( xR2 ); + + if( (pR1 == 0) || (pR2 == 0) ) + throw lang::IllegalArgumentException(); + + const ESelection& r1 = pR1->maSelection; + const ESelection& r2 = pR2->maSelection; + + if( r1.nEndPara == r2.nEndPara ) + { + if( r1.nEndPos == r2.nEndPos ) + return 0; + else + return r1.nEndPos < r2.nEndPos ? 1 : -1; + } + else + { + return r1.nEndPara < r2.nEndPara ? 1 : -1; + } +} + +// ==================================================================== +// class SvxUnoTextRange +// ==================================================================== + +uno::Sequence< uno::Type > SvxUnoTextRange::maTypeSequence; + +uno::Reference< uno::XInterface > SvxUnoTextRange_NewInstance() +{ + SvxUnoText aText; + uno::Reference< text::XTextRange > xRange( new SvxUnoTextRange( aText ) ); +#if (_MSC_VER < 1300) + return xRange; +#else + return (uno::Reference< uno::XInterface >)xRange; +#endif +} + +SvxUnoTextRange::SvxUnoTextRange( const SvxUnoTextBase& rParent, sal_Bool bPortion /* = sal_False */ ) throw() +:SvxUnoTextRangeBase( rParent.GetEditSource(), bPortion ? ImplGetSvxTextPortionSvxPropertySet() : rParent.getPropertySet() ), + mbPortion( bPortion ) +{ + xParentText = (text::XText*)&rParent; +} + +SvxUnoTextRange::~SvxUnoTextRange() throw() +{ +} + +uno::Any SAL_CALL SvxUnoTextRange::queryAggregation( const uno::Type & rType ) + throw(uno::RuntimeException) +{ + QUERYINT( text::XTextRange ); + else if( rType == ::getCppuType((const uno::Reference< beans::XMultiPropertyStates >*)0) ) + return uno::makeAny(uno::Reference< beans::XMultiPropertyStates >(this)); + else if( rType == ::getCppuType((const uno::Reference< beans::XPropertySet >*)0) ) + return uno::makeAny(uno::Reference< beans::XPropertySet >(this)); + else QUERYINT( beans::XPropertyState ); + else QUERYINT( text::XTextRangeCompare ); + else if( rType == ::getCppuType((const uno::Reference< beans::XMultiPropertySet >*)0) ) + return uno::makeAny(uno::Reference< beans::XMultiPropertySet >(this)); + else QUERYINT( lang::XServiceInfo ); + else QUERYINT( lang::XTypeProvider ); + else QUERYINT( lang::XUnoTunnel ); + else + return OWeakAggObject::queryAggregation( rType ); +} + +uno::Any SAL_CALL SvxUnoTextRange::queryInterface( const uno::Type & rType ) + throw(uno::RuntimeException) +{ + return OWeakAggObject::queryInterface(rType); +} + +void SAL_CALL SvxUnoTextRange::acquire() + throw( ) +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL SvxUnoTextRange::release() + throw( ) +{ + OWeakAggObject::release(); +} + +// XTypeProvider + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextRange::getTypes() + throw (uno::RuntimeException) +{ + if( maTypeSequence.getLength() == 0 ) + { + maTypeSequence.realloc( 9 ); // !DANGER! keep this updated + uno::Type* pTypes = maTypeSequence.getArray(); + + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextRange >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XMultiPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XMultiPropertyStates >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertyState >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XServiceInfo >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XTypeProvider >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XUnoTunnel >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextRangeCompare >*)0); + } + return maTypeSequence; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextRange::getImplementationId() + throw (uno::RuntimeException) +{ + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True ); + } + return aId; +} + +// XTextRange +uno::Reference< text::XText > SAL_CALL SvxUnoTextRange::getText() + throw(uno::RuntimeException) +{ + return xParentText; +} + +// lang::XServiceInfo +OUString SAL_CALL SvxUnoTextRange::getImplementationName() + throw(uno::RuntimeException) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM("SvxUnoTextRange")); +} + +// ==================================================================== +// class SvxUnoText +// ==================================================================== + +// UNO3_GETIMPLEMENTATION2_IMPL( SvxUnoText, SvxUnoTextRangeBase ); + +uno::Sequence< uno::Type > SvxUnoTextBase::maTypeSequence; + +SvxUnoTextBase::SvxUnoTextBase() throw() +: SvxUnoTextRangeBase( NULL ) +{ + +} + +SvxUnoTextBase::SvxUnoTextBase( const SvxItemPropertySet* _pSet ) throw() +: SvxUnoTextRangeBase( _pSet ) +{ +} + +SvxUnoTextBase::SvxUnoTextBase( const SvxEditSource* pSource, const SvxItemPropertySet* _pSet ) throw() +: SvxUnoTextRangeBase( pSource, _pSet ) +{ + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + SetSelection( aSelection ); +} + +SvxUnoTextBase::SvxUnoTextBase( const SvxEditSource* pSource, const SvxItemPropertySet* _pSet, uno::Reference < text::XText > xParent ) throw() +: SvxUnoTextRangeBase( pSource, _pSet ) +{ + xParentText = xParent; + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + SetSelection( aSelection ); +} + +SvxUnoTextBase::SvxUnoTextBase( const SvxUnoTextBase& rText ) throw() +: SvxUnoTextRangeBase( rText ) +, text::XTextAppend() +, text::XTextCopy() +, container::XEnumerationAccess() +, text::XTextRangeMover() +, lang::XTypeProvider() +{ + xParentText = rText.xParentText; +} + +SvxUnoTextBase::~SvxUnoTextBase() throw() +{ +} + +// Internal +ESelection SvxUnoTextBase::InsertField( const SvxFieldItem& rField ) throw() +{ + SvxTextForwarder* pForwarder = GetEditSource() ? GetEditSource()->GetTextForwarder() : NULL; + if( pForwarder ) + { + pForwarder->QuickInsertField( rField, GetSelection() ); + GetEditSource()->UpdateData(); + + // Selektion anpassen + //! Wenn die EditEngine bei QuickInsertText die Selektion zurueckgeben wuerde, + //! waer's einfacher... + + CollapseToStart(); + GoRight( 1, sal_True ); // Feld ist immer 1 Zeichen + } + + return GetSelection(); // Selektion mit dem Feld +} + +// XInterface +uno::Any SAL_CALL SvxUnoTextBase::queryAggregation( const uno::Type & rType ) + throw(uno::RuntimeException) +{ + QUERYINT( text::XText ); + QUERYINT( text::XSimpleText ); + if( rType == ::getCppuType((const uno::Reference< text::XTextRange >*)0) ) + return uno::makeAny(uno::Reference< text::XTextRange >((text::XText*)(this))); + QUERYINT(container::XEnumerationAccess ); + QUERYINT( container::XElementAccess ); + QUERYINT( beans::XMultiPropertyStates ); + QUERYINT( beans::XPropertySet ); + QUERYINT( beans::XMultiPropertySet ); + QUERYINT( beans::XPropertyState ); + QUERYINT( text::XTextRangeCompare ); + QUERYINT( lang::XServiceInfo ); + QUERYINT( text::XTextRangeMover ); + QUERYINT( text::XTextCopy ); + QUERYINT( text::XTextAppend ); + QUERYINT( text::XParagraphAppend ); + QUERYINT( text::XTextPortionAppend ); + QUERYINT( lang::XTypeProvider ); + QUERYINT( lang::XUnoTunnel ); + + return uno::Any(); +} + +// XTypeProvider + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextBase::getStaticTypes() throw() +{ + if( maTypeSequence.getLength() == 0 ) + { + maTypeSequence.realloc( 15 ); // !DANGER! keep this updated + uno::Type* pTypes = maTypeSequence.getArray(); + + *pTypes++ = ::getCppuType(( const uno::Reference< text::XText >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< container::XEnumerationAccess >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XMultiPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XMultiPropertyStates >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertyState >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextRangeMover >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextAppend >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextCopy >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XParagraphAppend >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextPortionAppend >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XServiceInfo >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XTypeProvider >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XUnoTunnel >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextRangeCompare >*)0); + } + return maTypeSequence; +} + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextBase::getTypes() + throw (uno::RuntimeException) +{ + return getStaticTypes(); +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextBase::getImplementationId() + throw (uno::RuntimeException) +{ + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True ); + } + return aId; +} + +uno::Reference< text::XTextCursor > SvxUnoTextBase::createTextCursorBySelection( const ESelection& rSel ) +{ + SvxUnoTextCursor* pCursor = new SvxUnoTextCursor( *this ); + uno::Reference< text::XTextCursor > xCursor( pCursor ); + pCursor->SetSelection( rSel ); + return xCursor; +} + +// XSimpleText + +uno::Reference< text::XTextCursor > SAL_CALL SvxUnoTextBase::createTextCursor() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return new SvxUnoTextCursor( *this ); +} + +uno::Reference< text::XTextCursor > SAL_CALL SvxUnoTextBase::createTextCursorByRange( const uno::Reference< text::XTextRange >& aTextPosition ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + uno::Reference< text::XTextCursor > xCursor; + + if( aTextPosition.is() ) + { + SvxUnoTextRangeBase* pRange = SvxUnoTextRangeBase::getImplementation( aTextPosition ); + if(pRange) + xCursor = createTextCursorBySelection( pRange->GetSelection() ); + } + + return xCursor; +} + +void SAL_CALL SvxUnoTextBase::insertString( const uno::Reference< text::XTextRange >& xRange, const OUString& aString, sal_Bool bAbsorb ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( !xRange.is() ) + return; + + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + SetSelection( aSelection ); + + SvxUnoTextRangeBase* pRange = SvxUnoTextRange::getImplementation( xRange ); + if(pRange) + { + // setString am SvxUnoTextRangeBase statt selber QuickInsertText und UpdateData, + // damit die Selektion am SvxUnoTextRangeBase angepasst wird. + //! Eigentlich muessten alle Cursor-Objekte dieses Textes angepasst werden! + + if (!bAbsorb) // nicht ersetzen -> hinten anhaengen + pRange->CollapseToEnd(); + + pRange->setString( aString ); + + pRange->CollapseToEnd(); + } +} + +void SAL_CALL SvxUnoTextBase::insertControlCharacter( const uno::Reference< text::XTextRange >& xRange, sal_Int16 nControlCharacter, sal_Bool bAbsorb ) + throw(lang::IllegalArgumentException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = GetEditSource() ? GetEditSource()->GetTextForwarder() : NULL; + + if( pForwarder ) + { + ESelection aSelection; + ::GetSelection( aSelection, pForwarder ); + SetSelection( aSelection ); + + switch( nControlCharacter ) + { + case text::ControlCharacter::PARAGRAPH_BREAK: + { + const String aText( (sal_Unicode)13 ); // '\r' geht auf'm Mac nicht + insertString( xRange, aText, bAbsorb ); + + return; + } + case text::ControlCharacter::LINE_BREAK: + { + SvxUnoTextRangeBase* pRange = SvxUnoTextRange::getImplementation( xRange ); + if(pRange) + { + ESelection aRange = pRange->GetSelection(); + + if( bAbsorb ) + { + const String aEmpty; + pForwarder->QuickInsertText( aEmpty, aRange ); + + aRange.nEndPos = aRange.nStartPos; + aRange.nEndPara = aRange.nStartPara; + } + else + { + aRange.nStartPos = aRange.nEndPos; + aRange.nStartPara = aRange.nStartPara; + } + + pForwarder->QuickInsertLineBreak( aRange ); + GetEditSource()->UpdateData(); + + aRange.nEndPos += 1; + if( !bAbsorb ) + aRange.nStartPos += 1; + + pRange->SetSelection( aRange ); + } + return; + } + case text::ControlCharacter::APPEND_PARAGRAPH: + { + SvxUnoTextRangeBase* pRange = SvxUnoTextRange::getImplementation( xRange ); + if(pRange) + { + ESelection aRange = pRange->GetSelection(); +// ESelection aOldSelection = aRange; + + aRange.nStartPos = pForwarder->GetTextLen( aRange.nStartPara ); + + aRange.nEndPara = aRange.nStartPara; + aRange.nEndPos = aRange.nStartPos; + + pRange->SetSelection( aRange ); + const String aText( (sal_Unicode)13 ); // '\r' geht auf'm Mac nicht + pRange->setString( aText ); + + aRange.nStartPos = 0; + aRange.nStartPara += 1; + aRange.nEndPos = 0; + aRange.nEndPara += 1; + + pRange->SetSelection( aRange ); + + return; + } + } + } + } + + throw lang::IllegalArgumentException(); +} + +// XText +void SAL_CALL SvxUnoTextBase::insertTextContent( const uno::Reference< text::XTextRange >& xRange, const uno::Reference< text::XTextContent >& xContent, sal_Bool bAbsorb ) + throw(lang::IllegalArgumentException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = GetEditSource() ? GetEditSource()->GetTextForwarder() : NULL; + if( pForwarder ) + { + + SvxUnoTextRangeBase* pRange = SvxUnoTextRange::getImplementation( xRange ); + SvxUnoTextField* pField = SvxUnoTextField::getImplementation( xContent ); + + if( pRange == NULL || pField == NULL ) + throw lang::IllegalArgumentException(); + + ESelection aSelection = pRange->GetSelection(); + if( !bAbsorb ) + { + aSelection.nStartPara = aSelection.nEndPara; + aSelection.nStartPos = aSelection.nEndPos; + } + + SvxFieldData* pFieldData = pField->CreateFieldData(); + if( pFieldData == NULL ) + throw lang::IllegalArgumentException(); + + SvxFieldItem aField( *pFieldData, EE_FEATURE_FIELD ); + pForwarder->QuickInsertField( aField, aSelection ); + GetEditSource()->UpdateData(); + + pField->SetAnchor( uno::Reference< text::XTextRange >::query( (cppu::OWeakObject*)this ) ); + + aSelection.nEndPos += 1; + aSelection.nStartPos = aSelection.nEndPos; + //maSelection = aSelection; //??? + pRange->SetSelection( aSelection ); + + delete pFieldData; + } +} + +void SAL_CALL SvxUnoTextBase::removeTextContent( const uno::Reference< text::XTextContent >& ) throw(container::NoSuchElementException, uno::RuntimeException) +{ +} + +// XTextRange + +uno::Reference< text::XText > SAL_CALL SvxUnoTextBase::getText() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if (GetEditSource()) + { + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + ((SvxUnoTextBase*)this)->SetSelection( aSelection ); + } + + return (text::XText*)this; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::getStart() + throw(uno::RuntimeException) +{ + return SvxUnoTextRangeBase::getStart(); +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::getEnd() + throw(uno::RuntimeException) +{ + return SvxUnoTextRangeBase::getEnd(); +} + +OUString SAL_CALL SvxUnoTextBase::getString() throw( uno::RuntimeException ) +{ + return SvxUnoTextRangeBase::getString(); +} + +void SAL_CALL SvxUnoTextBase::setString( const OUString& aString ) throw(uno::RuntimeException) +{ + SvxUnoTextRangeBase::setString(aString); +} + + +// XEnumerationAccess +uno::Reference< container::XEnumeration > SAL_CALL SvxUnoTextBase::createEnumeration() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + SetSelection( aSelection ); + + uno::Reference< container::XEnumeration > xEnum( (container::XEnumeration*) new SvxUnoTextContentEnumeration( *this ) ); + return xEnum; +} + +// XElementAccess ( container::XEnumerationAccess ) +uno::Type SAL_CALL SvxUnoTextBase::getElementType( ) throw(uno::RuntimeException) +{ + return ::getCppuType((const uno::Reference< text::XTextRange >*)0 ); +} + +sal_Bool SAL_CALL SvxUnoTextBase::hasElements( ) throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if(GetEditSource()) + { + SvxTextForwarder* pForwarder = GetEditSource()->GetTextForwarder(); + if(pForwarder) + return pForwarder->GetParagraphCount() != 0; + } + + return sal_False; +} + +// text::XTextRangeMover +void SAL_CALL SvxUnoTextBase::moveTextRange( const uno::Reference< text::XTextRange >&, sal_Int16 ) + throw(uno::RuntimeException) +{ +} + +void SvxPropertyValuesToItemSet( + SfxItemSet &rItemSet, + const uno::Sequence< beans::PropertyValue > rPropertyVaules, + const SfxItemPropertySet *pPropSet, + SvxTextForwarder *pForwarder /*needed for WID_NUMLEVEL*/, + USHORT nPara /*needed for WID_NUMLEVEL*/) + throw(lang::IllegalArgumentException, beans::UnknownPropertyException, uno::RuntimeException) +{ + sal_Int32 nProps = rPropertyVaules.getLength(); + const beans::PropertyValue *pProps = rPropertyVaules.getConstArray(); + for (sal_Int32 i = 0; i < nProps; ++i) + { + const SfxItemPropertySimpleEntry *pEntry = pPropSet->getPropertyMap()->getByName( pProps[i].Name ); + if (pEntry) + { + // Note: there is no need to take special care of the properties + // TextField (EE_FEATURE_FIELD) and + // TextPortionType (WID_PORTIONTYPE) + // since they are read-only and thus are already taken care of below. + + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + // should be PropertyVetoException which is not yet defined for the new import API's functions + throw uno::RuntimeException( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property is read-only: " ) ) + pProps[i].Name, static_cast < cppu::OWeakObject * > ( 0 ) ); + //throw PropertyVetoException ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Property is read-only: " ) ) + pProps[i].Name, static_cast < cppu::OWeakObject * > ( 0 ) ); + + if (pEntry->nWID == WID_FONTDESC) + { + awt::FontDescriptor aDesc; + if (pProps[i].Value >>= aDesc) + SvxUnoFontDescriptor::FillItemSet( aDesc, rItemSet ); + } + else if (pEntry->nWID == WID_NUMLEVEL) + { + if (pForwarder) + { + sal_Int16 nLevel = -1; + pProps[i].Value >>= nLevel; + + // #101004# Call interface method instead of unsafe cast + if (!pForwarder->SetDepth( nPara, nLevel )) + throw lang::IllegalArgumentException(); + } + } + else if (pEntry->nWID == WID_NUMBERINGSTARTVALUE ) + { + if( pForwarder ) + { + sal_Int16 nStartValue = -1; + if( !(pProps[i].Value >>= nStartValue) ) + throw lang::IllegalArgumentException(); + + pForwarder->SetNumberingStartValue( nPara, nStartValue ); + } + } + else if (pEntry->nWID == WID_PARAISNUMBERINGRESTART ) + { + if( pForwarder ) + { + sal_Bool bParaIsNumberingRestart = sal_False; + if( !(pProps[i].Value >>= bParaIsNumberingRestart) ) + throw lang::IllegalArgumentException(); + + pForwarder->SetParaIsNumberingRestart( nPara, bParaIsNumberingRestart ); + } + } + else + pPropSet->setPropertyValue( pProps[i].Name, pProps[i].Value, rItemSet ); + } + else + throw beans::UnknownPropertyException(OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Unknown property: " ) ) + pProps[i].Name, static_cast < cppu::OWeakObject * > ( 0 ) ); + } +} + +// com::sun::star::text::XParagraphAppend (new import API) +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::appendParagraph( + const uno::Sequence< beans::PropertyValue >& rCharAndParaProps ) + throw (lang::IllegalArgumentException, beans::UnknownPropertyException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + uno::Reference< text::XTextRange > xRet; + SvxEditSource *pEditSource = GetEditSource(); + SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : 0; + if (pTextForwarder) + { + USHORT nParaCount = pTextForwarder->GetParagraphCount(); + DBG_ASSERT( nParaCount > 0, "paragraph count is 0 or negative" ); + pTextForwarder->AppendParagraph(); + + // set properties for new appended (now last) paragraph + ESelection aSel( nParaCount, 0, nParaCount, 0 ); + SfxItemSet aItemSet( *pTextForwarder->GetEmptyItemSetPtr() ); + SvxPropertyValuesToItemSet( aItemSet, rCharAndParaProps, + ImplGetSvxUnoOutlinerTextCursorSfxPropertySet(), + pTextForwarder, + nParaCount ); + pTextForwarder->QuickSetAttribs( aItemSet, aSel ); + pEditSource->UpdateData(); + SvxUnoTextRange* pRange = new SvxUnoTextRange( *this ); + xRet = pRange; + pRange->SetSelection( aSel ); + } + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::finishParagraph( + const uno::Sequence< beans::PropertyValue >& rCharAndParaProps ) + throw (lang::IllegalArgumentException, beans::UnknownPropertyException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + uno::Reference< text::XTextRange > xRet; + SvxEditSource *pEditSource = GetEditSource(); + SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : 0; + if (pTextForwarder) + { + USHORT nParaCount = pTextForwarder->GetParagraphCount(); + DBG_ASSERT( nParaCount > 0, "paragraph count is 0 or negative" ); + pTextForwarder->AppendParagraph(); + + // set properties for the previously last paragraph + USHORT nPara = nParaCount - 1; + ESelection aSel( nPara, 0, nPara, 0 ); + SfxItemSet aItemSet( *pTextForwarder->GetEmptyItemSetPtr() ); + SvxPropertyValuesToItemSet( aItemSet, rCharAndParaProps, + ImplGetSvxUnoOutlinerTextCursorSfxPropertySet(), pTextForwarder, nPara ); + pTextForwarder->QuickSetAttribs( aItemSet, aSel ); + pEditSource->UpdateData(); + SvxUnoTextRange* pRange = new SvxUnoTextRange( *this ); + xRet = pRange; + pRange->SetSelection( aSel ); + } + return xRet; +} + +// com::sun::star::text::XTextPortionAppend (new import API) +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::appendTextPortion( + const ::rtl::OUString& rText, + const uno::Sequence< beans::PropertyValue >& rCharAndParaProps ) + throw (lang::IllegalArgumentException, beans::UnknownPropertyException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxEditSource *pEditSource = GetEditSource(); + SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : 0; + uno::Reference< text::XTextRange > xRet; + if (pTextForwarder) + { + USHORT nParaCount = pTextForwarder->GetParagraphCount(); + DBG_ASSERT( nParaCount > 0, "paragraph count is 0 or negative" ); + USHORT nPara = nParaCount - 1; + SfxItemSet aSet( pTextForwarder->GetParaAttribs( nPara ) ); + xub_StrLen nStart = pTextForwarder->AppendTextPortion( nPara, rText, aSet ); + pEditSource->UpdateData(); + xub_StrLen nEnd = pTextForwarder->GetTextLen( nPara ); + + // set properties for the new text portion + ESelection aSel( nPara, nStart, nPara, nEnd ); + pTextForwarder->RemoveAttribs( aSel, sal_False, 0 ); + pEditSource->UpdateData(); + + SfxItemSet aItemSet( *pTextForwarder->GetEmptyItemSetPtr() ); + SvxPropertyValuesToItemSet( aItemSet, rCharAndParaProps, + ImplGetSvxTextPortionSfxPropertySet(), pTextForwarder, nPara ); + pTextForwarder->QuickSetAttribs( aItemSet, aSel ); + SvxUnoTextRange* pRange = new SvxUnoTextRange( *this ); + xRet = pRange; + pRange->SetSelection( aSel ); + const beans::PropertyValue* pProps = rCharAndParaProps.getConstArray(); + for( sal_Int32 nProp = 0; nProp < rCharAndParaProps.getLength(); ++nProp ) + pRange->setPropertyValue( pProps[nProp].Name, pProps[nProp].Value ); + } + return xRet; +} +/*-- 25.03.2008 08:16:09--------------------------------------------------- + + -----------------------------------------------------------------------*/ +void SvxUnoTextBase::copyText( + const uno::Reference< text::XTextCopy >& xSource ) throw ( uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + uno::Reference< lang::XUnoTunnel > xUT( xSource, uno::UNO_QUERY ); + SvxEditSource *pEditSource = GetEditSource(); + SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : 0; + if( !pTextForwarder ) + return; + if( xUT.is() ) + { + SvxUnoTextBase* pSource = reinterpret_cast<SvxUnoTextBase*>(sal::static_int_cast<sal_uIntPtr>( + xUT->getSomething( SvxUnoTextBase::getUnoTunnelId()))); + SvxEditSource *pSourceEditSource = pSource->GetEditSource(); + SvxTextForwarder *pSourceTextForwarder = pSourceEditSource ? pSourceEditSource->GetTextForwarder() : 0; + if( pSourceTextForwarder ) + { + pTextForwarder->CopyText( *pSourceTextForwarder ); + pEditSource->UpdateData(); + } + } + else + { + uno::Reference< text::XText > xSourceText( xSource, uno::UNO_QUERY ); + if( xSourceText.is() ) + { + setString( xSourceText->getString() ); + } + } +} + +// lang::XServiceInfo +OUString SAL_CALL SvxUnoTextBase::getImplementationName() + throw(uno::RuntimeException) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM("SvxUnoTextBase")); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextBase::getSupportedServiceNames( ) + throw(uno::RuntimeException) +{ + return getSupportedServiceNames_Static(); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextBase::getSupportedServiceNames_Static( ) + SAL_THROW(()) +{ + uno::Sequence< OUString > aSeq( SvxUnoTextRangeBase::getSupportedServiceNames_Static() ); + comphelper::ServiceInfoHelper::addToSequence( aSeq, 1, "com.sun.star.text.Text" ); + return aSeq; +} + +const uno::Sequence< sal_Int8 > & SvxUnoTextBase::getUnoTunnelId() throw() +{ + static uno::Sequence< sal_Int8 > * pSeq = 0; + if( !pSeq ) + { + ::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ); + if( !pSeq ) + { + static uno::Sequence< sal_Int8 > aSeq( 16 ); + rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True ); + pSeq = &aSeq; + } + } + return *pSeq; +} + +SvxUnoTextBase* SvxUnoTextBase::getImplementation( const uno::Reference< uno::XInterface >& xInt ) +{ + uno::Reference< lang::XUnoTunnel > xUT( xInt, uno::UNO_QUERY ); + if( xUT.is() ) + return reinterpret_cast<SvxUnoTextBase*>(sal::static_int_cast<sal_uIntPtr>(xUT->getSomething( SvxUnoTextBase::getUnoTunnelId()))); + else + return NULL; +} + +sal_Int64 SAL_CALL SvxUnoTextBase::getSomething( const uno::Sequence< sal_Int8 >& rId ) throw(uno::RuntimeException) \ +{ + if( rId.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), + rId.getConstArray(), 16 ) ) + { + return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_uIntPtr>(this)); + } + else + { + return SvxUnoTextRangeBase::getSomething( rId ); + } +} + +// -------------------------------------------------------------------- + +SvxUnoText::SvxUnoText( ) throw() +{ +} + +SvxUnoText::SvxUnoText( const SvxItemPropertySet* _pSet ) throw() +: SvxUnoTextBase( _pSet ) +{ +} + +SvxUnoText::SvxUnoText( const SvxEditSource* pSource, const SvxItemPropertySet* _pSet, uno::Reference < text::XText > xParent ) throw() +: SvxUnoTextBase( pSource, _pSet, xParent ) +{ +} + +SvxUnoText::SvxUnoText( const SvxUnoText& rText ) throw() +: SvxUnoTextBase( rText ) +, cppu::OWeakAggObject() +{ +} + +SvxUnoText::~SvxUnoText() throw() +{ +} + +uno::Sequence< uno::Type > SAL_CALL getStaticTypes() throw() +{ + return SvxUnoTextBase::getStaticTypes(); +} + +// uno::XInterface +uno::Any SAL_CALL SvxUnoText::queryAggregation( const uno::Type & rType ) throw( uno::RuntimeException ) +{ + uno::Any aAny( SvxUnoTextBase::queryAggregation( rType ) ); + if( !aAny.hasValue() ) + aAny = OWeakAggObject::queryAggregation( rType ); + + return aAny; +} + +uno::Any SAL_CALL SvxUnoText::queryInterface( const uno::Type & rType ) throw( uno::RuntimeException ) +{ + return OWeakAggObject::queryInterface( rType ); +} + +void SAL_CALL SvxUnoText::acquire() throw( ) +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL SvxUnoText::release() throw( ) +{ + OWeakAggObject::release(); +} + +// lang::XTypeProvider +uno::Sequence< uno::Type > SAL_CALL SvxUnoText::getTypes( ) throw( uno::RuntimeException ) +{ + return SvxUnoTextBase::getTypes(); +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoText::getImplementationId( ) throw( uno::RuntimeException ) +{ + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True ); + } + return aId; +} + +SvxUnoText* SvxUnoText::getImplementation( const uno::Reference< uno::XInterface >& xInt ) +{ + uno::Reference< lang::XUnoTunnel > xUT( xInt, uno::UNO_QUERY ); + if( xUT.is() ) + return reinterpret_cast<SvxUnoText*>(sal::static_int_cast<sal_uIntPtr>(xUT->getSomething( SvxUnoText::getUnoTunnelId()))); + else + return NULL; +} + +const uno::Sequence< sal_Int8 > & SvxUnoText::getUnoTunnelId() throw() +{ + static uno::Sequence< sal_Int8 > * pSeq = 0; + if( !pSeq ) + { + ::osl::Guard< ::osl::Mutex > aGuard( ::osl::Mutex::getGlobalMutex() ); + if( !pSeq ) + { + static uno::Sequence< sal_Int8 > aSeq( 16 ); + rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True ); + pSeq = &aSeq; + } + } + return *pSeq; +} + +sal_Int64 SAL_CALL SvxUnoText::getSomething( const uno::Sequence< sal_Int8 >& rId ) throw(uno::RuntimeException) \ +{ + if( rId.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(), + rId.getConstArray(), 16 ) ) + { + return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_uIntPtr>(this)); + } + else + { + return SvxUnoTextBase::getSomething( rId ); + } +} + + +// -------------------------------------------------------------------- + +SvxDummyTextSource::~SvxDummyTextSource() +{ +}; + +SvxEditSource* SvxDummyTextSource::Clone() const +{ + return new SvxDummyTextSource(); +} + +SvxTextForwarder* SvxDummyTextSource::GetTextForwarder() +{ + return this; +} + +void SvxDummyTextSource::UpdateData() +{ +} + +sal_uInt16 SvxDummyTextSource::GetParagraphCount() const +{ + return 0; +} + +sal_uInt16 SvxDummyTextSource::GetTextLen( sal_uInt16 ) const +{ + return 0; +} + +String SvxDummyTextSource::GetText( const ESelection& ) const +{ + return String(); +} + +SfxItemSet SvxDummyTextSource::GetAttribs( const ESelection&, BOOL ) const +{ + // AW: Very dangerous: The former implementation used a SfxItemPool created on the + // fly which of course was deleted again ASAP. Thus, the returned SfxItemSet was using + // a deleted Pool by design. + return SfxItemSet(EditEngine::GetGlobalItemPool()); +} + +SfxItemSet SvxDummyTextSource::GetParaAttribs( sal_uInt16 ) const +{ + return GetAttribs(ESelection()); +} + +void SvxDummyTextSource::SetParaAttribs( sal_uInt16, const SfxItemSet& ) +{ +} + +void SvxDummyTextSource::RemoveAttribs( const ESelection& , sal_Bool , sal_uInt16 ) +{ +} + +void SvxDummyTextSource::GetPortions( sal_uInt16, SvUShorts& ) const +{ +} + +sal_uInt16 SvxDummyTextSource::GetItemState( const ESelection&, sal_uInt16 ) const +{ + return 0; +} + +sal_uInt16 SvxDummyTextSource::GetItemState( sal_uInt16, sal_uInt16 ) const +{ + return 0; +} + +SfxItemPool* SvxDummyTextSource::GetPool() const +{ + return NULL; +} + +void SvxDummyTextSource::QuickInsertText( const String&, const ESelection& ) +{ +} + +void SvxDummyTextSource::QuickInsertField( const SvxFieldItem&, const ESelection& ) +{ +} + +void SvxDummyTextSource::QuickSetAttribs( const SfxItemSet&, const ESelection& ) +{ +} + +void SvxDummyTextSource::QuickInsertLineBreak( const ESelection& ) +{ +}; + +XubString SvxDummyTextSource::CalcFieldValue( const SvxFieldItem&, sal_uInt16, sal_uInt16, Color*&, Color*& ) +{ + return XubString(); +} + +sal_Bool SvxDummyTextSource::IsValid() const +{ + return sal_False; +} + +void SvxDummyTextSource::SetNotifyHdl( const Link& ) +{ +} + +LanguageType SvxDummyTextSource::GetLanguage( USHORT, USHORT ) const +{ + return LANGUAGE_DONTKNOW; +} + +USHORT SvxDummyTextSource::GetFieldCount( USHORT ) const +{ + return 0; +} + +EFieldInfo SvxDummyTextSource::GetFieldInfo( USHORT, USHORT ) const +{ + return EFieldInfo(); +} + +EBulletInfo SvxDummyTextSource::GetBulletInfo( USHORT ) const +{ + return EBulletInfo(); +} + +Rectangle SvxDummyTextSource::GetCharBounds( USHORT, USHORT ) const +{ + return Rectangle(); +} + +Rectangle SvxDummyTextSource::GetParaBounds( USHORT ) const +{ + return Rectangle(); +} + +MapMode SvxDummyTextSource::GetMapMode() const +{ + return MapMode(); +} + +OutputDevice* SvxDummyTextSource::GetRefDevice() const +{ + return NULL; +} + +sal_Bool SvxDummyTextSource::GetIndexAtPoint( const Point&, USHORT&, USHORT& ) const +{ + return sal_False; +} + +sal_Bool SvxDummyTextSource::GetWordIndices( USHORT, USHORT, USHORT&, USHORT& ) const +{ + return sal_False; +} + +sal_Bool SvxDummyTextSource::GetAttributeRun( USHORT&, USHORT&, USHORT, USHORT ) const +{ + return sal_False; +} + +USHORT SvxDummyTextSource::GetLineCount( USHORT ) const +{ + return 0; +} + +USHORT SvxDummyTextSource::GetLineLen( USHORT, USHORT ) const +{ + return 0; +} + +void SvxDummyTextSource::GetLineBoundaries( /*out*/USHORT &rStart, /*out*/USHORT &rEnd, USHORT /*nParagraph*/, USHORT /*nLine*/ ) const +{ + rStart = rEnd = 0; +} + +USHORT SvxDummyTextSource::GetLineNumberAtIndex( USHORT /*nPara*/, USHORT /*nIndex*/ ) const +{ + return 0; +} + +sal_Bool SvxDummyTextSource::QuickFormatDoc( BOOL ) +{ + return sal_False; +} + +sal_Int16 SvxDummyTextSource::GetDepth( USHORT ) const +{ + return -1; +} + +sal_Bool SvxDummyTextSource::SetDepth( USHORT, sal_Int16 nNewDepth ) +{ + return nNewDepth == 0 ? sal_True : sal_False; +} + +sal_Bool SvxDummyTextSource::Delete( const ESelection& ) +{ + return sal_False; +} + +sal_Bool SvxDummyTextSource::InsertText( const String&, const ESelection& ) +{ + return sal_False; +} + +const SfxItemSet * SvxDummyTextSource::GetEmptyItemSetPtr() +{ + return 0; +} + +void SvxDummyTextSource::AppendParagraph() +{ +} + +xub_StrLen SvxDummyTextSource::AppendTextPortion( USHORT, const String &, const SfxItemSet & ) +{ + return 0; +} + +void SvxDummyTextSource::CopyText(const SvxTextForwarder& ) +{ +} + diff --git a/editeng/source/uno/unotext2.cxx b/editeng/source/uno/unotext2.cxx new file mode 100644 index 000000000000..6628477c3b04 --- /dev/null +++ b/editeng/source/uno/unotext2.cxx @@ -0,0 +1,714 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unotext2.cxx,v $ + * $Revision: 1.27 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <vcl/svapp.hxx> +#include <vos/mutex.hxx> + +#define _SVSTDARR_USHORTS +#include <svl/svstdarr.hxx> + +#include <rtl/uuid.h> +#include <rtl/memory.h> + +#include <editeng/eeitem.hxx> +#include <editeng/flditem.hxx> +#include <editeng/unofield.hxx> +#include <editeng/unotext.hxx> +#include <comphelper/serviceinfohelper.hxx> + +using namespace ::rtl; +using namespace ::vos; +using namespace ::cppu; +using namespace ::com::sun::star; + +#define QUERYINT( xint ) \ + if( rType == ::getCppuType((const uno::Reference< xint >*)0) ) \ + return uno::makeAny(uno::Reference< xint >(this)) + +// ==================================================================== +// SvxUnoTextContentEnumeration +// ==================================================================== + +SvxUnoTextContentEnumeration::SvxUnoTextContentEnumeration( const SvxUnoTextBase& _rText ) throw() +: mrText( _rText ) +{ + mxParentText = const_cast<SvxUnoTextBase*>(&_rText); + if( mrText.GetEditSource() ) + mpEditSource = mrText.GetEditSource()->Clone(); + else + mpEditSource = NULL; + mnNextParagraph = 0; +} + +SvxUnoTextContentEnumeration::~SvxUnoTextContentEnumeration() throw() +{ + delete mpEditSource; +} + +// container::XEnumeration +sal_Bool SAL_CALL SvxUnoTextContentEnumeration::hasMoreElements(void) + throw( uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + if( mpEditSource && mpEditSource->GetTextForwarder() ) + return mnNextParagraph < mpEditSource->GetTextForwarder()->GetParagraphCount(); + else + return sal_False; +} + +uno::Any SvxUnoTextContentEnumeration::nextElement(void) throw( container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException ) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if(!hasMoreElements()) + throw container::NoSuchElementException(); + + SvxUnoTextContent* pContent = 0; + + const SvxUnoTextRangeBaseList& rRanges( mpEditSource->getRanges() ); + SvxUnoTextRangeBaseList::const_iterator aIter; + for( aIter = rRanges.begin(); (aIter != rRanges.end()) && (pContent == 0); aIter++ ) + { + SvxUnoTextContent* pIterContent = dynamic_cast< SvxUnoTextContent* >( (*aIter ) ); + if( pIterContent && (pIterContent->mnParagraph == mnNextParagraph) ) + pContent = pIterContent; + } + + if( pContent == 0 ) + pContent = new SvxUnoTextContent( mrText, mnNextParagraph ); + + mnNextParagraph++; + + uno::Reference< text::XTextContent > xRef( pContent ); + return uno::makeAny( xRef ); +} + +// ==================================================================== +// class SvxUnoTextContent +// ==================================================================== +uno::Reference< text::XText > xDummyText; +uno::Sequence< uno::Type > SvxUnoTextContent::maTypeSequence; + +static SvxUnoText* getDummyText() throw() +{ + if(!xDummyText.is()) + xDummyText = new SvxUnoText(); + + return SvxUnoText::getImplementation( xDummyText ); +} + +SvxUnoTextContent::SvxUnoTextContent() throw() +: SvxUnoTextRangeBase(*getDummyText()) +, mnParagraph(0) +, mrParentText(*getDummyText()) +, maDisposeListeners(maDisposeContainerMutex) +, mbDisposing( false ) +{ +} + +SvxUnoTextContent::SvxUnoTextContent( const SvxUnoTextBase& rText, sal_uInt16 nPara ) throw() +: SvxUnoTextRangeBase(rText) +, mnParagraph(nPara) +, mrParentText(rText) +, maDisposeListeners(maDisposeContainerMutex) +, mbDisposing( false ) +{ + mxParentText = const_cast<SvxUnoTextBase*>(&rText); + if( GetEditSource() && GetEditSource()->GetTextForwarder() ) + SetSelection( ESelection( mnParagraph,0, mnParagraph, GetEditSource()->GetTextForwarder()->GetTextLen( mnParagraph ) ) ); +} + +SvxUnoTextContent::SvxUnoTextContent( const SvxUnoTextContent& rContent ) throw() +: SvxUnoTextRangeBase(rContent) +, text::XTextContent() +, container::XEnumerationAccess() +, lang::XTypeProvider() +, cppu::OWeakAggObject() +, mrParentText(rContent.mrParentText) +, maDisposeListeners(maDisposeContainerMutex) +, mbDisposing( false ) +{ + mxParentText = rContent.mxParentText; + mnParagraph = rContent.mnParagraph; + SetSelection( rContent.GetSelection() ); +} + +SvxUnoTextContent::~SvxUnoTextContent() throw() +{ +} + +// uno::XInterface +uno::Any SAL_CALL SvxUnoTextContent::queryAggregation( const uno::Type & rType ) throw( uno::RuntimeException ) +{ + QUERYINT( text::XTextRange ); + else QUERYINT( beans::XMultiPropertyStates ); + else QUERYINT( beans::XPropertySet ); + else QUERYINT( beans::XMultiPropertySet ); + else QUERYINT( beans::XPropertyState ); + else QUERYINT( text::XTextContent ); + else QUERYINT( text::XTextRangeCompare ); + else QUERYINT( lang::XComponent ); + else QUERYINT( container::XEnumerationAccess ); + else QUERYINT( container::XElementAccess ); + else QUERYINT( lang::XServiceInfo ); + else QUERYINT( lang::XTypeProvider ); + else QUERYINT( lang::XUnoTunnel ); + else + return OWeakAggObject::queryAggregation( rType ); +} + +uno::Any SAL_CALL SvxUnoTextContent::queryInterface( const uno::Type & rType ) throw( uno::RuntimeException ) +{ + return OWeakAggObject::queryInterface(rType); +} + +void SAL_CALL SvxUnoTextContent::acquire() throw( ) +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL SvxUnoTextContent::release() throw( ) +{ + OWeakAggObject::release(); +} + +// XTypeProvider + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextContent::getTypes() + throw (uno::RuntimeException) +{ + if( maTypeSequence.getLength() == 0 ) + { + maTypeSequence.realloc( 11 ); // !DANGER! keep this updated + uno::Type* pTypes = maTypeSequence.getArray(); + + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextRange >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XMultiPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XMultiPropertyStates >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertyState >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextRangeCompare >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextContent >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< container::XEnumerationAccess >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XServiceInfo >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XTypeProvider >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XUnoTunnel >*)0); + } + return maTypeSequence; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextContent::getImplementationId() + throw (uno::RuntimeException) +{ + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True ); + } + return aId; +} + +// text::XTextRange + +uno::Reference< text::XText > SAL_CALL SvxUnoTextContent::getText() + throw(uno::RuntimeException) +{ + return mxParentText; +} + +// text::XTextContent +void SAL_CALL SvxUnoTextContent::attach( const uno::Reference< text::XTextRange >& ) + throw(lang::IllegalArgumentException, uno::RuntimeException) +{ +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextContent::getAnchor() throw( uno::RuntimeException ) +{ + return uno::Reference< text::XTextRange >::query( mxParentText ); +} + +// XComponent + +void SAL_CALL SvxUnoTextContent::dispose() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( mbDisposing ) + return; // catched a recursion + + mbDisposing = true; + + lang::EventObject aEvt; + aEvt.Source = *(OWeakAggObject*) this; + maDisposeListeners.disposeAndClear(aEvt); + + if( mxParentText.is() ) + mxParentText->removeTextContent( this ); +} + +void SAL_CALL SvxUnoTextContent::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw(uno::RuntimeException) +{ + maDisposeListeners.addInterface(xListener); +} + +void SAL_CALL SvxUnoTextContent::removeEventListener( const uno::Reference< lang::XEventListener >& aListener ) + throw(uno::RuntimeException) +{ + maDisposeListeners.removeInterface(aListener); +} + +// XEnumerationAccess + +uno::Reference< container::XEnumeration > SAL_CALL SvxUnoTextContent::createEnumeration( ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + return new SvxUnoTextRangeEnumeration( mrParentText, mnParagraph ); +} + +// XElementAccess ( container::XEnumerationAccess ) + +uno::Type SAL_CALL SvxUnoTextContent::getElementType() + throw(uno::RuntimeException) +{ + return ::getCppuType((const uno::Reference< text::XTextRange >*)0); +} + +sal_Bool SAL_CALL SvxUnoTextContent::hasElements() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + SvxTextForwarder* pForwarder = GetEditSource() ? GetEditSource()->GetTextForwarder() : NULL; + if( pForwarder ) + { + SvUShorts aPortions; + pForwarder->GetPortions( mnParagraph, aPortions ); + return aPortions.Count() > 0; + } + else + { + return 0; + } +} + +// XPropertySet + +void SAL_CALL SvxUnoTextContent::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue ) + throw(beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + _setPropertyValue( aPropertyName, aValue, mnParagraph ); +} + +uno::Any SAL_CALL SvxUnoTextContent::getPropertyValue( const OUString& PropertyName ) + throw(beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException) +{ + return _getPropertyValue( PropertyName, mnParagraph ); +} + +// XMultiPropertySet +void SAL_CALL SvxUnoTextContent::setPropertyValues( const uno::Sequence< ::rtl::OUString >& aPropertyNames, const uno::Sequence< uno::Any >& aValues ) throw (beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException) +{ + _setPropertyValues( aPropertyNames, aValues, mnParagraph ); +} + +uno::Sequence< uno::Any > SAL_CALL SvxUnoTextContent::getPropertyValues( const uno::Sequence< ::rtl::OUString >& aPropertyNames ) throw (uno::RuntimeException) +{ + return _getPropertyValues( aPropertyNames, mnParagraph ); +} + +/*// XTolerantMultiPropertySet +uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL SvxUnoTextContent::setPropertyValuesTolerant( const uno::Sequence< ::rtl::OUString >& aPropertyNames, const uno::Sequence< uno::Any >& aValues ) throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + return _setPropertyValuesTolerant(aPropertyNames, aValues, mnParagraph); +} + +uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL SvxUnoTextContent::getPropertyValuesTolerant( const uno::Sequence< ::rtl::OUString >& aPropertyNames ) throw (uno::RuntimeException) +{ + return _getPropertyValuesTolerant(aPropertyNames, mnParagraph); +} + +uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL SvxUnoTextContent::getDirectPropertyValuesTolerant( const uno::Sequence< ::rtl::OUString >& aPropertyNames ) + throw (uno::RuntimeException) +{ + return _getDirectPropertyValuesTolerant(aPropertyNames, mnParagraph); +}*/ + +// beans::XPropertyState +beans::PropertyState SAL_CALL SvxUnoTextContent::getPropertyState( const OUString& PropertyName ) + throw(beans::UnknownPropertyException, uno::RuntimeException) +{ + return _getPropertyState( PropertyName, mnParagraph ); +} + +uno::Sequence< beans::PropertyState > SAL_CALL SvxUnoTextContent::getPropertyStates( const uno::Sequence< OUString >& aPropertyName ) + throw(beans::UnknownPropertyException, uno::RuntimeException) +{ + return _getPropertyStates( aPropertyName, mnParagraph ); +} + +void SAL_CALL SvxUnoTextContent::setPropertyToDefault( const OUString& PropertyName ) + throw(beans::UnknownPropertyException, uno::RuntimeException) +{ + _setPropertyToDefault( PropertyName, mnParagraph ); +} + +// lang::XServiceInfo + +OUString SAL_CALL SvxUnoTextContent::getImplementationName() + throw(uno::RuntimeException) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM("SvxUnoTextContent") ); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextContent::getSupportedServiceNames() + throw(uno::RuntimeException) +{ + uno::Sequence< OUString > aSeq( SvxUnoTextRangeBase::getSupportedServiceNames() ); + comphelper::ServiceInfoHelper::addToSequence( aSeq, 5, "com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesComplex", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.text.TextContent", + "com.sun.star.text.Paragraph"); + return aSeq; +} + +// ==================================================================== +// class SvxUnoTextRangeEnumeration +// ==================================================================== + +SvxUnoTextRangeEnumeration::SvxUnoTextRangeEnumeration( const SvxUnoTextBase& rText, sal_uInt16 nPara ) throw() +: mxParentText( const_cast<SvxUnoTextBase*>(&rText) ), + mrParentText( rText ), + mnParagraph( nPara ), + mnNextPortion( 0 ) +{ + mpEditSource = rText.GetEditSource() ? rText.GetEditSource()->Clone() : NULL; + + if( mpEditSource && mpEditSource->GetTextForwarder() ) + { + mpPortions = new SvUShorts; + mpEditSource->GetTextForwarder()->GetPortions( nPara, *mpPortions ); + } + else + { + mpPortions = NULL; + } +} + +SvxUnoTextRangeEnumeration::~SvxUnoTextRangeEnumeration() throw() +{ + delete mpEditSource; + delete mpPortions; +} + +// container::XEnumeration + +sal_Bool SAL_CALL SvxUnoTextRangeEnumeration::hasMoreElements() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + return mpPortions && mnNextPortion < mpPortions->Count(); +} + +uno::Any SAL_CALL SvxUnoTextRangeEnumeration::nextElement() + throw(container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( mpPortions == NULL || mnNextPortion >= mpPortions->Count() ) + throw container::NoSuchElementException(); + + sal_uInt16 nStartPos = 0; + if (mnNextPortion > 0) + nStartPos = mpPortions->GetObject(mnNextPortion-1); + sal_uInt16 nEndPos = mpPortions->GetObject(mnNextPortion); + ESelection aSel( mnParagraph, nStartPos, mnParagraph, nEndPos ); + + uno::Reference< text::XTextRange > xRange; + + const SvxUnoTextRangeBaseList& rRanges( mpEditSource->getRanges() ); + + SvxUnoTextRange* pRange = 0; + + SvxUnoTextRangeBaseList::const_iterator aIter; + for( aIter = rRanges.begin(); (aIter != rRanges.end()) && (pRange == 0); aIter++ ) + { + SvxUnoTextRange* pIterRange = dynamic_cast< SvxUnoTextRange* >( (*aIter ) ); + if( pIterRange && pIterRange->mbPortion && (aSel.IsEqual( pIterRange->maSelection ) ) ) + pRange = pIterRange; + } + + if( pRange == 0 ) + { + pRange = new SvxUnoTextRange( mrParentText, sal_True ); + pRange->SetSelection(aSel); + } + + xRange = pRange; + + mnNextPortion++; + + return uno::makeAny( xRange ); +} + +// ==================================================================== +// class SvxUnoTextCursor +// ==================================================================== + +uno::Sequence< uno::Type > SvxUnoTextCursor::maTypeSequence; + +uno::Reference< uno::XInterface > SvxUnoTextCursor_NewInstance() +{ + SvxUnoText aText; + uno::Reference< text::XText > xText( (text::XText*)new SvxUnoTextCursor( aText ) ); + uno::Reference< uno::XInterface > xInt( xText, uno::UNO_QUERY ); + return xInt; +} + +SvxUnoTextCursor::SvxUnoTextCursor( const SvxUnoTextBase& rText ) throw() +: SvxUnoTextRangeBase(rText), + mxParentText( const_cast<SvxUnoTextBase*>(&rText) ) +{ +} + +SvxUnoTextCursor::SvxUnoTextCursor( const SvxUnoTextCursor& rCursor ) throw() +: SvxUnoTextRangeBase(rCursor) +, text::XTextCursor() +, lang::XTypeProvider() +, cppu::OWeakAggObject() +, mxParentText(rCursor.mxParentText) +{ +} + +SvxUnoTextCursor::~SvxUnoTextCursor() throw() +{ +} + +// automatisch auskommentiert - [getIdlClass(es) or queryInterface] - Bitte XTypeProvider benutzen! +//sal_Bool SvxUnoTextCursor::queryInterface( uno::Uik aUIK, Reference< uno::XInterface > & xRef) +uno::Any SAL_CALL SvxUnoTextCursor::queryAggregation( const uno::Type & rType ) + throw(uno::RuntimeException) +{ + if( rType == ::getCppuType((const uno::Reference< text::XTextRange >*)0) ) + return uno::makeAny(uno::Reference< text::XTextRange >((text::XText*)(this))); + else QUERYINT( text::XTextCursor ); + else QUERYINT( beans::XMultiPropertyStates ); + else QUERYINT( beans::XPropertySet ); + else QUERYINT( beans::XMultiPropertySet ); + else QUERYINT( beans::XPropertyState ); + else QUERYINT( text::XTextRangeCompare ); + else QUERYINT( lang::XServiceInfo ); + else QUERYINT( lang::XTypeProvider ); + else QUERYINT( lang::XUnoTunnel ); + else + return OWeakAggObject::queryAggregation( rType ); +} + +uno::Any SAL_CALL SvxUnoTextCursor::queryInterface( const uno::Type & rType ) + throw(uno::RuntimeException) +{ + return OWeakAggObject::queryInterface(rType); +} + +void SAL_CALL SvxUnoTextCursor::acquire() throw ( ) +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL SvxUnoTextCursor::release() throw ( ) +{ + OWeakAggObject::release(); +} + +// XTypeProvider +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextCursor::getTypes() + throw(uno::RuntimeException) +{ + if( maTypeSequence.getLength() == 0 ) + { + maTypeSequence.realloc( 10 ); // !DANGER! keep this updated + uno::Type* pTypes = maTypeSequence.getArray(); + + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextRange >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextCursor >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XMultiPropertySet >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XMultiPropertyStates >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< beans::XPropertyState >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< text::XTextRangeCompare >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XServiceInfo >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XTypeProvider >*)0); + *pTypes++ = ::getCppuType(( const uno::Reference< lang::XUnoTunnel >*)0); + } + return maTypeSequence; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextCursor::getImplementationId() + throw (uno::RuntimeException) +{ + static uno::Sequence< sal_Int8 > aId; + if( aId.getLength() == 0 ) + { + aId.realloc( 16 ); + rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True ); + } + return aId; +} + +// text::XTextCursor +void SAL_CALL SvxUnoTextCursor::collapseToStart() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + CollapseToStart(); +} + +void SAL_CALL SvxUnoTextCursor::collapseToEnd() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + CollapseToEnd(); +} + +sal_Bool SAL_CALL SvxUnoTextCursor::isCollapsed() + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return IsCollapsed(); +} + +sal_Bool SAL_CALL SvxUnoTextCursor::goLeft( sal_Int16 nCount, sal_Bool bExpand ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return GoLeft( nCount, bExpand ); +} + +sal_Bool SAL_CALL SvxUnoTextCursor::goRight( sal_Int16 nCount, sal_Bool bExpand ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return GoRight( nCount, bExpand ); +} + +void SAL_CALL SvxUnoTextCursor::gotoStart( sal_Bool bExpand ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + GotoStart( bExpand ); +} + +void SAL_CALL SvxUnoTextCursor::gotoEnd( sal_Bool bExpand ) + throw(uno::RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + GotoEnd( bExpand ); +} + +void SAL_CALL SvxUnoTextCursor::gotoRange( const uno::Reference< text::XTextRange >& xRange, sal_Bool bExpand ) + throw(uno::RuntimeException) +{ + if( !xRange.is() ) + return; + + SvxUnoTextRangeBase* pRange = SvxUnoTextRangeBase::getImplementation( xRange ); + + if( pRange ) + { + ESelection aNewSel = pRange->GetSelection(); + + if( bExpand ) + { + const ESelection& rOldSel = GetSelection(); + aNewSel.nStartPara = rOldSel.nStartPara; + aNewSel.nStartPos = rOldSel.nStartPos; + } + + SetSelection( aNewSel ); + } +} + +// text::XTextRange (rest in SvxTextRange) +uno::Reference< text::XText > SAL_CALL SvxUnoTextCursor::getText(void) throw( uno::RuntimeException ) +{ + return mxParentText; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextCursor::getStart() + throw(uno::RuntimeException) +{ + return SvxUnoTextRangeBase::getStart(); +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextCursor::getEnd() + throw(uno::RuntimeException) +{ + return SvxUnoTextRangeBase::getEnd(); +} + +OUString SAL_CALL SvxUnoTextCursor::getString() throw( uno::RuntimeException ) +{ + return SvxUnoTextRangeBase::getString(); +} + +void SAL_CALL SvxUnoTextCursor::setString( const OUString& aString ) throw(uno::RuntimeException) +{ + SvxUnoTextRangeBase::setString(aString); +} +// lang::XServiceInfo +OUString SAL_CALL SvxUnoTextCursor::getImplementationName() throw(uno::RuntimeException) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM("SvxUnoTextCursor")); +} + +sal_Bool SAL_CALL SvxUnoTextCursor::supportsService( const OUString& ServiceName ) throw(uno::RuntimeException) +{ + return comphelper::ServiceInfoHelper::supportsService( ServiceName, getSupportedServiceNames() ); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextCursor::getSupportedServiceNames() throw(uno::RuntimeException) +{ + uno::Sequence< OUString > aSeq( SvxUnoTextRangeBase::getSupportedServiceNames() ); + comphelper::ServiceInfoHelper::addToSequence( aSeq, 4,"com.sun.star.style.ParagraphProperties", + "com.sun.star.style.ParagraphPropertiesComplex", + "com.sun.star.style.ParagraphPropertiesAsian", + "com.sun.star.text.TextCursor"); + return aSeq; +} + + diff --git a/editeng/source/uno/unoviwed.cxx b/editeng/source/uno/unoviwed.cxx new file mode 100644 index 000000000000..0847a784c538 --- /dev/null +++ b/editeng/source/uno/unoviwed.cxx @@ -0,0 +1,140 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unoviwed.cxx,v $ + * $Revision: 1.10 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> + +#include <editeng/unoviwed.hxx> +#include <editeng/editview.hxx> +#include <editeng/editeng.hxx> + +SvxEditEngineViewForwarder::SvxEditEngineViewForwarder( EditView& rView ) : + mrView( rView ) +{ +} + +SvxEditEngineViewForwarder::~SvxEditEngineViewForwarder() +{ +} + +BOOL SvxEditEngineViewForwarder::IsValid() const +{ + return sal_True; +} + +Rectangle SvxEditEngineViewForwarder::GetVisArea() const +{ + OutputDevice* pOutDev = mrView.GetWindow(); + + if( pOutDev ) + { + Rectangle aVisArea = mrView.GetVisArea(); + + // figure out map mode from edit engine + EditEngine* pEditEngine = mrView.GetEditEngine(); + + if( pEditEngine ) + { + MapMode aMapMode(pOutDev->GetMapMode()); + aVisArea = OutputDevice::LogicToLogic( aVisArea, + pEditEngine->GetRefMapMode(), + aMapMode.GetMapUnit() ); + aMapMode.SetOrigin(Point()); + return pOutDev->LogicToPixel( aVisArea, aMapMode ); + } + } + + return Rectangle(); +} + +Point SvxEditEngineViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + OutputDevice* pOutDev = mrView.GetWindow(); + + if( pOutDev ) + { + MapMode aMapMode(pOutDev->GetMapMode()); + Point aPoint( OutputDevice::LogicToLogic( rPoint, rMapMode, + aMapMode.GetMapUnit() ) ); + aMapMode.SetOrigin(Point()); + return pOutDev->LogicToPixel( aPoint, aMapMode ); + } + + return Point(); +} + +Point SvxEditEngineViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + OutputDevice* pOutDev = mrView.GetWindow(); + + if( pOutDev ) + { + MapMode aMapMode(pOutDev->GetMapMode()); + aMapMode.SetOrigin(Point()); + Point aPoint( pOutDev->PixelToLogic( rPoint, aMapMode ) ); + return OutputDevice::LogicToLogic( aPoint, + aMapMode.GetMapUnit(), + rMapMode ); + } + + return Point(); +} + +sal_Bool SvxEditEngineViewForwarder::GetSelection( ESelection& rSelection ) const +{ + rSelection = mrView.GetSelection(); + return sal_True; +} + +sal_Bool SvxEditEngineViewForwarder::SetSelection( const ESelection& rSelection ) +{ + mrView.SetSelection( rSelection ); + return sal_True; +} + +sal_Bool SvxEditEngineViewForwarder::Copy() +{ + mrView.Copy(); + return sal_True; +} + +sal_Bool SvxEditEngineViewForwarder::Cut() +{ + mrView.Cut(); + return sal_True; +} + +sal_Bool SvxEditEngineViewForwarder::Paste() +{ + mrView.Paste(); + return sal_True; +} diff --git a/editeng/source/uno/unoviwou.cxx b/editeng/source/uno/unoviwou.cxx new file mode 100644 index 000000000000..f7c5446772dd --- /dev/null +++ b/editeng/source/uno/unoviwou.cxx @@ -0,0 +1,176 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: unoviwou.cxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <vcl/outdev.hxx> +#include <vcl/window.hxx> + +#include <editeng/unoviwou.hxx> +#include <editeng/outliner.hxx> +#include <editeng/editeng.hxx> + +SvxDrawOutlinerViewForwarder::SvxDrawOutlinerViewForwarder( OutlinerView& rOutl ) : + mrOutlinerView ( rOutl ), maTextShapeTopLeft() +{ +} + +SvxDrawOutlinerViewForwarder::SvxDrawOutlinerViewForwarder( OutlinerView& rOutl, const Point& rShapePosTopLeft ) : + mrOutlinerView ( rOutl ), maTextShapeTopLeft( rShapePosTopLeft ) +{ +} + +SvxDrawOutlinerViewForwarder::~SvxDrawOutlinerViewForwarder() +{ +} + +Point SvxDrawOutlinerViewForwarder::GetTextOffset() const +{ + // #101029# calc text offset from shape anchor + Rectangle aOutputRect( mrOutlinerView.GetOutputArea() ); + + return aOutputRect.TopLeft() - maTextShapeTopLeft; +} + +BOOL SvxDrawOutlinerViewForwarder::IsValid() const +{ + return sal_True; +} + +Rectangle SvxDrawOutlinerViewForwarder::GetVisArea() const +{ + OutputDevice* pOutDev = mrOutlinerView.GetWindow(); + + if( pOutDev ) + { + Rectangle aVisArea = mrOutlinerView.GetVisArea(); + + // #101029# + Point aTextOffset( GetTextOffset() ); + aVisArea.Move( aTextOffset.X(), aTextOffset.Y() ); + + // figure out map mode from edit engine + Outliner* pOutliner = mrOutlinerView.GetOutliner(); + + if( pOutliner ) + { + MapMode aMapMode(pOutDev->GetMapMode()); + aVisArea = OutputDevice::LogicToLogic( aVisArea, + pOutliner->GetRefMapMode(), + aMapMode.GetMapUnit() ); + aMapMode.SetOrigin(Point()); + return pOutDev->LogicToPixel( aVisArea, aMapMode ); + } + } + + return Rectangle(); +} + +Point SvxDrawOutlinerViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + OutputDevice* pOutDev = mrOutlinerView.GetWindow(); + + if( pOutDev ) + { + Point aPoint1( rPoint ); + Point aTextOffset( GetTextOffset() ); + + // #101029# + aPoint1.X() += aTextOffset.X(); + aPoint1.Y() += aTextOffset.Y(); + + MapMode aMapMode(pOutDev->GetMapMode()); + Point aPoint2( OutputDevice::LogicToLogic( aPoint1, rMapMode, + aMapMode.GetMapUnit() ) ); + aMapMode.SetOrigin(Point()); + return pOutDev->LogicToPixel( aPoint2, aMapMode ); + } + + return Point(); +} + +Point SvxDrawOutlinerViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + OutputDevice* pOutDev = mrOutlinerView.GetWindow(); + + if( pOutDev ) + { + MapMode aMapMode(pOutDev->GetMapMode()); + aMapMode.SetOrigin(Point()); + Point aPoint1( pOutDev->PixelToLogic( rPoint, aMapMode ) ); + Point aPoint2( OutputDevice::LogicToLogic( aPoint1, + aMapMode.GetMapUnit(), + rMapMode ) ); + // #101029# + Point aTextOffset( GetTextOffset() ); + + aPoint2.X() -= aTextOffset.X(); + aPoint2.Y() -= aTextOffset.Y(); + + return aPoint2; + } + + return Point(); +} + +sal_Bool SvxDrawOutlinerViewForwarder::GetSelection( ESelection& rSelection ) const +{ + rSelection = mrOutlinerView.GetSelection(); + return sal_True; +} + +sal_Bool SvxDrawOutlinerViewForwarder::SetSelection( const ESelection& rSelection ) +{ + mrOutlinerView.SetSelection( rSelection ); + return sal_True; +} + +sal_Bool SvxDrawOutlinerViewForwarder::Copy() +{ + mrOutlinerView.Copy(); + return sal_True; +} + +sal_Bool SvxDrawOutlinerViewForwarder::Cut() +{ + mrOutlinerView.Cut(); + return sal_True; +} + +sal_Bool SvxDrawOutlinerViewForwarder::Paste() +{ + mrOutlinerView.Paste(); + return sal_True; +} + +void SvxDrawOutlinerViewForwarder::SetShapePos( const Point& rShapePosTopLeft ) +{ + maTextShapeTopLeft = rShapePosTopLeft; +} diff --git a/editeng/source/xml/editsource.hxx b/editeng/source/xml/editsource.hxx new file mode 100644 index 000000000000..d74e603ba9aa --- /dev/null +++ b/editeng/source/xml/editsource.hxx @@ -0,0 +1,55 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: editsource.hxx,v $ + * $Revision: 1.8 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _SVX_EDITSOURCE_HXX +#define _SVX_EDITSOURCE_HXX + +#include <editeng/unoedsrc.hxx> + +class EditEngine; +class SvxEditEngineSourceImpl; + +class SvxEditEngineSource : public SvxEditSource +{ +public: + SvxEditEngineSource( EditEngine* pEditEngine ); + virtual ~SvxEditEngineSource(); + + virtual SvxEditSource* Clone() const; + virtual SvxTextForwarder* GetTextForwarder(); + virtual void UpdateData(); + +private: + SvxEditEngineSource( SvxEditEngineSourceImpl* pImpl ); + + SvxEditEngineSourceImpl* mpImpl; +}; + +#endif diff --git a/editeng/source/xml/makefile.mk b/editeng/source/xml/makefile.mk new file mode 100644 index 000000000000..bfcfeb70f123 --- /dev/null +++ b/editeng/source/xml/makefile.mk @@ -0,0 +1,50 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.12 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=editeng +TARGET=xml + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- +SLOFILES = \ + $(SLO)$/xmltxtimp.obj \ + $(SLO)$/xmltxtexp.obj + +# --- Targets -------------------------------------------------------------- + +.INCLUDE : target.mk diff --git a/editeng/source/xml/xmltxtexp.cxx b/editeng/source/xml/xmltxtexp.cxx new file mode 100644 index 000000000000..aeada17eb913 --- /dev/null +++ b/editeng/source/xml/xmltxtexp.cxx @@ -0,0 +1,503 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xmltxtexp.cxx,v $ + * $Revision: 1.15 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" + +/** this file implements an export of a selected EditEngine content into + a xml stream. See editeng/source/inc/xmledit.hxx for interface */ +#include <com/sun/star/ucb/XAnyCompareFactory.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <tools/debug.hxx> +#include <svl/itemprop.hxx> +#include <svl/brdcst.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <sot/storage.hxx> +#include <rtl/ustrbuf.hxx> +#include <xmloff/xmluconv.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmlmetae.hxx> +#include <cppuhelper/implbase4.hxx> +#include <comphelper/processfactory.hxx> +#include <unotools/streamwrap.hxx> +#include <xmloff/xmlexp.hxx> +#include <editeng/unoedsrc.hxx> +#include <editeng/unofored.hxx> +#include <editeng/unotext.hxx> +#include <editeng/unoprnms.hxx> +#include <editeng/unofield.hxx> +#include <editeng/editeng.hxx> +#include "editsource.hxx" +#include <editeng/unonrule.hxx> +#include <editeng/unoipset.hxx> + +using namespace com::sun::star; +using namespace com::sun::star::container; +using namespace com::sun::star::document; +using namespace com::sun::star::uno; +using namespace com::sun::star::awt; +using namespace com::sun::star::lang; +using namespace com::sun::star::xml::sax; +using namespace ::rtl; +using namespace cppu; + +/////////////////////////////////////////////////////////////////////// + +class SvxEditEngineSourceImpl; + +/////////////////////////////////////////////////////////////////////// + +class SvxEditEngineSourceImpl +{ +private: + oslInterlockedCount maRefCount; + + EditEngine* mpEditEngine; + SvxTextForwarder* mpTextForwarder; + + ~SvxEditEngineSourceImpl(); + +public: + SvxEditEngineSourceImpl( EditEngine* pEditEngine ); + + void SAL_CALL acquire(); + void SAL_CALL release(); + + SvxTextForwarder* GetTextForwarder(); +}; + +/////////////////////////////////////////////////////////////////////// + + +//------------------------------------------------------------------------ + +SvxEditEngineSourceImpl::SvxEditEngineSourceImpl( EditEngine* pEditEngine ) +: maRefCount(0), + mpEditEngine( pEditEngine ), + mpTextForwarder(NULL) +{ +} + +//------------------------------------------------------------------------ + +SvxEditEngineSourceImpl::~SvxEditEngineSourceImpl() +{ + delete mpTextForwarder; +} + +//------------------------------------------------------------------------ + +void SAL_CALL SvxEditEngineSourceImpl::acquire() +{ + osl_incrementInterlockedCount( &maRefCount ); +} + +//------------------------------------------------------------------------ + +void SAL_CALL SvxEditEngineSourceImpl::release() +{ + if( ! osl_decrementInterlockedCount( &maRefCount ) ) + delete this; +} + +//------------------------------------------------------------------------ + +SvxTextForwarder* SvxEditEngineSourceImpl::GetTextForwarder() +{ + if (!mpTextForwarder) + mpTextForwarder = new SvxEditEngineForwarder( *mpEditEngine ); + + return mpTextForwarder; +} + +// -------------------------------------------------------------------- +// SvxTextEditSource +// -------------------------------------------------------------------- + +SvxEditEngineSource::SvxEditEngineSource( EditEngine* pEditEngine ) +{ + mpImpl = new SvxEditEngineSourceImpl( pEditEngine ); + mpImpl->acquire(); +} + +// -------------------------------------------------------------------- + +SvxEditEngineSource::SvxEditEngineSource( SvxEditEngineSourceImpl* pImpl ) +{ + mpImpl = pImpl; + mpImpl->acquire(); +} + +//------------------------------------------------------------------------ + +SvxEditEngineSource::~SvxEditEngineSource() +{ + mpImpl->release(); +} + +//------------------------------------------------------------------------ + +SvxEditSource* SvxEditEngineSource::Clone() const +{ + return new SvxEditEngineSource( mpImpl ); +} + +//------------------------------------------------------------------------ + +SvxTextForwarder* SvxEditEngineSource::GetTextForwarder() +{ + return mpImpl->GetTextForwarder(); +} + +//------------------------------------------------------------------------ + +void SvxEditEngineSource::UpdateData() +{ +} + +class SvxSimpleUnoModel : public cppu::WeakAggImplHelper4< + ::com::sun::star::frame::XModel, + ::com::sun::star::ucb::XAnyCompareFactory, + ::com::sun::star::style::XStyleFamiliesSupplier, + ::com::sun::star::lang::XMultiServiceFactory > +{ +public: + SvxSimpleUnoModel(); + virtual ~SvxSimpleUnoModel(); + + + // XMultiServiceFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstance( const ::rtl::OUString& aServiceSpecifier ) throw(::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& Arguments ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getAvailableServiceNames( ) throw(::com::sun::star::uno::RuntimeException); + + // XStyleFamiliesSupplier + virtual ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameAccess > SAL_CALL getStyleFamilies( ) throw(::com::sun::star::uno::RuntimeException); + + // XAnyCompareFactory + virtual ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XAnyCompare > SAL_CALL createAnyCompareByName( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::uno::RuntimeException); + + // XModel + virtual sal_Bool SAL_CALL attachResource( const ::rtl::OUString& aURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs ) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getURL( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL getArgs( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL connectController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& xController ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL disconnectController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& xController ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL lockControllers( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL unlockControllers( ) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL hasControllersLocked( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController > SAL_CALL getCurrentController( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setCurrentController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& xController ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getCurrentSelection( ) throw (::com::sun::star::uno::RuntimeException); + + // XComponent + virtual void SAL_CALL dispose( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + +}; + +SvxSimpleUnoModel::SvxSimpleUnoModel() +{ +} + +SvxSimpleUnoModel::~SvxSimpleUnoModel() +{ +} + +// XMultiServiceFactory ( SvxFmMSFactory ) +uno::Reference< uno::XInterface > SAL_CALL SvxSimpleUnoModel::createInstance( const OUString& aServiceSpecifier ) + throw(uno::Exception, uno::RuntimeException) +{ + if( 0 == aServiceSpecifier.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.text.NumberingRules" ) ) ) + { + return uno::Reference< uno::XInterface >( + SvxCreateNumRule(), uno::UNO_QUERY ); + } + if ( (0 == aServiceSpecifier.reverseCompareToAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.text.textfield.DateTime"))) + || (0 == aServiceSpecifier.reverseCompareToAsciiL( + RTL_CONSTASCII_STRINGPARAM("com.sun.star.text.TextField.DateTime"))) + ) + { + return (::cppu::OWeakObject * )new SvxUnoTextField( ID_EXT_DATEFIELD ); + } + + return SvxUnoTextCreateTextField( aServiceSpecifier ); + +} + +uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SvxSimpleUnoModel::createInstanceWithArguments( const ::rtl::OUString& ServiceSpecifier, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& ) throw (::com::sun::star::uno::Exception, ::com::sun::star::uno::RuntimeException) +{ + return createInstance( ServiceSpecifier ); +} + +Sequence< ::rtl::OUString > SAL_CALL SvxSimpleUnoModel::getAvailableServiceNames( ) throw(::com::sun::star::uno::RuntimeException) +{ + Sequence< OUString > aSeq; + return aSeq; +} + +// XAnyCompareFactory +uno::Reference< com::sun::star::ucb::XAnyCompare > SAL_CALL SvxSimpleUnoModel::createAnyCompareByName( const OUString& PropertyName ) + throw(uno::RuntimeException) +{ + (void)PropertyName; + return SvxCreateNumRuleCompare(); +} + +// XStyleFamiliesSupplier +uno::Reference< container::XNameAccess > SAL_CALL SvxSimpleUnoModel::getStyleFamilies( ) + throw(uno::RuntimeException) +{ + uno::Reference< container::XNameAccess > xStyles; + return xStyles; +} + +// XModel +sal_Bool SAL_CALL SvxSimpleUnoModel::attachResource( const ::rtl::OUString& aURL, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& aArgs ) throw (::com::sun::star::uno::RuntimeException) +{ + (void)aURL; + (void)aArgs; + return sal_False; +} + +::rtl::OUString SAL_CALL SvxSimpleUnoModel::getURL( ) throw (::com::sun::star::uno::RuntimeException) +{ + OUString aStr; + return aStr; +} + +::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > SAL_CALL SvxSimpleUnoModel::getArgs( ) throw (::com::sun::star::uno::RuntimeException) +{ + Sequence< beans::PropertyValue > aSeq; + return aSeq; +} + +void SAL_CALL SvxSimpleUnoModel::connectController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +void SAL_CALL SvxSimpleUnoModel::disconnectController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +void SAL_CALL SvxSimpleUnoModel::lockControllers( ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +void SAL_CALL SvxSimpleUnoModel::unlockControllers( ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +sal_Bool SAL_CALL SvxSimpleUnoModel::hasControllersLocked( ) throw (::com::sun::star::uno::RuntimeException) +{ + return sal_True; +} + +::com::sun::star::uno::Reference< ::com::sun::star::frame::XController > SAL_CALL SvxSimpleUnoModel::getCurrentController( ) throw (::com::sun::star::uno::RuntimeException) +{ + uno::Reference< frame::XController > xRet; + return xRet; +} + +void SAL_CALL SvxSimpleUnoModel::setCurrentController( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XController >& ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException) +{ +} + +::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL SvxSimpleUnoModel::getCurrentSelection( ) throw (::com::sun::star::uno::RuntimeException) +{ + uno::Reference< XInterface > xRet; + return xRet; +} + + +// XComponent +void SAL_CALL SvxSimpleUnoModel::dispose( ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +void SAL_CALL SvxSimpleUnoModel::addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +void SAL_CALL SvxSimpleUnoModel::removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XEventListener >& ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +/////////////////////////////////////////////////////////////////////// + +class SvxXMLTextExportComponent : public SvXMLExport +{ +public: + // #110680# + SvxXMLTextExportComponent( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + EditEngine* pEditEngine, + const ESelection& rSel, + const ::rtl::OUString& rFileName, + const com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler > & xHandler ); + + ~SvxXMLTextExportComponent(); + + // methods without content: + virtual void _ExportAutoStyles(); + virtual void _ExportMasterStyles(); + virtual void _ExportContent(); + +private: + com::sun::star::uno::Reference< com::sun::star::text::XText > mxText; + EditEngine* mpEditEngine; + ESelection maSelection; +}; + +/////////////////////////////////////////////////////////////////////// + +// #110680# +SvxXMLTextExportComponent::SvxXMLTextExportComponent( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + EditEngine* pEditEngine, + const ESelection& rSel, + const ::rtl::OUString& rFileName, + const com::sun::star::uno::Reference< com::sun::star::xml::sax::XDocumentHandler > & xHandler) +: SvXMLExport( xServiceFactory, rFileName, xHandler, ((frame::XModel*)new SvxSimpleUnoModel()), MAP_CM ), + mpEditEngine( pEditEngine ), + maSelection( rSel ) +{ + SvxEditEngineSource aEditSource( pEditEngine ); + + static const SfxItemPropertyMapEntry SvxXMLTextExportComponentPropertyMap[] = + { + SVX_UNOEDIT_CHAR_PROPERTIES, + SVX_UNOEDIT_FONT_PROPERTIES, +// SVX_UNOEDIT_OUTLINER_PROPERTIES, + {MAP_CHAR_LEN(UNO_NAME_NUMBERING_RULES), EE_PARA_NUMBULLET, &::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexReplace>*)0), 0, 0 }, + {MAP_CHAR_LEN(UNO_NAME_NUMBERING), EE_PARA_BULLETSTATE,&::getBooleanCppuType(), 0, 0 }, + {MAP_CHAR_LEN(UNO_NAME_NUMBERING_LEVEL), EE_PARA_OUTLLEVEL, &::getCppuType((const sal_Int16*)0), 0, 0 }, + SVX_UNOEDIT_PARA_PROPERTIES, + {0,0,0,0,0,0} + }; + static SvxItemPropertySet aSvxXMLTextExportComponentPropertySet( SvxXMLTextExportComponentPropertyMap, EditEngine::GetGlobalItemPool() ); + + SvxUnoText* pUnoText = new SvxUnoText( &aEditSource, &aSvxXMLTextExportComponentPropertySet, mxText ); + pUnoText->SetSelection( rSel ); + mxText = pUnoText; + + setExportFlags( EXPORT_AUTOSTYLES|EXPORT_CONTENT ); +} + +SvxXMLTextExportComponent::~SvxXMLTextExportComponent() +{ +} + +void SvxWriteXML( EditEngine& rEditEngine, SvStream& rStream, const ESelection& rSel ) +{ + try + { + do + { + // create service factory + + uno::Reference< lang::XMultiServiceFactory> xServiceFactory( ::comphelper::getProcessServiceFactory() ); + + if( !xServiceFactory.is() ) + { + DBG_ERROR( "got no service manager" ); + break; + } + + // create document handler + + uno::Reference< uno::XInterface > xWriter( xServiceFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.Writer" ) ) ) ); + + if( !xWriter.is() ) + { + DBG_ERROR( "com.sun.star.xml.sax.Writer service missing" ); + break; + } + + uno::Reference<xml::sax::XDocumentHandler> xHandler( xWriter, uno::UNO_QUERY ); + + // create output stream and active data source + uno::Reference<io::XOutputStream> xOut( new utl::OOutputStreamWrapper( rStream ) ); + +/* testcode + const OUString aURL( RTL_CONSTASCII_USTRINGPARAM( "file:///e:/test.xml" ) ); + SfxMedium aMedium( aURL, STREAM_WRITE | STREAM_TRUNC, TRUE ); + aMedium.IsRemote(); + uno::Reference<io::XOutputStream> xOut( new utl::OOutputStreamWrapper( *aMedium.GetOutStream() ) ); +*/ + + + uno::Reference<io::XActiveDataSource> xMetaSrc( xWriter, uno::UNO_QUERY ); + xMetaSrc->setOutputStream( xOut ); + + // export text + const OUString aName; + + // #110680# + // SvxXMLTextExportComponent aExporter( &rEditEngine, rSel, aName, xHandler ); + SvxXMLTextExportComponent aExporter( xServiceFactory, &rEditEngine, rSel, aName, xHandler ); + + aExporter.exportDoc(); + +/* testcode + aMedium.Commit(); +*/ + + } + while( 0 ); + } + catch( uno::Exception& ) + { + DBG_ERROR("exception during xml export"); + } +} + +// methods without content: +void SvxXMLTextExportComponent::_ExportAutoStyles() +{ + UniReference< XMLTextParagraphExport > xTextExport( GetTextParagraphExport() ); + + xTextExport->collectTextAutoStyles( mxText ); + xTextExport->exportTextAutoStyles(); +} + +void SvxXMLTextExportComponent::_ExportContent() +{ + UniReference< XMLTextParagraphExport > xTextExport( GetTextParagraphExport() ); + + xTextExport->exportText( mxText ); +} + +void SvxXMLTextExportComponent::_ExportMasterStyles() {} diff --git a/editeng/source/xml/xmltxtimp.cxx b/editeng/source/xml/xmltxtimp.cxx new file mode 100644 index 000000000000..ef36b91cb185 --- /dev/null +++ b/editeng/source/xml/xmltxtimp.cxx @@ -0,0 +1,263 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: xmltxtimp.cxx,v $ + * $Revision: 1.11 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_editeng.hxx" +#include <tools/debug.hxx> +#include <com/sun/star/io/XActiveDataControl.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/xml/sax/XParser.hpp> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/text/XText.hpp> +#include <comphelper/processfactory.hxx> +#include <unotools/streamwrap.hxx> +#include <rtl/ustrbuf.hxx> +#include <sot/storage.hxx> +#include <svl/itemprop.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlmetae.hxx> +#include <xmloff/xmlictxt.hxx> +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <xmloff/xmlstyle.hxx> +#include "editsource.hxx" +#include <editeng/editeng.hxx> +#include <editeng/unotext.hxx> +#include <editeng/unoprnms.hxx> +#include <editeng/unoipset.hxx> + +using namespace com::sun::star; +using namespace com::sun::star::document; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::xml::sax; +using namespace com::sun::star::text; +using namespace ::rtl; +using namespace cppu; +using namespace xmloff::token; + + +/////////////////////////////////////////////////////////////////////// + +class SvxXMLTextImportContext : public SvXMLImportContext +{ +public: + SvxXMLTextImportContext( SvXMLImport& rImport, USHORT nPrfx, const OUString& rLName, const uno::Reference< XAttributeList >& xAttrList, const uno::Reference< XText >& xText ); + virtual ~SvxXMLTextImportContext(); + + virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix, const OUString& rLocalName, const uno::Reference< XAttributeList >& xAttrList ); + +// SvxXMLXTableImport& getImport() const { return *(SvxXMLXTableImport*)&GetImport(); } + +private: + const uno::Reference< XText > mxText; +}; + +/////////////////////////////////////////////////////////////////////// + +SvxXMLTextImportContext::SvxXMLTextImportContext( SvXMLImport& rImport, USHORT nPrfx, const OUString& rLName, const uno::Reference< XAttributeList >&, const uno::Reference< XText >& xText ) +: SvXMLImportContext( rImport, nPrfx, rLName ), mxText( xText ) +{ +} + +SvxXMLTextImportContext::~SvxXMLTextImportContext() +{ +} + +SvXMLImportContext *SvxXMLTextImportContext::CreateChildContext( USHORT nPrefix, const OUString& rLocalName, const uno::Reference< XAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = NULL; + if(XML_NAMESPACE_OFFICE == nPrefix && IsXMLToken( rLocalName, XML_BODY ) ) + { + pContext = new SvxXMLTextImportContext( GetImport(), nPrefix, rLocalName, xAttrList, mxText ); + } + else if( XML_NAMESPACE_OFFICE == nPrefix && IsXMLToken( rLocalName, XML_AUTOMATIC_STYLES ) ) + { + pContext = new SvXMLStylesContext( GetImport(), nPrefix, rLocalName, xAttrList ); + GetImport().GetTextImport()->SetAutoStyles( (SvXMLStylesContext*)pContext ); + + } + else + { + pContext = GetImport().GetTextImport()->CreateTextChildContext( GetImport(), nPrefix, rLocalName, xAttrList ); + } + + if( NULL == pContext ) + pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName ); + + return pContext; +} + +/////////////////////////////////////////////////////////////////////// + +class SvxXMLXTextImportComponent : public SvXMLImport +{ +public: + // #110680# + SvxXMLXTextImportComponent( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const uno::Reference< XText > & xText ); + + virtual ~SvxXMLXTextImportComponent() throw (); + + static sal_Bool load( const rtl::OUString& rUrl, const com::sun::star::uno::Reference< com::sun::star::container::XNameContainer >& xTable ) throw(); +protected: + virtual SvXMLImportContext *CreateChildContext( USHORT nPrefix, const OUString& rLocalName, const uno::Reference< XAttributeList >& xAttrList ); + +private: + const uno::Reference< XText > mxText; +}; + +// -------------------------------------------------------------------- + +// #110680# +SvxXMLXTextImportComponent::SvxXMLXTextImportComponent( + const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceFactory, + const uno::Reference< XText > & xText ) +: SvXMLImport(xServiceFactory), + mxText( xText ) +{ + GetTextImport()->SetCursor( mxText->createTextCursor() ); +} + +SvxXMLXTextImportComponent::~SvxXMLXTextImportComponent() throw () +{ +} + +void SvxReadXML( EditEngine& rEditEngine, SvStream& rStream, const ESelection& rSel ) +{ + SvxEditEngineSource aEditSource( &rEditEngine ); + + static const SfxItemPropertyMapEntry SvxXMLTextImportComponentPropertyMap[] = + { + SVX_UNOEDIT_CHAR_PROPERTIES, + SVX_UNOEDIT_FONT_PROPERTIES, +// SVX_UNOEDIT_OUTLINER_PROPERTIES, + SVX_UNOEDIT_PARA_PROPERTIES, + {0,0,0,0,0,0} + }; + static SvxItemPropertySet aSvxXMLTextImportComponentPropertySet( SvxXMLTextImportComponentPropertyMap, EditEngine::GetGlobalItemPool() ); + + uno::Reference<text::XText > xParent; + SvxUnoText* pUnoText = new SvxUnoText( &aEditSource, &aSvxXMLTextImportComponentPropertySet, xParent ); + pUnoText->SetSelection( rSel ); + uno::Reference<text::XText > xText( pUnoText ); + + try + { + do + { + uno::Reference<lang::XMultiServiceFactory> xServiceFactory( ::comphelper::getProcessServiceFactory() ); + if( !xServiceFactory.is() ) + { + DBG_ERROR( "SvxXMLXTableImport::load: got no service manager" ); + break; + } + + uno::Reference< xml::sax::XParser > xParser( xServiceFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.xml.sax.Parser" ) ) ), uno::UNO_QUERY ); + if( !xParser.is() ) + { + DBG_ERROR( "com.sun.star.xml.sax.Parser service missing" ); + break; + } + + uno::Reference<io::XInputStream> xInputStream = new utl::OInputStreamWrapper( rStream ); + +/* testcode + const OUString aURL( RTL_CONSTASCII_USTRINGPARAM( "file:///e:/test.xml" ) ); + SfxMedium aMedium( aURL, STREAM_READ | STREAM_NOCREATE, TRUE ); + aMedium.IsRemote(); + uno::Reference<io::XOutputStream> xOut( new utl::OOutputStreamWrapper( *aMedium.GetOutStream() ) ); + + aMedium.GetInStream()->Seek( 0 ); + uno::Reference< io::XActiveDataSource > xSource( aMedium.GetDataSource() ); + + if( !xSource.is() ) + { + DBG_ERROR( "got no data source from medium" ); + break; + } + + uno::Reference< XInterface > xPipe( xServiceFactory->createInstance(OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.io.Pipe") ) ) ); + if( !xPipe.is() ) + { + DBG_ERROR( "XMLReader::Read: com.sun.star.io.Pipe service missing" ); + break; + } + + // connect pipe's output stream to the data source + xSource->setOutputStream( uno::Reference< io::XOutputStream >::query( xPipe ) ); + + xml::sax::InputSource aParserInput; + aParserInput.aInputStream = uno::Reference< io::XInputStream >::query( xPipe ); + aParserInput.sSystemId = aMedium.GetName(); + + + if( xSource.is() ) + { + uno::Reference< io::XActiveDataControl > xSourceControl( xSource, UNO_QUERY ); + xSourceControl->start(); + } + +*/ + + // #110680# + // uno::Reference< XDocumentHandler > xHandler( new SvxXMLXTextImportComponent( xText ) ); + uno::Reference< XDocumentHandler > xHandler( new SvxXMLXTextImportComponent( xServiceFactory, xText ) ); + + xParser->setDocumentHandler( xHandler ); + + xml::sax::InputSource aParserInput; + aParserInput.aInputStream = xInputStream; +// aParserInput.sSystemId = aMedium.GetName(); + xParser->parseStream( aParserInput ); + } + while(0); + } + catch( uno::Exception& ) + { + } +} + +SvXMLImportContext *SvxXMLXTextImportComponent::CreateChildContext( USHORT nPrefix, const OUString& rLocalName, const uno::Reference< XAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext; + if(XML_NAMESPACE_OFFICE == nPrefix && ( IsXMLToken( rLocalName, XML_DOCUMENT ) || IsXMLToken( rLocalName, XML_DOCUMENT_CONTENT ) ) ) + { + pContext = new SvxXMLTextImportContext(*this, nPrefix, rLocalName, xAttrList, mxText ); + } + else + { + pContext = SvXMLImport::CreateContext(nPrefix, rLocalName, xAttrList); + } + return pContext; +} + |