diff options
Diffstat (limited to 'svx/source/table')
40 files changed, 19551 insertions, 0 deletions
diff --git a/svx/source/table/accessiblecell.cxx b/svx/source/table/accessiblecell.cxx new file mode 100644 index 000000000000..71b94d021650 --- /dev/null +++ b/svx/source/table/accessiblecell.cxx @@ -0,0 +1,584 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <accessiblecell.hxx> + +#include "DescriptionGenerator.hxx" + +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <vcl/svapp.hxx> + +#include <unotools/accessiblestatesethelper.hxx> + +#include <editeng/outlobj.hxx> +#include <svx/unoshtxt.hxx> +#include <svx/svdotext.hxx> + +using ::rtl::OUString; +using namespace ::sdr::table; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; + +namespace accessibility { + +// -------------------------------------------------------------------- +// AccessibleCell +// -------------------------------------------------------------------- + +AccessibleCell::AccessibleCell( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxParent, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo ) +: AccessibleCellBase( rxParent, AccessibleRole::TABLE_CELL ) +, maShapeTreeInfo( rShapeTreeInfo ) +, mnIndexInParent( nIndex ) +, mpText( NULL ) +, mxCell( rCell ) +{ +} + +// -------------------------------------------------------------------- + +AccessibleCell::~AccessibleCell (void) +{ + DBG_ASSERT( mpText == 0, "svx::AccessibleCell::~AccessibleCell(), not disposed!?" ); +} + +// -------------------------------------------------------------------- + +void AccessibleCell::Init (void) +{ + SdrView* pView = maShapeTreeInfo.GetSdrView(); + const Window* pWindow = maShapeTreeInfo.GetWindow (); + if( (pView != NULL) && (pWindow != NULL) && mxCell.is()) + { + OutlinerParaObject* pOutlinerParaObject = mxCell->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active + + bool bOwnParaObject = pOutlinerParaObject != 0; + + if( !pOutlinerParaObject ) + pOutlinerParaObject = mxCell->GetOutlinerParaObject(); + + // create AccessibleTextHelper to handle this shape's text + if( pOutlinerParaObject ) + { + // non-empty text -> use full-fledged edit source right away + ::std::auto_ptr<SvxEditSource> pEditSource( new SvxTextEditSource( mxCell->GetObject(), mxCell.get(), *pView, *pWindow) ); + mpText = new AccessibleTextHelper( pEditSource ); + mpText->SetEventSource(this); + } + + if( bOwnParaObject) + delete pOutlinerParaObject; + } +} + +// -------------------------------------------------------------------- + +sal_Bool AccessibleCell::SetState (sal_Int16 aState) +{ + sal_Bool bStateHasChanged = sal_False; + + if (aState == AccessibleStateType::FOCUSED && mpText != NULL) + { + // Offer FOCUSED state to edit engine and detect whether the state + // changes. + sal_Bool bIsFocused = mpText->HaveFocus (); + mpText->SetFocus (sal_True); + bStateHasChanged = (bIsFocused != mpText->HaveFocus ()); + } + else + bStateHasChanged = AccessibleContextBase::SetState (aState); + + return bStateHasChanged; +} + +// -------------------------------------------------------------------- + +sal_Bool AccessibleCell::ResetState (sal_Int16 aState) +{ + sal_Bool bStateHasChanged = sal_False; + + if (aState == AccessibleStateType::FOCUSED && mpText != NULL) + { + // Try to remove FOCUSED state from the edit engine and detect + // whether the state changes. + sal_Bool bIsFocused = mpText->HaveFocus (); + mpText->SetFocus (sal_False); + bStateHasChanged = (bIsFocused != mpText->HaveFocus ()); + } + else + bStateHasChanged = AccessibleContextBase::ResetState (aState); + + return bStateHasChanged; +} + +// -------------------------------------------------------------------- + +sal_Bool AccessibleCell::GetState (sal_Int16 aState) +{ + if (aState == AccessibleStateType::FOCUSED && mpText != NULL) + { + // Just delegate the call to the edit engine. The state is not + // merged into the state set. + return mpText->HaveFocus(); + } + else + return AccessibleContextBase::GetState (aState); +} + +//----------------------------------------------------------------------------- + +bool AccessibleCell::operator== (const AccessibleCell& rAccessibleCell) +{ + return this == &rAccessibleCell; +} + +//----------------------------------------------------------------------------- +// XInterface +//----------------------------------------------------------------------------- + +Any SAL_CALL AccessibleCell::queryInterface( const Type& aType ) throw (RuntimeException) +{ + return AccessibleCellBase::queryInterface( aType ); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL AccessibleCell::acquire( ) throw () +{ + AccessibleCellBase::acquire(); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL AccessibleCell::release( ) throw () +{ + AccessibleCellBase::release(); +} + +// -------------------------------------------------------------------- +// XAccessibleContext +// -------------------------------------------------------------------- + +/** The children of this cell come from the paragraphs of text. +*/ +sal_Int32 SAL_CALL AccessibleCell::getAccessibleChildCount() throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + ThrowIfDisposed (); + return mpText != NULL ? mpText->GetChildCount () : 0; +} + +// -------------------------------------------------------------------- + +/** Forward the request to the shape. Return the requested shape or throw + an exception for a wrong index. +*/ +Reference<XAccessible> SAL_CALL AccessibleCell::getAccessibleChild (sal_Int32 nIndex) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + ThrowIfDisposed (); + + // todo: does GetChild throw IndexOutOfBoundsException? + return mpText->GetChild (nIndex); +} + +// -------------------------------------------------------------------- + +/** Return a copy of the state set. + Possible states are: + ENABLED + SHOWING + VISIBLE +*/ +Reference<XAccessibleStateSet> SAL_CALL AccessibleCell::getAccessibleStateSet (void) throw (RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + ::osl::MutexGuard aGuard (maMutex); + Reference<XAccessibleStateSet> xStateSet; + + if (rBHelper.bDisposed || mpText == NULL) + { + // Return a minimal state set that only contains the DEFUNC state. + xStateSet = AccessibleContextBase::getAccessibleStateSet (); + } + else + { + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + + if(pStateSet) + { + // Merge current FOCUSED state from edit engine. + if (mpText != NULL) + { + if (mpText->HaveFocus()) + pStateSet->AddState (AccessibleStateType::FOCUSED); + else + pStateSet->RemoveState (AccessibleStateType::FOCUSED); + } + + // Create a copy of the state set that may be modified by the + // caller without affecting the current state set. + xStateSet = Reference<XAccessibleStateSet>(new ::utl::AccessibleStateSetHelper (*pStateSet)); + } + } + + return xStateSet; +} + +// -------------------------------------------------------------------- +// XAccessibleComponent +// -------------------------------------------------------------------- + +sal_Bool SAL_CALL AccessibleCell::containsPoint( const ::com::sun::star::awt::Point& aPoint) throw (::com::sun::star::uno::RuntimeException) +{ + return AccessibleComponentBase::containsPoint( aPoint ); +} + +/** The implementation below is at the moment straightforward. It iterates + over all children (and thereby instances all children which have not + been already instatiated) until a child covering the specifed point is + found. + This leaves room for improvement. For instance, first iterate only over + the already instantiated children and only if no match is found + instantiate the remaining ones. +*/ +Reference<XAccessible > SAL_CALL AccessibleCell::getAccessibleAtPoint ( const ::com::sun::star::awt::Point& aPoint) throw(RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + ::osl::MutexGuard aGuard (maMutex); + + sal_Int32 nChildCount = getAccessibleChildCount (); + for (sal_Int32 i=0; i<nChildCount; ++i) + { + Reference<XAccessible> xChild (getAccessibleChild (i)); + if (xChild.is()) + { + Reference<XAccessibleComponent> xChildComponent (xChild->getAccessibleContext(), uno::UNO_QUERY); + if (xChildComponent.is()) + { + awt::Rectangle aBBox (xChildComponent->getBounds()); + if ( (aPoint.X >= aBBox.X) + && (aPoint.Y >= aBBox.Y) + && (aPoint.X < aBBox.X+aBBox.Width) + && (aPoint.Y < aBBox.Y+aBBox.Height) ) + return xChild; + } + } + } + + // Have not found a child under the given point. Returning empty + // reference to indicate this. + return uno::Reference<XAccessible>(); +} + +// -------------------------------------------------------------------- + +::com::sun::star::awt::Rectangle SAL_CALL AccessibleCell::getBounds(void) throw(RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + ::osl::MutexGuard aGuard (maMutex); + + ThrowIfDisposed (); + ::com::sun::star::awt::Rectangle aBoundingBox; + if( mxCell.is() ) + { + // Get the cell's bounding box in internal coordinates (in 100th of mm) + const ::Rectangle aCellRect( mxCell->getCellRect() ); + + // Transform coordinates from internal to pixel. + if (maShapeTreeInfo.GetViewForwarder() == NULL) + throw uno::RuntimeException (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleCell has no valid view forwarder")),static_cast<uno::XWeak*>(this)); + + ::Size aPixelSize( maShapeTreeInfo.GetViewForwarder()->LogicToPixel(::Size(aCellRect.GetWidth(), aCellRect.GetHeight())) ); + ::Point aPixelPosition( maShapeTreeInfo.GetViewForwarder()->LogicToPixel( aCellRect.TopLeft() )); + + // Clip the shape's bounding box with the bounding box of its parent. + Reference<XAccessibleComponent> xParentComponent ( getAccessibleParent(), uno::UNO_QUERY); + if (xParentComponent.is()) + { + // Make the coordinates relative to the parent. + awt::Point aParentLocation (xParentComponent->getLocationOnScreen()); + int x = aPixelPosition.getX() - aParentLocation.X; + int y = aPixelPosition.getY() - aParentLocation.Y; + + // Clip with parent (with coordinates relative to itself). + ::Rectangle aBBox ( x, y, x + aPixelSize.getWidth(), y + aPixelSize.getHeight()); + awt::Size aParentSize (xParentComponent->getSize()); + ::Rectangle aParentBBox (0,0, aParentSize.Width, aParentSize.Height); + aBBox = aBBox.GetIntersection (aParentBBox); + aBoundingBox = awt::Rectangle ( aBBox.getX(), aBBox.getY(), aBBox.getWidth(), aBBox.getHeight()); + } + else + { + OSL_TRACE ("parent does not support component"); + aBoundingBox = awt::Rectangle (aPixelPosition.getX(), aPixelPosition.getY(),aPixelSize.getWidth(), aPixelSize.getHeight()); + } + } + + return aBoundingBox; +} + +// -------------------------------------------------------------------- + +::com::sun::star::awt::Point SAL_CALL AccessibleCell::getLocation(void) throw (RuntimeException) +{ + ThrowIfDisposed (); + ::com::sun::star::awt::Rectangle aBoundingBox(getBounds()); + return ::com::sun::star::awt::Point(aBoundingBox.X, aBoundingBox.Y); +} + +// -------------------------------------------------------------------- + +::com::sun::star::awt::Point SAL_CALL AccessibleCell::getLocationOnScreen(void) throw(RuntimeException) +{ + ThrowIfDisposed (); + + // Get relative position... + ::com::sun::star::awt::Point aLocation(getLocation ()); + + // ... and add absolute position of the parent. + Reference<XAccessibleComponent> xParentComponent( getAccessibleParent(), uno::UNO_QUERY); + if(xParentComponent.is()) + { + ::com::sun::star::awt::Point aParentLocation(xParentComponent->getLocationOnScreen()); + aLocation.X += aParentLocation.X; + aLocation.Y += aParentLocation.Y; + } + else + { + OSL_TRACE ("getLocation: parent does not support XAccessibleComponent"); + } + + return aLocation; +} + +// -------------------------------------------------------------------- + +awt::Size SAL_CALL AccessibleCell::getSize (void) throw (RuntimeException) +{ + ThrowIfDisposed (); + awt::Rectangle aBoundingBox (getBounds()); + return awt::Size (aBoundingBox.Width, aBoundingBox.Height); +} + +// -------------------------------------------------------------------- + +void SAL_CALL AccessibleCell::addFocusListener ( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFocusListener >& xListener) throw (::com::sun::star::uno::RuntimeException) +{ + AccessibleComponentBase::addFocusListener( xListener ); +} + +// -------------------------------------------------------------------- + +void SAL_CALL AccessibleCell::removeFocusListener (const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFocusListener >& xListener ) throw (::com::sun::star::uno::RuntimeException) +{ + AccessibleComponentBase::removeFocusListener( xListener ); +} + +// -------------------------------------------------------------------- + +void SAL_CALL AccessibleCell::grabFocus (void) throw (::com::sun::star::uno::RuntimeException) +{ + AccessibleComponentBase::grabFocus(); +} + +// -------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleCell::getForeground(void) throw (RuntimeException) +{ + ThrowIfDisposed (); + sal_Int32 nColor (0x0ffffffL); + + // todo + return nColor; +} + +// -------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleCell::getBackground (void) throw (RuntimeException) +{ + ThrowIfDisposed (); + sal_Int32 nColor (0L); + + // todo + return nColor; +} + +// -------------------------------------------------------------------- +// XAccessibleExtendedComponent +// -------------------------------------------------------------------- + +::com::sun::star::uno::Reference< ::com::sun::star::awt::XFont > SAL_CALL AccessibleCell::getFont (void) throw (::com::sun::star::uno::RuntimeException) +{ +//todo + return AccessibleComponentBase::getFont(); +} + +// -------------------------------------------------------------------- + +::rtl::OUString SAL_CALL AccessibleCell::getTitledBorderText (void) throw (::com::sun::star::uno::RuntimeException) +{ + return AccessibleComponentBase::getTitledBorderText(); +} + +// -------------------------------------------------------------------- + +::rtl::OUString SAL_CALL AccessibleCell::getToolTipText (void) throw (::com::sun::star::uno::RuntimeException) +{ + return AccessibleComponentBase::getToolTipText(); +} + +// -------------------------------------------------------------------- +// XAccessibleEventBroadcaster +// -------------------------------------------------------------------- + +void SAL_CALL AccessibleCell::addEventListener( const Reference<XAccessibleEventListener >& rxListener) throw (RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + ::osl::MutexGuard aGuard (maMutex); + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + Reference<XInterface> xSource( static_cast<XComponent *>(this) ); + lang::EventObject aEventObj(xSource); + rxListener->disposing(aEventObj); + } + else + { + AccessibleContextBase::addEventListener (rxListener); + if (mpText != NULL) + mpText->AddEventListener (rxListener); + } +} + +// -------------------------------------------------------------------- + +void SAL_CALL AccessibleCell::removeEventListener( const Reference<XAccessibleEventListener >& rxListener) throw (RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + AccessibleContextBase::removeEventListener(rxListener); + if (mpText != NULL) + mpText->RemoveEventListener (rxListener); +} + +// -------------------------------------------------------------------- +// XServiceInfo +// -------------------------------------------------------------------- + +OUString SAL_CALL AccessibleCell::getImplementationName(void) throw (RuntimeException) +{ + return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleCell")); +} + +// -------------------------------------------------------------------- + +Sequence<OUString> SAL_CALL AccessibleCell::getSupportedServiceNames(void) throw (RuntimeException) +{ + ThrowIfDisposed (); + + // Get list of supported service names from base class... + uno::Sequence<OUString> aServiceNames = AccessibleContextBase::getSupportedServiceNames(); + sal_Int32 nCount (aServiceNames.getLength()); + + // ...and add additional names. + aServiceNames.realloc (nCount + 1); + static const OUString sAdditionalServiceName (RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.AccessibleCell")); + aServiceNames[nCount] = sAdditionalServiceName; + + return aServiceNames; +} + +// -------------------------------------------------------------------- +// IAccessibleViewForwarderListener +// -------------------------------------------------------------------- + +void AccessibleCell::ViewForwarderChanged (ChangeType /*aChangeType*/, const IAccessibleViewForwarder* /*pViewForwarder*/) +{ + // Inform all listeners that the graphical representation (i.e. size + // and/or position) of the shape has changed. + CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any()); + + // update our children that our screen position might have changed + if( mpText ) + mpText->UpdateChildren(); +} + +// -------------------------------------------------------------------- +// protected +// -------------------------------------------------------------------- + +void AccessibleCell::disposing (void) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + ::osl::MutexGuard aGuard (maMutex); + + // Make sure to send an event that this object looses the focus in the + // case that it has the focus. + ::utl::AccessibleStateSetHelper* pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get()); + if (pStateSet != NULL) + pStateSet->RemoveState(AccessibleStateType::FOCUSED); + + if (mpText != NULL) + { + mpText->Dispose(); + delete mpText; + mpText = NULL; + } + + // Cleanup. Remove references to objects to allow them to be + // destroyed. + mxCell.clear(); + maShapeTreeInfo = AccessibleShapeTreeInfo(); + + // Call base classes. + AccessibleContextBase::dispose (); +} + +sal_Int32 SAL_CALL AccessibleCell::getAccessibleIndexInParent (void) throw (RuntimeException) +{ + ThrowIfDisposed (); + return mnIndexInParent; +} + +::rtl::OUString SAL_CALL AccessibleCell::getAccessibleName (void) throw (::com::sun::star::uno::RuntimeException) +{ + ThrowIfDisposed (); + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + + if( mxCell.is() ) + return mxCell->getName(); + + return AccessibleCellBase::getAccessibleName(); +} + +} // end of namespace accessibility diff --git a/svx/source/table/accessiblecell.hxx b/svx/source/table/accessiblecell.hxx new file mode 100644 index 000000000000..9d7a3deef5f4 --- /dev/null +++ b/svx/source/table/accessiblecell.hxx @@ -0,0 +1,149 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_ACCESSIBILITY_ACCESSIBLE_CELL_HXX +#define _SVX_ACCESSIBILITY_ACCESSIBLE_CELL_HXX + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/drawing/XShape.hpp> + +#include <rtl/ref.hxx> + +#include <editeng/AccessibleContextBase.hxx> +#include <editeng/AccessibleComponentBase.hxx> +#include <svx/IAccessibleViewForwarderListener.hxx> +#include <svx/AccessibleTextHelper.hxx> +#include <svx/AccessibleShapeTreeInfo.hxx> + +#include <cppuhelper/implbase1.hxx> + +#include "cell.hxx" + +#include <boost/noncopyable.hpp> + +class SdrObject; + + +namespace accessibility +{ + +class AccessibleShapeInfo; +class AccessibleShapeTreeInfo; +class IAccessibleParent; + +typedef ::cppu::ImplInheritanceHelper1< AccessibleContextBase, ::com::sun::star::accessibility::XAccessibleExtendedComponent > AccessibleCellBase; + +class AccessibleCell : boost::noncopyable, public AccessibleCellBase, public AccessibleComponentBase, public IAccessibleViewForwarderListener +{ +public: + AccessibleCell( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible>& rxParent, const sdr::table::CellRef& rCell, sal_Int32 nIndex, const AccessibleShapeTreeInfo& rShapeTreeInfo); + virtual ~AccessibleCell (void); + + virtual void Init (void); + + virtual bool operator== (const AccessibleCell& rAccessibleCell); + + virtual sal_Bool SetState (sal_Int16 aState); + virtual sal_Bool ResetState (sal_Int16 aState); + sal_Bool GetState (sal_Int16 aState); + + // XInterface + virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& aType ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL acquire( ) throw (); + virtual void SAL_CALL release( ) throw (); + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount(void) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible> SAL_CALL getAccessibleChild(sal_Int32 nIndex) throw(::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleStateSet> SAL_CALL getAccessibleStateSet(void) throw(::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent(void) throw(::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getAccessibleName (void) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleComponent + virtual sal_Bool SAL_CALL containsPoint( const ::com::sun::star::awt::Point& aPoint) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint(const ::com::sun::star::awt::Point& aPoint) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Rectangle SAL_CALL getBounds(void) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocation(void) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Point SAL_CALL getLocationOnScreen(void) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::awt::Size SAL_CALL getSize(void) throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addFocusListener ( const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFocusListener >& xListener) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeFocusListener (const ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFocusListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL grabFocus (void) throw (::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getForeground(void) throw(::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL getBackground(void) throw(::com::sun::star::uno::RuntimeException); + + // XAccessibleExtendedComponent + virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XFont > SAL_CALL getFont (void) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getTitledBorderText (void) throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getToolTipText (void) throw (::com::sun::star::uno::RuntimeException); + + // XAccessibleEventBroadcaster + virtual void SAL_CALL addEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& rxListener) throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeEventListener( const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleEventListener >& rxListener) throw(::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName (void) throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString> SAL_CALL getSupportedServiceNames (void) throw(::com::sun::star::uno::RuntimeException); + + // IAccessibleViewForwarderListener + virtual void ViewForwarderChanged (ChangeType aChangeType, const IAccessibleViewForwarder* pViewForwarder); + + using cppu::WeakComponentImplHelperBase::addEventListener; + using cppu::WeakComponentImplHelperBase::removeEventListener; + + // Misc + + /** set the index _nIndex at the accessible cell param _nIndex The new index in parent. + */ + inline void setIndexInParent(sal_Int32 _nIndex) { mnIndexInParent = _nIndex; } + +protected: + /// Bundle of information passed to all shapes in a document tree. + AccessibleShapeTreeInfo maShapeTreeInfo; + + /// the index in parent. + sal_Int32 mnIndexInParent; + + /// The accessible text engine. May be NULL if it can not be created. + AccessibleTextHelper* mpText; + + sdr::table::CellRef mxCell; + + /// This method is called from the component helper base class while disposing. + virtual void SAL_CALL disposing (void); + +private: + explicit AccessibleCell(void); // not implemented + explicit AccessibleCell(const AccessibleCell&); // not implemented + AccessibleCell& operator=(const AccessibleCell&); // not implemented +}; + +} // end of namespace accessibility + +#endif diff --git a/svx/source/table/accessibletableshape.cxx b/svx/source/table/accessibletableshape.cxx new file mode 100644 index 000000000000..4dd7a4b58b47 --- /dev/null +++ b/svx/source/table/accessibletableshape.cxx @@ -0,0 +1,723 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/table/XMergeableCell.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <comphelper/accessiblewrapper.hxx> +#include <vos/mutex.hxx> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> + +#include <svx/AccessibleTableShape.hxx> +#include "tablecontroller.hxx" +#include "accessiblecell.hxx" + +#include <algorithm> + +#include <cppuhelper/implbase1.hxx> + +using ::rtl::OUString; + +using namespace ::accessibility; +using namespace ::sdr::table; +using namespace ::com::sun::star::accessibility; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::container; + +#define C2U(x) OUString(RTL_CONSTASCII_USTRINGPARAM(x)) + +namespace accessibility +{ + +struct hash +{ + std::size_t operator()( const Reference< XCell >& xCell ) const + { + return std::size_t( xCell.get() ); + } +}; + +typedef std::hash_map< Reference< XCell >, rtl::Reference< AccessibleCell >, hash > AccessibleCellMap; + +//----------------------------------------------------------------------------- +// AccessibleTableShapeImpl +//----------------------------------------------------------------------------- + +class AccessibleTableShapeImpl : public cppu::WeakImplHelper1< XModifyListener > +{ +public: + AccessibleTableShapeImpl( AccessibleShapeTreeInfo& rShapeTreeInfo ); + + void init( const Reference< XAccessible>& xAccessible, const Reference< XTable >& xTable ); + void dispose(); + + Reference< XAccessible > getAccessibleChild( sal_Int32 i ) throw(IndexOutOfBoundsException); + void getColumnAndRow( sal_Int32 nChildIndex, sal_Int32& rnColumn, sal_Int32& rnRow ) throw (IndexOutOfBoundsException ); + + // XModifyListener + virtual void SAL_CALL modified( const EventObject& aEvent ) throw (RuntimeException); + + // XEventListener + virtual void SAL_CALL disposing( const EventObject& Source ) throw (RuntimeException); + + AccessibleShapeTreeInfo& mrShapeTreeInfo; + Reference< XTable > mxTable; + AccessibleCellMap maChildMap; + Reference< XAccessible> mxAccessible; +}; + +//----------------------------------------------------------------------------- + +AccessibleTableShapeImpl::AccessibleTableShapeImpl( AccessibleShapeTreeInfo& rShapeTreeInfo ) +: mrShapeTreeInfo( rShapeTreeInfo ) +{ +} + +//----------------------------------------------------------------------------- + +void AccessibleTableShapeImpl::init( const Reference< XAccessible>& xAccessible, const Reference< XTable >& xTable ) +{ + mxAccessible = xAccessible; + mxTable = xTable; + + if( mxTable.is() ) + { + Reference< XModifyListener > xListener( this ); + mxTable->addModifyListener( xListener ); + } +} + +//----------------------------------------------------------------------------- + +void AccessibleTableShapeImpl::dispose() +{ + if( mxTable.is() ) + { + Reference< XModifyListener > xListener( this ); + mxTable->removeModifyListener( xListener ); + mxTable.clear(); + } + mxAccessible.clear(); +} + +//----------------------------------------------------------------------------- + +Reference< XAccessible > AccessibleTableShapeImpl::getAccessibleChild( sal_Int32 nChildIndex ) throw(IndexOutOfBoundsException) +{ + sal_Int32 nColumn = 0, nRow = 0; + getColumnAndRow( nChildIndex, nColumn, nRow ); + + Reference< XCell > xCell( mxTable->getCellByPosition( nColumn, nRow ) ); + AccessibleCellMap::iterator iter( maChildMap.find( xCell ) ); + + if( iter != maChildMap.end() ) + { + Reference< XAccessible > xChild( (*iter).second.get() ); + return xChild; + } + else + { + CellRef xCellRef( dynamic_cast< Cell* >( xCell.get() ) ); + + rtl::Reference< AccessibleCell > xAccessibleCell( new AccessibleCell( mxAccessible, xCellRef, nChildIndex, mrShapeTreeInfo ) ); + + maChildMap[xCell] = xAccessibleCell; + + xAccessibleCell->Init(); + + Reference< XAccessible > xChild( xAccessibleCell.get() ); + return xChild; + } +} + +//----------------------------------------------------------------------------- + +void AccessibleTableShapeImpl::getColumnAndRow( sal_Int32 nChildIndex, sal_Int32& rnColumn, sal_Int32& rnRow ) throw (IndexOutOfBoundsException ) +{ + rnRow = 0; + rnColumn = nChildIndex; + + if( mxTable.is() ) + { + const sal_Int32 nColumnCount = mxTable->getColumnCount(); + while( rnColumn >= nColumnCount ) + { + rnRow++; + rnColumn -= nColumnCount; + } + + if( rnRow < mxTable->getRowCount() ) + return; + } + + throw IndexOutOfBoundsException(); +} + +// XModifyListener +void SAL_CALL AccessibleTableShapeImpl::modified( const EventObject& /*aEvent*/ ) throw (RuntimeException) +{ + if( mxTable.is() ) try + { + // structural changes may have happened to the table, validate all accessible cell instances + AccessibleCellMap aTempChildMap; + aTempChildMap.swap( maChildMap ); + + // first move all still existing cells to maChildMap again and update their index + + const sal_Int32 nRowCount = mxTable->getRowCount(); + const sal_Int32 nColCount = mxTable->getColumnCount(); + + sal_Int32 nChildIndex = 0; + + for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow ) + { + for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol ) + { + Reference< XCell > xCell( mxTable->getCellByPosition( nCol, nRow ) ); + AccessibleCellMap::iterator iter( aTempChildMap.find( xCell ) ); + + if( iter != aTempChildMap.end() ) + { + rtl::Reference< AccessibleCell > xAccessibleCell( (*iter).second ); + xAccessibleCell->setIndexInParent( nChildIndex ); + xAccessibleCell->CommitChange(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any()); + + // move still existing cell from temporary child map to our child map + maChildMap[xCell] = xAccessibleCell; + aTempChildMap.erase( iter ); + } + + ++nChildIndex; + } + } + + // all accessible cell instances still left in aTempChildMap must be disposed + // as they are no longer part of the table + + for( AccessibleCellMap::iterator iter( aTempChildMap.begin() ); iter != aTempChildMap.end(); iter++ ) + { + (*iter).second->dispose(); + } + } + catch( Exception& ) + { + DBG_ERROR("svx::AccessibleTableShape::modified(), exception caught!"); + } +} + +// XEventListener +void SAL_CALL AccessibleTableShapeImpl::disposing( const EventObject& /*Source*/ ) throw (RuntimeException) +{ +} + +//----------------------------------------------------------------------------- +// AccessibleTableShape +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- + +AccessibleTableShape::AccessibleTableShape( const AccessibleShapeInfo& rShapeInfo, const AccessibleShapeTreeInfo& rShapeTreeInfo) +: AccessibleTableShape_Base(rShapeInfo, rShapeTreeInfo) +, mxImpl( new AccessibleTableShapeImpl( maShapeTreeInfo ) ) +{ +} + +//----------------------------------------------------------------------------- + +AccessibleTableShape::~AccessibleTableShape (void) +{ +} + +//----------------------------------------------------------------------------- + +void AccessibleTableShape::Init() +{ + try + { + + Reference< XPropertySet > xSet( mxShape, UNO_QUERY_THROW ); + Reference< XTable > xTable( xSet->getPropertyValue(C2U("Model")), UNO_QUERY_THROW ); + + mxImpl->init( this, xTable ); + } + catch( Exception& ) + { + DBG_ERROR("AccessibleTableShape::init(), exception caught?"); + } + + AccessibleTableShape_Base::Init(); +} + +//----------------------------------------------------------------------------- + +SvxTableController* AccessibleTableShape::getTableController() +{ + SdrView* pView = maShapeTreeInfo.GetSdrView (); + if( pView ) + return dynamic_cast< SvxTableController* >( pView->getSelectionController().get() ); + else + return 0; +} + +//----------------------------------------------------------------------------- +// XInterface +//----------------------------------------------------------------------------- + +Any SAL_CALL AccessibleTableShape::queryInterface( const Type& aType ) throw (RuntimeException) +{ + return AccessibleTableShape_Base::queryInterface( aType ); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL AccessibleTableShape::acquire( ) throw () +{ + AccessibleTableShape_Base::acquire(); +} + +//----------------------------------------------------------------------------- + +void SAL_CALL AccessibleTableShape::release( ) throw () +{ + AccessibleTableShape_Base::release(); +} + +//----------------------------------------------------------------------------- +// XAccessible +//----------------------------------------------------------------------------- + +Reference< XAccessibleContext > SAL_CALL AccessibleTableShape::getAccessibleContext(void) throw (RuntimeException) +{ + return AccessibleShape::getAccessibleContext (); +} + +//----------------------------------------------------------------------------- +OUString SAL_CALL AccessibleTableShape::getImplementationName(void) throw (RuntimeException) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.accessibility.AccessibleTableShape" ) ); +} + +//----------------------------------------------------------------------------- + +OUString AccessibleTableShape::CreateAccessibleBaseName(void) throw (RuntimeException) +{ + return OUString (RTL_CONSTASCII_USTRINGPARAM("TableShape"));; +} + +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleChildCount( ) throw(RuntimeException) +{ + ::vos::OGuard aSolarGuard(::Application::GetSolarMutex()); + return mxImpl->mxTable.is() ? mxImpl->mxTable->getRowCount() * mxImpl->mxTable->getColumnCount() : 0; +} + +//-------------------------------------------------------------------- +Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleChild( sal_Int32 i ) throw(IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + ThrowIfDisposed(); + + return mxImpl->getAccessibleChild( i ); +} + +//-------------------------------------------------------------------- +Reference< XAccessibleRelationSet > SAL_CALL AccessibleTableShape::getAccessibleRelationSet( ) throw (RuntimeException) +{ + return AccessibleShape::getAccessibleRelationSet( ); +} + +//-------------------------------------------------------------------- + +sal_Int16 SAL_CALL AccessibleTableShape::getAccessibleRole (void) throw (RuntimeException) +{ + return AccessibleRole::TABLE; +} + +//-------------------------------------------------------------------- + +void SAL_CALL AccessibleTableShape::disposing (void) +{ + mxImpl->dispose(); + + // let the base do it's stuff + AccessibleShape::disposing(); +} + +//-------------------------------------------------------------------- +// XAccessibleTable +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRowCount() throw (RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + return mxImpl->mxTable.is() ? mxImpl->mxTable->getRowCount() : 0; +} + +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumnCount( ) throw (RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + return mxImpl->mxTable.is() ? mxImpl->mxTable->getColumnCount() : 0; +} + +//-------------------------------------------------------------------- + +OUString SAL_CALL AccessibleTableShape::getAccessibleRowDescription( sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException) +{ + checkCellPosition( 0, nRow ); + return OUString(); +} + +//-------------------------------------------------------------------- + +OUString SAL_CALL AccessibleTableShape::getAccessibleColumnDescription( sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + checkCellPosition( nColumn, 0 ); + return OUString(); +} + +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + checkCellPosition( nColumn, nRow ); + if( mxImpl->mxTable.is() ) + { + Reference< XMergeableCell > xCell( mxImpl->mxTable->getCellByPosition( nColumn, nRow ), UNO_QUERY ); + if( xCell.is() ) + return xCell->getRowSpan(); + } + return 1; +} + +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + checkCellPosition( nColumn, nRow ); + if( mxImpl->mxTable.is() ) + { + Reference< XMergeableCell > xCell( mxImpl->mxTable->getCellByPosition( nColumn, nRow ), UNO_QUERY ); + if( xCell.is() ) + return xCell->getColumnSpan(); + } + return 1; +} + +//-------------------------------------------------------------------- + +Reference< XAccessibleTable > SAL_CALL AccessibleTableShape::getAccessibleRowHeaders( ) throw (RuntimeException) +{ + Reference< XAccessibleTable > xRet( this ); // todo + return xRet; +} + +//-------------------------------------------------------------------- + +Reference< XAccessibleTable > SAL_CALL AccessibleTableShape::getAccessibleColumnHeaders( ) throw (RuntimeException) +{ + Reference< XAccessibleTable > xRet( this ); // todo + return xRet; +} + +//-------------------------------------------------------------------- + +Sequence< sal_Int32 > SAL_CALL AccessibleTableShape::getSelectedAccessibleRows( ) throw (RuntimeException) +{ + Sequence< sal_Int32 > aRet; + return aRet; +} + +//-------------------------------------------------------------------- + +Sequence< sal_Int32 > SAL_CALL AccessibleTableShape::getSelectedAccessibleColumns( ) throw (RuntimeException) +{ + Sequence< sal_Int32 > aRet; + return aRet; +} + +//-------------------------------------------------------------------- + +sal_Bool SAL_CALL AccessibleTableShape::isAccessibleRowSelected( sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + checkCellPosition( 0, nRow ); + return sal_False; +} + +//-------------------------------------------------------------------- + +sal_Bool SAL_CALL AccessibleTableShape::isAccessibleColumnSelected( sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + checkCellPosition( nColumn, 0 ); + return sal_False; +} + +//-------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + checkCellPosition( nColumn, nRow ); + + sal_Int32 nChildIndex = 0; + if( mxImpl->mxTable.is() ) + nChildIndex = mxImpl->mxTable->getColumnCount() * nRow + nColumn; + + return getAccessibleChild( nChildIndex ); +} + +//-------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleCaption( ) throw (RuntimeException) +{ + Reference< XAccessible > xRet; + return xRet; +} + +//-------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL AccessibleTableShape::getAccessibleSummary( ) throw (RuntimeException) +{ + Reference< XAccessible > xRet; + return xRet; +} + +//-------------------------------------------------------------------- + +sal_Bool SAL_CALL AccessibleTableShape::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + checkCellPosition( nColumn, nRow ); + + SvxTableController* pController = getTableController(); + if( pController && pController->hasSelectedCells() ) + { + CellPos aFirstPos, aLastPos; + pController->getSelectedCells( aFirstPos, aLastPos ); + if( (aFirstPos.mnRow <= nRow) && (aFirstPos.mnCol <= nColumn) && (nRow <= aLastPos.mnRow) && (nColumn <= aLastPos.mnCol) ) + return sal_True; + } + + return sal_False; +} + +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + checkCellPosition( nColumn, nRow ); + return mxImpl->mxTable.is() ? (nRow * mxImpl->mxTable->getColumnCount() + nColumn) : 0; +} + +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleRow( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + sal_Int32 nColumn = 0, nRow = 0; + mxImpl->getColumnAndRow( nChildIndex, nColumn, nRow ); + return nRow; +} + +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getAccessibleColumn( sal_Int32 nChildIndex ) throw (IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + sal_Int32 nColumn = 0, nRow = 0; + mxImpl->getColumnAndRow( nChildIndex, nColumn, nRow ); + return nChildIndex; +} + +//-------------------------------------------------------------------- +// XAccessibleSelection +//-------------------------------------------------------------------- + +void SAL_CALL AccessibleTableShape::selectAccessibleChild( sal_Int32 nChildIndex ) throw ( IndexOutOfBoundsException, RuntimeException ) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + CellPos aPos; + mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow ); + + // todo, select table shape?!? + SvxTableController* pController = getTableController(); + if( pController ) + { + CellPos aFirstPos( aPos ), aLastPos( aPos ); + if( pController->hasSelectedCells() ) + { + pController->getSelectedCells( aFirstPos, aLastPos ); + + aFirstPos.mnRow = std::min( aFirstPos.mnRow, aPos.mnRow ); + aFirstPos.mnCol = std::min( aFirstPos.mnCol, aPos.mnCol ); + aLastPos.mnRow = std::max( aLastPos.mnRow, aPos.mnRow ); + aLastPos.mnCol = std::max( aLastPos.mnCol, aPos.mnCol ); + } + pController->setSelectedCells( aFirstPos, aLastPos ); + } +} + +//-------------------------------------------------------------------- + +sal_Bool SAL_CALL AccessibleTableShape::isAccessibleChildSelected( sal_Int32 nChildIndex ) throw ( IndexOutOfBoundsException, RuntimeException ) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + CellPos aPos; + mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow ); + + return isAccessibleSelected(aPos.mnCol, aPos.mnRow); +} + +//-------------------------------------------------------------------- + +void SAL_CALL AccessibleTableShape::clearAccessibleSelection() throw ( RuntimeException ) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + + SvxTableController* pController = getTableController(); + if( pController ) + pController->clearSelection(); +} +//-------------------------------------------------------------------- + +void SAL_CALL AccessibleTableShape::selectAllAccessibleChildren() throw ( RuntimeException ) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + + // todo: force selection of shape? + SvxTableController* pController = getTableController(); + if( pController ) + pController->selectAll(); +} + +//-------------------------------------------------------------------- + +sal_Int32 SAL_CALL AccessibleTableShape::getSelectedAccessibleChildCount() throw ( RuntimeException ) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + + SvxTableController* pController = getTableController(); + if( pController && pController->hasSelectedCells() ) + { + CellPos aFirstPos, aLastPos; + pController->getSelectedCells( aFirstPos, aLastPos ); + + const sal_Int32 nSelectedColumns = std::max( (sal_Int32)0, aLastPos.mnCol - aFirstPos.mnCol ) + 1; + const sal_Int32 nSelectedRows = std::max( (sal_Int32)0, aLastPos.mnRow - aFirstPos.mnRow ) + 1; + return nSelectedRows * nSelectedColumns; + } + + return 0; +} + +//-------------------------------------------------------------------- + +Reference< XAccessible > SAL_CALL AccessibleTableShape::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) throw ( IndexOutOfBoundsException, RuntimeException) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + + SvxTableController* pController = getTableController(); + if( pController && pController->hasSelectedCells() ) + { + CellPos aFirstPos, aLastPos; + pController->getSelectedCells( aFirstPos, aLastPos ); + + const sal_Int32 nSelectedColumns = std::max( (sal_Int32)0, aLastPos.mnCol - aFirstPos.mnCol ) + 1; + const sal_Int32 nSelectedRows = std::max( (sal_Int32)0, aLastPos.mnRow - aFirstPos.mnRow ) + 1; + + if( nSelectedChildIndex < (nSelectedRows * nSelectedColumns) ) + { + while( nSelectedChildIndex >= nSelectedColumns ) + { + aFirstPos.mnRow++; + nSelectedChildIndex -= nSelectedColumns; + } + return getAccessibleCellAt( nSelectedColumns, aFirstPos.mnRow ); + } + } + + throw IndexOutOfBoundsException(); +} + +//-------------------------------------------------------------------- + +void SAL_CALL AccessibleTableShape::deselectAccessibleChild( sal_Int32 nChildIndex ) throw ( IndexOutOfBoundsException, RuntimeException ) +{ + ::vos::OGuard aSolarGuard (::Application::GetSolarMutex()); + CellPos aPos; + mxImpl->getColumnAndRow( nChildIndex, aPos.mnCol, aPos.mnRow ); + + // todo, select table shape?!? + SvxTableController* pController = getTableController(); + if( pController && pController->hasSelectedCells() ) + { + CellPos aFirstPos, aLastPos; + pController->getSelectedCells( aFirstPos, aLastPos ); + + // create a selection where aPos is not part of anymore + aFirstPos.mnRow = std::min( aFirstPos.mnRow, aPos.mnRow+1 ); + aFirstPos.mnCol = std::min( aFirstPos.mnCol, aPos.mnCol+1 ); + aLastPos.mnRow = std::max( aLastPos.mnRow, aPos.mnRow-1 ); + aLastPos.mnCol = std::max( aLastPos.mnCol, aPos.mnCol-1 ); + + // new selection may be invalid (child to deselect is not at a border of the selection but in between) + if( (aFirstPos.mnRow > aLastPos.mnRow) || (aFirstPos.mnCol > aLastPos.mnCol) ) + pController->clearSelection(); // if selection is invalid, clear all + else + pController->setSelectedCells( aFirstPos, aLastPos ); + } +} + +//-------------------------------------------------------------------- + +void AccessibleTableShape::checkCellPosition( sal_Int32 nCol, sal_Int32 nRow ) throw ( IndexOutOfBoundsException ) +{ + if( (nCol >= 0) && (nRow >= 0) && mxImpl->mxTable.is() && (nCol < mxImpl->mxTable->getColumnCount()) && (nRow < mxImpl->mxTable->getRowCount()) ) + return; + + throw IndexOutOfBoundsException(); +} + +} diff --git a/svx/source/table/cell.cxx b/svx/source/table/cell.cxx new file mode 100644 index 000000000000..0f5467c99721 --- /dev/null +++ b/svx/source/table/cell.cxx @@ -0,0 +1,1809 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/drawing/BitmapMode.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/table/TableBorder.hpp> + +#include <cppuhelper/typeprovider.hxx> +#include <svl/style.hxx> +#include <svl/itemset.hxx> + +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> + +#include "svx/sdr/properties/textproperties.hxx" +#include "editeng/outlobj.hxx" +#include "editeng/writingmodeitem.hxx" +#include "svx/svdotable.hxx" +#include "svx/svdoutl.hxx" +#include "svx/unoshtxt.hxx" +#include "svx/svdmodel.hxx" + +#include "tableundo.hxx" +#include "cell.hxx" +#include "svx/svdotable.hxx" +#include "svx/svdoutl.hxx" +#include "svx/unoshtxt.hxx" +#include "svx/unoshprp.hxx" +#include "svx/unoshape.hxx" +#include "editeng/editobj.hxx" +#include "editeng/boxitem.hxx" +#include "svx/xflbstit.hxx" +#include "svx/xflbmtit.hxx" +#include <svx/svdpool.hxx> + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using ::vos::OGuard; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; + +// ----------------------------------------------------------------------------- + +static const SvxItemPropertySet* ImplGetSvxCellPropertySet() +{ + // Propertymap fuer einen Outliner Text + static const SfxItemPropertyMapEntry aSvxCellPropertyMap[] = + { + FILL_PROPERTIES +// { MAP_CHAR_LEN("HasLevels"), OWN_ATTR_HASLEVELS, &::getBooleanCppuType(), ::com::sun::star::beans::PropertyAttribute::READONLY, 0}, + { MAP_CHAR_LEN("Style"), OWN_ATTR_STYLE, &::com::sun::star::style::XStyle::static_type(), ::com::sun::star::beans::PropertyAttribute::MAYBEVOID, 0}, + { MAP_CHAR_LEN(UNO_NAME_TEXT_WRITINGMODE), SDRATTR_TEXTDIRECTION, &::getCppuType( (::com::sun::star::text::WritingMode*) 0 ), 0, 0}, + { MAP_CHAR_LEN(UNO_NAME_TEXT_HORZADJUST), SDRATTR_TEXT_HORZADJUST, &::getCppuType((const ::com::sun::star::drawing::TextHorizontalAdjust*)0), 0, 0}, \ + { MAP_CHAR_LEN(UNO_NAME_TEXT_LEFTDIST), SDRATTR_TEXT_LEFTDIST, &::getCppuType((const sal_Int32*)0), 0, SFX_METRIC_ITEM}, \ + { MAP_CHAR_LEN(UNO_NAME_TEXT_LOWERDIST), SDRATTR_TEXT_LOWERDIST, &::getCppuType((const sal_Int32*)0), 0, SFX_METRIC_ITEM}, \ + { MAP_CHAR_LEN(UNO_NAME_TEXT_RIGHTDIST), SDRATTR_TEXT_RIGHTDIST, &::getCppuType((const sal_Int32*)0), 0, SFX_METRIC_ITEM}, \ + { MAP_CHAR_LEN(UNO_NAME_TEXT_UPPERDIST), SDRATTR_TEXT_UPPERDIST, &::getCppuType((const sal_Int32*)0), 0, SFX_METRIC_ITEM}, \ + { MAP_CHAR_LEN(UNO_NAME_TEXT_VERTADJUST), SDRATTR_TEXT_VERTADJUST, &::getCppuType((const ::com::sun::star::drawing::TextVerticalAdjust*)0), 0, 0},\ + { MAP_CHAR_LEN(UNO_NAME_TEXT_WORDWRAP), SDRATTR_TEXT_WORDWRAP, &::getBooleanCppuType(), 0, 0}, \ + + { MAP_CHAR_LEN("TableBorder"), OWN_ATTR_TABLEBORDER, &::getCppuType((const TableBorder*)0), 0, 0 }, \ + { MAP_CHAR_LEN("TopBorder"), SDRATTR_TABLE_BORDER, &::getCppuType((const BorderLine*)0), 0, TOP_BORDER }, \ + { MAP_CHAR_LEN("BottomBorder"), SDRATTR_TABLE_BORDER, &::getCppuType((const BorderLine*)0), 0, BOTTOM_BORDER }, \ + { MAP_CHAR_LEN("LeftBorder"), SDRATTR_TABLE_BORDER, &::getCppuType((const BorderLine*)0), 0, LEFT_BORDER }, \ + { MAP_CHAR_LEN("RightBorder"), SDRATTR_TABLE_BORDER, &::getCppuType((const BorderLine*)0), 0, RIGHT_BORDER }, \ + + SVX_UNOEDIT_OUTLINER_PROPERTIES, + SVX_UNOEDIT_CHAR_PROPERTIES, + SVX_UNOEDIT_PARA_PROPERTIES, + {0,0,0,0,0,0} + }; + + static SvxItemPropertySet aSvxCellPropertySet( aSvxCellPropertyMap, SdrObject::GetGlobalDrawObjectItemPool() ); + return &aSvxCellPropertySet; +} + +namespace sdr +{ + namespace properties + { + class CellProperties : public TextProperties + { + protected: + // create a new itemset + SfxItemSet& CreateObjectSpecificItemSet(SfxItemPool& rPool); + + public: + // basic constructor + CellProperties(SdrObject& rObj, sdr::table::Cell* pCell ); + + // constructor for copying, but using new object + CellProperties(const CellProperties& rProps, SdrObject& rObj, sdr::table::Cell* pCell); + + // destructor + ~CellProperties(); + + // Clone() operator, normally just calls the local copy constructor + BaseProperties& Clone(SdrObject& rObj) const; + + void ForceDefaultAttributes(); + + void ItemSetChanged(const SfxItemSet& rSet); + + void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem); + + void SetStyleSheet(SfxStyleSheet* pNewStyleSheet, sal_Bool bDontRemoveHardAttr); + + sdr::table::CellRef mxCell; + }; + + // create a new itemset + SfxItemSet& CellProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool) + { + return *(new SfxItemSet(rPool, + + // range from SdrAttrObj + SDRATTR_START, SDRATTR_SHADOW_LAST, + SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST, + SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION, + + // range for SdrTableObj + SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST, + + // range from SdrTextObj + EE_ITEMS_START, EE_ITEMS_END, + + // end + 0, 0)); + } + + CellProperties::CellProperties(SdrObject& rObj, sdr::table::Cell* pCell) + : TextProperties(rObj) + , mxCell(pCell) + { + } + + CellProperties::CellProperties(const CellProperties& rProps, SdrObject& rObj, sdr::table::Cell* pCell) + : TextProperties(rProps, rObj) + , mxCell( pCell ) + { + } + + CellProperties::~CellProperties() + { + } + + BaseProperties& CellProperties::Clone(SdrObject& rObj) const + { + DBG_ERROR("CellProperties::Clone(), does not work yet!"); + return *(new CellProperties(*this, rObj,0)); + } + + void CellProperties::ForceDefaultAttributes() + { + } + + void CellProperties::ItemSetChanged(const SfxItemSet& rSet ) + { + SdrTextObj& rObj = (SdrTextObj&)GetSdrObject(); + + if( mxCell.is() ) + { + OutlinerParaObject* pParaObj = mxCell->GetEditOutlinerParaObject(); + + bool bOwnParaObj = pParaObj != 0; + + if( pParaObj == 0 ) + pParaObj = mxCell->GetOutlinerParaObject(); + + if(pParaObj) + { + // handle outliner attributes + Outliner* pOutliner = 0; + + if(mxCell->IsTextEditActive()) + { + pOutliner = rObj.GetTextEditOutliner(); + } + else + { + pOutliner = &rObj.ImpGetDrawOutliner(); + pOutliner->SetText(*pParaObj); + } + + sal_uInt32 nParaCount(pOutliner->GetParagraphCount()); + + for(sal_uInt16 nPara = 0; nPara < nParaCount; nPara++) + { + SfxItemSet aSet(pOutliner->GetParaAttribs(nPara)); + aSet.Put(rSet); + pOutliner->SetParaAttribs(nPara, aSet); + } + + if(!mxCell->IsTextEditActive()) + { + if(nParaCount) + { + // force ItemSet + GetObjectItemSet(); + + SfxItemSet aNewSet(pOutliner->GetParaAttribs(0L)); + mpItemSet->Put(aNewSet); + } + + OutlinerParaObject* pTemp = pOutliner->CreateParaObject(0, (sal_uInt16)nParaCount); + pOutliner->Clear(); + + mxCell->SetOutlinerParaObject(pTemp); + } + + if( bOwnParaObj ) + delete pParaObj; + } + } + + // call parent + AttributeProperties::ItemSetChanged(rSet); + + if( mxCell.is() ) + mxCell->notifyModified(); + } + + void CellProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem) + { + if(pNewItem && (SDRATTR_TEXTDIRECTION == nWhich)) + { + sal_Bool bVertical(com::sun::star::text::WritingMode_TB_RL == ((SvxWritingModeItem*)pNewItem)->GetValue()); + + sdr::table::SdrTableObj& rObj = (sdr::table::SdrTableObj&)GetSdrObject(); + if( rObj.IsVerticalWriting() != bVertical ) + rObj.SetVerticalWriting(bVertical); + } + + // call parent + AttributeProperties::ItemChange( nWhich, pNewItem ); + } + + void CellProperties::SetStyleSheet(SfxStyleSheet* pNewStyleSheet, sal_Bool bDontRemoveHardAttr) + { + TextProperties::SetStyleSheet( pNewStyleSheet, bDontRemoveHardAttr ); + } + } // end of namespace properties +} // end of namespace sdr + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// Cell +// ----------------------------------------------------------------------------- + +rtl::Reference< Cell > Cell::create( SdrTableObj& rTableObj, OutlinerParaObject* pOutlinerParaObject ) +{ + rtl::Reference< Cell > xCell( new Cell( rTableObj, pOutlinerParaObject ) ); + if( xCell->mxTable.is() ) + { + Reference< XEventListener > xListener( xCell.get() ); + xCell->mxTable->addEventListener( xListener ); + } + return xCell; +} + +// ----------------------------------------------------------------------------- + +Cell::Cell( SdrTableObj& rTableObj, OutlinerParaObject* pOutlinerParaObject ) throw() +: SdrText( rTableObj, pOutlinerParaObject ) +, SvxUnoTextBase( ImplGetSvxUnoOutlinerTextCursorSvxPropertySet() ) +, mpPropSet( ImplGetSvxCellPropertySet() ) +, mpProperties( new sdr::properties::CellProperties( rTableObj, this ) ) +, mnCellContentType( CellContentType_EMPTY ) +, mfValue( 0.0 ) +, mnError( 0 ) +, mbMerged( sal_False ) +, mnRowSpan( 1 ) +, mnColSpan( 1 ) +, mxTable( rTableObj.getTable() ) +{ + if( rTableObj.GetModel() ) + SetModel( rTableObj.GetModel() ); +} + +// ----------------------------------------------------------------------------- + +Cell::~Cell() throw() +{ + dispose(); +} + +// ----------------------------------------------------------------------------- + +void Cell::dispose() +{ + if( mxTable.is() ) + { + try + { + Reference< XEventListener > xThis( this ); + mxTable->removeEventListener( xThis ); + } + catch( Exception& ) + { + DBG_ERROR("Cell::dispose(), exception caught!"); + } + mxTable.clear(); + } + + if( mpProperties ) + { + delete mpProperties; + mpProperties = 0; + } + SetOutlinerParaObject( 0 ); +} + +// ----------------------------------------------------------------------------- + +void Cell::SetModel(SdrModel* pNewModel) +{ + SvxTextEditSource* pTextEditSource = dynamic_cast< SvxTextEditSource* >( GetEditSource() ); + if( (GetModel() != pNewModel) || ( pNewModel && !pTextEditSource) ) + { + if( mpProperties ) + { + SfxItemPool* pItemPool = mpProperties->GetObjectItemSet().GetPool(); + + // test for correct pool in ItemSet; move to new pool if necessary + if( pNewModel && pItemPool && pItemPool != &pNewModel->GetItemPool()) + mpProperties->MoveToItemPool(pItemPool, &pNewModel->GetItemPool(), pNewModel); + } + + if( pTextEditSource ) + { + pTextEditSource->ChangeModel( pNewModel ); + } + else + { + SetEditSource( new SvxTextEditSource( &GetObject(), this, static_cast< XWeak * >( this ) ) ); + } + + SetStyleSheet( 0, sal_True ); + SdrText::SetModel( pNewModel ); + ForceOutlinerParaObject( OUTLINERMODE_TEXTOBJECT ); + } +} + +// ----------------------------------------------------------------------------- + +void Cell::merge( sal_Int32 nColumnSpan, sal_Int32 nRowSpan ) +{ + if( (mnColSpan != nColumnSpan) || (mnRowSpan != nRowSpan) || (mbMerged != sal_False) ) + { + mnColSpan = nColumnSpan; + mnRowSpan = nRowSpan; + mbMerged = sal_False; + notifyModified(); + } +} + +// ----------------------------------------------------------------------------- + +void Cell::mergeContent( const CellRef& xSourceCell ) +{ + SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() ); + + if( xSourceCell->hasText() ) + { + SdrOutliner& rOutliner=rTableObj.ImpGetDrawOutliner(); + rOutliner.SetUpdateMode(TRUE); + + if( hasText() ) + { + rOutliner.SetText(*GetOutlinerParaObject()); + rOutliner.AddText(*xSourceCell->GetOutlinerParaObject()); + } + else + { + rOutliner.SetText(*xSourceCell->GetOutlinerParaObject()); + } + + SetOutlinerParaObject( rOutliner.CreateParaObject() ); + rOutliner.Clear(); + xSourceCell->SetOutlinerParaObject(rOutliner.CreateParaObject()); + rOutliner.Clear(); + SetStyleSheet( GetStyleSheet(), sal_True ); + } +} + +// ----------------------------------------------------------------------------- + +void Cell::cloneFrom( const CellRef& xCell ) +{ + if( xCell.is() ) + { + replaceContentAndFormating( xCell ); + + mnCellContentType = xCell->mnCellContentType; + + msFormula = xCell->msFormula; + mfValue = xCell->mfValue; + mnError = xCell->mnError; + + mbMerged = xCell->mbMerged; + mnRowSpan = xCell->mnRowSpan; + mnColSpan = xCell->mnColSpan; + + } + notifyModified(); +} + +void Cell::replaceContentAndFormating( const CellRef& xSourceCell ) +{ + if( xSourceCell.is() && mpProperties ) + { + mpProperties->SetMergedItemSet( xSourceCell->GetObjectItemSet() ); + SetOutlinerParaObject( new OutlinerParaObject(*xSourceCell->GetOutlinerParaObject()) ); + + SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() ); + SdrTableObj& rSourceTableObj = dynamic_cast< SdrTableObj& >( xSourceCell->GetObject() ); + + if(rSourceTableObj.GetModel() != rTableObj.GetModel()) + { + SetStyleSheet( 0, sal_True ); + } + } +} + +// ----------------------------------------------------------------------------- + +void Cell::setMerged() +{ + if( !mbMerged ) + { + mbMerged = sal_True; + notifyModified(); + } +} + +// ----------------------------------------------------------------------------- + +void Cell::notifyModified() +{ + if( mxTable.is() ) + mxTable->setModified( sal_True ); +} + +// ----------------------------------------------------------------------------- +// SdrTextShape proxy +// ----------------------------------------------------------------------------- + +bool Cell::IsTextEditActive() +{ + bool isActive = false; + SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() ); + if(rTableObj.getActiveCell().get() == this ) + { + OutlinerParaObject* pParaObj = rTableObj.GetEditOutlinerParaObject(); + if( pParaObj != 0 ) + { + isActive = true; + delete pParaObj; + } + } + return isActive; +} + +// ----------------------------------------------------------------------------- + +bool Cell::hasText() const +{ + OutlinerParaObject* pParaObj = GetOutlinerParaObject(); + if( pParaObj ) + { + const EditTextObject& rTextObj = pParaObj->GetTextObject(); + if( rTextObj.GetParagraphCount() >= 1 ) + { + if( rTextObj.GetParagraphCount() == 1 ) + { + if( rTextObj.GetText(0).Len() == 0 ) + return false; + } + return true; + } + } + + return false; +} + +// ----------------------------------------------------------------------------- + +OutlinerParaObject* Cell::GetEditOutlinerParaObject() const +{ + SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() ); + if( rTableObj.getActiveCell().get() == this ) + return rTableObj.GetEditOutlinerParaObject(); + return 0; +} + +// ----------------------------------------------------------------------------- + +void Cell::SetStyleSheet( SfxStyleSheet* pStyleSheet, sal_Bool bDontRemoveHardAttr ) +{ + // only allow cell styles for cells + if( pStyleSheet && pStyleSheet->GetFamily() != SFX_STYLE_FAMILY_FRAME ) + return; + + if( mpProperties && (mpProperties->GetStyleSheet() != pStyleSheet) ) + { + mpProperties->SetStyleSheet( pStyleSheet, bDontRemoveHardAttr ); + } +} + +// ----------------------------------------------------------------------------- + +const SfxItemSet& Cell::GetObjectItemSet() +{ + if( mpProperties ) + { + return mpProperties->GetObjectItemSet(); + } + else + { + DBG_ERROR("Cell::GetObjectItemSet(), called without properties!"); + return GetObject().GetObjectItemSet(); + } +} + +void Cell::SetObjectItem(const SfxPoolItem& rItem) +{ + if( mpProperties ) + { + mpProperties->SetObjectItem( rItem ); + notifyModified(); + } +} + +void Cell::SetMergedItem(const SfxPoolItem& rItem) +{ + SetObjectItem(rItem); +} + +SfxStyleSheet* Cell::GetStyleSheet() const +{ + if( mpProperties ) + return mpProperties->GetStyleSheet(); + else + return 0; +} + +// ----------------------------------------------------------------------------- + +SfxStyleSheetPool* Cell::GetStyleSheetPool() const +{ + if( mpProperties && mpProperties->GetStyleSheet() ) + return dynamic_cast< SfxStyleSheetPool* >( &mpProperties->GetStyleSheet()->GetPool() ); + else + return 0; +} + +// ----------------------------------------------------------------------------- + +const Rectangle& Cell::GetCurrentBoundRect() const +{ + return maCellRect; +} + +// ----------------------------------------------------------------------------- + +void Cell::TakeTextAnchorRect(Rectangle& rAnchorRect) const +{ + rAnchorRect.nLeft = maCellRect.nLeft + GetTextLeftDistance(); + rAnchorRect.nRight = maCellRect.nRight - GetTextRightDistance(); + rAnchorRect.nTop = maCellRect.nTop + GetTextUpperDistance(); + rAnchorRect.nBottom = maCellRect.nBottom - GetTextLowerDistance(); +} + +// ----------------------------------------------------------------------------- + +const SfxItemSet& Cell::GetItemSet() const +{ + return mpProperties->GetObjectItemSet(); +} + +// ----------------------------------------------------------------------------- + +void Cell::SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, sal_Bool bClearAllItems) +{ + if( mpProperties ) + { + mpProperties->SetMergedItemSetAndBroadcast(rSet, bClearAllItems); + notifyModified(); + } +} + +// ----------------------------------------------------------------------------- + +sal_Int32 Cell::getMinimumWidth() +{ + return GetTextLeftDistance() + GetTextRightDistance() + 100; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 Cell::getMinimumHeight() +{ + if( !mpProperties ) + return 0; + + SdrTableObj& rTableObj = dynamic_cast< SdrTableObj& >( GetObject() ); + sal_Int32 nMinimumHeight = 0; + + Rectangle aTextRect; + TakeTextAnchorRect( aTextRect ); + Size aSize( aTextRect.GetSize() ); + aSize.Height()=0x0FFFFFFF; + + SdrOutliner* pEditOutliner = rTableObj.GetCellTextEditOutliner( *this ); + if(pEditOutliner) + { + pEditOutliner->SetMaxAutoPaperSize(aSize); + nMinimumHeight = pEditOutliner->GetTextHeight()+1; + } + else /*if ( hasText() )*/ + { + Outliner& rOutliner=rTableObj.ImpGetDrawOutliner(); + rOutliner.SetPaperSize(aSize); + rOutliner.SetUpdateMode(TRUE); + ForceOutlinerParaObject( OUTLINERMODE_TEXTOBJECT ); + + if( GetOutlinerParaObject() ) + { + rOutliner.SetText(*GetOutlinerParaObject()); + } + nMinimumHeight=rOutliner.GetTextHeight()+1; + rOutliner.Clear(); + } + + nMinimumHeight += GetTextUpperDistance() + GetTextLowerDistance(); + return nMinimumHeight; +} + +// ----------------------------------------------------------------------------- + +long Cell::GetTextLeftDistance() const +{ + return ((SdrTextLeftDistItem&)(GetItemSet().Get(SDRATTR_TEXT_LEFTDIST))).GetValue(); +} + +// ----------------------------------------------------------------------------- + +long Cell::GetTextRightDistance() const +{ + return ((SdrTextRightDistItem&)(GetItemSet().Get(SDRATTR_TEXT_RIGHTDIST))).GetValue(); +} + +// ----------------------------------------------------------------------------- + +long Cell::GetTextUpperDistance() const +{ + return ((SdrTextUpperDistItem&)(GetItemSet().Get(SDRATTR_TEXT_UPPERDIST))).GetValue(); +} + +// ----------------------------------------------------------------------------- + +long Cell::GetTextLowerDistance() const +{ + return ((SdrTextLowerDistItem&)(GetItemSet().Get(SDRATTR_TEXT_LOWERDIST))).GetValue(); +} + +// ----------------------------------------------------------------------------- + +SdrTextVertAdjust Cell::GetTextVerticalAdjust() const +{ + return ((SdrTextVertAdjustItem&)(GetItemSet().Get(SDRATTR_TEXT_VERTADJUST))).GetValue(); +} + +// ----------------------------------------------------------------------------- + +SdrTextHorzAdjust Cell::GetTextHorizontalAdjust() const +{ + return ((SdrTextHorzAdjustItem&)(GetItemSet().Get(SDRATTR_TEXT_HORZADJUST))).GetValue(); +} + +// ----------------------------------------------------------------------------- + +void Cell::SetOutlinerParaObject( OutlinerParaObject* pTextObject ) +{ + SdrText::SetOutlinerParaObject( pTextObject ); + maSelection.nStartPara = 0xffff; + + if( pTextObject == 0 ) + ForceOutlinerParaObject( OUTLINERMODE_TEXTOBJECT ); +} + +// ----------------------------------------------------------------------------- + +void Cell::AddUndo() +{ + SdrObject& rObj = GetObject(); + if( rObj.IsInserted() && GetModel() && GetModel()->IsUndoEnabled() ) + { + CellRef xCell( this ); + GetModel()->AddUndo( new CellUndo( &rObj, xCell ) ); + } +} + +// ----------------------------------------------------------------------------- + +sdr::properties::TextProperties* Cell::CloneProperties( sdr::properties::TextProperties* pProperties, SdrObject& rNewObj, Cell& rNewCell ) +{ + if( pProperties ) + return new sdr::properties::CellProperties( *static_cast<sdr::properties::CellProperties*>(pProperties), rNewObj, &rNewCell ); + else + return 0; +} + +// ----------------------------------------------------------------------------- + +sdr::properties::TextProperties* Cell::CloneProperties( SdrObject& rNewObj, Cell& rNewCell ) +{ + return CloneProperties(mpProperties,rNewObj,rNewCell); +} + +// ----------------------------------------------------------------------------- +// XInterface +// ----------------------------------------------------------------------------- + +Any SAL_CALL Cell::queryInterface( const Type & rType ) throw(RuntimeException) +{ + if( rType == XMergeableCell::static_type() ) + return Any( Reference< XMergeableCell >( this ) ); + + if( rType == XCell::static_type() ) + return Any( Reference< XCell >( this ) ); + + if( rType == XLayoutConstrains::static_type() ) + return Any( Reference< XLayoutConstrains >( this ) ); + + if( rType == XEventListener::static_type() ) + return Any( Reference< XEventListener >( this ) ); + + Any aRet( SvxUnoTextBase::queryAggregation( rType ) ); + if( aRet.hasValue() ) + return aRet; + + return ::cppu::OWeakObject::queryInterface( rType ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::acquire() throw () +{ + ::cppu::OWeakObject::acquire(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::release() throw () +{ + ::cppu::OWeakObject::release(); +} + +// ----------------------------------------------------------------------------- +// XTypeProvider +// ----------------------------------------------------------------------------- + +Sequence< Type > SAL_CALL Cell::getTypes( ) throw (RuntimeException) +{ + Sequence< Type > aTypes( SvxUnoTextBase::getTypes() ); + + sal_Int32 nLen = aTypes.getLength(); + aTypes.realloc(nLen + 2); + aTypes[nLen++] = XMergeableCell::static_type(); + aTypes[nLen++] = XLayoutConstrains::static_type(); + + return aTypes; +} + +// ----------------------------------------------------------------------------- + +Sequence< sal_Int8 > SAL_CALL Cell::getImplementationId( ) throw (RuntimeException) +{ + static ::cppu::OImplementationId* pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} + +// ----------------------------------------------------------------------------- +// XServiceInfo +// ----------------------------------------------------------------------------- + +OUString SAL_CALL Cell::getImplementationName( ) throw (RuntimeException) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.svx.table.Cell" ) ); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL Cell::supportsService( const OUString& ServiceName ) throw (RuntimeException) +{ + if( ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.table.cell" ) ) == 0 ) + return sal_True; + + if( ServiceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.drawing.cell" ) ) == 0 ) + return sal_True; + + return SvxUnoTextBase::supportsService( ServiceName ); +} + +// ----------------------------------------------------------------------------- + +Sequence< OUString > SAL_CALL Cell::getSupportedServiceNames( ) throw (RuntimeException) +{ + Sequence< OUString > aSeq( SvxUnoTextBase::getSupportedServiceNames() ); + sal_Int32 nIndex = aSeq.getLength(); + aSeq.realloc( nIndex + 2 ); + aSeq[nIndex++] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.table.cell" ) ); + aSeq[nIndex++] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.drawing.cell" ) ); + return aSeq; +} + +// ----------------------------------------------------------------------------- +// XLayoutConstrains +// ----------------------------------------------------------------------------- + +::com::sun::star::awt::Size SAL_CALL Cell::getMinimumSize( ) throw (RuntimeException) +{ + return ::com::sun::star::awt::Size( getMinimumWidth(), getMinimumHeight() ); +} + +// ----------------------------------------------------------------------------- + +::com::sun::star::awt::Size SAL_CALL Cell::getPreferredSize( ) throw (RuntimeException) +{ + return getMinimumSize(); +} + +// ----------------------------------------------------------------------------- + +::com::sun::star::awt::Size SAL_CALL Cell::calcAdjustedSize( const ::com::sun::star::awt::Size& aNewSize ) throw (RuntimeException) +{ + return aNewSize; +} + +// ----------------------------------------------------------------------------- +// XMergeableCell +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL Cell::getRowSpan() throw (RuntimeException) +{ + return mnRowSpan; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL Cell::getColumnSpan() throw (RuntimeException) +{ + return mnColSpan; +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL Cell::isMerged() throw (RuntimeException) +{ + return mbMerged; +} + +// ----------------------------------------------------------------------------- +// XCell +// ----------------------------------------------------------------------------- + +OUString SAL_CALL Cell::getFormula( ) throw (RuntimeException) +{ + return msFormula; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setFormula( const OUString& aFormula ) throw (RuntimeException) +{ + if( msFormula != aFormula ) + { + msFormula = aFormula; + } +} + +// ----------------------------------------------------------------------------- + +double SAL_CALL Cell::getValue( ) throw (RuntimeException) +{ + return mfValue; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setValue( double nValue ) throw (RuntimeException) +{ + if( mfValue == nValue ) + { + mfValue = nValue; + mnCellContentType = CellContentType_VALUE; + } +} + +// ----------------------------------------------------------------------------- + +CellContentType SAL_CALL Cell::getType() throw (RuntimeException) +{ + return mnCellContentType; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL Cell::getError( ) throw (RuntimeException) +{ + return mnError; +} + +// ----------------------------------------------------------------------------- +// XPropertySet +// ----------------------------------------------------------------------------- + +Any Cell::GetAnyForItem( SfxItemSet& aSet, const SfxItemPropertySimpleEntry* pMap ) +{ + Any aAny( SvxItemPropertySet_getPropertyValue( *mpPropSet, pMap, aSet ) ); + + if( *pMap->pType != aAny.getValueType() ) + { + // since the sfx uint16 item now exports a sal_Int32, we may have to fix this here + if( ( *pMap->pType == ::getCppuType((const sal_Int16*)0)) && aAny.getValueType() == ::getCppuType((const sal_Int32*)0) ) + { + sal_Int32 nValue = 0; + aAny >>= nValue; + aAny <<= (sal_Int16)nValue; + } + else + { + DBG_ERROR("GetAnyForItem() Returnvalue has wrong Type!" ); + } + } + + return aAny; +} + +Reference< XPropertySetInfo > SAL_CALL Cell::getPropertySetInfo() throw(RuntimeException) +{ + return mpPropSet->getPropertySetInfo(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setPropertyValue( const OUString& rPropertyName, const Any& rValue ) throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (mpProperties == 0) || (GetModel() == 0) ) + throw DisposedException(); + + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry(rPropertyName); + if( pMap ) + { + if( (pMap->nFlags & PropertyAttribute::READONLY ) != 0 ) + throw PropertyVetoException(); + + switch( pMap->nWID ) + { + case OWN_ATTR_STYLE: + { + Reference< XStyle > xStyle; + if( !( rValue >>= xStyle ) ) + throw IllegalArgumentException(); + + SfxUnoStyleSheet* pStyle = SfxUnoStyleSheet::getUnoStyleSheet(xStyle); + SetStyleSheet( pStyle, sal_True ); + return; + } + case OWN_ATTR_TABLEBORDER: + { + if(rValue.getValueType() != ::getCppuType((const TableBorder*)0) ) + break; + + const TableBorder* pBorder = (const TableBorder* )rValue.getValue(); + if( pBorder == NULL ) + break; + + SvxBoxItem aBox( SDRATTR_TABLE_BORDER ); + SvxBoxInfoItem aBoxInfo( SDRATTR_TABLE_BORDER_INNER ); + SvxBorderLine aLine; + + sal_Bool bSet = SvxBoxItem::LineToSvxLine(pBorder->TopLine, aLine, false); + aBox.SetLine(bSet ? &aLine : 0, BOX_LINE_TOP); + aBoxInfo.SetValid(VALID_TOP, pBorder->IsTopLineValid); + + bSet = SvxBoxItem::LineToSvxLine(pBorder->BottomLine, aLine, false); + aBox.SetLine(bSet ? &aLine : 0, BOX_LINE_BOTTOM); + aBoxInfo.SetValid(VALID_BOTTOM, pBorder->IsBottomLineValid); + + bSet = SvxBoxItem::LineToSvxLine(pBorder->LeftLine, aLine, false); + aBox.SetLine(bSet ? &aLine : 0, BOX_LINE_LEFT); + aBoxInfo.SetValid(VALID_LEFT, pBorder->IsLeftLineValid); + + bSet = SvxBoxItem::LineToSvxLine(pBorder->RightLine, aLine, false); + aBox.SetLine(bSet ? &aLine : 0, BOX_LINE_RIGHT); + aBoxInfo.SetValid(VALID_RIGHT, pBorder->IsRightLineValid); + + bSet = SvxBoxItem::LineToSvxLine(pBorder->HorizontalLine, aLine, false); + aBoxInfo.SetLine(bSet ? &aLine : 0, BOXINFO_LINE_HORI); + aBoxInfo.SetValid(VALID_HORI, pBorder->IsHorizontalLineValid); + + bSet = SvxBoxItem::LineToSvxLine(pBorder->VerticalLine, aLine, false); + aBoxInfo.SetLine(bSet ? &aLine : 0, BOXINFO_LINE_VERT); + aBoxInfo.SetValid(VALID_VERT, pBorder->IsVerticalLineValid); + + aBox.SetDistance(pBorder->Distance, false); + aBoxInfo.SetValid(VALID_DISTANCE, pBorder->IsDistanceValid); + + mpProperties->SetObjectItem(aBox); + mpProperties->SetObjectItem(aBoxInfo); + return; + } + case OWN_ATTR_FILLBMP_MODE: + { + BitmapMode eMode; + if(!(rValue >>= eMode) ) + { + sal_Int32 nMode = 0; + if(!(rValue >>= nMode)) + throw IllegalArgumentException(); + + eMode = (BitmapMode)nMode; + } + + mpProperties->SetObjectItem( XFillBmpStretchItem( eMode == BitmapMode_STRETCH ) ); + mpProperties->SetObjectItem( XFillBmpTileItem( eMode == BitmapMode_REPEAT ) ); + return; + } + default: + { + SfxItemSet aSet( GetModel()->GetItemPool(), pMap->nWID, pMap->nWID); + aSet.Put(mpProperties->GetItem(pMap->nWID)); + + bool bSpecial = false; + + switch( pMap->nWID ) + { + case XATTR_FILLBITMAP: + case XATTR_FILLGRADIENT: + case XATTR_FILLHATCH: + case XATTR_FILLFLOATTRANSPARENCE: + case XATTR_LINEEND: + case XATTR_LINESTART: + case XATTR_LINEDASH: + { + if( pMap->nMemberId == MID_NAME ) + { + OUString aApiName; + if( rValue >>= aApiName ) + { + if( SvxShape::SetFillAttribute( pMap->nWID, aApiName, aSet, GetModel() ) ) + bSpecial = true; + } + } + } + break; + } + + if( !bSpecial ) + { + + if( !SvxUnoTextRangeBase::SetPropertyValueHelper( aSet, pMap, rValue, aSet )) + { + if( aSet.GetItemState( pMap->nWID ) != SFX_ITEM_SET ) + { + // Default aus ItemPool holen + if(GetModel()->GetItemPool().IsWhich(pMap->nWID)) + aSet.Put(GetModel()->GetItemPool().GetDefaultItem(pMap->nWID)); + } + + if( aSet.GetItemState( pMap->nWID ) == SFX_ITEM_SET ) + { + SvxItemPropertySet_setPropertyValue( *mpPropSet, pMap, rValue, aSet ); + } + } + } + + GetModel()->SetChanged(); + mpProperties->SetMergedItemSetAndBroadcast( aSet ); + return; + } + } + } + throw UnknownPropertyException(); +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL Cell::getPropertyValue( const OUString& PropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (mpProperties == 0) || (GetModel() == 0) ) + throw DisposedException(); + + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName); + if( pMap ) + { + switch( pMap->nWID ) + { +/* + case OWN_ATTR_HASLEVELS: + { + return Any( hasLevels() ); + } +*/ + case OWN_ATTR_STYLE: + { + return Any( Reference< XStyle >( dynamic_cast< SfxUnoStyleSheet* >( GetStyleSheet() ) ) ); + } + case OWN_ATTR_TABLEBORDER: + { + const SvxBoxInfoItem& rBoxInfoItem = static_cast<const SvxBoxInfoItem&>(mpProperties->GetItem(SDRATTR_TABLE_BORDER_INNER)); + const SvxBoxItem& rBox = static_cast<const SvxBoxItem&>(mpProperties->GetItem(SDRATTR_TABLE_BORDER)); + + TableBorder aTableBorder; + aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), false); + aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(VALID_TOP); + aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), false); + aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(VALID_BOTTOM); + aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), false); + aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(VALID_LEFT); + aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), false); + aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(VALID_RIGHT ); + aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), false); + aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(VALID_HORI); + aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), false); + aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(VALID_VERT); + aTableBorder.Distance = rBox.GetDistance(); + aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(VALID_DISTANCE); + + return Any( aTableBorder ); + } + case OWN_ATTR_FILLBMP_MODE: + { + const XFillBmpStretchItem& rStretchItem = static_cast<const XFillBmpStretchItem&>(mpProperties->GetItem(XATTR_FILLBMP_STRETCH)); + const XFillBmpTileItem& rTileItem = static_cast<const XFillBmpTileItem&>(mpProperties->GetItem(XATTR_FILLBMP_TILE)); + if( rTileItem.GetValue() ) + { + return Any( BitmapMode_REPEAT ); + } + else if( rStretchItem.GetValue() ) + { + return Any( BitmapMode_STRETCH ); + } + else + { + return Any( BitmapMode_NO_REPEAT ); + } + } + default: + { + SfxItemSet aSet( GetModel()->GetItemPool(), pMap->nWID, pMap->nWID); + aSet.Put(mpProperties->GetItem(pMap->nWID)); + + Any aAny; + if(!SvxUnoTextRangeBase::GetPropertyValueHelper( aSet, pMap, aAny )) + { + if(!aSet.Count()) + { + // Default aus ItemPool holen + if(GetModel()->GetItemPool().IsWhich(pMap->nWID)) + aSet.Put(GetModel()->GetItemPool().GetDefaultItem(pMap->nWID)); + } + + if( aSet.Count() ) + aAny = GetAnyForItem( aSet, pMap ); + } + + return aAny; + } + } + } + throw UnknownPropertyException(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*aListener*/ ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::addVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::removeVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- +// XMultiPropertySet +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setPropertyValues( const Sequence< OUString >& aPropertyNames, const Sequence< Any >& aValues ) throw (PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + OGuard aSolarGuard( Application::GetSolarMutex() ); + + if( (mpProperties == 0) || (GetModel() == 0) ) + throw DisposedException(); + + const sal_Int32 nCount = aPropertyNames.getLength(); + + const OUString* pNames = aPropertyNames.getConstArray(); + const Any* pValues = aValues.getConstArray(); + + for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++, pNames++, pValues++ ) + { + try + { + setPropertyValue( *pNames, *pValues ); + } + catch( UnknownPropertyException& ) + { + DBG_ERROR("svx::Cell::setPropertyValues(), unknown property!" ); + } + catch( Exception& ) + { + DBG_ERROR("svx::Cell::setPropertyValues(), Exception caught!" ); + } + } +} + +// ----------------------------------------------------------------------------- + +Sequence< Any > SAL_CALL Cell::getPropertyValues( const Sequence< OUString >& aPropertyNames ) throw (RuntimeException) +{ + OGuard aSolarGuard( Application::GetSolarMutex() ); + + if( (mpProperties == 0) || (GetModel() == 0) ) + throw DisposedException(); + + const sal_Int32 nCount = aPropertyNames.getLength(); + const OUString* pNames = aPropertyNames.getConstArray(); + + Sequence< Any > aRet( nCount ); + Any* pValue = aRet.getArray(); + + for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++, pValue++, pNames++ ) + { + try + { + *pValue = getPropertyValue( *pNames ); + } + catch( UnknownPropertyException& ) + { + DBG_ERROR("svx::Cell::setPropertyValues(), unknown property!" ); + } + catch( Exception& ) + { + DBG_ERROR( "svx::Cell::getPropertyValues(), Exception caught!" ); + } + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::addPropertiesChangeListener( const Sequence< OUString >& /*aPropertyNames*/, const Reference< XPropertiesChangeListener >& /*xListener*/ ) throw (RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& /*xListener*/ ) throw (RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::firePropertiesChangeEvent( const Sequence< OUString >& /*aPropertyNames*/, const Reference< XPropertiesChangeListener >& /*xListener*/ ) throw (RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- +// XPropertyState +// ----------------------------------------------------------------------------- + +PropertyState SAL_CALL Cell::getPropertyState( const OUString& PropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (mpProperties == 0) || (GetModel() == 0) ) + throw DisposedException(); + + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName); + + if( pMap ) + { + PropertyState eState; + switch( pMap->nWID ) + { + case OWN_ATTR_FILLBMP_MODE: + { + const SfxItemSet& rSet = mpProperties->GetMergedItemSet(); + + const bool bStretch = rSet.GetItemState( XATTR_FILLBMP_STRETCH, false ) == SFX_ITEM_SET; + const bool bTile = rSet.GetItemState( XATTR_FILLBMP_TILE, false ) == SFX_ITEM_SET; + if( bStretch || bTile ) + { + eState = PropertyState_DIRECT_VALUE; + } + else + { + eState = PropertyState_DEFAULT_VALUE; + } + } +/* + case OWN_ATTR_HASLEVELS: + { + return PropertyState_DIRECT_VALUE; + } +*/ + case OWN_ATTR_STYLE: + { + return PropertyState_DIRECT_VALUE; + } + case OWN_ATTR_TABLEBORDER: + { + const SfxItemSet& rSet = mpProperties->GetMergedItemSet(); + if( (rSet.GetItemState( SDRATTR_TABLE_BORDER_INNER, sal_False ) == SFX_ITEM_DEFAULT) && (rSet.GetItemState( SDRATTR_TABLE_BORDER, sal_False ) == SFX_ITEM_DEFAULT) ) + return PropertyState_DEFAULT_VALUE; + + return PropertyState_DIRECT_VALUE; + } + default: + { + const SfxItemSet& rSet = mpProperties->GetMergedItemSet(); + + switch( rSet.GetItemState( pMap->nWID, sal_False ) ) + { + case SFX_ITEM_READONLY: + case SFX_ITEM_SET: + eState = PropertyState_DIRECT_VALUE; + break; + case SFX_ITEM_DEFAULT: + eState = PropertyState_DEFAULT_VALUE; + break; + // case SFX_ITEM_UNKNOWN: + // case SFX_ITEM_DONTCARE: + // case SFX_ITEM_DISABLED: + default: + eState = PropertyState_AMBIGUOUS_VALUE; + break; + } + + // if a item is set, this doesn't mean we want it :) + if( ( PropertyState_DIRECT_VALUE == eState ) ) + { + switch( pMap->nWID ) + { + // the following items are disabled by changing the + // fill style or the line style. so there is no need + // to export items without names which should be empty + case XATTR_FILLBITMAP: + case XATTR_FILLGRADIENT: + case XATTR_FILLHATCH: + case XATTR_LINEDASH: + { + NameOrIndex* pItem = (NameOrIndex*)rSet.GetItem((USHORT)pMap->nWID); + if( ( pItem == NULL ) || ( pItem->GetName().Len() == 0) ) + eState = PropertyState_DEFAULT_VALUE; + } + break; + + // #i36115# + // If e.g. the LineStart is on NONE and thus the string has length 0, it still + // may be a hard attribute covering the set LineStart of the parent (Style). + // #i37644# + // same is for fill float transparency + case XATTR_LINEEND: + case XATTR_LINESTART: + case XATTR_FILLFLOATTRANSPARENCE: + { + NameOrIndex* pItem = (NameOrIndex*)rSet.GetItem((USHORT)pMap->nWID); + if( ( pItem == NULL ) ) + eState = PropertyState_DEFAULT_VALUE; + } + break; + } + } + } + } + return eState; + } + throw UnknownPropertyException(); +} + +// ----------------------------------------------------------------------------- + +Sequence< PropertyState > SAL_CALL Cell::getPropertyStates( const Sequence< OUString >& aPropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (mpProperties == 0) || (GetModel() == 0) ) + throw DisposedException(); + + const sal_Int32 nCount = aPropertyName.getLength(); + + Sequence< PropertyState > aRet( nCount ); + + const OUString* pNames = aPropertyName.getConstArray(); + PropertyState* pState = aRet.getArray(); + + for( sal_Int32 nIdx = 0; nIdx < nCount; nIdx++, pNames++, pState++ ) + { + try + { + *pState = getPropertyState( *pNames ); + } + catch( Exception& ) + { + *pState = PropertyState_AMBIGUOUS_VALUE; + } + } + + return aRet; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setPropertyToDefault( const OUString& PropertyName ) throw(UnknownPropertyException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (mpProperties == 0) || (GetModel() == 0) ) + throw DisposedException(); + + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName); + if( pMap ) + { + switch( pMap->nWID ) + { + case OWN_ATTR_FILLBMP_MODE: + { + mpProperties->ClearObjectItem( XATTR_FILLBMP_STRETCH ); + mpProperties->ClearObjectItem( XATTR_FILLBMP_TILE ); + break; + } +// case OWN_ATTR_HASLEVELS: + case OWN_ATTR_STYLE: + break; + + case OWN_ATTR_TABLEBORDER: + { + mpProperties->ClearObjectItem( SDRATTR_TABLE_BORDER_INNER ); + mpProperties->ClearObjectItem( SDRATTR_TABLE_BORDER ); + break; + } + + default: + { + mpProperties->ClearObjectItem( pMap->nWID ); + } + } + + GetModel()->SetChanged(); + return; + } + throw UnknownPropertyException(); +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL Cell::getPropertyDefault( const OUString& aPropertyName ) throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (mpProperties == 0) || (GetModel() == 0) ) + throw DisposedException(); + + const SfxItemPropertySimpleEntry* pMap = mpPropSet->getPropertyMapEntry(aPropertyName); + if( pMap ) + { + switch( pMap->nWID ) + { + case OWN_ATTR_FILLBMP_MODE: + return Any( BitmapMode_NO_REPEAT ); + +/* + case OWN_ATTR_HASLEVELS: + return Any( sal_False ); +*/ + case OWN_ATTR_STYLE: + { + Reference< XStyle > xStyle; + return Any( xStyle ); + } + + case OWN_ATTR_TABLEBORDER: + { + TableBorder aBorder; + return Any( aBorder ); + } + + default: + { + if( GetModel()->GetItemPool().IsWhich(pMap->nWID) ) + { + SfxItemSet aSet( GetModel()->GetItemPool(), pMap->nWID, pMap->nWID); + aSet.Put(GetModel()->GetItemPool().GetDefaultItem(pMap->nWID)); + return GetAnyForItem( aSet, pMap ); + } + } + } + } + throw UnknownPropertyException(); +} + +// ----------------------------------------------------------------------------- +// XMultiPropertyStates +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setAllPropertiesToDefault( ) throw (RuntimeException) +{ + if( mpProperties ) + delete mpProperties; + mpProperties = new sdr::properties::CellProperties( static_cast< SdrTableObj& >( GetObject() ), this ); + + SdrOutliner& rOutliner = GetObject().ImpGetDrawOutliner(); + + OutlinerParaObject* pParaObj = GetOutlinerParaObject(); + if( pParaObj ) + { + rOutliner.SetText(*pParaObj); + sal_uInt32 nParaCount(rOutliner.GetParagraphCount()); + + if(nParaCount) + { + ESelection aSelection( 0, 0, EE_PARA_ALL, EE_PARA_ALL); + rOutliner.RemoveAttribs(aSelection, sal_True, 0); + + OutlinerParaObject* pTemp = rOutliner.CreateParaObject(0, (sal_uInt16)nParaCount); + rOutliner.Clear(); + + SetOutlinerParaObject(pTemp); + } + } +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setPropertiesToDefault( const Sequence< OUString >& aPropertyNames ) throw (UnknownPropertyException, RuntimeException) +{ + sal_Int32 nCount = aPropertyNames.getLength(); + const OUString* pName = aPropertyNames.getConstArray(); + + while(nCount--) + setPropertyToDefault( *pName++ ); +} + +// ----------------------------------------------------------------------------- + +Sequence< Any > SAL_CALL Cell::getPropertyDefaults( const Sequence< OUString >& aPropertyNames ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + sal_Int32 nCount = aPropertyNames.getLength(); + Sequence< Any > aDefaults( nCount ); + Any* pDefaults = aDefaults.getArray(); + const OUString* pName = aPropertyNames.getConstArray(); + + while(nCount--) + *pDefaults++ = getPropertyDefault( *pName++ ); + + return aDefaults; +} + +// ----------------------------------------------------------------------------- +// XFastPropertySet +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setFastPropertyValue( sal_Int32 nHandle, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + (void)aValue; + (void)nHandle; + throw UnknownPropertyException(); +} + +// ----------------------------------------------------------------------------- +// TODO: Refactor this method! +Any SAL_CALL Cell::getFastPropertyValue( sal_Int32 nHandle ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + (void)nHandle; + throw UnknownPropertyException(); +} + +// ----------------------------------------------------------------------------- +// XText +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::insertTextContent( const Reference< XTextRange >& xRange, const Reference< XTextContent >& xContent, sal_Bool bAbsorb ) throw (IllegalArgumentException, RuntimeException) +{ + SvxUnoTextBase::insertTextContent( xRange, xContent, bAbsorb ); + notifyModified(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::removeTextContent( const Reference< XTextContent >& xContent ) throw (NoSuchElementException, RuntimeException) +{ + SvxUnoTextBase::removeTextContent( xContent ); + notifyModified(); +} + +// ----------------------------------------------------------------------------- +// XSimpleText +// ----------------------------------------------------------------------------- + +Reference< XTextCursor > SAL_CALL Cell::createTextCursor( ) throw (RuntimeException) +{ + return SvxUnoTextBase::createTextCursor(); +} + +// ----------------------------------------------------------------------------- + +Reference< XTextCursor > SAL_CALL Cell::createTextCursorByRange( const Reference< XTextRange >& aTextPosition ) throw (RuntimeException) +{ + return SvxUnoTextBase::createTextCursorByRange( aTextPosition ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::insertString( const Reference< XTextRange >& xRange, const OUString& aString, sal_Bool bAbsorb ) throw (RuntimeException) +{ + SvxUnoTextBase::insertString( xRange, aString, bAbsorb ); + notifyModified(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::insertControlCharacter( const Reference< XTextRange >& xRange, sal_Int16 nControlCharacter, sal_Bool bAbsorb ) throw (IllegalArgumentException, RuntimeException) +{ + SvxUnoTextBase::insertControlCharacter( xRange, nControlCharacter, bAbsorb ); + notifyModified(); +} + +// ----------------------------------------------------------------------------- +// XTextRange +// ----------------------------------------------------------------------------- + +Reference< XText > SAL_CALL Cell::getText( ) throw (RuntimeException) +{ + return SvxUnoTextBase::getText(); +} + +// ----------------------------------------------------------------------------- + +Reference< XTextRange > SAL_CALL Cell::getStart( ) throw (RuntimeException) +{ + return SvxUnoTextBase::getStart(); +} + +// ----------------------------------------------------------------------------- + +Reference< XTextRange > SAL_CALL Cell::getEnd( ) throw (RuntimeException) +{ + return SvxUnoTextBase::getEnd(); +} + +// ----------------------------------------------------------------------------- + +OUString SAL_CALL Cell::getString( ) throw (RuntimeException) +{ + maSelection.nStartPara = 0xffff; + return SvxUnoTextBase::getString(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL Cell::setString( const OUString& aString ) throw (RuntimeException) +{ + SvxUnoTextBase::setString( aString ); + notifyModified(); +} + +// XEventListener +void SAL_CALL Cell::disposing( const EventObject& /*Source*/ ) throw (RuntimeException) +{ + mxTable.clear(); + dispose(); +} + +static OUString getCellName( sal_Int32 nCol, sal_Int32 nRow ) +{ + rtl::OUStringBuffer aBuf; + + if (nCol < 26*26) + { + if (nCol < 26) + aBuf.append( static_cast<sal_Unicode>( 'A' + + static_cast<sal_uInt16>(nCol))); + else + { + aBuf.append( static_cast<sal_Unicode>( 'A' + + (static_cast<sal_uInt16>(nCol) / 26) - 1)); + aBuf.append( static_cast<sal_Unicode>( 'A' + + (static_cast<sal_uInt16>(nCol) % 26))); + } + } + else + { + String aStr; + while (nCol >= 26) + { + sal_Int32 nC = nCol % 26; + aStr += static_cast<sal_Unicode>( 'A' + + static_cast<sal_uInt16>(nC)); + nCol = nCol - nC; + nCol = nCol / 26 - 1; + } + aStr += static_cast<sal_Unicode>( 'A' + + static_cast<sal_uInt16>(nCol)); + aStr.Reverse(); + aBuf.append( aStr); + } + aBuf.append( OUString::valueOf(nRow+1) ); + return aBuf.makeStringAndClear(); +} + +OUString Cell::getName() +{ + // todo: optimize! + OUString sName; + if( mxTable.is() ) try + { + Reference< XCell > xThis( static_cast< XCell* >( this ) ); + + sal_Int32 nRowCount = mxTable->getRowCount(); + sal_Int32 nColCount = mxTable->getColumnCount(); + for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ ) + { + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) + { + Reference< XCell > xCell( mxTable->getCellByPosition( nCol, nRow ) ); + if( xCell == xThis ) + { + return getCellName( nCol, nRow ); + } + } + } + } + catch( Exception& ) + { + } + + return sName; +} + +} } + diff --git a/svx/source/table/cell.hxx b/svx/source/table/cell.hxx new file mode 100644 index 000000000000..9bd2e9440d8c --- /dev/null +++ b/svx/source/table/cell.hxx @@ -0,0 +1,244 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_CELL_HXX_ +#define _SVX_CELL_HXX_ + +#include <com/sun/star/table/XMergeableCell.hpp> +#include <com/sun/star/awt/XLayoutConstrains.hpp> +#include <com/sun/star/beans/XMultiPropertyStates.hpp> +#include <com/sun/star/lang/XEventListener.hpp> + +#include <rtl/ref.hxx> +#include <svl/style.hxx> +#include "svx/sdtaitm.hxx" +#include "tablemodel.hxx" +#include "editeng/unotext.hxx" +#include "svx/svdtext.hxx" + +// ----------------------------------------------------------------------------- + +class SfxItemSet; +class OutlinerParaObject; +class SdrObject; + +namespace sdr { namespace properties { + class TextProperties; +} } + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- + +class SVX_DLLPUBLIC Cell : public SdrText, + public SvxUnoTextBase, + public ::com::sun::star::table::XMergeableCell, + public ::com::sun::star::awt::XLayoutConstrains, + public ::com::sun::star::lang::XEventListener, + public ::cppu::OWeakObject +{ + friend class CellUndo; + +public: + SVX_DLLPRIVATE static rtl::Reference< Cell > create( SdrTableObj& rTableObj, OutlinerParaObject* pOutlinerParaObject ); + + // private + SVX_DLLPRIVATE void dispose(); + + // SdrTextShape proxy + bool IsTextEditActive(); + SVX_DLLPRIVATE bool hasText() const; + + SVX_DLLPRIVATE void cloneFrom( const CellRef& rCell ); + + SVX_DLLPRIVATE void setCellRect( ::Rectangle& rCellRect ) { maCellRect = rCellRect; } + SVX_DLLPRIVATE const ::Rectangle& getCellRect() const { return maCellRect; } + SVX_DLLPRIVATE ::Rectangle& getCellRect() { return maCellRect; } + + OutlinerParaObject* GetEditOutlinerParaObject() const; + SVX_DLLPRIVATE void SetStyleSheet( SfxStyleSheet* pStyleSheet, sal_Bool bDontRemoveHardAttr ); + SVX_DLLPRIVATE virtual SfxStyleSheet* GetStyleSheet() const; + SfxStyleSheetPool* GetStyleSheetPool() const; + SVX_DLLPRIVATE virtual const Rectangle& GetCurrentBoundRect() const; + SVX_DLLPRIVATE virtual void TakeTextAnchorRect(Rectangle& rAnchorRect) const; + + SVX_DLLPRIVATE virtual const SfxItemSet& GetItemSet() const; + SVX_DLLPRIVATE void SetMergedItemSetAndBroadcast(const SfxItemSet& rSet, sal_Bool bClearAllItems); + void SetMergedItem(const SfxPoolItem& rItem); + + SVX_DLLPRIVATE sal_Int32 getMinimumWidth(); + SVX_DLLPRIVATE sal_Int32 getMinimumHeight(); + + SVX_DLLPRIVATE long GetTextLeftDistance() const; + SVX_DLLPRIVATE long GetTextRightDistance() const; + SVX_DLLPRIVATE long GetTextUpperDistance() const; + SVX_DLLPRIVATE long GetTextLowerDistance() const; + + SVX_DLLPRIVATE SdrTextVertAdjust GetTextVerticalAdjust() const; + SdrTextHorzAdjust GetTextHorizontalAdjust() const; + + SVX_DLLPRIVATE virtual void SetModel(SdrModel* pNewModel); + + SVX_DLLPRIVATE void merge( sal_Int32 nColumnSpan, sal_Int32 nRowSpan ); + SVX_DLLPRIVATE void mergeContent( const CellRef& xSourceCell ); + SVX_DLLPRIVATE void replaceContentAndFormating( const CellRef& xSourceCell ); + + SVX_DLLPRIVATE void setMerged(); + + // XInterface + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& Type ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL acquire() throw (); + SVX_DLLPRIVATE virtual void SAL_CALL release() throw (); + + // XTypeProvider + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL getTypes( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Sequence< ::sal_Int8 > SAL_CALL getImplementationId( ) throw (::com::sun::star::uno::RuntimeException); + + // XServiceInfo + SVX_DLLPRIVATE virtual ::rtl::OUString SAL_CALL getImplementationName( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) throw (::com::sun::star::uno::RuntimeException); + + // XLayoutConstrains + SVX_DLLPRIVATE virtual ::com::sun::star::awt::Size SAL_CALL getMinimumSize( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::awt::Size SAL_CALL getPreferredSize( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::awt::Size SAL_CALL calcAdjustedSize( const ::com::sun::star::awt::Size& aNewSize ) throw (::com::sun::star::uno::RuntimeException); + + // XMergeableCell + SVX_DLLPRIVATE virtual ::sal_Int32 SAL_CALL getRowSpan() throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::sal_Int32 SAL_CALL getColumnSpan() throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::sal_Bool SAL_CALL isMerged() throw (::com::sun::star::uno::RuntimeException); + + // XCell + SVX_DLLPRIVATE virtual ::rtl::OUString SAL_CALL getFormula() throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL setFormula( const ::rtl::OUString& aFormula ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual double SAL_CALL getValue() throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL setValue( double nValue ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::table::CellContentType SAL_CALL getType() throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual sal_Int32 SAL_CALL getError() throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::beans::XPropertySet + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() throw(::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XMultiPropertySet + SVX_DLLPRIVATE virtual void SAL_CALL setPropertyValues( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aValues ) throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > SAL_CALL getPropertyValues( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL addPropertiesChangeListener( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL removePropertiesChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL firePropertiesChangeEvent( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::beans::XPropertyState + SVX_DLLPRIVATE virtual ::com::sun::star::beans::PropertyState SAL_CALL getPropertyState( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyState > SAL_CALL getPropertyStates( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL setPropertyToDefault( const ::rtl::OUString& PropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Any SAL_CALL getPropertyDefault( const ::rtl::OUString& aPropertyName ) throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XMultiPropertyStates + SVX_DLLPRIVATE virtual void SAL_CALL setAllPropertiesToDefault( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL setPropertiesToDefault( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > SAL_CALL getPropertyDefaults( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XFastPropertySet + SVX_DLLPRIVATE virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XText + SVX_DLLPRIVATE virtual void SAL_CALL insertTextContent( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >& xRange, const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextContent >& xContent, ::sal_Bool bAbsorb ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL removeTextContent( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextContent >& xContent ) throw (::com::sun::star::container::NoSuchElementException, ::com::sun::star::uno::RuntimeException); + + // XSimpleText + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextCursor > SAL_CALL createTextCursor( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextCursor > SAL_CALL createTextCursorByRange( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >& aTextPosition ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL insertString( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >& xRange, const ::rtl::OUString& aString, ::sal_Bool bAbsorb ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL insertControlCharacter( const ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange >& xRange, ::sal_Int16 nControlCharacter, ::sal_Bool bAbsorb ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + + // XTextRange + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XText > SAL_CALL getText( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > SAL_CALL getStart( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::com::sun::star::uno::Reference< ::com::sun::star::text::XTextRange > SAL_CALL getEnd( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual ::rtl::OUString SAL_CALL getString( ) throw (::com::sun::star::uno::RuntimeException); + SVX_DLLPRIVATE virtual void SAL_CALL setString( const ::rtl::OUString& aString ) throw (::com::sun::star::uno::RuntimeException); + + // XEventListener + SVX_DLLPRIVATE virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + + SVX_DLLPRIVATE virtual void SetOutlinerParaObject( OutlinerParaObject* pTextObject ); + + SVX_DLLPRIVATE void AddUndo(); + + using SvxUnoTextRangeBase::setPropertyValue; + using SvxUnoTextRangeBase::getPropertyValue; + + SVX_DLLPRIVATE sdr::properties::TextProperties* CloneProperties( SdrObject& rNewObj, Cell& rNewCell ); + + SVX_DLLPRIVATE static sdr::properties::TextProperties* CloneProperties( sdr::properties::TextProperties* pProperties, SdrObject& rNewObj, Cell& rNewCell ); + + SVX_DLLPRIVATE void notifyModified(); + + ::rtl::OUString getName(); + +protected: + SVX_DLLPRIVATE virtual const SfxItemSet& GetObjectItemSet(); + SVX_DLLPRIVATE virtual void SetObjectItem(const SfxPoolItem& rItem); + + SVX_DLLPRIVATE ::com::sun::star::uno::Any GetAnyForItem( SfxItemSet& aSet, const SfxItemPropertySimpleEntry* pMap ); + +private: + SVX_DLLPRIVATE Cell( SdrTableObj& rTableObj, OutlinerParaObject* pOutlinerParaObject ) throw(); + SVX_DLLPRIVATE virtual ~Cell() throw(); + + const SvxItemPropertySet* mpPropSet; + + sdr::properties::TextProperties* mpProperties; + + ::com::sun::star::table::CellContentType mnCellContentType; + + ::rtl::OUString msFormula; + double mfValue; + ::sal_Int32 mnError; + ::sal_Bool mbMerged; + ::sal_Int32 mnRowSpan; + ::sal_Int32 mnColSpan; + + Rectangle maCellRect; + + ::com::sun::star::uno::Reference< ::com::sun::star::table::XTable > mxTable; +}; + +// ----------------------------------------------------------------------------- + +} } + +#endif diff --git a/svx/source/table/cellcursor.cxx b/svx/source/table/cellcursor.cxx new file mode 100644 index 000000000000..70329213d01a --- /dev/null +++ b/svx/source/table/cellcursor.cxx @@ -0,0 +1,590 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include "svx/svdotable.hxx" +#include "cellcursor.hxx" +#include "tablelayouter.hxx" +#include "cell.hxx" +#include "svx/svdmodel.hxx" +#include "svdstr.hrc" +#include "svdglob.hxx" + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::table; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// CellCursor +// ----------------------------------------------------------------------------- + +CellCursor::CellCursor( const TableModelRef & xTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) +: CellCursorBase( xTable, nLeft, nTop, nRight, nBottom ) +{ +} + +// ----------------------------------------------------------------------------- + +CellCursor::~CellCursor() +{ +} + +// ----------------------------------------------------------------------------- +// XCellCursor +// ----------------------------------------------------------------------------- + +Reference< XCell > SAL_CALL CellCursor::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException) +{ + return CellRange::getCellByPosition( nColumn, nRow ); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL CellCursor::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException) +{ + return CellRange::getCellRangeByPosition( nLeft, nTop, nRight, nBottom ); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL CellCursor::getCellRangeByName( const OUString& aRange ) throw (RuntimeException) +{ + return CellRange::getCellRangeByName( aRange ); +} + +// ----------------------------------------------------------------------------- +// XCellCursor +// ----------------------------------------------------------------------------- + +void SAL_CALL CellCursor::gotoStart( ) throw (RuntimeException) +{ + mnRight = mnLeft; + mnBottom = mnTop; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL CellCursor::gotoEnd( ) throw (RuntimeException) +{ + mnLeft = mnRight; + mnTop = mnBottom; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL CellCursor::gotoNext( ) throw (RuntimeException) +{ + if( mxTable.is() ) + { + mnRight++; + if( mnRight >= mxTable->getColumnCount() ) + { + // if we past the last column, try skip to the row line + mnTop++; + if( mnTop >= mxTable->getRowCount() ) + { + // if we past the last row, do not move cursor at all + mnTop--; + mnRight--; + } + else + { + // restart at the first column on the next row + mnRight = 0; + } + } + } + + mnLeft = mnRight; + mnTop = mnBottom; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL CellCursor::gotoPrevious( ) throw (RuntimeException) +{ + if( mxTable.is() ) + { + if( mnLeft > 0 ) + { + --mnLeft; + } + else if( mnTop > 0 ) + { + --mnTop; + mnLeft = mxTable->getColumnCount() - 1; + } + } + + mnRight = mnLeft; + mnBottom = mnTop; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL CellCursor::gotoOffset( ::sal_Int32 nColumnOffset, ::sal_Int32 nRowOffset ) throw (RuntimeException) +{ + if( mxTable.is() ) + { + const sal_Int32 nLeft = mnLeft + nColumnOffset; + if( (nLeft >= 0) && (nLeft < mxTable->getColumnCount() ) ) + mnRight = mnLeft = nLeft; + + const sal_Int32 nTop = mnTop + nRowOffset; + if( (nTop >= 0) && (nTop < mxTable->getRowCount()) ) + mnTop = mnBottom = nTop; + } +} + +// ----------------------------------------------------------------------------- +// XMergeableCellCursor +// ----------------------------------------------------------------------------- + +/** returns true and the merged cell positions if a merge is valid or false if a merge is + not valid for that range */ +bool CellCursor::GetMergedSelection( CellPos& rStart, CellPos& rEnd ) +{ + rStart.mnCol = mnLeft; rStart.mnRow = mnTop; + rEnd.mnCol = mnRight; rEnd.mnRow = mnBottom; + + // single cell merge is never valid + if( mxTable.is() && ((mnLeft != mnRight) || (mnTop != mnBottom)) ) try + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( mnLeft, mnTop ).get() ) ); + + // check if first cell is merged + if( xCell.is() && xCell->isMerged() ) + findMergeOrigin( mxTable, mnLeft, mnTop, rStart.mnCol, rStart.mnRow ); + + // check if last cell is merged + xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( mnRight, mnBottom ).get() ) ); + if( xCell.is() ) + { + if( xCell->isMerged() ) + { + findMergeOrigin( mxTable, mnRight, mnBottom, rEnd.mnCol, rEnd.mnRow ); + // merge not possible if selection is only one cell and all its merges + if( rEnd == rStart ) + return false; + xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rEnd.mnCol, rEnd.mnRow ).get() ) ); + } + } + if( xCell.is() ) + { + rEnd.mnCol += xCell->getColumnSpan()-1; + rEnd.mnRow += xCell->getRowSpan()-1; + } + + // now check if everything is inside the given bounds + sal_Int32 nRow, nCol; + for( nRow = rStart.mnRow; nRow <= rEnd.mnRow; nRow++ ) + { + for( nCol = rStart.mnCol; nCol <= rEnd.mnCol; nCol++ ) + { + xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( !xCell.is() ) + continue; + + if( xCell->isMerged() ) + { + sal_Int32 nOriginCol, nOriginRow; + if( findMergeOrigin( mxTable, nCol, nRow, nOriginCol, nOriginRow ) ) + { + if( (nOriginCol < rStart.mnCol) || (nOriginRow < rStart.mnRow) ) + return false; + + xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( nOriginCol, nOriginRow ).get() ) ); + if( xCell.is() ) + { + nOriginCol += xCell->getColumnSpan()-1; + nOriginRow += xCell->getRowSpan()-1; + + if( (nOriginCol > rEnd.mnCol) || (nOriginRow > rEnd.mnRow) ) + return false; + } + } + } + else if( ((nCol + xCell->getColumnSpan() - 1) > rEnd.mnCol) || ((nRow + xCell->getRowSpan() - 1 ) > rEnd.mnRow) ) + { + return false; + } + } + } + return true; + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::SvmxTableController::GetMergedSelection(), exception caught!"); + } + return false; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL CellCursor::merge( ) throw (NoSupportException, RuntimeException) +{ + CellPos aStart, aEnd; + if( !GetMergedSelection( aStart, aEnd ) ) + throw NoSupportException(); + + if( !mxTable.is() || (mxTable->getSdrTableObj() == 0) ) + throw DisposedException(); + + SdrModel* pModel = mxTable->getSdrTableObj()->GetModel(); + const bool bUndo = pModel && mxTable->getSdrTableObj()->IsInserted() && pModel->IsUndoEnabled(); + + if( bUndo ) + pModel->BegUndo( ImpGetResStr(STR_TABLE_MERGE) ); + + try + { + mxTable->merge( aStart.mnCol, aStart.mnRow, aEnd.mnCol - aStart.mnCol + 1, aEnd.mnRow - aStart.mnRow + 1 ); + mxTable->optimize(); + mxTable->setModified(sal_True); + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::CellCursor::merge(), exception caught!"); + } + + if( bUndo ) + pModel->EndUndo(); + + if( pModel ) + pModel->SetChanged(); +} + +// ----------------------------------------------------------------------------- + +void CellCursor::split_column( sal_Int32 nCol, sal_Int32 nColumns, std::vector< sal_Int32 >& rLeftOvers ) +{ + const sal_Int32 nRowCount = mxTable->getRowCount(); + + sal_Int32 nNewCols = 0, nRow; + + // first check how many columns we need to add + for( nRow = mnTop; nRow <= mnBottom; ++nRow ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() && !xCell->isMerged() ) + nNewCols = std::max( nNewCols, nColumns - xCell->getColumnSpan() + 1 - rLeftOvers[nRow] ); + } + + if( nNewCols > 0 ) + { + const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM("Width") ); + Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_QUERY_THROW ); + Reference< XPropertySet > xRefColumn( xCols->getByIndex( nCol ), UNO_QUERY_THROW ); + sal_Int32 nWidth = 0; + xRefColumn->getPropertyValue( sWidth ) >>= nWidth; + const sal_Int32 nNewWidth = nWidth / (nNewCols + 1); + + // reference column gets new width + rounding errors + xRefColumn->setPropertyValue( sWidth, Any( nWidth - (nNewWidth * nNewCols) ) ); + + xCols->insertByIndex( nCol + 1, nNewCols ); + mnRight += nNewCols; + + // distribute new width + for( sal_Int32 nNewCol = nCol + nNewCols; nNewCol > nCol; --nNewCol ) + { + Reference< XPropertySet > xNewCol( xCols->getByIndex( nNewCol ), UNO_QUERY_THROW ); + xNewCol->setPropertyValue( sWidth, Any( nNewWidth ) ); + } + } + + for( nRow = 0; nRow < nRowCount; ++nRow ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( !xCell.is() || xCell->isMerged() ) + { + if( nNewCols > 0 ) + { + // merged cells are ignored, but newly added columns will be added to leftovers + xCell.set( dynamic_cast< Cell* >(mxTable->getCellByPosition( nCol+1, nRow ).get() ) ); + if( !xCell.is() || !xCell->isMerged() ) + rLeftOvers[nRow] += nNewCols; + } + } + else + { + sal_Int32 nRowSpan = xCell->getRowSpan() - 1; + sal_Int32 nColSpan = xCell->getColumnSpan() - 1; + + if( (nRow >= mnTop) && (nRow <= mnBottom) ) + { + sal_Int32 nCellsAvailable = 1 + nColSpan + rLeftOvers[nRow]; + if( nColSpan == 0 ) + nCellsAvailable += nNewCols; + + DBG_ASSERT( nCellsAvailable > nColumns, "sdr::table::CellCursor::split_column(), somethings wrong" ); + + sal_Int32 nSplitSpan = (nCellsAvailable / (nColumns + 1)) - 1; + + sal_Int32 nSplitCol = nCol; + sal_Int32 nSplits = nColumns + 1; + while( nSplits-- ) + { + // last split eats rounding cells + if( nSplits == 0 ) + nSplitSpan = nCellsAvailable - ((nSplitSpan+1) * nColumns) - 1; + + mxTable->merge( nSplitCol, nRow, nSplitSpan + 1, nRowSpan + 1); + if( nSplits > 0 ) + nSplitCol += nSplitSpan + 1; + } + + do + { + rLeftOvers[nRow++] = 0; + } + while( nRowSpan-- ); + --nRow; + } + else + { + // cope with outside cells, merge if needed + if( nColSpan < (rLeftOvers[nRow] + nNewCols) ) + mxTable->merge( nCol, nRow, (rLeftOvers[nRow] + nNewCols) + 1, nRowSpan + 1 ); + + do + { + rLeftOvers[nRow++] = 0; // consumed + } + while( nRowSpan-- ); + --nRow; + } + } + } +} + +// ----------------------------------------------------------------------------- + +void CellCursor::split_horizontal( sal_Int32 nColumns ) +{ + const sal_Int32 nRowCount = mxTable->getRowCount(); + + std::vector< sal_Int32 > aLeftOvers( nRowCount ); + + for( sal_Int32 nCol = mnRight; nCol >= mnLeft; --nCol ) + split_column( nCol, nColumns, aLeftOvers ); +} + +// ----------------------------------------------------------------------------- + +void CellCursor::split_row( sal_Int32 nRow, sal_Int32 nRows, std::vector< sal_Int32 >& rLeftOvers ) +{ + const sal_Int32 nColCount = mxTable->getColumnCount(); + + sal_Int32 nNewRows = 0, nCol; + + // first check how many columns we need to add + for( nCol = mnLeft; nCol <= mnRight; ++nCol ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() && !xCell->isMerged() ) + nNewRows = std::max( nNewRows, nRows - xCell->getRowSpan() + 1 - rLeftOvers[nCol] ); + } + + if( nNewRows > 0 ) + { + const OUString sHeight( RTL_CONSTASCII_USTRINGPARAM("Height") ); + Reference< XTableRows > xRows( mxTable->getRows(), UNO_QUERY_THROW ); + Reference< XPropertySet > xRefRow( xRows->getByIndex( nRow ), UNO_QUERY_THROW ); + sal_Int32 nHeight = 0; + xRefRow->getPropertyValue( sHeight ) >>= nHeight; + const sal_Int32 nNewHeight = nHeight / (nNewRows + 1); + + // reference row gets new height + rounding errors + xRefRow->setPropertyValue( sHeight, Any( nHeight - (nNewHeight * nNewRows) ) ); + + xRows->insertByIndex( nRow + 1, nNewRows ); + mnBottom += nNewRows; + + // distribute new width + for( sal_Int32 nNewRow = nRow + nNewRows; nNewRow > nRow; --nNewRow ) + { + Reference< XPropertySet > xNewRow( xRows->getByIndex( nNewRow ), UNO_QUERY_THROW ); + xNewRow->setPropertyValue( sHeight, Any( nNewHeight ) ); + } + } + + for( nCol = 0; nCol < nColCount; ++nCol ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( !xCell.is() || xCell->isMerged() ) + { + if( nNewRows ) + { + // merged cells are ignored, but newly added columns will be added to leftovers + xCell.set( dynamic_cast< Cell* >(mxTable->getCellByPosition( nCol, nRow+1 ).get() ) ); + if( !xCell.is() || !xCell->isMerged() ) + rLeftOvers[nCol] += nNewRows; + } + } + else + { + sal_Int32 nRowSpan = xCell->getRowSpan() - 1; + sal_Int32 nColSpan = xCell->getColumnSpan() - 1; + + if( (nCol >= mnLeft) && (nCol <= mnRight) ) + { + sal_Int32 nCellsAvailable = 1 + nRowSpan + rLeftOvers[nCol]; + if( nRowSpan == 0 ) + nCellsAvailable += nNewRows; + + DBG_ASSERT( nCellsAvailable > nRows, "sdr::table::CellCursor::split_row(), somethings wrong" ); + + sal_Int32 nSplitSpan = (nCellsAvailable / (nRows + 1)) - 1; + + sal_Int32 nSplitRow = nRow; + sal_Int32 nSplits = nRows + 1; + while( nSplits-- ) + { + // last split eats rounding cells + if( nSplits == 0 ) + nSplitSpan = nCellsAvailable - ((nSplitSpan+1) * nRows) - 1; + + mxTable->merge( nCol, nSplitRow, nColSpan + 1, nSplitSpan + 1 ); + if( nSplits > 0 ) + nSplitRow += nSplitSpan + 1; + } + + do + { + rLeftOvers[nCol++] = 0; + } + while( nColSpan-- ); + --nCol; + } + else + { + // cope with outside cells, merge if needed + if( nRowSpan < (rLeftOvers[nCol] + nNewRows) ) + mxTable->merge( nCol, nRow, nColSpan + 1, (rLeftOvers[nCol] + nNewRows) + 1 ); + + do + { + rLeftOvers[nCol++] = 0; // consumed + } + while( nColSpan-- ); + --nCol; + } + } + } +} + +// ----------------------------------------------------------------------------- + +void CellCursor::split_vertical( sal_Int32 nRows ) +{ + const sal_Int32 nColCount = mxTable->getColumnCount(); + + std::vector< sal_Int32 > aLeftOvers( nColCount ); + + for( sal_Int32 nRow = mnBottom; nRow >= mnTop; --nRow ) + split_row( nRow, nRows, aLeftOvers ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL CellCursor::split( sal_Int32 nColumns, sal_Int32 nRows ) throw (NoSupportException, IllegalArgumentException, RuntimeException) +{ + if( (nColumns < 0) || (nRows < 0) ) + throw IllegalArgumentException(); + + if( !mxTable.is() || (mxTable->getSdrTableObj() == 0) ) + throw DisposedException(); + + SdrModel* pModel = mxTable->getSdrTableObj()->GetModel(); + const bool bUndo = pModel && mxTable->getSdrTableObj()->IsInserted() && pModel->IsUndoEnabled(); + if( bUndo ) + pModel->BegUndo( ImpGetResStr(STR_TABLE_SPLIT) ); + + try + { + if( nColumns > 0 ) + split_horizontal( nColumns ); + + if( nRows > 0 ) + split_vertical( nRows ); + + if( nColumns > 0 ||nRows > 0 ) + mxTable->setModified(sal_True); + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::CellCursor::split(), exception caught!"); + throw NoSupportException(); + } + + if( bUndo ) + pModel->EndUndo(); + + if( pModel ) + pModel->SetChanged(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL CellCursor::isMergeable( ) throw (RuntimeException) +{ + CellPos aStart, aEnd; + return GetMergedSelection( aStart, aEnd ) ? sal_True : sal_False; +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL CellCursor::isUnmergeable( ) throw (RuntimeException) +{ + // this is true if there is at least one merged cell in the current range + for( sal_Int32 nRow = mnTop; nRow <= mnBottom; nRow++ ) + { + for( sal_Int32 nCol = mnLeft; nCol <= mnRight; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() && ( (xCell->getRowSpan() > 1) || (xCell->getColumnSpan() > 1) ) ) + return sal_True; + } + } + return sal_False; +} + +// ----------------------------------------------------------------------------- + +} } diff --git a/svx/source/table/cellcursor.hxx b/svx/source/table/cellcursor.hxx new file mode 100644 index 000000000000..39b5a082416c --- /dev/null +++ b/svx/source/table/cellcursor.hxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_CELLCURSOR_HXX_ +#define _SVX_CELLCURSOR_HXX_ + +#include <com/sun/star/table/XMergeableCellRange.hpp> +#include <com/sun/star/table/XCellCursor.hpp> +#include <cppuhelper/implbase2.hxx> +#include "cellrange.hxx" + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +struct CellPos; + +// ----------------------------------------------------------------------------- +// CellCursor +// ----------------------------------------------------------------------------- + +typedef ::cppu::ImplInheritanceHelper2< CellRange, ::com::sun::star::table::XCellCursor, ::com::sun::star::table::XMergeableCellRange > CellCursorBase; + +class CellCursor : public CellCursorBase +{ +public: + CellCursor( const TableModelRef& xTableModel, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ); + virtual ~CellCursor(); + + // XCellRange + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByName( const ::rtl::OUString& aRange ) throw (::com::sun::star::uno::RuntimeException); + + // XCellCursor + virtual void SAL_CALL gotoStart( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL gotoEnd( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL gotoNext( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL gotoPrevious( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL gotoOffset( ::sal_Int32 nColumnOffset, ::sal_Int32 nRowOffset ) throw (::com::sun::star::uno::RuntimeException); + + // XMergeableCellRange + virtual void SAL_CALL merge( ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL split( ::sal_Int32 Columns, ::sal_Int32 Rows ) throw (::com::sun::star::lang::NoSupportException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL isMergeable( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL isUnmergeable( ) throw (::com::sun::star::uno::RuntimeException); + +protected: + bool GetMergedSelection( CellPos& rStart, CellPos& rEnd ); + + void split_column( sal_Int32 nCol, sal_Int32 nColumns, std::vector< sal_Int32 >& rLeftOvers ); + void split_horizontal( sal_Int32 nColumns ); + void split_row( sal_Int32 nRow, sal_Int32 nRows, std::vector< sal_Int32 >& rLeftOvers ); + void split_vertical( sal_Int32 nRows ); +}; + +} } + +#endif diff --git a/svx/source/table/celleditsource.cxx b/svx/source/table/celleditsource.cxx new file mode 100644 index 000000000000..218d8631cb75 --- /dev/null +++ b/svx/source/table/celleditsource.cxx @@ -0,0 +1,1056 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/linguistic2/XLinguServiceManager.hpp> + +#include <rtl/ref.hxx> +#include <osl/mutex.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <comphelper/processfactory.hxx> +#include <svl/lstner.hxx> +#include <svl/hint.hxx> +#include <svl/style.hxx> + +#include "celleditsource.hxx" +#include "cell.hxx" +#include "svx/svdmodel.hxx" +#include "svx/svdoutl.hxx" +#include "svx/svdobj.hxx" +#include "editeng/unoedhlp.hxx" +#include "svx/svdview.hxx" +#include "svx/svdetc.hxx" +#include "editeng/outliner.hxx" +#include "editeng/unoforou.hxx" +#include "editeng/unoviwou.hxx" +#include "editeng/outlobj.hxx" +#include "svx/svdotext.hxx" +#include "svx/svdpage.hxx" +#include "editeng/editeng.hxx" +#include "editeng/unotext.hxx" +#include "sdrpaintwindow.hxx" + +//------------------------------------------------------------------------ + +using ::rtl::OUString; +using namespace ::osl; +using namespace ::vos; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::linguistic2; +using namespace ::com::sun::star::lang; + +//------------------------------------------------------------------------ + +namespace sdr { namespace table { + +//------------------------------------------------------------------------ +// CellEditSourceImpl +//------------------------------------------------------------------------ + +/** @descr + <p>This class essentially provides the text and view forwarders. If + no SdrView is given, this class handles the UNO objects, which are + currently not concerned with view issues. In this case, + GetViewForwarder() always returns NULL and the underlying + EditEngine of the SvxTextForwarder is a background one (i.e. not + the official DrawOutliner, but one created exclusively for this + object, with no relation to a view). + </p> + + <p>If a SdrView is given at construction time, the caller is + responsible for destroying this object when the view becomes + invalid (the views cannot notify). If GetViewForwarder(sal_True) + is called, the underlying shape is put into edit mode, the view + forwarder returned encapsulates the OutlinerView and the next call + to GetTextForwarder() yields a forwarder encapsulating the actual + DrawOutliner. Thus, changes on that Outliner are immediately + reflected on the screen. If the object leaves edit mode, the old + behaviour is restored.</p> + */ +class CellEditSourceImpl : public SfxListener, public SfxBroadcaster +{ +private: + oslInterlockedCount maRefCount; + + SdrView* mpView; + const Window* mpWindow; + SdrModel* mpModel; + SdrOutliner* mpOutliner; + SvxOutlinerForwarder* mpTextForwarder; + SvxDrawOutlinerViewForwarder* mpViewForwarder; + Reference< ::com::sun::star::linguistic2::XLinguServiceManager > mxLinguServiceManager; + Point maTextOffset; + bool mbDataValid; + bool mbDisposed; + bool mbIsLocked; + bool mbNeedsUpdate; + bool mbOldUndoMode; + bool mbForwarderIsEditMode; // have to reflect that, since ENDEDIT can happen more often + bool mbShapeIsEditMode; // #104157# only true, if HINT_BEGEDIT was received + bool mbNotificationsDisabled; // prevent EditEngine/Outliner notifications (e.g. when setting up forwarder) + + CellRef mxCell; + SvxUnoTextRangeBaseList maTextRanges; + + SvxTextForwarder* GetBackgroundTextForwarder(); + SvxTextForwarder* GetEditModeTextForwarder(); + SvxDrawOutlinerViewForwarder* CreateViewForwarder(); + + void SetupOutliner(); + void UpdateOutliner(); + + bool HasView() const { return mpView != 0; } + bool IsEditMode() const { return mxCell->IsTextEditActive(); }; + void dispose(); + +public: + CellEditSourceImpl( const CellRef& xCell ); + CellEditSourceImpl( const CellRef& xCell, SdrView& rView, const Window& rWindow ); + ~CellEditSourceImpl(); + + void SAL_CALL acquire(); + void SAL_CALL release(); + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ); + + SvxEditSource* Clone() const; + SvxTextForwarder* GetTextForwarder(); + SvxEditViewForwarder* GetEditViewForwarder( sal_Bool ); + void UpdateData(); + + void addRange( SvxUnoTextRangeBase* pNewRange ); + void removeRange( SvxUnoTextRangeBase* pOldRange ); + const SvxUnoTextRangeBaseList& getRanges() const; + + void lock(); + void unlock(); + + BOOL IsValid() const; + + Rectangle GetVisArea(); + Point LogicToPixel( const Point&, const MapMode& rMapMode ); + Point PixelToLogic( const Point&, const MapMode& rMapMode ); + + DECL_LINK( NotifyHdl, EENotify* ); + + void ChangeModel( SdrModel* pNewModel ); +}; + +//------------------------------------------------------------------------ + +CellEditSourceImpl::CellEditSourceImpl( const CellRef& xCell ) + : maRefCount ( 0 ), + mpView ( NULL ), + mpWindow ( NULL ), + mpModel ( NULL ), + mpOutliner ( NULL ), + mpTextForwarder ( NULL ), + mpViewForwarder ( NULL ), + mbDataValid ( false ), + mbDisposed ( false ), + mbIsLocked ( false ), + mbNeedsUpdate ( false ), + mbOldUndoMode ( false ), + mbForwarderIsEditMode ( false ), + mbShapeIsEditMode ( false ), + mbNotificationsDisabled ( false ), + mxCell( xCell ) +{ +} + +//------------------------------------------------------------------------ + +CellEditSourceImpl::CellEditSourceImpl( const CellRef& xCell, SdrView& rView, const Window& rWindow ) + : maRefCount ( 0 ), + mpView ( &rView ), + mpWindow ( &rWindow ), + mpModel ( NULL ), + mpOutliner ( NULL ), + mpTextForwarder ( NULL ), + mpViewForwarder ( NULL ), + mbDataValid ( false ), + mbDisposed ( false ), + mbIsLocked ( false ), + mbNeedsUpdate ( false ), + mbOldUndoMode ( false ), + mbForwarderIsEditMode ( false ), + mbShapeIsEditMode ( true ), + mbNotificationsDisabled ( false ), + mxCell( xCell ) +{ + if( mpView ) + StartListening( *mpView ); + + // #104157# Init edit mode state from shape info (IsTextEditActive()) + mbShapeIsEditMode = IsEditMode(); +} + +//------------------------------------------------------------------------ + +CellEditSourceImpl::~CellEditSourceImpl() +{ + DBG_ASSERT( mbIsLocked == sal_False, "CellEditSourceImpl::~CellEditSourceImpl(), was not unlocked before dispose!" ); + dispose(); +} + +//------------------------------------------------------------------------ + +void CellEditSourceImpl::addRange( SvxUnoTextRangeBase* pNewRange ) +{ + if( pNewRange ) + if( std::find( maTextRanges.begin(), maTextRanges.end(), pNewRange ) == maTextRanges.end() ) + maTextRanges.push_back( pNewRange ); +} + +//------------------------------------------------------------------------ + +void CellEditSourceImpl::removeRange( SvxUnoTextRangeBase* pOldRange ) +{ + if( pOldRange ) + maTextRanges.remove( pOldRange ); +} + +//------------------------------------------------------------------------ + +const SvxUnoTextRangeBaseList& CellEditSourceImpl::getRanges() const +{ + return maTextRanges; +} + +//------------------------------------------------------------------------ + +void SAL_CALL CellEditSourceImpl::acquire() +{ + osl_incrementInterlockedCount( &maRefCount ); +} + +//------------------------------------------------------------------------ + +void SAL_CALL CellEditSourceImpl::release() +{ + if( ! osl_decrementInterlockedCount( &maRefCount ) ) + delete this; +} + +void CellEditSourceImpl::ChangeModel( SdrModel* pNewModel ) +{ + if( mpModel != pNewModel ) + { + if( mpOutliner ) + { + if( mpModel ) + mpModel->disposeOutliner( mpOutliner ); + else + delete mpOutliner; + mpOutliner = 0; + } + + if( mpView ) + { + EndListening( *mpView ); + mpView = 0; + } + + mpWindow = 0; + mxLinguServiceManager.clear(); + + mpModel = pNewModel; + + if( mpTextForwarder ) + { + delete mpTextForwarder; + mpTextForwarder = 0; + } + + if( mpViewForwarder ) + { + delete mpViewForwarder; + mpViewForwarder = 0; + } + } +} + +//------------------------------------------------------------------------ + +void CellEditSourceImpl::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + const SdrHint* pSdrHint = PTR_CAST( SdrHint, &rHint ); + const SvxViewHint* pViewHint = PTR_CAST( SvxViewHint, &rHint ); + + if( pViewHint ) + { + switch( pViewHint->GetHintType() ) + { + case SvxViewHint::SVX_HINT_VIEWCHANGED: + Broadcast( *pViewHint ); + break; + } + } + else if( pSdrHint ) + { + switch( pSdrHint->GetKind() ) + { + case HINT_OBJCHG: + { + mbDataValid = FALSE; // Text muss neu geholt werden + + if( HasView() ) + { + // #104157# Update maTextOffset, object has changed + // #105196#, #105203#: Cannot call that // here, + // since TakeTextRect() (called from there) // + // changes outliner content. + // UpdateOutliner(); + + // #101029# Broadcast object changes, as they might change visible attributes + SvxViewHint aHint(SvxViewHint::SVX_HINT_VIEWCHANGED); + Broadcast( aHint ); + } + break; + } + + case HINT_BEGEDIT: +/* todo + if( mpObject == pSdrHint->GetObject() ) + { + // invalidate old forwarder + if( !mbForwarderIsEditMode ) + { + delete mpTextForwarder; + mpTextForwarder = NULL; + } + + // register as listener - need to broadcast state change messages + if( mpView && mpView->GetTextEditOutliner() ) + mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, CellEditSourceImpl, NotifyHdl) ); + + // #104157# Only now we're really in edit mode + mbShapeIsEditMode = TRUE; + + Broadcast( *pSdrHint ); + } +*/ + break; + + case HINT_ENDEDIT: +/* todo + if( mpObject == pSdrHint->GetObject() ) + { + Broadcast( *pSdrHint ); + + // #104157# We're no longer in edit mode + mbShapeIsEditMode = FALSE; + + // remove as listener - outliner might outlive ourselves + if( mpView && mpView->GetTextEditOutliner() ) + mpView->GetTextEditOutliner()->SetNotifyHdl( Link() ); + + // destroy view forwarder, OutlinerView no longer + // valid (no need for UpdateData(), it's been + // synched on SdrEndTextEdit) + delete mpViewForwarder; + mpViewForwarder = NULL; + + // #100424# Invalidate text forwarder, we might + // not be called again before entering edit mode a + // second time! Then, the old outliner might be + // invalid. + if( mbForwarderIsEditMode ) + { + mbForwarderIsEditMode = sal_False; + delete mpTextForwarder; + mpTextForwarder = NULL; + } + } +*/ + break; + + case HINT_MODELCLEARED: + dispose(); + break; + default: + break; + } + } +} + +/* unregister at all objects and set all references to 0 */ +void CellEditSourceImpl::dispose() +{ + if( mpTextForwarder ) + { + delete mpTextForwarder; + mpTextForwarder = 0; + } + + if( mpViewForwarder ) + { + delete mpViewForwarder; + mpViewForwarder = 0; + } + + if( mpOutliner ) + { + if( mpModel ) + { + mpModel->disposeOutliner( mpOutliner ); + } + else + { + delete mpOutliner; + } + mpOutliner = 0; + } + + if( mpView ) + { + EndListening( *mpView ); + mpView = 0; + } + + mpModel = 0; + mpWindow = 0; +} + +//------------------------------------------------------------------------ + +void CellEditSourceImpl::SetupOutliner() +{ + // #101029# + // only for UAA edit source: setup outliner equivalently as in + // SdrTextObj::Paint(), such that formatting equals screen + // layout +/* todo + if( mpObject && mpOutliner ) + { + SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); + Rectangle aPaintRect; + if( pTextObj ) + { + Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() ); + pTextObj->SetupOutlinerFormatting( *mpOutliner, aPaintRect ); + + // #101029# calc text offset from shape anchor + maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft(); + } + } +*/ +} + +//------------------------------------------------------------------------ + +void CellEditSourceImpl::UpdateOutliner() +{ + // #104157# + // only for UAA edit source: update outliner equivalently as in + // SdrTextObj::Paint(), such that formatting equals screen + // layout +/* todo + if( mpObject && mpOutliner ) + { + SdrTextObj* pTextObj = PTR_CAST( SdrTextObj, mpObject ); + Rectangle aPaintRect; + if( pTextObj ) + { + Rectangle aBoundRect( pTextObj->GetCurrentBoundRect() ); + pTextObj->UpdateOutlinerFormatting( *mpOutliner, aPaintRect ); + + // #101029# calc text offset from shape anchor + maTextOffset = aPaintRect.TopLeft() - aBoundRect.TopLeft(); + } + } +*/ +} + +//------------------------------------------------------------------------ + + +SvxTextForwarder* CellEditSourceImpl::GetBackgroundTextForwarder() +{ + sal_Bool bCreated = sal_False; + + // #99840#: prevent EE/Outliner notifications during setup + mbNotificationsDisabled = true; + + if (!mpTextForwarder) + { + if( mpOutliner == NULL ) + { + mpOutliner = mpModel->createOutliner( OUTLINERMODE_TEXTOBJECT ); + + // #109151# Do the setup after outliner creation, would be useless otherwise + if( HasView() ) + { + // #101029#, #104157# Setup outliner _before_ filling it + SetupOutliner(); + } + +// todo? mpOutliner->SetTextObjNoInit( pTextObj ); + + if( mbIsLocked ) + { + ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_False ); + mbOldUndoMode = ((EditEngine*)&(mpOutliner->GetEditEngine()))->IsUndoEnabled(); + ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( sal_False ); + } + + if ( !mxLinguServiceManager.is() ) + { + Reference< XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); + mxLinguServiceManager = Reference< XLinguServiceManager >( + xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.linguistic2.LinguServiceManager" ))), UNO_QUERY ); + } + + if ( mxLinguServiceManager.is() ) + { + Reference< XHyphenator > xHyphenator( mxLinguServiceManager->getHyphenator(), UNO_QUERY ); + if( xHyphenator.is() ) + mpOutliner->SetHyphenator( xHyphenator ); + } + } + + mpTextForwarder = new SvxOutlinerForwarder( *mpOutliner ); + + // delay listener subscription and UAA initialization until Outliner is fully setup + bCreated = true; + mbForwarderIsEditMode = false; + } + + if( !mbDataValid ) + { + mpTextForwarder->flushCache(); + + OutlinerParaObject* pOutlinerParaObject = NULL; + bool bTextEditActive = false; + + pOutlinerParaObject = mxCell->GetEditOutlinerParaObject(); // Get the OutlinerParaObject if text edit is active + + if( pOutlinerParaObject ) + bTextEditActive = true; // text edit active + else + pOutlinerParaObject = mxCell->GetOutlinerParaObject(); + + if( pOutlinerParaObject ) + { + mpOutliner->SetText( *pOutlinerParaObject ); + } + else + { + bool bVertical = false; // todo? + + // set objects style sheet on empty outliner + SfxStyleSheetPool* pPool = mxCell->GetStyleSheetPool(); + if( pPool ) + mpOutliner->SetStyleSheetPool( pPool ); + + SfxStyleSheet* pStyleSheet = mxCell->GetStyleSheet(); + if( pStyleSheet ) + mpOutliner->SetStyleSheet( 0, pStyleSheet ); + + if( bVertical ) + mpOutliner->SetVertical( sal_True ); + } + + // evtually we have to set the border attributes + if (mpOutliner->GetParagraphCount()==1) + { + // if we only have one paragraph we check if it is empty + XubString aStr( mpOutliner->GetText( mpOutliner->GetParagraph( 0 ) ) ); + + if(!aStr.Len()) + { + // its empty, so we have to force the outliner to initialise itself + mpOutliner->SetText( String(), mpOutliner->GetParagraph( 0 ) ); + + if(mxCell->GetStyleSheet()) + mpOutliner->SetStyleSheet( 0, mxCell->GetStyleSheet()); + } + } + + if( bTextEditActive ) + delete pOutlinerParaObject; + + mbDataValid = true; + } + + if( bCreated && mpOutliner && HasView() ) + { + // register as listener - need to broadcast state change messages + // registration delayed until outliner is completely set up + mpOutliner->SetNotifyHdl( LINK(this, CellEditSourceImpl, NotifyHdl) ); + } + + // #99840#: prevent EE/Outliner notifications during setup + mbNotificationsDisabled = false; + + return mpTextForwarder; +} + +//------------------------------------------------------------------------ + +SvxTextForwarder* CellEditSourceImpl::GetEditModeTextForwarder() +{ + if( !mpTextForwarder && HasView() ) + { + SdrOutliner* pEditOutliner = mpView->GetTextEditOutliner(); + + if( pEditOutliner ) + { + mpTextForwarder = new SvxOutlinerForwarder( *pEditOutliner ); + mbForwarderIsEditMode = true; + } + } + + return mpTextForwarder; +} + +//------------------------------------------------------------------------ + +SvxTextForwarder* CellEditSourceImpl::GetTextForwarder() +{ + if( mbDisposed ) + return NULL; + + if( mpModel == NULL ) + return NULL; + + // distinguish the cases + // a) connected to view, maybe edit mode is active, can work directly on the EditOutliner + // b) background Outliner, reflect changes into ParaOutlinerObject (this is exactly the old UNO code) + if( HasView() ) + { + if( IsEditMode() != mbForwarderIsEditMode ) + { + // forwarder mismatch - create new + delete mpTextForwarder; + mpTextForwarder = NULL; + } + + if( IsEditMode() ) + return GetEditModeTextForwarder(); + else + return GetBackgroundTextForwarder(); + } + else + return GetBackgroundTextForwarder(); +} + +//------------------------------------------------------------------------ + +SvxDrawOutlinerViewForwarder* CellEditSourceImpl::CreateViewForwarder() +{ + if( mpView->GetTextEditOutlinerView() ) + { + // register as listener - need to broadcast state change messages + mpView->GetTextEditOutliner()->SetNotifyHdl( LINK(this, CellEditSourceImpl, NotifyHdl) ); + + Rectangle aBoundRect( mxCell->GetCurrentBoundRect() ); + OutlinerView& rOutlView = *mpView->GetTextEditOutlinerView(); + + return new SvxDrawOutlinerViewForwarder( rOutlView, aBoundRect.TopLeft() ); + } + + return NULL; +} + +SvxEditViewForwarder* CellEditSourceImpl::GetEditViewForwarder( sal_Bool bCreate ) +{ + if( mbDisposed ) + return NULL; + + if( mpModel == NULL ) + return NULL; + + // shall we delete? + if( mpViewForwarder ) + { + if( !IsEditMode() ) + { + // destroy all forwarders (no need for UpdateData(), + // it's been synched on SdrEndTextEdit) + delete mpViewForwarder; + mpViewForwarder = NULL; + } + } + // which to create? Directly in edit mode, create new, or none? + else if( mpView ) + { + if( IsEditMode() ) + { + // create new view forwarder + mpViewForwarder = CreateViewForwarder(); + } + else if( bCreate ) + { + // dispose old text forwarder + UpdateData(); + + delete mpTextForwarder; + mpTextForwarder = NULL; + + // enter edit mode + mpView->SdrEndTextEdit(); + +/* todo + if(mpView->SdrBeginTextEdit(mpObject, 0L, 0L, sal_False, (SdrOutliner*)0L, 0L, sal_False, sal_False)) + { + if( mxCell->IsTextEditActive() ) + { + // create new view forwarder + mpViewForwarder = CreateViewForwarder(); + } + else + { + // failure. Somehow, SdrBeginTextEdit did not set + // our SdrTextObj into edit mode + mpView->SdrEndTextEdit(); + } + } +*/ + } + } + + return mpViewForwarder; +} + +//------------------------------------------------------------------------ + +void CellEditSourceImpl::UpdateData() +{ + // if we have a view and in edit mode, we're working with the + // DrawOutliner. Thus, all changes made on the text forwarder are + // reflected on the view and committed to the model on + // SdrEndTextEdit(). Thus, no need for explicit updates here. + if( !HasView() || !IsEditMode() ) + { + if( mbIsLocked ) + { + mbNeedsUpdate = true; + } + else + { + if( mpOutliner && !mbDisposed ) + { + if( mpOutliner->GetParagraphCount() != 1 || mpOutliner->GetEditEngine().GetTextLen( 0 ) ) + { + mxCell->SetOutlinerParaObject( mpOutliner->CreateParaObject() ); + } + else + { + mxCell->SetOutlinerParaObject( NULL ); + } + } + } + } +} + +void CellEditSourceImpl::lock() +{ + mbIsLocked = true; + if( mpOutliner ) + { + ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_False ); + mbOldUndoMode = ((EditEngine*)&(mpOutliner->GetEditEngine()))->IsUndoEnabled(); + ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( sal_False ); + } +} + +void CellEditSourceImpl::unlock() +{ + mbIsLocked = false; + + if( mbNeedsUpdate ) + { + UpdateData(); + mbNeedsUpdate = false; + } + + if( mpOutliner ) + { + ((EditEngine*)&(mpOutliner->GetEditEngine()))->SetUpdateMode( sal_True ); + ((EditEngine*)&(mpOutliner->GetEditEngine()))->EnableUndo( mbOldUndoMode ); + } +} + +BOOL CellEditSourceImpl::IsValid() const +{ + return mpView && mpWindow ? TRUE : FALSE; +} + +Rectangle CellEditSourceImpl::GetVisArea() +{ + if( IsValid() ) + { + SdrPaintWindow* pPaintWindow = mpView->FindPaintWindow(*mpWindow); + Rectangle aVisArea; + + if(pPaintWindow) + { + aVisArea = pPaintWindow->GetVisibleArea(); + } + + // offset vis area by edit engine left-top position + Rectangle aAnchorRect; + mxCell->TakeTextAnchorRect( aAnchorRect ); + aVisArea.Move( -aAnchorRect.Left(), -aAnchorRect.Top() ); + + MapMode aMapMode(mpWindow->GetMapMode()); + aMapMode.SetOrigin(Point()); + return mpWindow->LogicToPixel( aVisArea, aMapMode ); + } + + return Rectangle(); +} + +Point CellEditSourceImpl::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) +{ + // #101029#: The responsibilities of ViewForwarder happen to be + // somewhat mixed in this case. On the one hand, we need the + // different interface queries on the SvxEditSource interface, + // since we need both VisAreas. On the other hand, if an + // EditViewForwarder exists, maTextOffset does not remain static, + // but may change with every key press. + if( IsEditMode() ) + { + SvxEditViewForwarder* pForwarder = GetEditViewForwarder(sal_False); + + if( pForwarder ) + return pForwarder->LogicToPixel( rPoint, rMapMode ); + } + else if( IsValid() && mpModel ) + { + // #101029# + Point aPoint1( rPoint ); + aPoint1.X() += maTextOffset.X(); + aPoint1.Y() += maTextOffset.Y(); + + Point aPoint2( OutputDevice::LogicToLogic( aPoint1, rMapMode, + MapMode(mpModel->GetScaleUnit()) ) ); + MapMode aMapMode(mpWindow->GetMapMode()); + aMapMode.SetOrigin(Point()); + return mpWindow->LogicToPixel( aPoint2, aMapMode ); + } + + return Point(); +} + +Point CellEditSourceImpl::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) +{ + // #101029#: The responsibilities of ViewForwarder happen to be + // somewhat mixed in this case. On the one hand, we need the + // different interface queries on the SvxEditSource interface, + // since we need both VisAreas. On the other hand, if an + // EditViewForwarder exists, maTextOffset does not remain static, + // but may change with every key press. + if( IsEditMode() ) + { + SvxEditViewForwarder* pForwarder = GetEditViewForwarder(sal_False); + + if( pForwarder ) + return pForwarder->PixelToLogic( rPoint, rMapMode ); + } + else if( IsValid() && mpModel ) + { + MapMode aMapMode(mpWindow->GetMapMode()); + aMapMode.SetOrigin(Point()); + Point aPoint1( mpWindow->PixelToLogic( rPoint, aMapMode ) ); + Point aPoint2( OutputDevice::LogicToLogic( aPoint1, + MapMode(mpModel->GetScaleUnit()), + rMapMode ) ); + // #101029# + aPoint2.X() -= maTextOffset.X(); + aPoint2.Y() -= maTextOffset.Y(); + + return aPoint2; + } + + return Point(); +} + +IMPL_LINK(CellEditSourceImpl, NotifyHdl, EENotify*, aNotify) +{ + if( aNotify && !mbNotificationsDisabled ) + { + ::std::auto_ptr< SfxHint > aHint( SvxEditSourceHelper::EENotification2Hint( aNotify) ); + + if( aHint.get() ) + Broadcast( *aHint.get() ); + } + + return 0; +} + +//------------------------------------------------------------------------ + +// -------------------------------------------------------------------- +// CellEditSource +// -------------------------------------------------------------------- + +CellEditSource::CellEditSource( const CellRef& xCell ) +{ + mpImpl = new CellEditSourceImpl( xCell ); + mpImpl->acquire(); +} + +// -------------------------------------------------------------------- +CellEditSource::CellEditSource( const CellRef& xCell, SdrView& rView, const Window& rWindow ) +{ + mpImpl = new CellEditSourceImpl( xCell, rView, rWindow ); + mpImpl->acquire(); +} + +// -------------------------------------------------------------------- + +CellEditSource::CellEditSource( CellEditSourceImpl* pImpl ) +{ + mpImpl = pImpl; + mpImpl->acquire(); +} + +//------------------------------------------------------------------------ +CellEditSource::~CellEditSource() +{ + OGuard aGuard( Application::GetSolarMutex() ); + mpImpl->release(); +} + +//------------------------------------------------------------------------ +SvxEditSource* CellEditSource::Clone() const +{ + return new CellEditSource( mpImpl ); +} + +//------------------------------------------------------------------------ +SvxTextForwarder* CellEditSource::GetTextForwarder() +{ + return mpImpl->GetTextForwarder(); +} + +//------------------------------------------------------------------------ +SvxEditViewForwarder* CellEditSource::GetEditViewForwarder( sal_Bool bCreate ) +{ + return mpImpl->GetEditViewForwarder( bCreate ); +} + +//------------------------------------------------------------------------ + +SvxViewForwarder* CellEditSource::GetViewForwarder() +{ + return this; +} + +//------------------------------------------------------------------------ + +void CellEditSource::UpdateData() +{ + mpImpl->UpdateData(); +} + +//------------------------------------------------------------------------ + +SfxBroadcaster& CellEditSource::GetBroadcaster() const +{ + return *mpImpl; +} + +//------------------------------------------------------------------------ + +void CellEditSource::lock() +{ + mpImpl->lock(); +} + +//------------------------------------------------------------------------ + +void CellEditSource::unlock() +{ + mpImpl->unlock(); +} + +//------------------------------------------------------------------------ + +BOOL CellEditSource::IsValid() const +{ + return mpImpl->IsValid(); +} + +//------------------------------------------------------------------------ + +Rectangle CellEditSource::GetVisArea() const +{ + return mpImpl->GetVisArea(); +} + +//------------------------------------------------------------------------ + +Point CellEditSource::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + return mpImpl->LogicToPixel( rPoint, rMapMode ); +} + +//------------------------------------------------------------------------ + +Point CellEditSource::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + return mpImpl->PixelToLogic( rPoint, rMapMode ); +} + +//------------------------------------------------------------------------ + +void CellEditSource::addRange( SvxUnoTextRangeBase* pNewRange ) +{ + mpImpl->addRange( pNewRange ); +} + +//------------------------------------------------------------------------ + +void CellEditSource::removeRange( SvxUnoTextRangeBase* pOldRange ) +{ + mpImpl->removeRange( pOldRange ); +} + +//------------------------------------------------------------------------ + +const SvxUnoTextRangeBaseList& CellEditSource::getRanges() const +{ + return mpImpl->getRanges(); +} + +//------------------------------------------------------------------------ + +void CellEditSource::ChangeModel( SdrModel* pNewModel ) +{ + mpImpl->ChangeModel( pNewModel ); +} + +//------------------------------------------------------------------------ + +} } diff --git a/svx/source/table/celleditsource.hxx b/svx/source/table/celleditsource.hxx new file mode 100644 index 000000000000..561086106fbf --- /dev/null +++ b/svx/source/table/celleditsource.hxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLE_CELLEDITSOURCE_HXX +#define SVX_TABLE_CELLEDITSOURCE_HXX + +#include "cell.hxx" +#include "celltypes.hxx" +#include "editeng/unoedsrc.hxx" + +class SvxTextForwarder; +class SdrObject; +class SdrModel; +class SdrView; +class Window; + +namespace sdr { namespace table { + +class CellEditSourceImpl; + +class CellEditSource : public SvxEditSource, public SvxViewForwarder +{ +public: + CellEditSource( const CellRef& xCell ); + + /** Since the views don't broadcast their dying, make sure that + this object gets destroyed if the view becomes invalid + + The window is necessary, since our views can display on multiple windows + */ + CellEditSource( const CellRef& xCell, SdrView& rView, const Window& rViewWindow ); + virtual ~CellEditSource(); + + virtual SvxEditSource* Clone() const; + virtual SvxTextForwarder* GetTextForwarder(); + virtual SvxViewForwarder* GetViewForwarder(); + virtual SvxEditViewForwarder* GetEditViewForwarder( sal_Bool bCreate = sal_False ); + virtual void UpdateData(); + + virtual void addRange( SvxUnoTextRangeBase* pNewRange ); + virtual void removeRange( SvxUnoTextRangeBase* pOldRange ); + virtual const SvxUnoTextRangeBaseList& getRanges() const; + + virtual SfxBroadcaster& GetBroadcaster() const; + + void lock(); + void unlock(); + + // the SvxViewForwarder interface + virtual BOOL IsValid() const; + virtual Rectangle GetVisArea() const; + virtual Point LogicToPixel( const Point&, const MapMode& ) const; + virtual Point PixelToLogic( const Point&, const MapMode& ) const; + + void ChangeModel( SdrModel* pNewModel ); + +private: + CellEditSource( CellEditSourceImpl* pImpl ); + + CellEditSourceImpl* mpImpl; +}; + +} } + +#endif diff --git a/svx/source/table/cellrange.cxx b/svx/source/table/cellrange.cxx new file mode 100644 index 000000000000..29fc043090a3 --- /dev/null +++ b/svx/source/table/cellrange.cxx @@ -0,0 +1,132 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include "cellrange.hxx" + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::table; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// CellRange +// ----------------------------------------------------------------------------- + +CellRange::CellRange( const TableModelRef & xTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) +: mxTable( xTable ) +, mnLeft(nLeft) +, mnTop(nTop) +, mnRight(nRight) +, mnBottom(nBottom) +{ +} + +// ----------------------------------------------------------------------------- + +CellRange::~CellRange() +{ +} + +// ----------------------------------------------------------------------------- +// ICellRange +// ----------------------------------------------------------------------------- + +sal_Int32 CellRange::getLeft() +{ + return mnLeft; +} + +sal_Int32 CellRange::getTop() +{ + return mnTop; +} + +sal_Int32 CellRange::getRight() +{ + return mnRight; +} + +sal_Int32 CellRange::getBottom() +{ + return mnBottom; +} + +Reference< XTable > CellRange::getTable() +{ + return mxTable.get(); +} + +// ----------------------------------------------------------------------------- +// XCellRange +// ----------------------------------------------------------------------------- + +Reference< XCell > SAL_CALL CellRange::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException) +{ + return mxTable->getCellByPosition( mnLeft + nColumn, mnTop + nRow ); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL CellRange::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException) +{ + if( (nLeft >= 0 ) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) ) + { + nLeft += mnLeft; + nTop += mnTop; + nRight += mnLeft; + nBottom += mnTop; + + const sal_Int32 nMaxColumns = (mnRight == -1) ? mxTable->getColumnCount() : mnLeft; + const sal_Int32 nMaxRows = (mnBottom == -1) ? mxTable->getRowCount() : mnBottom; + if( (nLeft < nMaxColumns) && (nRight < nMaxColumns) && (nTop < nMaxRows) && (nBottom < nMaxRows) ) + { + return mxTable->getCellRangeByPosition( nLeft, nTop, nRight, nBottom ); + } + } + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL CellRange::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException) +{ + return Reference< XCellRange >(); +} + +// ----------------------------------------------------------------------------- + +} } diff --git a/svx/source/table/cellrange.hxx b/svx/source/table/cellrange.hxx new file mode 100644 index 000000000000..8932bc735ff7 --- /dev/null +++ b/svx/source/table/cellrange.hxx @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_CELLRANGE_HXX_ +#define _SVX_CELLRANGE_HXX_ + +#include <com/sun/star/table/XCellRange.hpp> +#include <cppuhelper/implbase1.hxx> + +#include "tablemodel.hxx" + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// CellRange +// ----------------------------------------------------------------------------- + +class CellRange : public ::cppu::WeakAggImplHelper1< ::com::sun::star::table::XCellRange >, public ICellRange +{ +public: + CellRange( const TableModelRef & xTable, sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ); + virtual ~CellRange(); + + // ICellRange + virtual sal_Int32 getLeft(); + virtual sal_Int32 getTop(); + virtual sal_Int32 getRight(); + virtual sal_Int32 getBottom(); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XTable > getTable(); + + // XCellRange + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByName( const ::rtl::OUString& aRange ) throw (::com::sun::star::uno::RuntimeException); + +protected: + TableModelRef mxTable; + sal_Int32 mnLeft; + sal_Int32 mnTop; + sal_Int32 mnRight; + sal_Int32 mnBottom; +}; + +} } + +#endif diff --git a/svx/source/table/celltypes.hxx b/svx/source/table/celltypes.hxx new file mode 100644 index 000000000000..78ef7b617968 --- /dev/null +++ b/svx/source/table/celltypes.hxx @@ -0,0 +1,109 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_CELLTYPES_HXX_ +#define _SVX_CELLTYPES_HXX_ + +#include <rtl/ref.hxx> +#include <vector> + +namespace sdr { namespace table { + +class Cell; +class TableModel; +class TableRow; +class TableColumn; +class TableRows; +class TableColumns; +typedef rtl::Reference< Cell > CellRef; +typedef rtl::Reference< TableModel > TableModelRef; +typedef rtl::Reference< TableRow > TableRowRef; +typedef rtl::Reference< TableColumn > TableColumnRef; +typedef rtl::Reference< TableRows > TableRowsRef; +typedef rtl::Reference< TableColumns > TableColumnsRef; +typedef std::vector< CellRef > CellVector; +typedef std::vector< TableRowRef > RowVector; +typedef std::vector< TableColumnRef > ColumnVector; + +class TableDesignUser +{ +public: + virtual bool isInUse() = 0; +}; + +template< typename T > +class RangeIterator +{ +public: + /** creates an iterator from rStart (including) to rEnd (excluding) if + bForeward is true or from nEnd (excluding to nStart (including). + rStart must be <= rEnd. + */ + RangeIterator( const T& rStart, const T& rEnd, bool bForeward = true ) + { + if( bForeward ) + { + maIter = rStart; + maEnd = rEnd; + } + else + { + maIter = rEnd-1; + maEnd = rStart-1; + } + } + + /* returns true if the next call to next() will return true also. */ + bool hasNext() const + { + return maIter != maEnd; + } + + /* iterates in the configured direction and returns true if rValue + now contains a valid positon in the range of this iterator */ + bool next( T& rValue ) + { + if( maIter == maEnd ) + return false; + + rValue = maIter; + if( maIter < maEnd ) + maIter++; + else + maIter--; + return true; + } + +private: + T maEnd; + T maIter; +}; + +} } + +#endif + diff --git a/svx/source/table/makefile.mk b/svx/source/table/makefile.mk new file mode 100644 index 000000000000..1eaaef12aa02 --- /dev/null +++ b/svx/source/table/makefile.mk @@ -0,0 +1,80 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# 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 + +PRJNAME=svx +TARGET=table +LIBTARGET=NO +ENABLE_EXCEPTIONS=TRUE; + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/makefile.pmk + +# --- Files -------------------------------------------------------- + +LIB1TARGET= $(SLB)$/$(TARGET)-core.lib +LIB1OBJFILES= \ + $(SLO)$/propertyset.obj\ + $(SLO)$/cell.obj\ + $(SLO)$/cellrange.obj\ + $(SLO)$/cellcursor.obj\ + $(SLO)$/tablerow.obj\ + $(SLO)$/tablerows.obj\ + $(SLO)$/tablecolumn.obj\ + $(SLO)$/tablecolumns.obj\ + $(SLO)$/tablemodel.obj\ + $(SLO)$/svdotable.obj\ + $(SLO)$/viewcontactoftableobj.obj\ + $(SLO)$/tablelayouter.obj\ + $(SLO)$/tablehandles.obj\ + $(SLO)$/tablecontroller.obj\ + $(SLO)$/tableundo.obj + +LIB2TARGET= $(SLB)$/$(TARGET).lib +LIB2OBJFILES= \ + $(SLO)$/celleditsource.obj \ + $(SLO)$/tabledesign.obj \ + $(SLO)$/accessibletableshape.obj \ + $(SLO)$/accessiblecell.obj \ + $(SLO)$/tablertfexporter.obj \ + $(SLO)$/tablertfimporter.obj + +SLOFILES = $(LIB1OBJFILES) $(LIB2OBJFILES) + +SRS1NAME=table +SRC1FILES= table.src + +# --- Targets ------------------------------------------------------- + +.INCLUDE : target.mk + diff --git a/svx/source/table/propertyset.cxx b/svx/source/table/propertyset.cxx new file mode 100644 index 000000000000..f5297afc770d --- /dev/null +++ b/svx/source/table/propertyset.cxx @@ -0,0 +1,259 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include "propertyset.hxx" + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +namespace comphelper { + +// ----------------------------------------------------------------------------- +// FastPropertySetInfo +// ----------------------------------------------------------------------------- + +FastPropertySetInfo::FastPropertySetInfo() +{ +} + +// ----------------------------------------------------------------------------- + +FastPropertySetInfo::FastPropertySetInfo( const PropertyVector& rProps ) +{ + addProperties( rProps ); +} + +// ----------------------------------------------------------------------------- + +FastPropertySetInfo::~FastPropertySetInfo() +{ +} + +// ----------------------------------------------------------------------------- + +void FastPropertySetInfo::addProperty( const Property& rProperty ) +{ + maProperties.push_back( rProperty ); + maMap[ rProperty.Name ] = maProperties.size() - 1; +} + +// ----------------------------------------------------------------------------- + +void FastPropertySetInfo::addProperties( const PropertyVector& rProps ) +{ + sal_uInt32 nIndex = maProperties.size(); + sal_uInt32 nCount = rProps.size(); + maProperties.resize( nIndex + nCount ); + PropertyVector::const_iterator aIter( rProps.begin() ); + while( nCount-- ) + { + const Property& rProperty = (*aIter++); + maProperties[nIndex] = rProperty; + maMap[ rProperty.Name ] = nIndex++; + } +} + +// ----------------------------------------------------------------------------- + +const Property& FastPropertySetInfo::getProperty( const OUString& aName ) throw (UnknownPropertyException ) +{ + PropertyMap::iterator aIter( maMap.find( aName ) ); + if( aIter == maMap.end() ) + throw UnknownPropertyException(); + return maProperties[(*aIter).second]; +} + +// ----------------------------------------------------------------------------- + +const Property* FastPropertySetInfo::hasProperty( const OUString& aName ) +{ + PropertyMap::iterator aIter( maMap.find( aName ) ); + if( aIter == maMap.end() ) + return 0; + else + return &maProperties[(*aIter).second]; +} + +// ----------------------------------------------------------------------------- +// XPropertySetInfo +// ----------------------------------------------------------------------------- + +Sequence< Property > SAL_CALL FastPropertySetInfo::getProperties() throw (RuntimeException) +{ + return Sequence< Property >( &maProperties[0], maProperties.size() ); +} + +// ----------------------------------------------------------------------------- + +Property SAL_CALL FastPropertySetInfo::getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException) +{ + return getProperty( aName ); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL FastPropertySetInfo::hasPropertyByName( const OUString& aName ) throw (RuntimeException) +{ + return hasProperty( aName ) != 0 ? sal_True : sal_False;; +} + +// ----------------------------------------------------------------------------- +// FastPropertySet +// ----------------------------------------------------------------------------- + +FastPropertySet::FastPropertySet( const rtl::Reference< FastPropertySetInfo >& xInfo ) +: mxInfo( xInfo ) +{ +} + +// ----------------------------------------------------------------------------- + +FastPropertySet::~FastPropertySet() +{ +} + +// ----------------------------------------------------------------------------- +// XPropertySet +// ----------------------------------------------------------------------------- + +Reference< XPropertySetInfo > SAL_CALL FastPropertySet::getPropertySetInfo( ) throw (RuntimeException) +{ + return Reference< XPropertySetInfo >( mxInfo.get() ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + setFastPropertyValue( mxInfo->getProperty( aPropertyName ).Handle, aValue ); +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL FastPropertySet::getPropertyValue( const OUString& aPropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + return getFastPropertyValue( mxInfo->getProperty( aPropertyName ).Handle ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- +// XMultiPropertySet +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::setPropertyValues( const Sequence< OUString >& aPropertyNames, const Sequence< Any >& aValues ) throw (PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + const OUString* pPropertyNames = aPropertyNames.getConstArray(); + const Any* pValues = aValues.getConstArray(); + sal_Int32 nCount = aPropertyNames.getLength(); + if( nCount != aValues.getLength() ) + throw IllegalArgumentException(); + + while( nCount-- ) + { + const Property* pProperty = mxInfo->hasProperty( *pPropertyNames++ ); + if( pProperty ) try + { + setFastPropertyValue( pProperty->Handle, *pValues ); + } + catch( UnknownPropertyException& ) + { + } + pValues++; + } +} + +// ----------------------------------------------------------------------------- + +Sequence< Any > SAL_CALL FastPropertySet::getPropertyValues( const Sequence< OUString >& aPropertyNames ) throw (RuntimeException) +{ + sal_Int32 nCount = aPropertyNames.getLength(); + Sequence< Any > aValues( nCount ); + + const OUString* pPropertyNames = aPropertyNames.getConstArray(); + Any* pValues = aValues.getArray(); + while( nCount-- ) + { + const Property* pProperty = mxInfo->hasProperty( *pPropertyNames++ ); + if( pProperty ) try + { + *pValues = getFastPropertyValue( pProperty->Handle ); + } + catch( UnknownPropertyException& ) + { + } + pValues++; + } + return aValues; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::addPropertiesChangeListener( const Sequence< OUString >&, const Reference< XPropertiesChangeListener >& ) throw (RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& ) throw (RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL FastPropertySet::firePropertiesChangeEvent( const Sequence< OUString >&, const Reference< XPropertiesChangeListener >& ) throw (RuntimeException) +{ +} + +} diff --git a/svx/source/table/propertyset.hxx b/svx/source/table/propertyset.hxx new file mode 100644 index 000000000000..241395272889 --- /dev/null +++ b/svx/source/table/propertyset.hxx @@ -0,0 +1,109 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 _COMPHELPER_PROPERTYSET_HXX_ +#define _COMPHELPER_PROPERTYSET_HXX_ + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <rtl/ref.hxx> +#include <functional> +#include <hash_map> +#include <vector> + +#include <cppuhelper/implbase1.hxx> +#include <cppuhelper/implbase3.hxx> + +namespace comphelper { + +// ----------------------------------------------------------------------------- + +typedef std::vector< ::com::sun::star::beans::Property > PropertyVector; +typedef std::hash_map< ::rtl::OUString, ::sal_uInt32, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > PropertyMap; + +// ----------------------------------------------------------------------------- + +class FastPropertySetInfo : public ::cppu::WeakAggImplHelper1< ::com::sun::star::beans::XPropertySetInfo > +{ +public: + FastPropertySetInfo(); + FastPropertySetInfo( const PropertyVector& rProps ); + virtual ~FastPropertySetInfo(); + + void addProperty( const ::com::sun::star::beans::Property& rProperty ); + void addProperties( const PropertyVector& rProps ); + + const ::com::sun::star::beans::Property& getProperty( const ::rtl::OUString& aName ) throw (::com::sun::star::beans::UnknownPropertyException ); + const ::com::sun::star::beans::Property* hasProperty( const ::rtl::OUString& aName ); + + // XPropertySetInfo + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::beans::Property > SAL_CALL getProperties( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::beans::Property SAL_CALL getPropertyByName( const ::rtl::OUString& aName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL hasPropertyByName( const ::rtl::OUString& Name ) throw (::com::sun::star::uno::RuntimeException); + +private: + PropertyVector maProperties; + PropertyMap maMap; +}; + +// ----------------------------------------------------------------------------- + +class FastPropertySet : public ::cppu::WeakAggImplHelper3< ::com::sun::star::beans::XPropertySet, ::com::sun::star::beans::XMultiPropertySet, ::com::sun::star::beans::XFastPropertySet > +{ +public: + FastPropertySet( const rtl::Reference< FastPropertySetInfo >& xInfo ); + virtual ~FastPropertySet(); + + // XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XMultiPropertySet +// virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValues( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames, const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any >& aValues ) throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > SAL_CALL getPropertyValues( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPropertiesChangeListener( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertiesChangeListener( const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL firePropertiesChangeEvent( const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aPropertyNames, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertiesChangeListener >& xListener ) throw (::com::sun::star::uno::RuntimeException); + + // XFastPropertySet + virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) = 0; + virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) = 0; + +private: + rtl::Reference< FastPropertySetInfo > mxInfo; +}; + +} + +#endif diff --git a/svx/source/table/svdotable.cxx b/svx/source/table/svdotable.cxx new file mode 100644 index 000000000000..e928f94d88ec --- /dev/null +++ b/svx/source/table/svdotable.cxx @@ -0,0 +1,2820 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#define ITEMID_BOX SDRATTR_TABLE_BORDER +#define ITEMID_BOXINFO SDRATTR_TABLE_BORDER_INNER + +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> + +#include <vcl/canvastools.hxx> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <svl/style.hxx> +#include "editeng/editstat.hxx" +#include "editeng/outlobj.hxx" +#include "svx/svdview.hxx" +#include "svx/sdr/properties/textproperties.hxx" +#include "svx/svdotable.hxx" +#include "svx/svdhdl.hxx" +#include "viewcontactoftableobj.hxx" +#include "svx/svdoutl.hxx" +#include "svx/svddrag.hxx" +#include "svx/svdpagv.hxx" +#include "tablemodel.hxx" +#include "cell.hxx" +#include "svx/xflclit.hxx" +#include "tablelayouter.hxx" +#include "svx/svdetc.hxx" +#include "tablehandles.hxx" +#include "editeng/boxitem.hxx" +#include "svx/framelink.hxx" +#include "svx/sdr/table/tabledesign.hxx" +#include "svx/svdundo.hxx" +#include "svdstr.hrc" +#include "svdglob.hxx" +#include "editeng/writingmodeitem.hxx" +#include "editeng/frmdiritem.hxx" +#include "svx/xflhtit.hxx" +#include "svx/xflftrit.hxx" +#include "svx/xfltrit.hxx" + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::container::XIndexAccess; +using ::com::sun::star::style::XStyle; +using ::com::sun::star::table::XTableRows; +using ::com::sun::star::table::XTableColumns; +using ::com::sun::star::table::XTable; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::util::XModifyBroadcaster; +using sdr::properties::TextProperties; +using sdr::properties::BaseProperties; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; + +namespace sdr { namespace table { + +class TableProperties : public TextProperties +{ +protected: + // create a new itemset + SfxItemSet& CreateObjectSpecificItemSet(SfxItemPool& rPool); + +public: + // basic constructor + TableProperties(SdrObject& rObj ); + + // constructor for copying, but using new object + TableProperties(const TableProperties& rProps, SdrObject& rObj ); + + // destructor + ~TableProperties(); + + // Clone() operator, normally just calls the local copy constructor + BaseProperties& Clone(SdrObject& rObj) const; + + virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem); +}; + +TableProperties::TableProperties(SdrObject& rObj) +: TextProperties(rObj) +{ +} + +TableProperties::TableProperties(const TableProperties& rProps, SdrObject& rObj) +: TextProperties(rProps, rObj) +{ +} + +TableProperties::~TableProperties() +{ +} + +BaseProperties& TableProperties::Clone(SdrObject& rObj) const +{ + return *(new TableProperties(*this, rObj)); +} + +void TableProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem) +{ + if( nWhich == SDRATTR_TEXTDIRECTION ) + AttributeProperties::ItemChange( nWhich, pNewItem ); + else + TextProperties::ItemChange( nWhich, pNewItem ); +} + +// create a new itemset +SfxItemSet& TableProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool) +{ + return *(new SfxItemSet(rPool, + + // range from SdrAttrObj + SDRATTR_START, SDRATTR_SHADOW_LAST, + SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST, + SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION, + + // range for SdrTableObj + SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST, + + // range from SdrTextObj + EE_ITEMS_START, EE_ITEMS_END, + + // end + 0, 0)); +} + +class TableObjectGeoData : public SdrTextObjGeoData +{ +public: + Rectangle maLogicRect; +}; + +//------------------------------------------------------------------------ +// TableStyleSettings +//------------------------------------------------------------------------ + +TableStyleSettings::TableStyleSettings() +: mbUseFirstRow(true) +, mbUseLastRow(false) +, mbUseFirstColumn(false) +, mbUseLastColumn(false) +, mbUseRowBanding(true) +, mbUseColumnBanding(false) +{ +} + +TableStyleSettings::TableStyleSettings( const TableStyleSettings& rStyle ) +{ + (*this) = rStyle; +} + +TableStyleSettings& TableStyleSettings::operator=(const TableStyleSettings& rStyle) +{ + mbUseFirstRow = rStyle.mbUseFirstRow; + mbUseLastRow = rStyle.mbUseLastRow; + mbUseFirstColumn = rStyle.mbUseFirstColumn; + mbUseLastColumn = rStyle.mbUseLastColumn; + mbUseRowBanding = rStyle.mbUseRowBanding; + mbUseColumnBanding = rStyle.mbUseColumnBanding; + return *this; +} + +bool TableStyleSettings::operator==( const TableStyleSettings& rStyle ) const +{ + return + (mbUseFirstRow == rStyle.mbUseFirstRow) && + (mbUseLastRow == rStyle.mbUseLastRow) && + (mbUseFirstColumn == rStyle.mbUseFirstColumn) && + (mbUseLastColumn == rStyle.mbUseLastColumn) && + (mbUseRowBanding == rStyle.mbUseRowBanding) && + (mbUseColumnBanding == rStyle.mbUseColumnBanding); +} + +// ----------------------------------------------------------------------------- + +class SdrTableObjImpl : public TableDesignUser, public ::cppu::WeakImplHelper1< ::com::sun::star::util::XModifyListener > +{ +public: + CellRef mxActiveCell; + TableModelRef mxTable; + SdrTableObj* mpTableObj; + TableLayouter* mpLayouter; + CellPos maEditPos; + TableStyleSettings maTableStyle; + Reference< XIndexAccess > mxTableStyle; + bool mbModifyPending; +// sal_Int32 mnSavedEditRowHeight; + + void SetModel(SdrModel* pOldModel, SdrModel* pNewModel); + + CellRef getCell( const CellPos& rPos ) const; + void LayoutTable( Rectangle& rArea, bool bFitWidth, bool bFitHeight ); + + bool ApplyCellStyles(); + void UpdateCells( Rectangle& rArea ); + + SdrTableObjImpl(); + virtual ~SdrTableObjImpl(); + + void init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows ); + void dispose(); + + sal_Int32 getColumnCount() const; + sal_Int32 getRowCount() const; + + void DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset ); + + const SfxPoolItem* GetCellItem( const CellPos& rPos, sal_uInt16 nWhich ) const; +// void GetBorderLines( const CellPos& rPos, const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop, const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const; + + void operator=( const SdrTableObjImpl& rSource ); + + // XModifyListener + virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException); + + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + + void update(); + + void connectTableStyle(); + void disconnectTableStyle(); + virtual bool isInUse(); + + bool UpdateWritingMode(); +}; + +// ----------------------------------------------------------------------------- + +SdrTableObjImpl::SdrTableObjImpl() +: mpTableObj( 0 ) +, mpLayouter( 0 ) +{ +} + +// ----------------------------------------------------------------------------- + +SdrTableObjImpl::~SdrTableObjImpl() +{ +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows ) +{ + mpTableObj = pTable; + mxTable = new TableModel( pTable ); + mxTable->init( nColumns, nRows ); + mpLayouter = new TableLayouter( mxTable ); + Reference< XModifyListener > xListener( static_cast< ::com::sun::star::util::XModifyListener* >(this) ); + mxTable->addModifyListener( xListener ); + UpdateWritingMode(); + LayoutTable( mpTableObj->aRect, true, true ); + mpTableObj->maLogicRect = mpTableObj->aRect; +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::operator=( const SdrTableObjImpl& rSource ) +{ + if( mpLayouter ) + { + delete mpLayouter; + mpLayouter = 0; + } + + if( mxTable.is() ) + { + Reference< XModifyListener > xListener( static_cast< ::com::sun::star::util::XModifyListener* >(this) ); + mxTable->removeModifyListener( xListener ); + mxTable->dispose(); + mxTable.clear(); + } + + maTableStyle = rSource.maTableStyle; + + mxTable = new TableModel( mpTableObj, rSource.mxTable ); + mpLayouter = new TableLayouter( mxTable ); + Reference< XModifyListener > xListener( static_cast< ::com::sun::star::util::XModifyListener* >(this) ); + mxTable->addModifyListener( xListener ); + mxTableStyle = rSource.mxTableStyle; + UpdateWritingMode(); + ApplyCellStyles(); + mpTableObj->aRect = mpTableObj->maLogicRect; + LayoutTable( mpTableObj->aRect, false, false ); +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::SetModel(SdrModel* /*pOldModel*/, SdrModel* pNewModel) +{ + // try to find new table style + + Reference< XIndexAccess > xNewTableStyle; + if( mxTableStyle.is() ) try + { + const OUString sStyleName( Reference< XNamed >( mxTableStyle, UNO_QUERY_THROW )->getName() ); + + Reference< XStyleFamiliesSupplier > xSFS( pNewModel->getUnoModel(), UNO_QUERY_THROW ); + Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), UNO_QUERY_THROW ); + const rtl::OUString sFamilyName( RTL_CONSTASCII_USTRINGPARAM( "table" ) ); + Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( sFamilyName ), UNO_QUERY_THROW ); + + if( xTableFamilyAccess->hasByName( sStyleName ) ) + { + // found table style with the same name + xTableFamilyAccess->getByName( sStyleName ) >>= xNewTableStyle; + } + else + { + // copy or? + Reference< XIndexAccess > xIndexAccess( xTableFamilyAccess, UNO_QUERY_THROW ); + xIndexAccess->getByIndex( 0 ) >>= xNewTableStyle; + } + } + catch( Exception& ) + { + DBG_ERROR("svx::SdrTableObjImpl::SetModel(), exception caught!"); + } + + mxTableStyle = xNewTableStyle; + + update(); +} + +// ----------------------------------------------------------------------------- + +bool SdrTableObjImpl::ApplyCellStyles() +{ + if( !mxTable.is() || !mxTable.is() || !mxTableStyle.is() ) + return false; + + bool bChanges = false; + + const sal_Int32 nColCount = getColumnCount(); + const sal_Int32 nRowCount = getRowCount(); + + const TableStyleSettings& rStyle = maTableStyle; + + CellPos aPos; + for( aPos.mnRow = 0; aPos.mnRow < nRowCount; ++aPos.mnRow ) + { + const bool bFirstRow = (aPos.mnRow == 0) && rStyle.mbUseFirstRow; + const bool bLastRow = (aPos.mnRow == nRowCount-1) && rStyle.mbUseLastRow; + + for( aPos.mnCol = 0; aPos.mnCol < nColCount; ++aPos.mnCol ) + { + Reference< XStyle > xStyle; + + // first and last row win first, if used and available + if( bFirstRow ) + { + mxTableStyle->getByIndex(first_row_style) >>= xStyle; + } + else if( bLastRow ) + { + mxTableStyle->getByIndex(last_row_style) >>= xStyle; + } + + if( !xStyle.is() ) + { + // next come first and last column, if used and available + if( rStyle.mbUseFirstColumn && (aPos.mnCol == 0) ) + { + mxTableStyle->getByIndex(first_column_style) >>= xStyle; + } + else if( rStyle.mbUseLastColumn && (aPos.mnCol == nColCount-1) ) + { + mxTableStyle->getByIndex(last_column_style) >>= xStyle; + } + } + + if( !xStyle.is() && rStyle.mbUseRowBanding ) + { + if( (aPos.mnRow & 1) == 0 ) + { + mxTableStyle->getByIndex(even_rows_style) >>= xStyle; + } + else + { + mxTableStyle->getByIndex(odd_rows_style) >>= xStyle; + } + } + + if( !xStyle.is() && rStyle.mbUseColumnBanding ) + { + if( (aPos.mnCol & 1) == 0 ) + { + mxTableStyle->getByIndex(even_columns_style) >>= xStyle; + } + else + { + mxTableStyle->getByIndex(odd_columns_style) >>= xStyle; + } + } + + if( !xStyle.is() ) + { + // use default cell style if non found yet + mxTableStyle->getByIndex(body_style) >>= xStyle; + } + + + if( xStyle.is() ) + { + SfxUnoStyleSheet* pStyle = SfxUnoStyleSheet::getUnoStyleSheet(xStyle); + + if( pStyle ) + { + CellRef xCell( getCell( aPos ) ); + if( xCell.is() && ( xCell->GetStyleSheet() != pStyle ) ) + { + bChanges = true; + xCell->SetStyleSheet( pStyle, sal_True ); + } + } + } + } + } + + return bChanges; +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::dispose() +{ + if( mxTable.is() ) + mxTable->dispose(); +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset ) +{ + if( (nEdge > 0) && mxTable.is()) try + { + const OUString sSize( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ); + nEdge--; + if( mbHorizontal ) + { + if( (nEdge >= 0) && (nEdge < getRowCount()) ) + { + sal_Int32 nHeigth = mpLayouter->getRowHeight( nEdge ); + nHeigth += nOffset; + Reference< XIndexAccess > xRows( mxTable->getRows(), UNO_QUERY_THROW ); + Reference< XPropertySet > xRowSet( xRows->getByIndex( nEdge ), UNO_QUERY_THROW ); + xRowSet->setPropertyValue( sSize, Any( nHeigth ) ); + } + } + else + { + if( (nEdge >= 0) && (nEdge < getColumnCount()) ) + { + sal_Int32 nWidth = mpLayouter->getColumnWidth( nEdge ); + nWidth += nOffset; + + Reference< XIndexAccess > xCols( mxTable->getColumns(), UNO_QUERY_THROW ); + Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge ), UNO_QUERY_THROW ); + xColSet->setPropertyValue( sSize, Any( nWidth ) ); + + if( nEdge > 0 && nEdge < mxTable->getColumnCount() ) + { + const bool bRTL = mpLayouter->GetWritingMode() == WritingMode_RL_TB; + + if( bRTL ) + nEdge--; + else + nEdge++; + + if( (bRTL && (nEdge >= 0)) || (!bRTL && (nEdge < mxTable->getColumnCount())) ) + { + nWidth = mpLayouter->getColumnWidth( nEdge ); + nWidth = std::max( (sal_Int32)(nWidth - nOffset), (sal_Int32)0 ); + + xColSet = Reference< XPropertySet >( xCols->getByIndex( nEdge ), UNO_QUERY_THROW ); + xColSet->setPropertyValue( sSize, Any( nWidth ) ); + } + } + } + } + } + catch( Exception& ) + { + DBG_ERROR( "svx::SdrTableObjImpl::DragEdge(), exception caught!" ); + } +} + +// ----------------------------------------------------------------------------- +// XModifyListener +// ----------------------------------------------------------------------------- + +void SAL_CALL SdrTableObjImpl::modified( const ::com::sun::star::lang::EventObject& /*aEvent*/ ) throw (::com::sun::star::uno::RuntimeException) +{ + update(); +} + +void SdrTableObjImpl::update() +{ + // source can be the table model itself or the assigned table template + TableModelNotifyGuard aGuard( mxTable.get() ); + if( mpTableObj ) + { + if( (maEditPos.mnRow >= getRowCount()) || (maEditPos.mnCol >= getColumnCount()) || (getCell( maEditPos ) != mxActiveCell) ) + { + if(maEditPos.mnRow >= getRowCount()) + maEditPos.mnRow = getRowCount()-1; + + if(maEditPos.mnCol >= getColumnCount()) + maEditPos.mnCol = getColumnCount()-1; + + mpTableObj->setActiveCell( maEditPos ); + } + + ApplyCellStyles(); + + mpTableObj->aRect = mpTableObj->maLogicRect; + LayoutTable( mpTableObj->aRect, false, false ); + + mpTableObj->SetRectsDirty(); + mpTableObj->ActionChanged(); + mpTableObj->BroadcastObjectChange(); + } +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::connectTableStyle() +{ + if( mxTableStyle.is() ) + { + Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY ); + if( xBroadcaster.is() ) + { + Reference< XModifyListener > xListener( static_cast< ::com::sun::star::util::XModifyListener* >(this) ); + xBroadcaster->addModifyListener( xListener ); + } + } +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::disconnectTableStyle() +{ + if( mxTableStyle.is() ) + { + Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY ); + if( xBroadcaster.is() ) + { + Reference< XModifyListener > xListener( static_cast< ::com::sun::star::util::XModifyListener* >(this) ); + xBroadcaster->removeModifyListener( xListener ); + } + } +} + +// ----------------------------------------------------------------------------- + +bool SdrTableObjImpl::isInUse() +{ + return mpTableObj && mpTableObj->IsInserted(); +} + +// ----------------------------------------------------------------------------- +// XEventListener +// ----------------------------------------------------------------------------- + +void SAL_CALL SdrTableObjImpl::disposing( const ::com::sun::star::lang::EventObject& /*Source*/ ) throw (::com::sun::star::uno::RuntimeException) +{ + mxActiveCell.clear(); + mxTable.clear(); + if( mpLayouter ) + { + delete mpLayouter; + mpLayouter = 0; + } + mpTableObj = 0; +} + +// ----------------------------------------------------------------------------- + +CellRef SdrTableObjImpl::getCell( const CellPos& rPos ) const +{ + CellRef xCell; + if( mxTable.is() ) try + { + xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) ); + } + catch( Exception& ) + { + DBG_ERROR( "svx::SdrTableObjImpl::getCell(), exception caught!" ); + } + return xCell; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SdrTableObjImpl::getColumnCount() const +{ + return mxTable.is() ? mxTable->getColumnCount() : 0; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SdrTableObjImpl::getRowCount() const +{ + return mxTable.is() ? mxTable->getRowCount() : 0; +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::LayoutTable( Rectangle& rArea, bool bFitWidth, bool bFitHeight ) +{ + if( mpLayouter && mpTableObj->GetModel() ) + { + TableModelNotifyGuard aGuard( mxTable.get() ); + mpLayouter->LayoutTable( rArea, bFitWidth, bFitHeight ); + } +} + +// ----------------------------------------------------------------------------- + +bool SdrTableObjImpl::UpdateWritingMode() +{ + if( mpTableObj && mpLayouter ) + { + WritingMode eWritingMode = (WritingMode)static_cast< const SvxWritingModeItem& >( mpTableObj->GetObjectItem( SDRATTR_TEXTDIRECTION ) ).GetValue(); + + if( eWritingMode != WritingMode_TB_RL ) + { + if( static_cast< const SvxFrameDirectionItem& >( mpTableObj->GetObjectItem( EE_PARA_WRITINGDIR ) ).GetValue() == FRMDIR_HORI_LEFT_TOP ) + eWritingMode = WritingMode_LR_TB; + else + eWritingMode = WritingMode_RL_TB; + } + + if( eWritingMode != mpLayouter->GetWritingMode() ) + { + mpLayouter->SetWritingMode( eWritingMode ); + return true; + } + } + return false; +} + +// ----------------------------------------------------------------------------- + +void SdrTableObjImpl::UpdateCells( Rectangle& rArea ) +{ + if( mpLayouter && mxTable.is() ) + { + TableModelNotifyGuard aGuard( mxTable.get() ); + mpLayouter->updateCells( rArea ); + mxTable->setModified(sal_True); + } +} + +// ----------------------------------------------------------------------------- + +const SfxPoolItem* SdrTableObjImpl::GetCellItem( const CellPos& rPos, sal_uInt16 nWhich ) const +{ + CellRef xCell( getCell( rPos ) ); + if( xCell.is() ) + return xCell->GetItemSet().GetItem( nWhich ); + else + return 0; +} + +// ----------------------------------------------------------------------------- +// BaseProperties section +// ----------------------------------------------------------------------------- + +sdr::properties::BaseProperties* SdrTableObj::CreateObjectSpecificProperties() +{ + return new TableProperties(*this); +} + +// ----------------------------------------------------------------------------- +// DrawContact section +// ----------------------------------------------------------------------------- + +sdr::contact::ViewContact* SdrTableObj::CreateObjectSpecificViewContact() +{ + return new sdr::contact::ViewContactOfTableObj(*this); +} + +// -------------------------------------------------------------------- + +TYPEINIT1(SdrTableObj,SdrTextObj); + +// -------------------------------------------------------------------- + +SdrTableObj::SdrTableObj(SdrModel* _pModel) +{ + pModel = _pModel; + init( 1, 1 ); +} + +// -------------------------------------------------------------------- + +SdrTableObj::SdrTableObj(SdrModel* _pModel, const ::Rectangle& rNewRect, sal_Int32 nColumns, sal_Int32 nRows) +: SdrTextObj( rNewRect ) +, maLogicRect( rNewRect ) +{ + pModel = _pModel; + + if( nColumns <= 0 ) + nColumns = 1; + + if( nRows <= 0 ) + nRows = 1; + + init( nColumns, nRows ); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::init( sal_Int32 nColumns, sal_Int32 nRows ) +{ + bClosedObj = TRUE; + + mpImpl = new SdrTableObjImpl; + mpImpl->acquire(); + mpImpl->init( this, nColumns, nRows ); +} + +// -------------------------------------------------------------------- + +SdrTableObj::~SdrTableObj() +{ + mpImpl->dispose(); + mpImpl->release(); +} + +// -------------------------------------------------------------------- +// table stuff +// -------------------------------------------------------------------- + +Reference< XTable > SdrTableObj::getTable() const +{ + return Reference< XTable >( mpImpl->mxTable.get() ); +} + +// -------------------------------------------------------------------- + +bool SdrTableObj::isValid( const CellPos& rPos ) const +{ + return (rPos.mnCol >= 0) && (rPos.mnCol < mpImpl->getColumnCount()) && (rPos.mnRow >= 0) && (rPos.mnRow < mpImpl->getRowCount()); +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getFirstCell() const +{ + return CellPos( 0,0 ); +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getLastCell() const +{ + CellPos aPos; + if( mpImpl->mxTable.is() ) + { + aPos.mnCol = mpImpl->getColumnCount()-1; + aPos.mnRow = mpImpl->getRowCount()-1; + } + return aPos; +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getLeftCell( const CellPos& rPos, bool bEdgeTravel ) const +{ + switch( GetWritingMode() ) + { + default: + case WritingMode_LR_TB: + return getPreviousCell( rPos, bEdgeTravel ); + case WritingMode_RL_TB: + return getNextCell( rPos, bEdgeTravel ); + case WritingMode_TB_RL: + return getPreviousRow( rPos, bEdgeTravel ); + } +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getRightCell( const CellPos& rPos, bool bEdgeTravel ) const +{ + switch( GetWritingMode() ) + { + default: + case WritingMode_LR_TB: + return getNextCell( rPos, bEdgeTravel ); + case WritingMode_RL_TB: + return getPreviousCell( rPos, bEdgeTravel ); + case WritingMode_TB_RL: + return getNextRow( rPos, bEdgeTravel ); + } +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getUpCell( const CellPos& rPos, bool bEdgeTravel ) const +{ + switch( GetWritingMode() ) + { + default: + case WritingMode_LR_TB: + case WritingMode_RL_TB: + return getPreviousRow( rPos, bEdgeTravel ); + case WritingMode_TB_RL: + return getPreviousCell( rPos, bEdgeTravel ); + } +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getDownCell( const CellPos& rPos, bool bEdgeTravel ) const +{ + switch( GetWritingMode() ) + { + default: + case WritingMode_LR_TB: + case WritingMode_RL_TB: + return getNextRow( rPos, bEdgeTravel ); + case WritingMode_TB_RL: + return getNextCell( rPos, bEdgeTravel ); + } +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getPreviousCell( const CellPos& rPos, bool bEdgeTravel ) const +{ + CellPos aPos( rPos ); + if( mpImpl ) + { + CellRef xCell( mpImpl->getCell( aPos ) ); + if( xCell.is() && xCell->isMerged() ) + { + sal_Int32 nTemp = 0; + findMergeOrigin( mpImpl->mxTable.get(), aPos.mnCol, aPos.mnRow, aPos.mnCol, nTemp ); + } + + if( aPos.mnCol > 0 ) + { + --aPos.mnCol; + } + + else if( bEdgeTravel && (aPos.mnRow > 0) ) + { + aPos.mnCol = mpImpl->mxTable->getColumnCount()-1; + --aPos.mnRow; + } + } + return aPos; +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getNextCell( const CellPos& rPos, bool bEdgeTravel ) const +{ + CellPos aPos( rPos ); + if( mpImpl ) + { + CellRef xCell( mpImpl->getCell( aPos ) ); + if( xCell.is() ) + { + if( xCell->isMerged() ) + { + findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow ); + + xCell = mpImpl->getCell(aPos); + + if( xCell.is() ) + { + aPos.mnCol += xCell->getColumnSpan(); + aPos.mnRow = rPos.mnRow; + } + } + else + { + aPos.mnCol += xCell->getColumnSpan(); + } + + if( aPos.mnCol < mpImpl->mxTable->getColumnCount() ) + return aPos; + + if( bEdgeTravel && ((aPos.mnRow + 1) < mpImpl->getRowCount()) ) + { + aPos.mnCol = 0; + aPos.mnRow += 1; + return aPos; + } + } + } + + // last cell reached, no traveling possible + return rPos; +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getPreviousRow( const CellPos& rPos, bool bEdgeTravel ) const +{ + CellPos aPos( rPos ); + if( mpImpl ) + { + CellRef xCell( mpImpl->getCell( aPos ) ); + if( xCell.is() ) + { + if( xCell->isMerged() ) + { + sal_Int32 nTemp = 0; + findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, nTemp, aPos.mnRow ); + } + } + + if( aPos.mnRow > 0 ) + { + --aPos.mnRow; + } + else if( bEdgeTravel && (aPos.mnCol > 0) ) + { + aPos.mnRow = mpImpl->mxTable->getRowCount()-1; + --aPos.mnCol; + } + } + return aPos; +} + +// -------------------------------------------------------------------- + +CellPos SdrTableObj::getNextRow( const CellPos& rPos, bool bEdgeTravel ) const +{ + CellPos aPos( rPos ); + + if( mpImpl ) + { + CellRef xCell( mpImpl->getCell( rPos ) ); + if( xCell.is() ) + { + if( xCell->isMerged() ) + { + findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow ); + xCell = mpImpl->getCell(aPos); + aPos.mnCol = rPos.mnCol; + } + + if( xCell.is() ) + aPos.mnRow += xCell->getRowSpan(); + + if( aPos.mnRow < mpImpl->mxTable->getRowCount() ) + return aPos; + + if( bEdgeTravel && (aPos.mnCol + 1) < mpImpl->mxTable->getColumnCount() ) + { + aPos.mnRow = 0; + aPos.mnCol += 1; + + while( aPos.mnCol < mpImpl->mxTable->getColumnCount() ) + { + xCell = mpImpl->getCell( aPos ); + if( xCell.is() && !xCell->isMerged() ) + return aPos; + aPos.mnCol += 1; + } + } + } + } + + // last position reached, no more traveling possible + return rPos; +} + +// -------------------------------------------------------------------- + +const TableStyleSettings& SdrTableObj::getTableStyleSettings() const +{ + if( mpImpl ) + { + return mpImpl->maTableStyle; + } + else + { + static TableStyleSettings aTmp; + return aTmp; + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::setTableStyleSettings( const TableStyleSettings& rStyle ) +{ + if( mpImpl ) + { + mpImpl->maTableStyle = rStyle; + mpImpl->update(); + } +} + +// -------------------------------------------------------------------- + +TableHitKind SdrTableObj::CheckTableHit( const Point& rPos, sal_Int32& rnX, sal_Int32& rnY, int nTol ) const +{ + if( !mpImpl || !mpImpl->mxTable.is() ) + return SDRTABLEHIT_NONE; + + rnX = 0; + rnY = 0; + + const sal_Int32 nColCount = mpImpl->getColumnCount(); + const sal_Int32 nRowCount = mpImpl->getRowCount(); + + sal_Int32 nX = rPos.X() + nTol - aRect.nLeft; + sal_Int32 nY = rPos.Y() + nTol - aRect.nTop; + + if( (nX < 0) || (nX > (aRect.GetWidth() + nTol)) || (nY < 0) || (nY > (aRect.GetHeight() + nTol) ) ) + return SDRTABLEHIT_NONE; + + // get vertical edge number and check for a hit + const bool bRTL = GetWritingMode() == WritingMode_RL_TB; + bool bVrtHit = false; + if( nX >= 0 ) + { + if( !bRTL ) + { + while( rnX <= nColCount ) + { + if( nX <= (2*nTol) ) + { + bVrtHit = true; + break; + } + + if( rnX == nColCount ) + break; + + nX -= mpImpl->mpLayouter->getColumnWidth( rnX ); + if( nX < 0 ) + break; + rnX++; + } + } + else + { + rnX = nColCount; + while( rnX >= 0 ) + { + if( nX <= (2*nTol) ) + { + bVrtHit = true; + break; + } + + if( rnX == 0 ) + break; + + rnX--; + nX -= mpImpl->mpLayouter->getColumnWidth( rnX ); + if( nX < 0 ) + break; + } + } + } + + // rnX is now the edge number left to the pointer, if it was hit bHrzHit is also true + + // get vertical edge number and check for a hit + bool bHrzHit = false; + if( nY >= 0 ) + { + while( rnY <= nRowCount ) + { + if( nY <= (2*nTol) ) + { + bHrzHit = true; + break; + } + + if( rnY == nRowCount ) + break; + + nY -= mpImpl->mpLayouter->getRowHeight(rnY); + if( nY < 0 ) + break; + rnY++; + } + } + + // rnY is now the edge number above the pointer, if it was hit bVrtHit is also true + + if( bVrtHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, false ) ) + return SDRTABLEHIT_VERTICAL_BORDER; + + if( bHrzHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, true ) ) + return SDRTABLEHIT_HORIZONTAL_BORDER; + + CellRef xCell( mpImpl->getCell( CellPos( rnX, rnY ) ) ); + if( xCell.is() && xCell->isMerged() ) + findMergeOrigin( mpImpl->mxTable.get(), rnX, rnY, rnX, rnY ); + + if( xCell.is() ) + { + nX += mpImpl->mpLayouter->getColumnWidth( rnX ); + if( nX < xCell->GetTextLeftDistance() ) + return SDRTABLEHIT_CELL; + } + + return SDRTABLEHIT_CELLTEXTAREA; +} + +const SfxItemSet& SdrTableObj::GetActiveCellItemSet() const +{ + return getActiveCell()->GetItemSet(); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::InsertRows( sal_Int32 nIndex, sal_Int32 nCount /*= 1*/ ) +{ + if( mpImpl->mxTable.is() ) try + { + Reference< XTableRows > xRows( mpImpl->mxTable->getRows(), UNO_QUERY_THROW ); + xRows->insertByIndex( nIndex, nCount ); + } + catch( Exception& ) + { + DBG_ERROR("SdrTableObj::InsertRows(), exception caught!"); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::InsertColumns( sal_Int32 nIndex, sal_Int32 nCount /*= 1*/ ) +{ + if( mpImpl->mxTable.is() ) try + { + Reference< XTableColumns > xColumns( mpImpl->mxTable->getColumns(), UNO_QUERY_THROW ); + xColumns->insertByIndex( nIndex, nCount ); + } + catch( Exception& ) + { + DBG_ERROR("SdrTableObj::InsertColumns(), exception caught!"); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::DeleteRows( sal_Int32 nIndex, sal_Int32 nCount /*= 1*/ ) +{ + if( mpImpl->mxTable.is() ) try + { + Reference< XTableRows > xRows( mpImpl->mxTable->getRows(), UNO_QUERY_THROW ); + xRows->removeByIndex( nIndex, nCount ); + } + catch( Exception& ) + { + DBG_ERROR("SdrTableObj::DeleteRows(), exception caught!"); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::DeleteColumns( sal_Int32 nIndex, sal_Int32 nCount /*= 1*/ ) +{ + if( mpImpl->mxTable.is() ) try + { + Reference< XTableColumns > xColumns( mpImpl->mxTable->getColumns(), UNO_QUERY_THROW ); + xColumns->removeByIndex( nIndex, nCount ); + } + catch( Exception& ) + { + DBG_ERROR("SdrTableObj::DeleteColumns(), exception caught!"); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::setTableStyle( const Reference< XIndexAccess >& xTableStyle ) +{ + if( mpImpl && (mpImpl->mxTableStyle != xTableStyle) ) + { + mpImpl->disconnectTableStyle(); + mpImpl->mxTableStyle = xTableStyle; + mpImpl->connectTableStyle(); + mpImpl->update(); + } +} + +// -------------------------------------------------------------------- + +const Reference< XIndexAccess >& SdrTableObj::getTableStyle() const +{ + if( mpImpl ) + { + return mpImpl->mxTableStyle; + } + else + { + static Reference< XIndexAccess > aTmp; + return aTmp; + } +} + +// -------------------------------------------------------------------- +// text stuff +// -------------------------------------------------------------------- + +/** returns the currently active text. */ +SdrText* SdrTableObj::getActiveText() const +{ + return dynamic_cast< SdrText* >( getActiveCell().get() ); +} + +// -------------------------------------------------------------------- + +/** returns the nth available text. */ +SdrText* SdrTableObj::getText( sal_Int32 nIndex ) const +{ + if( mpImpl->mxTable.is() ) + { + const sal_Int32 nColCount = mpImpl->getColumnCount(); + if( nColCount ) + { + CellPos aPos( nIndex % nColCount, nIndex / nColCount ); + + CellRef xCell( mpImpl->getCell( aPos ) ); + return dynamic_cast< SdrText* >( xCell.get() ); + } + } + return 0; +} + +// -------------------------------------------------------------------- + +/** returns the number of texts available for this object. */ +sal_Int32 SdrTableObj::getTextCount() const +{ + if( mpImpl->mxTable.is() ) + { + const sal_Int32 nColCount = mpImpl->getColumnCount(); + const sal_Int32 nRowCount = mpImpl->getRowCount(); + + return nColCount * nRowCount; + } + else + { + return 0; + } +} + +// -------------------------------------------------------------------- + +/** changes the current active text */ +void SdrTableObj::setActiveText( sal_Int32 nIndex ) +{ + if( mpImpl && mpImpl->mxTable.is() ) + { + const sal_Int32 nColCount = mpImpl->mxTable->getColumnCount(); + if( nColCount ) + { + CellPos aPos( nIndex % nColCount, nIndex / nColCount ); + if( isValid( aPos ) ) + setActiveCell( aPos ); + } + } +} + +// -------------------------------------------------------------------- + +/** returns the index of the text that contains the given point or -1 */ +sal_Int32 SdrTableObj::CheckTextHit(const Point& rPnt) const +{ + if( mpImpl && mpImpl->mxTable.is() ) + { + CellPos aPos; + if( CheckTableHit( rPnt, aPos.mnCol, aPos.mnRow, 0 ) == SDRTABLEHIT_CELLTEXTAREA ) + return aPos.mnRow * mpImpl->mxTable->getColumnCount() + aPos.mnCol; + } + + return 0; +} + +// -------------------------------------------------------------------- + +SdrOutliner* SdrTableObj::GetCellTextEditOutliner( const Cell& rCell ) const +{ + if( mpImpl && (mpImpl->getCell( mpImpl->maEditPos ).get() == &rCell) ) + return pEdtOutl; + else + return 0; +} + + +// -------------------------------------------------------------------- + +const TableLayouter& SdrTableObj::getTableLayouter() const +{ + OSL_ENSURE(mpImpl && mpImpl->mpLayouter, "getTableLayouter() error: no mpImpl or mpLayouter (!)"); + return *(mpImpl->mpLayouter); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::FitFrameToTextSize() +{ + // todo +} + +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::IsAutoGrowHeight() const +{ + return TRUE; +} + +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::IsAutoGrowWidth() const +{ + return TRUE; +} + +// -------------------------------------------------------------------- + +bool SdrTableObj::HasText() const +{ + return true; +} + +// -------------------------------------------------------------------- + +bool SdrTableObj::IsTextEditActive( const CellPos& rPos ) +{ + return pEdtOutl && mpImpl && (rPos == mpImpl->maEditPos); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus ) +{ + if( (pEditStatus->GetStatusWord() & EE_STAT_TEXTHEIGHTCHANGED) && mpImpl && mpImpl->mpLayouter ) + { + Rectangle aRect0( aRect ); + aRect = maLogicRect; +// mpImpl->mpLayouter->setRowHeight( mpImpl->maEditPos.mnRow, mpImpl->mnSavedEditRowHeight ); + mpImpl->LayoutTable( aRect, false, false ); + SetRectsDirty(); + ActionChanged(); + BroadcastObjectChange(); + if( aRect0 != aRect ) + SendUserCall(SDRUSERCALL_RESIZE,aRect0); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const +{ + rInfo.bResizeFreeAllowed=TRUE; + rInfo.bResizePropAllowed=TRUE; + rInfo.bRotateFreeAllowed=FALSE; + rInfo.bRotate90Allowed =FALSE; + rInfo.bMirrorFreeAllowed=FALSE; + rInfo.bMirror45Allowed =FALSE; + rInfo.bMirror90Allowed =FALSE; + + // allow transparence + rInfo.bTransparenceAllowed = TRUE; + + // gradient depends on fillstyle + XFillStyle eFillStyle = ((XFillStyleItem&)(GetObjectItem(XATTR_FILLSTYLE))).GetValue(); + rInfo.bGradientAllowed = (eFillStyle == XFILL_GRADIENT); + rInfo.bShearAllowed =FALSE; + rInfo.bEdgeRadiusAllowed=FALSE; + rInfo.bCanConvToPath =FALSE; + rInfo.bCanConvToPoly =FALSE; + rInfo.bCanConvToPathLineToArea=FALSE; + rInfo.bCanConvToPolyLineToArea=FALSE; + rInfo.bCanConvToContour = FALSE; +} + +// -------------------------------------------------------------------- + +UINT16 SdrTableObj::GetObjIdentifier() const +{ + return static_cast<UINT16>(OBJ_TABLE); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::SetPage(SdrPage* pNewPage) +{ + SdrTextObj::SetPage(pNewPage); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::SetModel(SdrModel* pNewModel) +{ + SdrModel* pOldModel = GetModel(); + if( pNewModel != pOldModel ) + { + SdrTextObj::SetModel(pNewModel); + + if( mpImpl ) + { + mpImpl->SetModel( pOldModel, pNewModel ); + + if( !maLogicRect.IsEmpty() ) + { + aRect = maLogicRect; + mpImpl->LayoutTable( aRect, false, false ); + } + } + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeTextRect( SdrOutliner& rOutliner, Rectangle& rTextRect, FASTBOOL bNoEditText, Rectangle* pAnchorRect, BOOL bLineWidth ) const +{ + if( mpImpl ) + TakeTextRect( mpImpl->maEditPos, rOutliner, rTextRect, bNoEditText, pAnchorRect, bLineWidth ); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeTextRect( const CellPos& rPos, SdrOutliner& rOutliner, Rectangle& rTextRect, FASTBOOL bNoEditText, Rectangle* pAnchorRect, BOOL /*bLineWidth*/ ) const +{ + if( !mpImpl ) + return; + + CellRef xCell( mpImpl->getCell( rPos ) ); + if( !xCell.is() ) + return; + + Rectangle aAnkRect; + TakeTextAnchorRect( rPos, aAnkRect ); + + SdrTextVertAdjust eVAdj=xCell->GetTextVerticalAdjust(); +// SdrTextHorzAdjust eHAdj=xCell->GetTextHorizontalAdjust(); + + ULONG nStat0=rOutliner.GetControlWord(); + Size aNullSize; + nStat0 |= EE_CNTRL_AUTOPAGESIZE; + rOutliner.SetControlWord(nStat0); + rOutliner.SetMinAutoPaperSize(aNullSize); + rOutliner.SetMaxAutoPaperSize(aAnkRect.GetSize()); + rOutliner.SetPaperSize(aAnkRect.GetSize()); + + // #103516# New try with _BLOCK for hor and ver after completely + // supporting full width for vertical text. +// if( SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting()) +// { + rOutliner.SetMinAutoPaperSize(Size(aAnkRect.GetWidth(), 0)); +// } +// else if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting()) +// { +// rOutliner.SetMinAutoPaperSize(Size(0, aAnkRect.GetHeight())); +// } + + // --- + + // set text at outliner, maybe from edit outliner + OutlinerParaObject* pPara= xCell->GetOutlinerParaObject(); + if (pEdtOutl && !bNoEditText && mpImpl->mxActiveCell == xCell ) + pPara=pEdtOutl->CreateParaObject(); + + if (pPara) + { + const bool bHitTest = pModel && (&pModel->GetHitTestOutliner() == &rOutliner); + + const SdrTextObj* pTestObj = rOutliner.GetTextObj(); + if( !pTestObj || !bHitTest || (pTestObj != this) || (pTestObj->GetOutlinerParaObject() != xCell->GetOutlinerParaObject()) ) + { + if( bHitTest ) // #i33696# take back fix #i27510# + rOutliner.SetTextObj( this ); + + rOutliner.SetUpdateMode(TRUE); + rOutliner.SetText(*pPara); + } + } + else + { + rOutliner.SetTextObj( NULL ); + } + + if (pEdtOutl && !bNoEditText && pPara && mpImpl->mxActiveCell == xCell ) + delete pPara; + + rOutliner.SetUpdateMode(TRUE); + rOutliner.SetControlWord(nStat0); + + Point aTextPos(aAnkRect.TopLeft()); + Size aTextSiz(rOutliner.GetPaperSize()); +/* + if (eHAdj==SDRTEXTHORZADJUST_CENTER || eHAdj==SDRTEXTHORZADJUST_RIGHT) + { + long nFreeWdt=aAnkRect.GetWidth()-aTextSiz.Width(); + if (eHAdj==SDRTEXTHORZADJUST_CENTER) + aTextPos.X()+=nFreeWdt/2; + if (eHAdj==SDRTEXTHORZADJUST_RIGHT) + aTextPos.X()+=nFreeWdt; + } +*/ + if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM) + { + long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height(); + if (eVAdj==SDRTEXTVERTADJUST_CENTER) + aTextPos.Y()+=nFreeHgt/2; + if (eVAdj==SDRTEXTVERTADJUST_BOTTOM) + aTextPos.Y()+=nFreeHgt; + } + + if (pAnchorRect) + *pAnchorRect=aAnkRect; + + rTextRect=Rectangle(aTextPos,aTextSiz); +} + +// -------------------------------------------------------------------- + +const CellRef& SdrTableObj::getActiveCell() const +{ + if( mpImpl ) + { + if( !mpImpl->mxActiveCell.is() ) + { + CellPos aPos; + const_cast< SdrTableObj* >(this)->setActiveCell( aPos ); + } + return mpImpl->mxActiveCell; + } + else + { + static CellRef xCell; + return xCell; + } +} + +// -------------------------------------------------------------------- + +sal_Int32 SdrTableObj::getRowCount() const +{ + return mpImpl ? mpImpl->getRowCount() : 0; +} + +// -------------------------------------------------------------------- + +sal_Int32 SdrTableObj::getColumnCount() const +{ + return mpImpl ? mpImpl->getColumnCount() : 0; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::setActiveCell( const CellPos& rPos ) +{ + if( mpImpl && mpImpl->mxTable.is() ) try + { + mpImpl->mxActiveCell.set( dynamic_cast< Cell* >( mpImpl->mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) ); + if( mpImpl->mxActiveCell.is() && mpImpl->mxActiveCell->isMerged() ) + { + CellPos aOrigin; + findMergeOrigin( mpImpl->mxTable.get(), rPos.mnCol, rPos.mnRow, aOrigin.mnCol, aOrigin.mnRow ); + mpImpl->mxActiveCell.set( dynamic_cast< Cell* >( mpImpl->mxTable->getCellByPosition( aOrigin.mnCol, aOrigin.mnRow ).get() ) ); + mpImpl->maEditPos = aOrigin; + } + else + { + mpImpl->maEditPos = rPos; + } + } + catch( Exception& ) + { + DBG_ERROR("SdrTableObj::setActiveCell(), exception caught!"); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::getActiveCellPos( CellPos& rPos ) const +{ + rPos = mpImpl->maEditPos; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::getCellBounds( const CellPos& rPos, ::Rectangle& rCellRect ) +{ + if( mpImpl ) + { + CellRef xCell( mpImpl->getCell( rPos ) ); + if( xCell.is() ) + rCellRect = xCell->getCellRect(); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeTextAnchorRect(Rectangle& rAnchorRect) const +{ + if( mpImpl ) + TakeTextAnchorRect( mpImpl->maEditPos, rAnchorRect ); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeTextAnchorRect( const CellPos& rPos, Rectangle& rAnchorRect ) const +{ + Rectangle aAnkRect(aRect); + + if( mpImpl ) + { + CellRef xCell( mpImpl->getCell( rPos ) ); + if( xCell.is() ) + xCell->TakeTextAnchorRect( aAnkRect ); + } + + ImpJustifyRect(aAnkRect); + rAnchorRect=aAnkRect; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* pViewInit, Rectangle* pViewMin) const +{ + if( mpImpl ) + TakeTextEditArea( mpImpl->maEditPos, pPaperMin, pPaperMax, pViewInit, pViewMin ); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeTextEditArea( const CellPos& rPos, Size* pPaperMin, Size* pPaperMax, Rectangle* pViewInit, Rectangle* pViewMin ) const +{ + Size aPaperMin,aPaperMax; + Rectangle aViewInit; + TakeTextAnchorRect( rPos, aViewInit ); + + Size aAnkSiz(aViewInit.GetSize()); + aAnkSiz.Width()--; aAnkSiz.Height()--; // weil GetSize() ein draufaddiert + + Size aMaxSiz(aAnkSiz.Width(),1000000); + if (pModel!=NULL) + { + Size aTmpSiz(pModel->GetMaxObjSize()); + if (aTmpSiz.Height()!=0) + aMaxSiz.Height()=aTmpSiz.Height(); + } + + CellRef xCell( mpImpl->getCell( rPos ) ); + SdrTextVertAdjust eVAdj = xCell.is() ? xCell->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_TOP; +// SdrTextHorzAdjust eHAdj = xCell.is() ? xCell->GetTextHorizontalAdjust() : SDRTEXTHORZADJUST_LEFT; + + aPaperMax=aMaxSiz; + +// if((SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting()) || (SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())) + aPaperMin.Width() = aAnkSiz.Width(); + + if (pViewMin!=NULL) + { + *pViewMin=aViewInit; +/* + long nXFree=aAnkSiz.Width()-aPaperMin.Width(); + + if (eHAdj==SDRTEXTHORZADJUST_LEFT) + { + pViewMin->Right()-=nXFree; + } + else if (eHAdj==SDRTEXTHORZADJUST_RIGHT) + { + pViewMin->Left()+=nXFree; + } + else + { + pViewMin->Left()+=nXFree/2; + pViewMin->Right()=pViewMin->Left()+aPaperMin.Width(); + } +*/ + long nYFree=aAnkSiz.Height()-aPaperMin.Height(); + + if (eVAdj==SDRTEXTVERTADJUST_TOP) + { + pViewMin->Bottom()-=nYFree; + } + else if (eVAdj==SDRTEXTVERTADJUST_BOTTOM) + { + pViewMin->Top()+=nYFree; + } + else + { + pViewMin->Top()+=nYFree/2; + pViewMin->Bottom()=pViewMin->Top()+aPaperMin.Height(); + } + } + + + if(IsVerticalWriting()) + aPaperMin.Width() = 0; + else + aPaperMin.Height() = 0; + + if (pPaperMin!=NULL) *pPaperMin=aPaperMin; + if (pPaperMax!=NULL) *pPaperMax=aPaperMax; + if (pViewInit!=NULL) *pViewInit=aViewInit; +} + +// -------------------------------------------------------------------- + +USHORT SdrTableObj::GetOutlinerViewAnchorMode() const +{ + EVAnchorMode eRet=ANCHOR_TOP_LEFT; + CellRef xCell( getActiveCell() ); + if( xCell.is() ) + { + SdrTextVertAdjust eV=xCell->GetTextVerticalAdjust(); +// SdrTextHorzAdjust eH=xCell->GetTextHorizontalAdjust(); + +// if (eH==SDRTEXTHORZADJUST_LEFT) + { + if (eV==SDRTEXTVERTADJUST_TOP) + { + eRet=ANCHOR_TOP_LEFT; + } + else if (eV==SDRTEXTVERTADJUST_BOTTOM) + { + eRet=ANCHOR_BOTTOM_LEFT; + } + else + { + eRet=ANCHOR_VCENTER_LEFT; + } + } +/* + else if (eH==SDRTEXTHORZADJUST_RIGHT) + { + if (eV==SDRTEXTVERTADJUST_TOP) + { + eRet=ANCHOR_TOP_RIGHT; + } + else if (eV==SDRTEXTVERTADJUST_BOTTOM) + { + eRet=ANCHOR_BOTTOM_RIGHT; + } + else + { + eRet=ANCHOR_VCENTER_RIGHT; + } + } + else + { + if (eV==SDRTEXTVERTADJUST_TOP) + { + eRet=ANCHOR_TOP_HCENTER; + } + else if (eV==SDRTEXTVERTADJUST_BOTTOM) + { + eRet=ANCHOR_BOTTOM_HCENTER; + } + else + { + eRet=ANCHOR_VCENTER_HCENTER; + } + } +*/ + } + return (USHORT)eRet; +} + +// -------------------------------------------------------------------- + +OutlinerParaObject* SdrTableObj::GetEditOutlinerParaObject() const +{ + return SdrTextObj::GetEditOutlinerParaObject(); +} + +// -------------------------------------------------------------------- + +SdrOutliner* SdrTableObj::GetCellTextEditOutliner( const CellPos& rPos ) const +{ + if( pEdtOutl && mpImpl && (mpImpl->maEditPos == rPos) ) + return pEdtOutl; + else + return 0; +} + +// -------------------------------------------------------------------- + +struct ImplTableShadowPaintInfo +{ + Color maShadowColor; + sal_uInt32 mnXDistance; + sal_uInt32 mnYDistance; + sal_uInt16 mnShadowTransparence; + + ImplTableShadowPaintInfo( const SfxItemSet& rSet ) + { + const SdrShadowColorItem& rShadColItem = ((const SdrShadowColorItem&)(rSet.Get(SDRATTR_SHADOWCOLOR))); + maShadowColor = rShadColItem.GetColorValue(); + mnShadowTransparence = ((const SdrShadowTransparenceItem&)(rSet.Get(SDRATTR_SHADOWTRANSPARENCE))).GetValue(); + + mnXDistance = ((SdrShadowXDistItem&)(rSet.Get(SDRATTR_SHADOWXDIST))).GetValue(); + mnYDistance = ((SdrShadowYDistItem&)(rSet.Get(SDRATTR_SHADOWYDIST))).GetValue(); + } +}; + +// -------------------------------------------------------------------- + +void lcl_VertLineEnds( OutputDevice& rDev, const Point& rTop, const Point& rBottom, + const Color& rColor, long nXOffs, long nWidth, + const svx::frame::Style& rTopLine, const svx::frame::Style& rBottomLine ) +{ + rDev.SetLineColor(rColor); // PEN_NULL ??? + rDev.SetFillColor(rColor); + + // Position oben/unten muss unabhaengig von der Liniendicke sein, + // damit der Winkel stimmt (oder X-Position auch anpassen) + long nTopPos = rTop.Y(); + long nBotPos = rBottom.Y(); + + long nTopLeft = rTop.X() + nXOffs; + long nTopRight = nTopLeft + nWidth - 1; + + long nBotLeft = rBottom.X() + nXOffs; + long nBotRight = nBotLeft + nWidth - 1; + + // oben abschliessen + + if ( rTopLine.Prim() ) + { + long nLineW = rTopLine.GetWidth(); + if (nLineW >= 2) + { + Point aTriangle[3]; + aTriangle[0] = Point( nTopLeft, nTopPos ); // wie aPoints[0] + aTriangle[1] = Point( nTopRight, nTopPos ); // wie aPoints[1] + aTriangle[2] = Point( rTop.X(), nTopPos - (nLineW - 1) / 2 ); + Polygon aTriPoly( 3, aTriangle ); + rDev.DrawPolygon( aTriPoly ); + } + } + + // unten abschliessen + + if ( rBottomLine.Prim() ) + { + long nLineW = rBottomLine.GetWidth(); + if (nLineW >= 2) + { + Point aTriangle[3]; + aTriangle[0] = Point( nBotLeft, nBotPos ); // wie aPoints[3] + aTriangle[1] = Point( nBotRight, nBotPos ); // wie aPoints[2] + aTriangle[2] = Point( rBottom.X(), nBotPos - (nLineW - 1) / 2 + nLineW - 1 ); + Polygon aTriPoly( 3, aTriangle ); + rDev.DrawPolygon( aTriPoly ); + } + } +} + +void lcl_VertLine( OutputDevice& rDev, const Point& rTop, const Point& rBottom, + const svx::frame::Style& rLine, + const svx::frame::Style& rTopLine, const svx::frame::Style& rBottomLine, + const Color* pForceColor ) +{ + if( rLine.Prim() ) + { + svx::frame::DrawVerFrameBorderSlanted( rDev, rTop, rBottom, rLine, pForceColor ); + + svx::frame::Style aScaled( rLine ); + aScaled.ScaleSelf( 1.0 / cos( svx::frame::GetVerDiagAngle( rTop, rBottom ) ) ); + if( pForceColor ) + aScaled.SetColor( *pForceColor ); + + long nXOffs = (aScaled.GetWidth() - 1) / -2L; + + lcl_VertLineEnds( rDev, rTop, rBottom, aScaled.GetColor(), + nXOffs, aScaled.Prim(), rTopLine, rBottomLine ); + + if( aScaled.Secn() ) + lcl_VertLineEnds( rDev, rTop, rBottom, aScaled.GetColor(), + nXOffs + aScaled.Prim() + aScaled.Dist(), aScaled.Secn(), rTopLine, rBottomLine ); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeObjNameSingul(XubString& rName) const +{ + rName = ImpGetResStr(STR_ObjNameSingulTable); + + String aName( GetName() ); + if(aName.Len()) + { + rName += sal_Unicode(' '); + rName += sal_Unicode('\''); + rName += aName; + rName += sal_Unicode('\''); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::TakeObjNamePlural(XubString& rName) const +{ + rName = ImpGetResStr(STR_ObjNamePluralTable); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::operator=(const SdrObject& rObj) +{ + // call parent + SdrObject::operator=(rObj); + + const SdrTableObj* pTableObj = dynamic_cast< const SdrTableObj* >( &rObj ); + if (pTableObj!=NULL) + { + TableModelNotifyGuard aGuard( mpImpl ? mpImpl->mxTable.get() : 0 ); + + maLogicRect = pTableObj->maLogicRect; + aRect = pTableObj->aRect; + aGeo = pTableObj->aGeo; + eTextKind = pTableObj->eTextKind; + bTextFrame = pTableObj->bTextFrame; + aTextSize = pTableObj->aTextSize; + bTextSizeDirty = pTableObj->bTextSizeDirty; + bNoShear = pTableObj->bNoShear; + bNoRotate = pTableObj->bNoRotate; + bNoMirror = pTableObj->bNoMirror; + bDisableAutoWidthOnDragging = pTableObj->bDisableAutoWidthOnDragging; + + if( pTableObj->mpImpl ) + *mpImpl = *pTableObj->mpImpl; + } +} + +// -------------------------------------------------------------------- + +basegfx::B2DPolyPolygon SdrTableObj::TakeXorPoly() const +{ + return SdrTextObj::TakeXorPoly(); +} + +// -------------------------------------------------------------------- + +basegfx::B2DPolyPolygon SdrTableObj::TakeContour() const +{ + return SdrTextObj::TakeContour(); +} + +// -------------------------------------------------------------------- + +const Rectangle& SdrTableObj::GetSnapRect() const +{ + return aRect; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::NbcSetSnapRect(const Rectangle& rRect) +{ + NbcSetLogicRect( rRect ); +} + +// -------------------------------------------------------------------- + +const Rectangle& SdrTableObj::GetLogicRect() const +{ + return maLogicRect; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::RecalcSnapRect() +{ +} + +// -------------------------------------------------------------------- + +sal_uInt32 SdrTableObj::GetSnapPointCount() const +{ + return SdrTextObj::GetSnapPointCount(); +} + +// -------------------------------------------------------------------- + + +Point SdrTableObj::GetSnapPoint(sal_uInt32 i) const +{ + return SdrTextObj::GetSnapPoint(i); +} + +// -------------------------------------------------------------------- + +sal_Bool SdrTableObj::BegTextEdit(SdrOutliner& rOutl) +{ + if( pEdtOutl != NULL ) + return sal_False; + + pEdtOutl=&rOutl; + +// ForceOutlinerParaObject(); + + mbInEditMode = TRUE; + + rOutl.Init( OUTLINERMODE_TEXTOBJECT ); + rOutl.SetRefDevice( pModel->GetRefDevice() ); + +// -- + FASTBOOL bUpdMerk=rOutl.GetUpdateMode(); + if (bUpdMerk) rOutl.SetUpdateMode(FALSE); + Size aPaperMin; + Size aPaperMax; + Rectangle aEditArea; + TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,NULL); + + rOutl.SetMinAutoPaperSize(aPaperMin); + rOutl.SetMaxAutoPaperSize(aPaperMax); + rOutl.SetPaperSize(aPaperMax); + + if (bUpdMerk) rOutl.SetUpdateMode(TRUE); +//--- + + ULONG nStat=rOutl.GetControlWord(); +// nStat &= ~EE_CNTRL_AUTOPAGESIZE; + nStat |= EE_CNTRL_AUTOPAGESIZE; + nStat &=~EE_CNTRL_STRETCHING; + rOutl.SetControlWord(nStat); + + OutlinerParaObject* pPara = GetOutlinerParaObject(); + if(pPara) + rOutl.SetText(*pPara); + + rOutl.UpdateFields(); + rOutl.ClearModifyFlag(); + +// mpImpl->mnSavedEditRowHeight = mpImpl->mpLayouter->getRowHeight( mpImpl->maEditPos.mnRow ); + + return sal_True; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::EndTextEdit(SdrOutliner& rOutl) +{ + if(rOutl.IsModified()) + { + if( GetModel() && GetModel()->IsUndoEnabled() ) + GetModel()->AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*this) ); + + OutlinerParaObject* pNewText = 0; + Paragraph* p1stPara = rOutl.GetParagraph( 0 ); + UINT32 nParaAnz = rOutl.GetParagraphCount(); + + if(p1stPara) + { + if(nParaAnz == 1) + { + // if its only one paragraph, check if it is empty + XubString aStr(rOutl.GetText(p1stPara)); + + if(!aStr.Len()) + { + // gotcha! + nParaAnz = 0; + } + } + + // to remove the grey field background + rOutl.UpdateFields(); + + if(nParaAnz != 0) + { + // create new text object + pNewText = rOutl.CreateParaObject( 0, (sal_uInt16)nParaAnz ); + } + } + SetOutlinerParaObject(pNewText); + } + + pEdtOutl = 0; + rOutl.Clear(); + UINT32 nStat = rOutl.GetControlWord(); + nStat &= ~EE_CNTRL_AUTOPAGESIZE; + rOutl.SetControlWord(nStat); + + mbInEditMode = FALSE; +} + +// -------------------------------------------------------------------- + +OutlinerParaObject* SdrTableObj::GetOutlinerParaObject() const +{ + CellRef xCell( getActiveCell() ); + if( xCell.is() ) + return xCell->GetOutlinerParaObject(); + else + return 0; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::NbcSetOutlinerParaObject( OutlinerParaObject* pTextObject) +{ + CellRef xCell( getActiveCell() ); + if( xCell.is() ) + { + if( pModel ) + { + // Update HitTestOutliner + const SdrTextObj* pTestObj = pModel->GetHitTestOutliner().GetTextObj(); + if( pTestObj && pTestObj->GetOutlinerParaObject() == xCell->GetOutlinerParaObject() ) + pModel->GetHitTestOutliner().SetTextObj( NULL ); + } + + xCell->SetOutlinerParaObject( pTextObject ); + + SetTextSizeDirty(); + NbcAdjustTextFrameWidthAndHeight(); +// ImpSetTextStyleSheetListeners(); +// ImpCheckMasterCachable(); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::NbcSetLogicRect(const Rectangle& rRect) +{ + maLogicRect=rRect; + ImpJustifyRect(maLogicRect); + const bool bWidth = maLogicRect.getWidth() != aRect.getWidth(); + const bool bHeight = maLogicRect.getHeight() != aRect.getHeight(); + aRect=maLogicRect; + NbcAdjustTextFrameWidthAndHeight( !bHeight, !bWidth ); + SetRectsDirty(); +} + + +// -------------------------------------------------------------------- + +void SdrTableObj::AdjustToMaxRect( const Rectangle& rMaxRect, bool /* bShrinkOnly = false */ ) +{ + Rectangle aAdjustRect( rMaxRect ); + aAdjustRect.setHeight( GetLogicRect().getHeight() ); + SetLogicRect( aAdjustRect ); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::NbcMove(const Size& rSiz) +{ + MoveRect(maLogicRect,rSiz); + SdrTextObj::NbcMove( rSiz ); + if( mpImpl ) + mpImpl->UpdateCells( aRect ); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) +{ + Rectangle aOldRect( maLogicRect ); + ResizeRect(maLogicRect,rRef,xFact,yFact); + + aRect = maLogicRect; + NbcAdjustTextFrameWidthAndHeight( maLogicRect.GetHeight() == aOldRect.GetHeight(), maLogicRect.GetWidth() == aOldRect.GetWidth() ); + SetRectsDirty(); +} + +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::AdjustTextFrameWidthAndHeight(FASTBOOL bHgt, FASTBOOL bWdt) +{ + Rectangle aNeuRect(maLogicRect); + FASTBOOL bRet=AdjustTextFrameWidthAndHeight(aNeuRect,bHgt,bWdt); + if (bRet) + { + Rectangle aBoundRect0; + if (pUserCall!=NULL) + aBoundRect0=GetLastBoundRect(); + aRect=aNeuRect; + SetRectsDirty(); + SetChanged(); + BroadcastObjectChange(); + SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0); + } + return bRet; +} + +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::AdjustTextFrameWidthAndHeight(Rectangle& rR, FASTBOOL bHeight, FASTBOOL bWidth) const +{ + if((pModel == NULL) || rR.IsEmpty() || !mpImpl || !mpImpl->mxTable.is() ) + return FALSE; + + Rectangle aRectangle( rR ); + mpImpl->LayoutTable( aRectangle, !bWidth, !bHeight ); + + if( aRectangle != rR ) + { + rR = aRectangle; + return TRUE; + } + else + { + return FALSE; + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::NbcReformatText() +{ + NbcAdjustTextFrameWidthAndHeight(); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::ReformatText() +{ + Rectangle aBoundRect0; + if (pUserCall!=NULL) + aBoundRect0=GetLastBoundRect(); + NbcReformatText(); + SetChanged(); + BroadcastObjectChange(); + SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0); +} + +// -------------------------------------------------------------------- + +sal_Bool SdrTableObj::IsVerticalWriting() const +{ + const SvxWritingModeItem* pModeItem = dynamic_cast< const SvxWritingModeItem* >( &GetObjectItem( SDRATTR_TEXTDIRECTION ) ); + return pModeItem && pModeItem->GetValue() == com::sun::star::text::WritingMode_TB_RL; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::SetVerticalWriting(sal_Bool bVertical ) +{ + if( bVertical != IsVerticalWriting() ) + { + SvxWritingModeItem aModeItem( com::sun::star::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION ); + SetObjectItem( aModeItem ); + } +} + +// -------------------------------------------------------------------- + +WritingMode SdrTableObj::GetWritingMode() const +{ + WritingMode eMode = WritingMode_LR_TB; + if( mpImpl && mpImpl->mpLayouter ) + eMode = mpImpl->mpLayouter->GetWritingMode(); + return eMode; +} + +// -------------------------------------------------------------------- + +// gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon +// with the base geometry and returns TRUE. Otherwise it returns FALSE. +sal_Bool SdrTableObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& rPolyPolygon ) const +{ + return SdrTextObj::TRGetBaseGeometry( rMatrix, rPolyPolygon ); +} + +// -------------------------------------------------------------------- + +// sets the base geometry of the object using infos contained in the homogen 3x3 matrix. +// If it's an SdrPathObj it will use the provided geometry information. The Polygon has +// to use (0,0) as upper left and will be scaled to the given size in the matrix. +void SdrTableObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& rPolyPolygon ) +{ + SdrTextObj::TRSetBaseGeometry( rMatrix, rPolyPolygon ); +} + +// -------------------------------------------------------------------- + +bool SdrTableObj::IsRealyEdited() const +{ + return pEdtOutl && pEdtOutl->IsModified(); +} + +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::IsFontwork() const +{ + return FALSE; +} + +// -------------------------------------------------------------------- + +sal_uInt32 SdrTableObj::GetHdlCount() const +{ + sal_uInt32 nCount = SdrTextObj::GetHdlCount(); + const sal_Int32 nRowCount = mpImpl->getRowCount(); + const sal_Int32 nColCount = mpImpl->getColumnCount(); + + if( nRowCount && nColCount ) + nCount += nRowCount + nColCount + 2 + 1; + + return nCount; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::AddToHdlList(SdrHdlList& rHdlList) const +{ + const sal_Int32 nRowCount = mpImpl->getRowCount(); + const sal_Int32 nColCount = mpImpl->getColumnCount(); + + // first add row handles + std::vector< TableEdgeHdl* > aRowEdges( nRowCount + 1 ); + + for( sal_Int32 nRow = 0; nRow <= nRowCount; nRow++ ) + { + sal_Int32 nEdgeMin, nEdgeMax; + const sal_Int32 nEdge = mpImpl->mpLayouter->getHorizontalEdge( nRow, &nEdgeMin, &nEdgeMax ); + nEdgeMin -= nEdge; + nEdgeMax -= nEdge; + + Point aPoint( aRect.TopLeft() ); + aPoint.Y() += nEdge; + + TableEdgeHdl* pHdl= new TableEdgeHdl(aPoint,true,nEdgeMin,nEdgeMax,nColCount+1); + pHdl->SetPointNum( nRow ); + rHdlList.AddHdl( pHdl ); + aRowEdges[nRow] = pHdl; + } + + // second add column handles + std::vector< TableEdgeHdl* > aColEdges( nColCount + 1 ); + + for( sal_Int32 nCol = 0; nCol <= nColCount; nCol++ ) + { + sal_Int32 nEdgeMin, nEdgeMax; + const sal_Int32 nEdge = mpImpl->mpLayouter->getVerticalEdge( nCol, &nEdgeMin, &nEdgeMax ); + nEdgeMin -= nEdge; + nEdgeMax -= nEdge; + + Point aPoint( aRect.TopLeft() ); + aPoint.X() += nEdge; + + TableEdgeHdl* pHdl = new TableEdgeHdl(aPoint,false,nEdgeMin,nEdgeMax, nRowCount+1); + pHdl->SetPointNum( nCol ); + rHdlList.AddHdl( pHdl ); + aColEdges[nCol] = pHdl; + } + + // now add visible edges to row and column handles + if( mpImpl && mpImpl->mpLayouter ) + { + TableLayouter& rLayouter = *mpImpl->mpLayouter; + + sal_Int32 nY = 0; + + for( sal_Int32 nRow = 0; nRow <= nRowCount; ++nRow ) + { + const sal_Int32 nRowHeight = (nRow == nRowCount) ? 0 : rLayouter.getRowHeight(nRow); + sal_Int32 nX = 0; + + for( sal_Int32 nCol = 0; nCol <= nColCount; ++nCol ) + { + const sal_Int32 nColWidth = (nCol == nColCount) ? 0 : rLayouter.getColumnWidth(nCol); + + if( nRowHeight > 0 ) + { + if( rLayouter.isEdgeVisible( nCol, nRow, false ) ) + aColEdges[nCol]->SetEdge( nRow, nY, nY + nRowHeight, (rLayouter.getBorderLine( nCol, nRow, false ) == 0) ? Visible : Invisible); + } + + if( nColWidth > 0 ) + { + if( rLayouter.isEdgeVisible( nCol, nRow, true ) ) + aRowEdges[nRow]->SetEdge( nCol, nX, nX + nColWidth, (rLayouter.getBorderLine( nCol, nRow, true ) == 0) ? Visible : Invisible); + } + + nX += nColWidth; + } + + nY += nRowHeight; + } + } + + // add remaining handles + SdrHdl* pH=0; + rHdlList.AddHdl( pH = new TableBorderHdl( aRect ) ); pH->SetMoveOutside( true ); + rHdlList.AddHdl( pH = new SdrHdl(aRect.TopLeft(),HDL_UPLFT) ); pH->SetMoveOutside( true ); + rHdlList.AddHdl( pH = new SdrHdl(aRect.TopCenter(),HDL_UPPER) ); pH->SetMoveOutside( true ); + rHdlList.AddHdl( pH = new SdrHdl(aRect.TopRight(),HDL_UPRGT) ); pH->SetMoveOutside( true ); + rHdlList.AddHdl( pH = new SdrHdl(aRect.LeftCenter(),HDL_LEFT) ); pH->SetMoveOutside( true ); + rHdlList.AddHdl( pH = new SdrHdl(aRect.RightCenter(),HDL_RIGHT) ); pH->SetMoveOutside( true ); + rHdlList.AddHdl( pH = new SdrHdl(aRect.BottomLeft(),HDL_LWLFT) ); pH->SetMoveOutside( true ); + rHdlList.AddHdl( pH = new SdrHdl(aRect.BottomCenter(),HDL_LOWER) ); pH->SetMoveOutside( true ); + rHdlList.AddHdl( pH = new SdrHdl(aRect.BottomRight(),HDL_LWRGT) ); pH->SetMoveOutside( true ); + + ULONG nHdlCount = rHdlList.GetHdlCount(); + for( ULONG nHdl = 0; nHdl < nHdlCount; nHdl++ ) + rHdlList.GetHdl(nHdl)->SetObj((SdrObject*)this); +} + +// -------------------------------------------------------------------- + +SdrHdl* SdrTableObj::GetHdl(sal_uInt32 nHdlNum) const +{ + // #i73248# + // Warn the user that this is ineffective and show alternatives. Should not be used at all. + OSL_ENSURE(false, "SdrTableObj::GetHdl(): ineffective, use AddToHdlList instead (!)"); + + // to have an alternative, get single handle using the ineffective way + SdrHdl* pRetval = 0; + SdrHdlList aLocalList(0); + AddToHdlList(aLocalList); + const sal_uInt32 nHdlCount(aLocalList.GetHdlCount()); + + if(nHdlCount && nHdlNum < nHdlCount) + { + // remove and remember. The other created handles will be deleted again with the + // destruction of the local list + pRetval = aLocalList.RemoveHdl(nHdlNum); + } + + return pRetval; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Draging + +bool SdrTableObj::hasSpecialDrag() const +{ + return true; +} + +bool SdrTableObj::beginSpecialDrag(SdrDragStat& rDrag) const +{ + const SdrHdl* pHdl = rDrag.GetHdl(); + const SdrHdlKind eHdl((pHdl == NULL) ? HDL_MOVE : pHdl->GetKind()); + + switch( eHdl ) + { + case HDL_UPLFT: + case HDL_UPPER: + case HDL_UPRGT: + case HDL_LEFT: + case HDL_RIGHT: + case HDL_LWLFT: + case HDL_LOWER: + case HDL_LWRGT: + case HDL_MOVE: + { + break; + } + + case HDL_USER: + { + rDrag.SetEndDragChangesAttributes(false); + rDrag.SetNoSnap(true); + break; + } + + default: + { + return false; + } + } + + return true; +} + +bool SdrTableObj::applySpecialDrag(SdrDragStat& rDrag) +{ + bool bRet(true); + const SdrHdl* pHdl = rDrag.GetHdl(); + const SdrHdlKind eHdl((pHdl == NULL) ? HDL_MOVE : pHdl->GetKind()); + + switch( eHdl ) + { + case HDL_UPLFT: + case HDL_UPPER: + case HDL_UPRGT: + case HDL_LEFT: + case HDL_RIGHT: + case HDL_LWLFT: + case HDL_LOWER: + case HDL_LWRGT: + { + const Rectangle aNewRectangle(ImpDragCalcRect(rDrag)); + + if(aNewRectangle != aRect) + { + NbcSetLogicRect(aNewRectangle); + } + + break; + } + + case HDL_MOVE: + { + NbcMove( Size( rDrag.GetDX(), rDrag.GetDY() ) ); + break; + } + + case HDL_USER: + { + rDrag.SetEndDragChangesAttributes(false); + rDrag.SetNoSnap(true); + const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl ); + + if( pEdgeHdl ) + { + if( GetModel() && IsInserted() ) + { + rDrag.SetEndDragChangesAttributes(true); + } + + mpImpl->DragEdge( pEdgeHdl->IsHorizontalEdge(), pEdgeHdl->GetPointNum(), pEdgeHdl->GetValidDragOffset( rDrag ) ); + } + break; + } + + default: + { + bRet = false; + } + } + + return bRet; +} + +String SdrTableObj::getSpecialDragComment(const SdrDragStat& rDrag) const +{ + return SdrTextObj::getSpecialDragComment( rDrag ); +} + +basegfx::B2DPolyPolygon SdrTableObj::getSpecialDragPoly(const SdrDragStat& rDrag) const +{ + basegfx::B2DPolyPolygon aRetval; + const SdrHdl* pHdl = rDrag.GetHdl(); + + if( pHdl && (HDL_USER == pHdl->GetKind()) ) + { + const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl ); + + if( pEdgeHdl ) + { + aRetval = pEdgeHdl->getSpecialDragPoly( rDrag ); + } + } + + return aRetval; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Create +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::BegCreate(SdrDragStat& rStat) +{ + rStat.SetOrtho4Possible(); + Rectangle aRect1(rStat.GetStart(), rStat.GetNow()); + aRect1.Justify(); + rStat.SetActionRect(aRect1); + aRect = aRect1; + return TRUE; +} + +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::MovCreate(SdrDragStat& rStat) +{ + Rectangle aRect1; + rStat.TakeCreateRect(aRect1); + ImpJustifyRect(aRect1); + rStat.SetActionRect(aRect1); + aRect=aRect1; // fuer ObjName + SetBoundRectDirty(); + bSnapRectDirty=TRUE; + return TRUE; +} + +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) +{ + rStat.TakeCreateRect(aRect); + ImpJustifyRect(aRect); + return (eCmd==SDRCREATE_FORCEEND || rStat.GetPointAnz()>=2); +} + +void SdrTableObj::BrkCreate(SdrDragStat& /*rStat*/) +{ +} + +// -------------------------------------------------------------------- + +FASTBOOL SdrTableObj::BckCreate(SdrDragStat& /*rStat*/) +{ + return TRUE; +} + +// -------------------------------------------------------------------- + +basegfx::B2DPolyPolygon SdrTableObj::TakeCreatePoly(const SdrDragStat& rDrag) const +{ + Rectangle aRect1; + rDrag.TakeCreateRect(aRect1); + aRect1.Justify(); + + basegfx::B2DPolyPolygon aRetval; + const basegfx::B2DRange aRange(aRect1.Left(), aRect1.Top(), aRect1.Right(), aRect1.Bottom()); + aRetval.append(basegfx::tools::createPolygonFromRect(aRange)); + return aRetval; +} + +// -------------------------------------------------------------------- + +Pointer SdrTableObj::GetCreatePointer() const +{ + return Pointer(POINTER_CROSS); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::createCell( CellRef& xNewCell ) +{ + xNewCell = Cell::create( *this, 0 ); +} + +// -------------------------------------------------------------------- + +SdrObjGeoData *SdrTableObj::NewGeoData() const +{ + return new TableObjectGeoData; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::SaveGeoData(SdrObjGeoData& rGeo) const +{ + DBG_ASSERT( dynamic_cast< TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" ); + SdrTextObj::SaveGeoData (rGeo); + + ((TableObjectGeoData &) rGeo).maLogicRect = maLogicRect; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::RestGeoData(const SdrObjGeoData& rGeo) +{ + DBG_ASSERT( dynamic_cast< const TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" ); + + maLogicRect = ((TableObjectGeoData &) rGeo).maLogicRect; + + SdrTextObj::RestGeoData (rGeo); + + if( mpImpl ) + mpImpl->LayoutTable( aRect, false, false ); + ActionChanged(); +} + +// -------------------------------------------------------------------- + +SdrTableObj* SdrTableObj::CloneRange( const CellPos& rStart, const CellPos& rEnd ) +{ + const sal_Int32 nColumns = rEnd.mnCol - rStart.mnCol + 1; + const sal_Int32 nRows = rEnd.mnRow - rStart.mnRow + 1; + + SdrTableObj* pNewTableObj = new SdrTableObj( GetModel(), GetCurrentBoundRect(), nColumns, nRows); + pNewTableObj->setTableStyleSettings( getTableStyleSettings() ); + pNewTableObj->setTableStyle( getTableStyle() ); + + Reference< XTable > xTable( getTable() ); + Reference< XTable > xNewTable( pNewTableObj->getTable() ); + + if( !xTable.is() || !xNewTable.is() ) + { + delete pNewTableObj; + return 0; + } + + // copy cells + for( sal_Int32 nRow = 0; nRow < nRows; ++nRow ) + { + for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol ) try + { + CellRef xTargetCell( dynamic_cast< Cell* >( xNewTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xTargetCell.is() ) + xTargetCell->cloneFrom( dynamic_cast< Cell* >( xTable->getCellByPosition( rStart.mnCol + nCol, rStart.mnRow + nRow ).get() ) ); + } + catch( Exception& ) + { + DBG_ERROR( "svx::SvxTableController::GetMarkedObjModel(), exception caught!" ); + } + } + + // copy row heights + Reference< XTableRows > xNewRows( xNewTable->getRows(), UNO_QUERY_THROW ); + const OUString sHeight( RTL_CONSTASCII_USTRINGPARAM( "Height" ) ); + for( sal_Int32 nRow = 0; nRow < nRows; ++nRow ) + { + Reference< XPropertySet > xNewSet( xNewRows->getByIndex( nRow ), UNO_QUERY_THROW ); + xNewSet->setPropertyValue( sHeight, Any( mpImpl->mpLayouter->getRowHeight( rStart.mnRow + nRow ) ) ); + } + + // copy column widths + Reference< XTableColumns > xNewColumns( xNewTable->getColumns(), UNO_QUERY_THROW ); + const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM( "Width" ) ); + for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol ) + { + Reference< XPropertySet > xNewSet( xNewColumns->getByIndex( nCol ), UNO_QUERY_THROW ); + xNewSet->setPropertyValue( sWidth, Any( mpImpl->mpLayouter->getColumnWidth( rStart.mnCol + nCol ) ) ); + } + + pNewTableObj->NbcReformatText(); + pNewTableObj->SetLogicRect( pNewTableObj->GetCurrentBoundRect() ); + + return pNewTableObj; +} + +// -------------------------------------------------------------------- + +void SdrTableObj::DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn ) +{ + if( mpImpl && mpImpl->mpLayouter ) + { + TableModelNotifyGuard aGuard( mpImpl->mxTable.get() ); + mpImpl->mpLayouter->DistributeColumns( aRect, nFirstColumn, nLastColumn ); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::DistributeRows( sal_Int32 nFirstRow, sal_Int32 nLastRow ) +{ + if( mpImpl && mpImpl->mpLayouter ) + { + TableModelNotifyGuard aGuard( mpImpl->mxTable.get() ); + mpImpl->mpLayouter->DistributeRows( aRect, nFirstRow, nLastRow ); + } +} + +// -------------------------------------------------------------------- + +void SdrTableObj::SetChanged() +{ + if( mpImpl ) + { + if( mpImpl->UpdateWritingMode() ) + mpImpl->LayoutTable( aRect, false, false ); + } + + ::SdrTextObj::SetChanged(); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::uno_lock() +{ + if( mpImpl && mpImpl->mxTable.is() ) + mpImpl->mxTable->lockBroadcasts(); +} + +// -------------------------------------------------------------------- + +void SdrTableObj::uno_unlock() +{ + if( mpImpl && mpImpl->mxTable.is() ) + mpImpl->mxTable->unlockBroadcasts(); +} + +// -------------------------------------------------------------------- + + + +} } diff --git a/svx/source/table/table.src b/svx/source/table/table.src new file mode 100644 index 000000000000..9ef928599575 --- /dev/null +++ b/svx/source/table/table.src @@ -0,0 +1,34 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 "svx/dialogs.hrc" + +String RID_SVXSTR_STYLEFAMILY_TABLEDESIGN +{ + Text [ en-US ] = "Table Design Styles"; +}; + diff --git a/svx/source/table/tablecolumn.cxx b/svx/source/table/tablecolumn.cxx new file mode 100644 index 000000000000..9c0df0e77664 --- /dev/null +++ b/svx/source/table/tablecolumn.cxx @@ -0,0 +1,305 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/lang/DisposedException.hpp> + +#include "tablecolumn.hxx" +#include "tableundo.hxx" +#include "svx/svdmodel.hxx" +#include "svx/svdotable.hxx" + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::beans; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +const sal_Int32 Property_Width = 0; +const sal_Int32 Property_OptimalWidth = 1; +const sal_Int32 Property_IsVisible = 2; +const sal_Int32 Property_IsStartOfNewPage = 3; + +// ----------------------------------------------------------------------------- +// TableRow +// ----------------------------------------------------------------------------- + +TableColumn::TableColumn( const TableModelRef& xTableModel, sal_Int32 nColumn ) +: TableColumnBase( getStaticPropertySetInfo() ) +, mxTableModel( xTableModel ) +, mnColumn( nColumn ) +, mnWidth( 0 ) +, mbOptimalWidth( sal_True ) +, mbIsVisible( sal_True ) +, mbIsStartOfNewPage( sal_False ) +{ +} + +// ----------------------------------------------------------------------------- + +TableColumn::~TableColumn() +{ +} + +// ----------------------------------------------------------------------------- + +void TableColumn::dispose() +{ + mxTableModel.clear(); +} + +// ----------------------------------------------------------------------------- + +void TableColumn::throwIfDisposed() const throw (::com::sun::star::uno::RuntimeException) +{ + if( !mxTableModel.is() ) + throw DisposedException(); +} + +// ----------------------------------------------------------------------------- + +TableColumn& TableColumn::operator=( const TableColumn& r ) +{ + mnWidth = r.mnWidth; + mbOptimalWidth = r.mbOptimalWidth; + mbIsVisible = r.mbIsVisible; + mbIsStartOfNewPage = r.mbIsStartOfNewPage; + + return *this; +} + +// ----------------------------------------------------------------------------- +// XCellRange +// ----------------------------------------------------------------------------- + +Reference< XCell > SAL_CALL TableColumn::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException) +{ + throwIfDisposed(); + if( nColumn != 0 ) + throw IndexOutOfBoundsException(); + + return mxTableModel->getCellByPosition( mnColumn, nRow ); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL TableColumn::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException) +{ + throwIfDisposed(); + if( (nTop >= 0 ) && (nLeft == 0) && (nBottom >= nTop) && (nRight == 0) ) + { + return mxTableModel->getCellRangeByPosition( mnColumn, nTop, mnColumn, nBottom ); + } + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL TableColumn::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException) +{ + return Reference< XCellRange >(); +} + +// ----------------------------------------------------------------------------- +// XNamed +// ----------------------------------------------------------------------------- + +OUString SAL_CALL TableColumn::getName() throw (RuntimeException) +{ + return maName; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableColumn::setName( const OUString& aName ) throw (RuntimeException) +{ + maName = aName; +} + +// ----------------------------------------------------------------------------- +// XFastPropertySet +// ----------------------------------------------------------------------------- + +void SAL_CALL TableColumn::setFastPropertyValue( sal_Int32 nHandle, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, RuntimeException) +{ + bool bOk = false; + bool bChange = false; + + SdrModel* pModel = mxTableModel->getSdrTableObj()->GetModel(); + + TableColumnUndo* pUndo = 0; + if( mxTableModel.is() && mxTableModel->getSdrTableObj() && mxTableModel->getSdrTableObj()->IsInserted() && pModel && pModel->IsUndoEnabled() ) + { + TableColumnRef xThis( this ); + pUndo = new TableColumnUndo( xThis ); + } + + switch( nHandle ) + { + case Property_Width: + { + sal_Int32 nWidth = mnWidth; + bOk = aValue >>= nWidth; + if( bOk && (nWidth != mnWidth) ) + { + mnWidth = nWidth; + mbOptimalWidth = mnWidth == 0; + bChange = true; + } + break; + } + case Property_OptimalWidth: + { + sal_Bool bOptimalWidth = mbOptimalWidth; + bOk = aValue >>= bOptimalWidth; + if( bOk && (mbOptimalWidth != bOptimalWidth) ) + { + mbOptimalWidth = bOptimalWidth; + if( bOptimalWidth ) + mnWidth = 0; + bChange = true; + } + break; + } + case Property_IsVisible: + { + sal_Bool bIsVisible = mbIsVisible; + bOk = aValue >>= bIsVisible; + if( bOk && (mbIsVisible != bIsVisible) ) + { + mbIsVisible = bIsVisible; + bChange = true; + } + break; + } + + case Property_IsStartOfNewPage: + { + sal_Bool bIsStartOfNewPage = mbIsStartOfNewPage; + bOk = aValue >>= bIsStartOfNewPage; + if( bOk && (mbIsStartOfNewPage != bIsStartOfNewPage) ) + { + mbIsStartOfNewPage = bIsStartOfNewPage; + bChange = true; + } + break; + } + default: + throw UnknownPropertyException(); + } + if( !bOk ) + throw IllegalArgumentException(); + + if( bChange ) + { + if( pUndo ) + { + pModel->AddUndo( pUndo ); + pUndo = 0; + } + mxTableModel->setModified(sal_True); + } + + if( pUndo ) + delete pUndo; +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL TableColumn::getFastPropertyValue( sal_Int32 nHandle ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + switch( nHandle ) + { + case Property_Width: return Any( mnWidth ); + case Property_OptimalWidth: return Any( mbOptimalWidth ); + case Property_IsVisible: return Any( mbIsVisible ); + case Property_IsStartOfNewPage: return Any( mbIsStartOfNewPage ); + default: throw UnknownPropertyException(); + } +} + +// ----------------------------------------------------------------------------- + +rtl::Reference< ::comphelper::FastPropertySetInfo > TableColumn::getStaticPropertySetInfo() +{ + static rtl::Reference< ::comphelper::FastPropertySetInfo > xInfo; + if( !xInfo.is() ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if( !xInfo.is() ) + { + comphelper::PropertyVector aProperties(6); + + aProperties[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Width" ) ); + aProperties[0].Handle = Property_Width; + aProperties[0].Type = ::getCppuType((const sal_Int32*)0); + aProperties[0].Attributes = 0; + + aProperties[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "OptimalWidth" ) ); + aProperties[1].Handle = Property_OptimalWidth; + aProperties[1].Type = ::getBooleanCppuType(); + aProperties[1].Attributes = 0; + + aProperties[2].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsVisible" ) ); + aProperties[2].Handle = Property_IsVisible; + aProperties[2].Type = ::getBooleanCppuType(); + aProperties[2].Attributes = 0; + + aProperties[3].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsStartOfNewPage" ) ); + aProperties[3].Handle = Property_IsStartOfNewPage; + aProperties[3].Type = ::getBooleanCppuType(); + aProperties[3].Attributes = 0; + + aProperties[4].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ); + aProperties[4].Handle = Property_Width; + aProperties[4].Type = ::getCppuType((const sal_Int32*)0); + aProperties[4].Attributes = 0; + + aProperties[5].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "OptimalSize" ) ); + aProperties[5].Handle = Property_OptimalWidth; + aProperties[5].Type = ::getBooleanCppuType(); + aProperties[5].Attributes = 0; + + xInfo.set( new ::comphelper::FastPropertySetInfo(aProperties) ); + } + } + + return xInfo; +} + +// ----------------------------------------------------------------------------- + +} } diff --git a/svx/source/table/tablecolumn.hxx b/svx/source/table/tablecolumn.hxx new file mode 100644 index 000000000000..e020354fe1a7 --- /dev/null +++ b/svx/source/table/tablecolumn.hxx @@ -0,0 +1,88 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLECOLUMN_HXX_ +#define _SVX_TABLECOLUMN_HXX_ + +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <cppuhelper/implbase2.hxx> + +#include "propertyset.hxx" +#include "tablemodel.hxx" + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// TableColumn +// ----------------------------------------------------------------------------- + +typedef ::cppu::ImplInheritanceHelper2< ::comphelper::FastPropertySet, ::com::sun::star::table::XCellRange, ::com::sun::star::container::XNamed > TableColumnBase; + +class TableColumn : public TableColumnBase +{ + friend class TableColumnUndo; + friend class TableModel; +public: + TableColumn( const TableModelRef& xTableModel, sal_Int32 nColumn ); + virtual ~TableColumn(); + + void dispose(); + void throwIfDisposed() const throw (::com::sun::star::uno::RuntimeException); + + TableColumn& operator=( const TableColumn& ); + + // XCellRange + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByName( const ::rtl::OUString& aRange ) throw (::com::sun::star::uno::RuntimeException); + + // XNamed + virtual ::rtl::OUString SAL_CALL getName() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setName( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException); + + // XFastPropertySet + virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + +private: + static rtl::Reference< ::comphelper::FastPropertySetInfo > getStaticPropertySetInfo(); + + TableModelRef mxTableModel; + sal_Int32 mnColumn; + sal_Int32 mnWidth; + sal_Bool mbOptimalWidth; + sal_Bool mbIsVisible; + sal_Bool mbIsStartOfNewPage; + ::rtl::OUString maName; +}; + +} } + +#endif diff --git a/svx/source/table/tablecolumns.cxx b/svx/source/table/tablecolumns.cxx new file mode 100644 index 000000000000..7d0e89a252cd --- /dev/null +++ b/svx/source/table/tablecolumns.cxx @@ -0,0 +1,141 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/lang/DisposedException.hpp> + +#include "tablecolumns.hxx" +#include "tablecolumn.hxx" + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::table; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// TableColumns +// ----------------------------------------------------------------------------- + +TableColumns::TableColumns( const TableModelRef& xTableModel ) +: mxTableModel( xTableModel ) +{ +} + +// ----------------------------------------------------------------------------- + +TableColumns::~TableColumns() +{ + dispose(); +} + +// ----------------------------------------------------------------------------- + +void TableColumns::dispose() +{ + mxTableModel.clear(); +} + +// ----------------------------------------------------------------------------- + +void TableColumns::throwIfDisposed() const throw (::com::sun::star::uno::RuntimeException) +{ + if( !mxTableModel.is() ) + throw DisposedException(); +} + +// ----------------------------------------------------------------------------- +// XTableRows +// ----------------------------------------------------------------------------- + +void SAL_CALL TableColumns::insertByIndex( sal_Int32 nIndex, sal_Int32 nCount ) throw (RuntimeException) +{ + throwIfDisposed(); + mxTableModel->insertColumns( nIndex, nCount ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableColumns::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount ) throw (RuntimeException) +{ + throwIfDisposed(); + mxTableModel->removeColumns( nIndex, nCount ); +} + +// ----------------------------------------------------------------------------- +// XIndexAccess +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL TableColumns::getCount() throw (RuntimeException) +{ + throwIfDisposed(); + return mxTableModel->getColumnCount(); +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL TableColumns::getByIndex( sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException) +{ + throwIfDisposed(); + + if( ( Index < 0 ) || ( Index >= mxTableModel->getColumnCount() ) ) + throw IndexOutOfBoundsException(); + + return Any( Reference< XCellRange >( mxTableModel->getColumn( Index ).get() ) ); +} + +// ----------------------------------------------------------------------------- +// XElementAccess +// ----------------------------------------------------------------------------- + +Type SAL_CALL TableColumns::getElementType() throw (RuntimeException) +{ + throwIfDisposed(); + + return XCellRange::static_type(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL TableColumns::hasElements() throw (RuntimeException) +{ + throwIfDisposed(); + + return mxTableModel->getColumnCount() != 0; +} + +// ----------------------------------------------------------------------------- + +} } diff --git a/svx/source/table/tablecolumns.hxx b/svx/source/table/tablecolumns.hxx new file mode 100644 index 000000000000..2a7be2851141 --- /dev/null +++ b/svx/source/table/tablecolumns.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLECOLUMNS_HXX_ +#define _SVX_TABLECOLUMNS_HXX_ + +#include <com/sun/star/table/XTableColumns.hpp> +#include <cppuhelper/implbase1.hxx> + +#include "tablemodel.hxx" + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// TableColumns +// ----------------------------------------------------------------------------- + +class TableColumns : public ::cppu::WeakAggImplHelper1< ::com::sun::star::table::XTableColumns > +{ +public: + TableColumns( const TableModelRef& xTableModel ); + virtual ~TableColumns(); + + void dispose(); + void throwIfDisposed() const throw (::com::sun::star::uno::RuntimeException); + + // XTableColumns + virtual void SAL_CALL insertByIndex( sal_Int32 nIndex, sal_Int32 nCount ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeByIndex( sal_Int32 nIndex, sal_Int32 nCount ) throw (::com::sun::star::uno::RuntimeException); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // Methods + virtual ::com::sun::star::uno::Type SAL_CALL getElementType() throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL hasElements() throw (::com::sun::star::uno::RuntimeException); + +private: + TableModelRef mxTableModel; +}; + +} } + +#endif diff --git a/svx/source/table/tablecontroller.cxx b/svx/source/table/tablecontroller.cxx new file mode 100644 index 000000000000..4a0432c0c15f --- /dev/null +++ b/svx/source/table/tablecontroller.cxx @@ -0,0 +1,2618 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include "tablecontroller.hxx" + +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/table/XMergeableCellRange.hpp> +#include <com/sun/star/table/XMergeableCell.hpp> + +#include <sal/config.h> + +#include <vcl/svapp.hxx> +#include <svl/whiter.hxx> + +#include <sfx2/request.hxx> + +#include <editeng/scripttypeitem.hxx> +#include <svx/svdotable.hxx> +#include <svx/sdr/overlay/overlayobjectcell.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <svx/svxids.hrc> +#include <editeng/outlobj.hxx> +#include <svx/svdoutl.hxx> +#include <svx/svdpagv.hxx> +#include <svx/svdetc.hxx> +#include <editeng/editobj.hxx> +#include "editeng/editstat.hxx" +#include "editeng/unolingu.hxx" +#include "svx/sdrpagewindow.hxx" +#include <svx/selectioncontroller.hxx> +#include <svx/svdmodel.hxx> +#include "sdrpaintwindow.hxx" +#include <svx/svxdlg.hxx> +#include <editeng/boxitem.hxx> +#include "cell.hxx" +#include <editeng/borderline.hxx> +#include <editeng/colritem.hxx> +#include "editeng/bolnitem.hxx" +#include "svdstr.hrc" +#include "svdglob.hxx" +#include "svx/svdpage.hxx" +#include "tableundo.hxx" +#include "tablelayouter.hxx" + +using ::rtl::OUString; +using namespace ::sdr::table; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; + +namespace sdr { namespace table { + +// -------------------------------------------------------------------- +// class SvxTableControllerModifyListener +// -------------------------------------------------------------------- + +class SvxTableControllerModifyListener : public ::cppu::WeakImplHelper1< ::com::sun::star::util::XModifyListener > +{ +public: + SvxTableControllerModifyListener( SvxTableController* pController ) + : mpController( pController ) {} + + // XModifyListener + virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException); + + // XEventListener + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + + SvxTableController* mpController; +}; + +// -------------------------------------------------------------------- +// XModifyListener +// -------------------------------------------------------------------- + +void SAL_CALL SvxTableControllerModifyListener::modified( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException) +{ + if( mpController ) + mpController->onTableModified(); +} + +// -------------------------------------------------------------------- +// XEventListener +// -------------------------------------------------------------------- + +void SAL_CALL SvxTableControllerModifyListener::disposing( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException) +{ + mpController = 0; +} + +// -------------------------------------------------------------------- +// class SvxTableController +// -------------------------------------------------------------------- + +rtl::Reference< sdr::SelectionController > CreateTableController( SdrObjEditView* pView, const SdrObject* pObj, const rtl::Reference< sdr::SelectionController >& xRefController ) +{ + return SvxTableController::create( pView, pObj, xRefController ); +} + +// -------------------------------------------------------------------- + +rtl::Reference< sdr::SelectionController > SvxTableController::create( SdrObjEditView* pView, const SdrObject* pObj, const rtl::Reference< sdr::SelectionController >& xRefController ) +{ + if( xRefController.is() ) + { + SvxTableController* pController = dynamic_cast< SvxTableController* >( xRefController.get() ); + if( pController && (pController->mxTableObj.get() == pObj) && (pController->mpView == pView) ) + return xRefController; + } + return new SvxTableController( pView, pObj ); +} + +// -------------------------------------------------------------------- + +SvxTableController::SvxTableController( SdrObjEditView* pView, const SdrObject* pObj ) +: mbCellSelectionMode(false) +, mbLeftButtonDown(false) +, mpSelectionOverlay(0) +, mpView( dynamic_cast< SdrView* >( pView ) ) +, mxTableObj( dynamic_cast< SdrTableObj* >( const_cast< SdrObject* >( pObj ) ) ) +, mpModel( 0 ) +, mnUpdateEvent( 0 ) +{ + if( pObj ) + mpModel = pObj->GetModel(); + + if( mxTableObj.is() ) + { + static_cast< const SdrTableObj* >( pObj )->getActiveCellPos( maCursorFirstPos ); + maCursorLastPos = maCursorFirstPos; + + Reference< XTable > xTable( static_cast< const SdrTableObj* >( pObj )->getTable() ); + if( xTable.is() ) + { + mxModifyListener = new SvxTableControllerModifyListener( this ); + xTable->addModifyListener( mxModifyListener ); + + mxTable.set( dynamic_cast< TableModel* >( xTable.get() ) ); + } + } +} + +// -------------------------------------------------------------------- + +SvxTableController::~SvxTableController() +{ + if( mnUpdateEvent ) + { + Application::RemoveUserEvent( mnUpdateEvent ); + } + + if( mxModifyListener.is() && mxTableObj.get() ) + { + Reference< XTable > xTable( static_cast< SdrTableObj* >( mxTableObj.get() )->getTable() ); + if( xTable.is() ) + { + xTable->removeModifyListener( mxModifyListener ); + mxModifyListener.clear(); + } + } +} + +// -------------------------------------------------------------------- + +const sal_uInt16 ACTION_NONE = 0; +const sal_uInt16 ACTION_GOTO_FIRST_CELL = 1; +const sal_uInt16 ACTION_GOTO_FIRST_COLUMN = 2; +const sal_uInt16 ACTION_GOTO_FIRST_ROW = 3; +const sal_uInt16 ACTION_GOTO_LEFT_CELL = 4; +const sal_uInt16 ACTION_GOTO_UP_CELL = 5; +const sal_uInt16 ACTION_GOTO_RIGHT_CELL = 6; +const sal_uInt16 ACTION_GOTO_DOWN_CELL = 7; +const sal_uInt16 ACTION_GOTO_LAST_CELL = 8; +const sal_uInt16 ACTION_GOTO_LAST_COLUMN = 9; +const sal_uInt16 ACTION_GOTO_LAST_ROW = 10; +const sal_uInt16 ACTION_EDIT_CELL = 11; +const sal_uInt16 ACTION_STOP_TEXT_EDIT = 12; +const sal_uInt16 ACTION_REMOVE_SELECTION = 13; +const sal_uInt16 ACTION_START_SELECTION = 14; +const sal_uInt16 ACTION_HANDLED_BY_VIEW = 15; +const sal_uInt16 ACTION_TAB = 18; + +bool SvxTableController::onKeyInput(const KeyEvent& rKEvt, Window* pWindow ) +{ + if( !checkTableObject() ) + return false; + + // check if we are read only + if( mpModel && mpModel->IsReadOnly()) + { + switch( rKEvt.GetKeyCode().GetCode() ) + { + case awt::Key::DOWN: + case awt::Key::UP: + case awt::Key::LEFT: + case awt::Key::RIGHT: + case awt::Key::TAB: + case awt::Key::HOME: + case awt::Key::END: + case awt::Key::NUM2: + case awt::Key::NUM4: + case awt::Key::NUM6: + case awt::Key::NUM8: + case awt::Key::ESCAPE: + case awt::Key::F2: + break; + default: + // tell the view we eat the event, no further processing needed + return true; + } + } + + sal_uInt16 nAction = getKeyboardAction( rKEvt, pWindow ); + + return executeAction( nAction, ( rKEvt.GetKeyCode().IsShift() ) ? sal_True : sal_False, pWindow ); +} + +// -------------------------------------------------------------------- +// ::com::sun::star::awt::XMouseClickHandler: +// -------------------------------------------------------------------- + +bool SvxTableController::onMouseButtonDown(const MouseEvent& rMEvt, Window* pWindow ) +{ + if( !pWindow || !checkTableObject() ) + return false; + + SdrViewEvent aVEvt; + if( !rMEvt.IsRight() && mpView->PickAnything(rMEvt,SDRMOUSEBUTTONDOWN, aVEvt) == SDRHIT_HANDLE ) + return false; + + TableHitKind eHit = static_cast< SdrTableObj* >(mxTableObj.get())->CheckTableHit( pWindow->PixelToLogic(rMEvt.GetPosPixel()), maMouseDownPos.mnCol, maMouseDownPos.mnRow, 0 ); + + mbLeftButtonDown = (rMEvt.GetClicks() == 1) && rMEvt.IsLeft(); + + if( eHit == SDRTABLEHIT_CELL ) + { + StartSelection( maMouseDownPos ); + return true; + } + + if( rMEvt.IsRight() && eHit != SDRTABLEHIT_NONE ) + return true; // right click will become context menu + + // for cell selektion with the mouse remember our first hit + if( mbLeftButtonDown ) + { + RemoveSelection(); + + Point aPnt(rMEvt.GetPosPixel()); + if (pWindow!=NULL) + aPnt=pWindow->PixelToLogic(aPnt); + + SdrHdl* pHdl = mpView->PickHandle(aPnt); + + if( pHdl ) + { + mbLeftButtonDown = false; + } + else + { + ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + + if( !pWindow || !pTableObj || eHit == SDRTABLEHIT_NONE) + { + mbLeftButtonDown = false; + } + } + } + + return false; +} + +// -------------------------------------------------------------------- + +bool SvxTableController::onMouseButtonUp(const MouseEvent& rMEvt, Window* /*pWin*/) +{ + if( !checkTableObject() ) + return false; + + mbLeftButtonDown = false; + + if( rMEvt.GetClicks() == 2 ) + return true; + + return false; +} + +// -------------------------------------------------------------------- + +bool SvxTableController::onMouseMove(const MouseEvent& rMEvt, Window* pWindow ) +{ + if( !checkTableObject() ) + return false; + + if( rMEvt.IsLeft() ) + { + int i = 0; + i++; + } + + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() ); + CellPos aPos; + if( mbLeftButtonDown && pTableObj && pTableObj->CheckTableHit( pWindow->PixelToLogic(rMEvt.GetPosPixel()), aPos.mnCol, aPos.mnRow, 0 ) != SDRTABLEHIT_NONE ) + { + if(aPos != maMouseDownPos) + { + if( mbCellSelectionMode ) + { + setSelectedCells( maMouseDownPos, aPos ); + return true; + } + else + { + StartSelection( maMouseDownPos ); + } + } + else if( mbCellSelectionMode ) + { + UpdateSelection( aPos ); + return true; + } + } + return false; +} + +// -------------------------------------------------------------------- + +void SvxTableController::onSelectionHasChanged() +{ + bool bSelected = false; + + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() ); + if( pTableObj && pTableObj->IsTextEditActive() ) + { + pTableObj->getActiveCellPos( maCursorFirstPos ); + maCursorLastPos = maCursorFirstPos; + mbCellSelectionMode = false; + } + else + { + const SdrMarkList& rMarkList= mpView->GetMarkedObjectList(); + if( rMarkList.GetMarkCount() == 1 ) + bSelected = mxTableObj.get() == rMarkList.GetMark(0)->GetMarkedSdrObj(); + } + + if( bSelected ) + { + updateSelectionOverlay(); + } + else + { + destroySelectionOverlay(); + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::GetState( SfxItemSet& rSet ) +{ + if( !mxTable.is() || !mxTableObj.is() || !mxTableObj->GetModel() ) + return; + + SfxItemSet* pSet = 0; + + bool bVertDone = false; + + // Iterate over all requested items in the set. + SfxWhichIter aIter( rSet ); + USHORT nWhich = aIter.FirstWhich(); + while (nWhich) + { + switch (nWhich) + { + case SID_TABLE_VERT_BOTTOM: + case SID_TABLE_VERT_CENTER: + case SID_TABLE_VERT_NONE: + { + if( !mxTable.is() || !mxTableObj->GetModel() ) + { + rSet.DisableItem(nWhich); + } + else if(!bVertDone) + { + if( !pSet ) + { + pSet = new SfxItemSet( mxTableObj->GetModel()->GetItemPool() ); + MergeAttrFromSelectedCells(*pSet, FALSE); + } + + SdrTextVertAdjust eAdj = SDRTEXTVERTADJUST_BLOCK; + + if( pSet->GetItemState( SDRATTR_TEXT_VERTADJUST ) != SFX_ITEM_DONTCARE ) + eAdj = ((SdrTextVertAdjustItem&)(pSet->Get(SDRATTR_TEXT_VERTADJUST))).GetValue(); + + rSet.Put(SfxBoolItem(SID_TABLE_VERT_BOTTOM, eAdj == SDRTEXTVERTADJUST_BOTTOM)); + rSet.Put(SfxBoolItem(SID_TABLE_VERT_CENTER, eAdj == SDRTEXTVERTADJUST_CENTER)); + rSet.Put(SfxBoolItem(SID_TABLE_VERT_NONE, eAdj == SDRTEXTVERTADJUST_TOP)); + bVertDone = true; + } + break; + } + case SID_TABLE_DELETE_ROW: + if( !mxTable.is() || !hasSelectedCells() || (mxTable->getRowCount() <= 1) ) + rSet.DisableItem(SID_TABLE_DELETE_ROW); + break; + case SID_TABLE_DELETE_COL: + if( !mxTable.is() || !hasSelectedCells() || (mxTable->getColumnCount() <= 1) ) + rSet.DisableItem(SID_TABLE_DELETE_COL); + break; + case SID_TABLE_MERGE_CELLS: + if( !mxTable.is() || !hasSelectedCells() ) + rSet.DisableItem(SID_TABLE_MERGE_CELLS); + break; + case SID_TABLE_SPLIT_CELLS: + if( !hasSelectedCells() || !mxTable.is() ) + rSet.DisableItem(SID_TABLE_SPLIT_CELLS); + break; + + case SID_OPTIMIZE_TABLE: + case SID_TABLE_DISTRIBUTE_COLUMNS: + case SID_TABLE_DISTRIBUTE_ROWS: + { + bool bDistributeColumns = false; + bool bDistributeRows = false; + if( mxTable.is() ) + { + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + bDistributeColumns = aStart.mnCol != aEnd.mnCol; + bDistributeRows = aStart.mnRow != aEnd.mnRow; + } + if( !bDistributeColumns && !bDistributeRows ) + rSet.DisableItem(SID_OPTIMIZE_TABLE); + if( !bDistributeColumns ) + rSet.DisableItem(SID_TABLE_DISTRIBUTE_COLUMNS); + if( !bDistributeRows ) + rSet.DisableItem(SID_TABLE_DISTRIBUTE_ROWS); + break; + } + + case SID_AUTOFORMAT: + case SID_TABLE_SORT_DIALOG: + case SID_TABLE_AUTOSUM: +// if( !mxTable.is() ) +// rSet.DisableItem( nWhich ); + break; + default: + break; + } + nWhich = aIter.NextWhich(); + } + if( pSet ) + delete pSet; +} + +// -------------------------------------------------------------------- + +void SvxTableController::onInsert( sal_uInt16 nSId, const SfxItemSet* pArgs ) +{ + ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( !pTableObj ) + return; + + if( mxTable.is() ) try + { + // + bool bInsertAfter = true; + sal_uInt16 nCount = 0; + if( pArgs ) + { + const SfxPoolItem* pItem = 0; + pArgs->GetItemState(nSId, FALSE, &pItem); + if (pItem) + { + nCount = ((const SfxInt16Item* )pItem)->GetValue(); + if(SFX_ITEM_SET == pArgs->GetItemState(SID_TABLE_PARAM_INSERT_AFTER, TRUE, &pItem)) + bInsertAfter = ((const SfxBoolItem* )pItem)->GetValue(); + } + } + + CellPos aStart, aEnd; + if( hasSelectedCells() ) + { + getSelectedCells( aStart, aEnd ); + } + else + { + if( bInsertAfter ) + { + aStart.mnCol = mxTable->getColumnCount() - 1; + aStart.mnRow = mxTable->getRowCount() - 1; + aEnd = aStart; + } + } + + if( pTableObj->IsTextEditActive() ) + mpView->SdrEndTextEdit(sal_True); + + RemoveSelection(); + + const OUString sSize( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ); + + const bool bUndo = mpModel && mpModel->IsUndoEnabled(); + + switch( nSId ) + { + case SID_TABLE_INSERT_COL: + { + TableModelNotifyGuard aGuard( mxTable.get() ); + + if( bUndo ) + { + mpModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) ); + mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) ); + } + + Reference< XTableColumns > xCols( mxTable->getColumns() ); + const sal_Int32 nNewColumns = (nCount == 0) ? (aEnd.mnCol - aStart.mnCol + 1) : nCount; + const sal_Int32 nNewStartColumn = aEnd.mnCol + (bInsertAfter ? 1 : 0); + xCols->insertByIndex( nNewStartColumn, nNewColumns ); + + for( sal_Int32 nOffset = 0; nOffset < nNewColumns; nOffset++ ) + { + Reference< XPropertySet >( xCols->getByIndex( aEnd.mnCol + nOffset + 1 ), UNO_QUERY_THROW )-> + setPropertyValue( sSize, + Reference< XPropertySet >( xCols->getByIndex( aStart.mnCol + nOffset ), UNO_QUERY_THROW )-> + getPropertyValue( sSize ) ); + } + + if( bUndo ) + mpModel->EndUndo(); + + aStart.mnCol = nNewStartColumn; + aStart.mnRow = 0; + aEnd.mnCol = aStart.mnCol + nNewColumns - 1; + aEnd.mnRow = mxTable->getRowCount() - 1; + break; + } + + case SID_TABLE_INSERT_ROW: + { + TableModelNotifyGuard aGuard( mxTable.get() ); + + if( bUndo ) + { + mpModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW ) ); + mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) ); + } + + Reference< XTableRows > xRows( mxTable->getRows() ); + const sal_Int32 nNewRows = (nCount == 0) ? (aEnd.mnRow - aStart.mnRow + 1) : nCount; + const sal_Int32 nNewRowStart = aEnd.mnRow + (bInsertAfter ? 1 : 0); + xRows->insertByIndex( nNewRowStart, nNewRows ); + + for( sal_Int32 nOffset = 0; nOffset < nNewRows; nOffset++ ) + { + Reference< XPropertySet >( xRows->getByIndex( aEnd.mnRow + nOffset + 1 ), UNO_QUERY_THROW )-> + setPropertyValue( sSize, + Reference< XPropertySet >( xRows->getByIndex( aStart.mnRow + nOffset ), UNO_QUERY_THROW )-> + getPropertyValue( sSize ) ); + } + + if( bUndo ) + mpModel->EndUndo(); + + aStart.mnCol = 0; + aStart.mnRow = nNewRowStart; + aEnd.mnCol = mxTable->getColumnCount() - 1; + aEnd.mnRow = aStart.mnRow + nNewRows - 1; + break; + } + } + + StartSelection( aStart ); + UpdateSelection( aEnd ); + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("svx::SvxTableController::onInsert(), exception caught!"); + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::onDelete( sal_uInt16 nSId ) +{ + ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( !pTableObj ) + return; + + if( mxTable.is() && hasSelectedCells() ) + { + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + if( pTableObj->IsTextEditActive() ) + mpView->SdrEndTextEdit(sal_True); + + RemoveSelection(); + + bool bDeleteTable = false; + switch( nSId ) + { + case SID_TABLE_DELETE_COL: + { + const sal_Int32 nRemovedColumns = aEnd.mnCol - aStart.mnCol + 1; + if( nRemovedColumns == mxTable->getColumnCount() ) + { + bDeleteTable = true; + } + else + { + Reference< XTableColumns > xCols( mxTable->getColumns() ); + xCols->removeByIndex( aStart.mnCol, nRemovedColumns ); + } + break; + } + + case SID_TABLE_DELETE_ROW: + { + const sal_Int32 nRemovedRows = aEnd.mnRow - aStart.mnRow + 1; + if( nRemovedRows == mxTable->getRowCount() ) + { + bDeleteTable = true; + } + else + { + Reference< XTableRows > xRows( mxTable->getRows() ); + xRows->removeByIndex( aStart.mnRow, nRemovedRows ); + } + break; + } + } + + if( bDeleteTable ) + mpView->DeleteMarkedObj(); + else + UpdateTableShape(); + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::onSelect( sal_uInt16 nSId ) +{ + if( mxTable.is() ) + { + const sal_Int32 nRowCount = mxTable->getRowCount(); + const sal_Int32 nColCount = mxTable->getColumnCount(); + if( nRowCount && nColCount ) + { + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + switch( nSId ) + { + case SID_TABLE_SELECT_ALL: + aEnd.mnCol = 0; aEnd.mnRow = 0; + aStart.mnCol = nColCount - 1; aStart.mnRow = nRowCount - 1; + break; + case SID_TABLE_SELECT_COL: + aEnd.mnRow = nRowCount - 1; + aStart.mnRow = 0; + break; + case SID_TABLE_SELECT_ROW: + aEnd.mnCol = nColCount - 1; + aStart.mnCol = 0; + break; + } + + StartSelection( aEnd ); + gotoCell( aStart, true, 0 ); + } + } +} + +// -------------------------------------------------------------------- +void SvxTableController::onFormatTable( SfxRequest& rReq ) +{ + ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( !pTableObj ) + return; + + const SfxItemSet* pArgs = rReq.GetArgs(); + + if( !pArgs && pTableObj->GetModel() ) + { + SfxItemSet aNewAttr( pTableObj->GetModel()->GetItemPool() ); + MergeAttrFromSelectedCells(aNewAttr, FALSE); + + // merge drawing layer text distance items into SvxBoxItem used by the dialog + SvxBoxItem aBoxItem( static_cast< const SvxBoxItem& >( aNewAttr.Get( SDRATTR_TABLE_BORDER ) ) ); + aBoxItem.SetDistance( sal::static_int_cast< USHORT >( ((SdrTextLeftDistItem&)(aNewAttr.Get(SDRATTR_TEXT_LEFTDIST))).GetValue()), BOX_LINE_LEFT ); + aBoxItem.SetDistance( sal::static_int_cast< USHORT >( ((SdrTextRightDistItem&)(aNewAttr.Get(SDRATTR_TEXT_RIGHTDIST))).GetValue()), BOX_LINE_RIGHT ); + aBoxItem.SetDistance( sal::static_int_cast< USHORT >( ((SdrTextUpperDistItem&)(aNewAttr.Get(SDRATTR_TEXT_UPPERDIST))).GetValue()), BOX_LINE_TOP ); + aBoxItem.SetDistance( sal::static_int_cast< USHORT >( ((SdrTextLowerDistItem&)(aNewAttr.Get(SDRATTR_TEXT_LOWERDIST))).GetValue()), BOX_LINE_BOTTOM ); + aNewAttr.Put( aBoxItem ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + std::auto_ptr< SfxAbstractTabDialog > pDlg( pFact ? pFact->CreateSvxFormatCellsDialog( NULL, &aNewAttr, pTableObj->GetModel(), pTableObj) : 0 ); + if( pDlg.get() && pDlg->Execute() ) + { + SfxItemSet aNewSet( *(pDlg->GetOutputItemSet ()) ); + + SvxBoxItem aNewBoxItem( static_cast< const SvxBoxItem& >( aNewSet.Get( SDRATTR_TABLE_BORDER ) ) ); + + if( aNewBoxItem.GetDistance( BOX_LINE_LEFT ) != aBoxItem.GetDistance( BOX_LINE_LEFT ) ) + aNewSet.Put(SdrTextLeftDistItem( aNewBoxItem.GetDistance( BOX_LINE_LEFT ) ) ); + + if( aNewBoxItem.GetDistance( BOX_LINE_RIGHT ) != aBoxItem.GetDistance( BOX_LINE_RIGHT ) ) + aNewSet.Put(SdrTextRightDistItem( aNewBoxItem.GetDistance( BOX_LINE_RIGHT ) ) ); + + if( aNewBoxItem.GetDistance( BOX_LINE_TOP ) != aBoxItem.GetDistance( BOX_LINE_TOP ) ) + aNewSet.Put(SdrTextUpperDistItem( aNewBoxItem.GetDistance( BOX_LINE_TOP ) ) ); + + if( aNewBoxItem.GetDistance( BOX_LINE_BOTTOM ) != aBoxItem.GetDistance( BOX_LINE_BOTTOM ) ) + aNewSet.Put(SdrTextLowerDistItem( aNewBoxItem.GetDistance( BOX_LINE_BOTTOM ) ) ); + + SetAttrToSelectedCells(aNewSet, FALSE); + } + UpdateTableShape(); + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::Execute( SfxRequest& rReq ) +{ + const sal_uInt16 nSId = rReq.GetSlot(); + switch( nSId ) + { + case SID_TABLE_INSERT_ROW: + case SID_TABLE_INSERT_COL: + onInsert( nSId, rReq.GetArgs() ); + break; + case SID_TABLE_DELETE_ROW: + case SID_TABLE_DELETE_COL: + onDelete( nSId ); + break; + case SID_TABLE_SELECT_ALL: + case SID_TABLE_SELECT_COL: + case SID_TABLE_SELECT_ROW: + onSelect( nSId ); + break; + case SID_FORMAT_TABLE_DLG: + onFormatTable( rReq ); + break; + + case SID_FRAME_LINESTYLE: + case SID_FRAME_LINECOLOR: + case SID_ATTR_BORDER: + { + const SfxItemSet* pArgs = rReq.GetArgs(); + if( pArgs ) + ApplyBorderAttr( *pArgs ); + } + break; + + case SID_ATTR_FILL_STYLE: + { + const SfxItemSet* pArgs = rReq.GetArgs(); + if( pArgs ) + SetAttributes( *pArgs, false ); + } + break; + + case SID_TABLE_MERGE_CELLS: + MergeMarkedCells(); + break; + + case SID_TABLE_SPLIT_CELLS: + SplitMarkedCells(); + break; + + case SID_TABLE_DISTRIBUTE_COLUMNS: + DistributeColumns(); + break; + + case SID_TABLE_DISTRIBUTE_ROWS: + DistributeRows(); + break; + + case SID_TABLE_VERT_BOTTOM: + case SID_TABLE_VERT_CENTER: + case SID_TABLE_VERT_NONE: + SetVertical( nSId ); + break; + + case SID_AUTOFORMAT: + case SID_TABLE_SORT_DIALOG: + case SID_TABLE_AUTOSUM: + default: + break; + + case SID_TABLE_STYLE: + SetTableStyle( rReq.GetArgs() ); + break; + + case SID_TABLE_STYLE_SETTINGS: + SetTableStyleSettings( rReq.GetArgs() ); + break; + } +} + +void SvxTableController::SetTableStyle( const SfxItemSet* pArgs ) +{ + SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + SdrModel* pModel = pTableObj ? pTableObj->GetModel() : 0; + + if( !pTableObj || !pModel || !pArgs || (SFX_ITEM_SET != pArgs->GetItemState(SID_TABLE_STYLE, FALSE)) ) + return; + + const SfxStringItem* pArg = dynamic_cast< const SfxStringItem* >( &pArgs->Get( SID_TABLE_STYLE ) ); + if( pArg && mxTable.is() ) try + { + Reference< XStyleFamiliesSupplier > xSFS( pModel->getUnoModel(), UNO_QUERY_THROW ); + Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), UNO_QUERY_THROW ); + const OUString sFamilyName( RTL_CONSTASCII_USTRINGPARAM( "table" ) ); + Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( sFamilyName ), UNO_QUERY_THROW ); + + if( xTableFamilyAccess->hasByName( pArg->GetValue() ) ) + { + // found table style with the same name + Reference< XIndexAccess > xNewTableStyle( xTableFamilyAccess->getByName( pArg->GetValue() ), UNO_QUERY_THROW ); + + const bool bUndo = pModel->IsUndoEnabled(); + + if( bUndo ) + { + pModel->BegUndo( ImpGetResStr(STR_TABLE_STYLE) ); + pModel->AddUndo( new TableStyleUndo( *pTableObj ) ); + } + + pTableObj->setTableStyle( xNewTableStyle ); + + const sal_Int32 nRowCount = mxTable->getRowCount(); + const sal_Int32 nColCount = mxTable->getColumnCount(); + for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ ) + { + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) try + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() ) + { + SfxItemSet aSet( xCell->GetItemSet() ); + bool bChanges = false; + const SfxItemSet& rStyleAttribs = xCell->GetStyleSheet()->GetItemSet(); + + for ( USHORT nWhich = SDRATTR_START; nWhich <= SDRATTR_TABLE_LAST; nWhich++ ) + { + if( (rStyleAttribs.GetItemState( nWhich ) == SFX_ITEM_ON) && (aSet.GetItemState( nWhich ) == SFX_ITEM_ON) ) + { + aSet.ClearItem( nWhich ); + bChanges = true; + } + } + + if( bChanges ) + { + if( bUndo ) + xCell->AddUndo(); + + xCell->SetMergedItemSetAndBroadcast( aSet, sal_True ); + } + } + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR( "svx::SvxTableController::SetTableStyle(), exception caught!" ); + } + } + + if( bUndo ) + pModel->EndUndo(); + } + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR( "svx::SvxTableController::SetTableStyle(), exception caught!" ); + } +} + +void SvxTableController::SetTableStyleSettings( const SfxItemSet* pArgs ) +{ + SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + SdrModel* pModel = pTableObj ? pTableObj->GetModel() : 0; + + if( !pTableObj || !pModel ) + return; + + TableStyleSettings aSettings( pTableObj->getTableStyleSettings() ); + + const SfxPoolItem *pPoolItem=NULL; + + if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEFIRSTROWSTYLE, FALSE,&pPoolItem)) ) + aSettings.mbUseFirstRow = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue(); + + if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USELASTROWSTYLE, FALSE,&pPoolItem)) ) + aSettings.mbUseLastRow = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue(); + + if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEBANDINGROWSTYLE, FALSE,&pPoolItem)) ) + aSettings.mbUseRowBanding = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue(); + + if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEFIRSTCOLUMNSTYLE, FALSE,&pPoolItem)) ) + aSettings.mbUseFirstColumn = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue(); + + if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USELASTCOLUMNSTYLE, FALSE,&pPoolItem)) ) + aSettings.mbUseLastColumn = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue(); + + if( (SFX_ITEM_SET == pArgs->GetItemState(ID_VAL_USEBANDINGCOLUMNSTYLE, FALSE,&pPoolItem)) ) + aSettings.mbUseColumnBanding = static_cast< const SfxBoolItem* >(pPoolItem)->GetValue(); + + if( aSettings == pTableObj->getTableStyleSettings() ) + return; + + const bool bUndo = pModel->IsUndoEnabled(); + + if( bUndo ) + { + pModel->BegUndo( ImpGetResStr(STR_TABLE_STYLE_SETTINGS) ); + pModel->AddUndo( new TableStyleUndo( *pTableObj ) ); + } + + pTableObj->setTableStyleSettings( aSettings ); + + if( bUndo ) + pModel->EndUndo(); +} + +void SvxTableController::SetVertical( sal_uInt16 nSId ) +{ + SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( mxTable.is() && pTableObj ) + { + TableModelNotifyGuard aGuard( mxTable.get() ); + + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + SdrTextVertAdjust eAdj = SDRTEXTVERTADJUST_TOP; + + switch( nSId ) + { + case SID_TABLE_VERT_BOTTOM: + eAdj = SDRTEXTVERTADJUST_BOTTOM; + break; + case SID_TABLE_VERT_CENTER: + eAdj = SDRTEXTVERTADJUST_CENTER; + break; + //case SID_TABLE_VERT_NONE: + default: + break; + } + + SdrTextVertAdjustItem aItem( eAdj ); + + for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ ) + { + for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() ) + xCell->SetMergedItem(aItem); + } + } + + UpdateTableShape(); + } +} + +void SvxTableController::MergeMarkedCells() +{ + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( pTableObj ) + { + if( pTableObj->IsTextEditActive() ) + mpView->SdrEndTextEdit(sal_True); + + TableModelNotifyGuard aGuard( mxTable.get() ); + MergeRange( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow ); + } +} + +void SvxTableController::SplitMarkedCells() +{ + if( mxTable.is() ) + { + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + std::auto_ptr< SvxAbstractSplittTableDialog > xDlg( pFact ? pFact->CreateSvxSplittTableDialog( NULL, false, 99, 99 ) : 0 ); + if( xDlg.get() && xDlg->Execute() ) + { + const sal_Int32 nCount = xDlg->GetCount() - 1; + if( nCount < 1 ) + return; + + getSelectedCells( aStart, aEnd ); + + Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow ) ), UNO_QUERY_THROW ); + + const sal_Int32 nRowCount = mxTable->getRowCount(); + const sal_Int32 nColCount = mxTable->getColumnCount(); + + + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() ); + if( pTableObj ) + { + if( pTableObj->IsTextEditActive() ) + mpView->SdrEndTextEdit(sal_True); + + TableModelNotifyGuard aGuard( mxTable.get() ); + + const bool bUndo = mpModel && mpModel->IsUndoEnabled(); + if( bUndo ) + { + mpModel->BegUndo( ImpGetResStr(STR_TABLE_SPLIT) ); + mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) ); + } + + if( xDlg->IsHorizontal() ) + { + xRange->split( 0, nCount ); + } + else + { + xRange->split( nCount, 0 ); + } + + if( bUndo ) + mpModel->EndUndo(); + } + aEnd.mnRow += mxTable->getRowCount() - nRowCount; + aEnd.mnCol += mxTable->getColumnCount() - nColCount; + + setSelectedCells( aStart, aEnd ); + } + } +} + +void SvxTableController::DistributeColumns() +{ + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() ); + if( pTableObj ) + { + const bool bUndo = mpModel && mpModel->IsUndoEnabled(); + if( bUndo ) + { + mpModel->BegUndo( ImpGetResStr(STR_TABLE_DISTRIBUTE_COLUMNS) ); + mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) ); + } + + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + pTableObj->DistributeColumns( aStart.mnCol, aEnd.mnCol ); + + if( bUndo ) + mpModel->EndUndo(); + } +} + +void SvxTableController::DistributeRows() +{ + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxTableObj.get() ); + if( pTableObj ) + { + const bool bUndo = mpModel && mpModel->IsUndoEnabled(); + if( bUndo ) + { + mpModel->BegUndo( ImpGetResStr(STR_TABLE_DISTRIBUTE_ROWS) ); + mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*pTableObj) ); + } + + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + pTableObj->DistributeRows( aStart.mnRow, aEnd.mnRow ); + + if( bUndo ) + mpModel->EndUndo(); + } +} + +bool SvxTableController::DeleteMarked() +{ + if( mbCellSelectionMode ) + { + if( mxTable.is() ) + { + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ ) + { + for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() ) + xCell->SetOutlinerParaObject( 0 ); + } + } + + UpdateTableShape(); + return true; + } + } + + return false; +} + +bool SvxTableController::GetStyleSheet( SfxStyleSheet*& rpStyleSheet ) const +{ + if( hasSelectedCells() ) + { + rpStyleSheet = 0; + + if( mxTable.is() ) + { + SfxStyleSheet* pRet=0; + bool b1st=true; + + CellPos aStart, aEnd; + const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd ); + + for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ ) + { + for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() ) + { + SfxStyleSheet* pSS=xCell->GetStyleSheet(); + if(b1st) + { + pRet=pSS; + } + else if(pRet != pSS) + { + return true; + } + b1st=false; + } + } + } + rpStyleSheet = pRet; + return true; + } + } + return false; +} + +bool SvxTableController::SetStyleSheet( SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr ) +{ + if( hasSelectedCells() && (!pStyleSheet || pStyleSheet->GetFamily() == SFX_STYLE_FAMILY_FRAME) ) + { + if( mxTable.is() ) + { + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ ) + { + for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() ) + xCell->SetStyleSheet(pStyleSheet,bDontRemoveHardAttr); + } + } + + UpdateTableShape(); + return true; + } + } + return false; +} + +// -------------------------------------------------------------------- +// internals +// -------------------------------------------------------------------- + +bool SvxTableController::checkTableObject() +{ + return mxTableObj.is(); +} + +// -------------------------------------------------------------------- + +sal_uInt16 SvxTableController::getKeyboardAction( const KeyEvent& rKEvt, Window* /*pWindow*/ ) +{ + const bool bMod1 = rKEvt.GetKeyCode().IsMod1(); // ctrl + const bool bMod2 = rKEvt.GetKeyCode().IsMod2() != 0; // Alt + + const bool bTextEdit = mpView->IsTextEdit(); + + sal_uInt16 nAction = ACTION_HANDLED_BY_VIEW; + + ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( !pTableObj ) + return nAction; + + // handle special keys + const sal_Int16 nCode = rKEvt.GetKeyCode().GetCode(); + switch( nCode ) + { + case awt::Key::ESCAPE: // handle escape + { + if( bTextEdit ) + { + // escape during text edit ends text edit + nAction = ACTION_STOP_TEXT_EDIT; + } + if( mbCellSelectionMode ) + { + // escape with selected cells removes selection + nAction = ACTION_REMOVE_SELECTION; + } + break; + } + case awt::Key::RETURN: // handle return + { + if( !bMod1 && !bMod2 && !bTextEdit ) + { + // when not already editing, return starts text edit + setSelectionStart( pTableObj->getFirstCell() ); + nAction = ACTION_EDIT_CELL; + } + break; + } + case awt::Key::F2: // f2 toggles text edit + { + if( bMod1 || bMod2 ) // f2 with modifiers is handled by the view + { + } + else if( bTextEdit ) + { + // f2 during text edit stops text edit + nAction = ACTION_STOP_TEXT_EDIT; + } + else if( mbCellSelectionMode ) + { + // f2 with selected cells removes selection + nAction = ACTION_REMOVE_SELECTION; + } + else + { + // f2 with no selection and no text edit starts text edit + setSelectionStart( pTableObj->getFirstCell() ); + nAction = ACTION_EDIT_CELL; + } + break; + } + case awt::Key::HOME: + case awt::Key::NUM7: + { + if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) ) + { + if( bMod1 && !bMod2 ) + { + // strg + home jumps to first cell + nAction = ACTION_GOTO_FIRST_CELL; + } + else if( !bMod1 && bMod2 ) + { + // alt + home jumps to first column + nAction = ACTION_GOTO_FIRST_COLUMN; + } + } + break; + } + case awt::Key::END: + case awt::Key::NUM1: + { + if( (bMod1 || bMod2) && (bTextEdit || mbCellSelectionMode) ) + { + if( bMod1 && !bMod2 ) + { + // strg + end jumps to last cell + nAction = ACTION_GOTO_LAST_CELL; + } + else if( !bMod1 && bMod2 ) + { + // alt + home jumps to last column + nAction = ACTION_GOTO_LAST_COLUMN; + } + } + break; + } + + case awt::Key::TAB: + { + if( bTextEdit || mbCellSelectionMode ) + nAction = ACTION_TAB; + break; + } + + case awt::Key::UP: + case awt::Key::NUM8: + case awt::Key::DOWN: + case awt::Key::NUM2: + case awt::Key::LEFT: + case awt::Key::NUM4: + case awt::Key::RIGHT: + case awt::Key::NUM6: + { + bool bTextMove = false; + + if( !bMod1 && bMod2 ) + { + if( (nCode == awt::Key::UP) || (nCode == awt::Key::NUM8) ) + { + nAction = ACTION_GOTO_LEFT_CELL; + } + else if( (nCode == awt::Key::DOWN) || (nCode == awt::Key::NUM2) ) + { + nAction = ACTION_GOTO_RIGHT_CELL; + } + break; + } + + if( !bTextMove ) + { + OutlinerView* pOLV = mpView->GetTextEditOutlinerView(); + if( pOLV ) + { + RemoveSelection(); + // during text edit, check if we navigate out of the cell + ESelection aOldSelection = pOLV->GetSelection(); + pOLV->PostKeyEvent(rKEvt); + bTextMove = pOLV && ( aOldSelection.IsEqual(pOLV->GetSelection()) ); + if( !bTextMove ) + { + nAction = ACTION_NONE; + } + } + } + + if( mbCellSelectionMode || bTextMove ) + { + // no text edit, navigate in cells if selection active + switch( nCode ) + { + case awt::Key::LEFT: + case awt::Key::NUM4: + nAction = ACTION_GOTO_LEFT_CELL; + break; + case awt::Key::RIGHT: + case awt::Key::NUM6: + nAction = ACTION_GOTO_RIGHT_CELL; + break; + case awt::Key::DOWN: + case awt::Key::NUM2: + nAction = ACTION_GOTO_DOWN_CELL; + break; + case awt::Key::UP: + case awt::Key::NUM8: + nAction = ACTION_GOTO_UP_CELL; + break; + } + } + break; + } + case awt::Key::PAGEUP: + if( bMod2 ) + nAction = ACTION_GOTO_FIRST_ROW; + break; + + case awt::Key::PAGEDOWN: + if( bMod2 ) + nAction = ACTION_GOTO_LAST_ROW; + break; + } + return nAction; +} + +bool SvxTableController::executeAction( sal_uInt16 nAction, bool bSelect, Window* pWindow ) +{ + ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( !pTableObj ) + return false; + + switch( nAction ) + { + case ACTION_GOTO_FIRST_CELL: + { + gotoCell( pTableObj->getFirstCell(), bSelect, pWindow, nAction ); + break; + } + + case ACTION_GOTO_LEFT_CELL: + { + gotoCell( pTableObj->getLeftCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction ); + break; + } + + case ACTION_GOTO_RIGHT_CELL: + { + gotoCell( pTableObj->getRightCell( getSelectionEnd(), !bSelect ), bSelect, pWindow, nAction); + break; + } + + case ACTION_GOTO_LAST_CELL: + { + gotoCell( pTableObj->getLastCell(), bSelect, pWindow, nAction ); + break; + } + + case ACTION_GOTO_FIRST_COLUMN: + { + CellPos aPos( pTableObj->getFirstCell().mnCol, getSelectionEnd().mnRow ); + gotoCell( aPos, bSelect, pWindow, nAction ); + break; + } + + case ACTION_GOTO_LAST_COLUMN: + { + CellPos aPos( pTableObj->getLastCell().mnCol, getSelectionEnd().mnRow ); + gotoCell( aPos, bSelect, pWindow, nAction ); + break; + } + + case ACTION_GOTO_FIRST_ROW: + { + CellPos aPos( getSelectionEnd().mnCol, pTableObj->getFirstCell().mnRow ); + gotoCell( aPos, bSelect, pWindow, nAction ); + break; + } + + case ACTION_GOTO_UP_CELL: + { + gotoCell( pTableObj->getUpCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction ); + break; + } + + case ACTION_GOTO_DOWN_CELL: + { + gotoCell( pTableObj->getDownCell(getSelectionEnd(), !bSelect), bSelect, pWindow, nAction ); + break; + } + + case ACTION_GOTO_LAST_ROW: + { + CellPos aPos( getSelectionEnd().mnCol, pTableObj->getLastCell().mnRow ); + gotoCell( aPos, bSelect, pWindow, nAction ); + break; + } + + case ACTION_EDIT_CELL: + EditCell( getSelectionStart(), pWindow, 0, nAction ); + break; + + case ACTION_STOP_TEXT_EDIT: + StopTextEdit(); + break; + + case ACTION_REMOVE_SELECTION: + RemoveSelection(); + break; + + case ACTION_START_SELECTION: + StartSelection( getSelectionStart() ); + break; + + case ACTION_TAB: + { + if( bSelect ) + gotoCell( pTableObj->getPreviousCell( getSelectionEnd(), true ), false, pWindow, nAction ); + else + { + CellPos aSelectionEnd( getSelectionEnd() ); + CellPos aNextCell( pTableObj->getNextCell( aSelectionEnd, true ) ); + if( aSelectionEnd == aNextCell ) + { + onInsert( SID_TABLE_INSERT_ROW, 0 ); + aNextCell = pTableObj->getNextCell( aSelectionEnd, true ); + } + gotoCell( aNextCell, false, pWindow, nAction ); + } + break; + } + } + + return nAction != ACTION_HANDLED_BY_VIEW; +} + +// -------------------------------------------------------------------- + +void SvxTableController::gotoCell( const CellPos& rPos, bool bSelect, Window* pWindow, sal_uInt16 nAction ) +{ + if( mxTableObj.is() && static_cast<SdrTableObj*>(mxTableObj.get())->IsTextEditActive() ) + mpView->SdrEndTextEdit(sal_True); + + if( bSelect ) + { + maCursorLastPos = rPos; + if( mxTableObj.is() ) + static_cast< SdrTableObj* >( mxTableObj.get() )->setActiveCell( rPos ); + + if( !mbCellSelectionMode ) + { + setSelectedCells( maCursorFirstPos, rPos ); + } + else + { + UpdateSelection( rPos ); + } + } + else + { + RemoveSelection(); + EditCell( rPos, pWindow, 0, nAction ); + } +} + +// -------------------------------------------------------------------- + +const CellPos& SvxTableController::getSelectionStart() +{ + checkCell( maCursorFirstPos ); + return maCursorFirstPos; +} + +// -------------------------------------------------------------------- + +void SvxTableController::setSelectionStart( const CellPos& rPos ) +{ + maCursorFirstPos = rPos; +} + +// -------------------------------------------------------------------- + +const CellPos& SvxTableController::getSelectionEnd() +{ + checkCell( maCursorLastPos ); + return maCursorLastPos; +} + +// -------------------------------------------------------------------- + +Reference< XCellCursor > SvxTableController::getSelectionCursor() +{ + Reference< XCellCursor > xCursor; + + if( mxTable.is() ) + { + if( hasSelectedCells() ) + { + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + xCursor = mxTable->createCursorByRange( mxTable->getCellRangeByPosition( aStart.mnCol, aStart.mnRow, aEnd.mnCol, aEnd.mnRow ) ); + } + else + { + xCursor = mxTable->createCursor(); + } + } + + return xCursor; +} + +void SvxTableController::MergeRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) +{ + if( mxTable.is() ) try + { + Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( nFirstCol, nFirstRow,nLastCol, nLastRow ) ), UNO_QUERY_THROW ); + if( xRange->isMergeable() ) + { + const bool bUndo = mpModel && mpModel->IsUndoEnabled(); + if( bUndo ) + { + mpModel->BegUndo( ImpGetResStr(STR_TABLE_MERGE) ); + mpModel->AddUndo( mpModel->GetSdrUndoFactory().CreateUndoGeoObject(*mxTableObj.get()) ); + } + + xRange->merge(); + + if( bUndo ) + mpModel->EndUndo(); + } + } + catch( Exception& ) + { + DBG_ASSERT( false, "sdr::table::SvxTableController::MergeRange(), exception caught!" ); + } +} + + + +// -------------------------------------------------------------------- + +void SvxTableController::checkCell( CellPos& rPos ) +{ + if( mxTable.is() ) try + { + if( rPos.mnCol >= mxTable->getColumnCount() ) + rPos.mnCol = mxTable->getColumnCount()-1; + + if( rPos.mnRow >= mxTable->getRowCount() ) + rPos.mnRow = mxTable->getRowCount()-1; + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("sdr::table::SvxTableController::checkCell(), exception caught!" ); + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::findMergeOrigin( CellPos& rPos ) +{ + if( mxTable.is() ) try + { + Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ), UNO_QUERY_THROW ); + if( xCell.is() && xCell->isMerged() ) + { + ::findMergeOrigin( mxTable, rPos.mnCol, rPos.mnRow, rPos.mnCol, rPos.mnRow ); + } + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("sdr::table::SvxTableController::findMergeOrigin(), exception caught!" ); + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::EditCell( const CellPos& rPos, ::Window* pWindow, const awt::MouseEvent* pMouseEvent /*= 0*/, sal_uInt16 nAction /*= ACTION_NONE */ ) +{ + SdrPageView* pPV = mpView->GetSdrPageView(); + + ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( pTableObj && pTableObj->GetPage() == pPV->GetPage() ) + { + bool bEmptyOutliner = false; + + if(!pTableObj->GetOutlinerParaObject() && mpView->GetTextEditOutliner()) + { + ::Outliner* pOutl = mpView->GetTextEditOutliner(); + ULONG nParaAnz = pOutl->GetParagraphCount(); + Paragraph* p1stPara = pOutl->GetParagraph( 0 ); + + if(nParaAnz==1 && p1stPara) + { + // Bei nur einem Pararaph + if (pOutl->GetText(p1stPara).Len() == 0) + { + bEmptyOutliner = true; + } + } + } + + CellPos aPos( rPos ); + findMergeOrigin( aPos ); + + if( pTableObj != mpView->GetTextEditObject() || bEmptyOutliner || !pTableObj->IsTextEditActive( aPos ) ) + { + if( pTableObj->IsTextEditActive() ) + mpView->SdrEndTextEdit(sal_True); + + pTableObj->setActiveCell( aPos ); + + // create new outliner, owner will be the SdrObjEditView + SdrOutliner* pOutl = SdrMakeOutliner( OUTLINERMODE_OUTLINEOBJECT, mpModel ); + if( pTableObj->IsVerticalWriting() ) + pOutl->SetVertical( TRUE ); + + if(mpView->SdrBeginTextEdit(pTableObj, pPV, pWindow, sal_True, pOutl)) + { + maCursorLastPos = maCursorFirstPos = rPos; + + OutlinerView* pOLV = mpView->GetTextEditOutlinerView(); + + bool bNoSel = true; + + if( pMouseEvent ) + { + ::MouseEvent aMEvt( *pMouseEvent ); + + SdrViewEvent aVEvt; + SdrHitKind eHit = mpView->PickAnything(aMEvt, SDRMOUSEBUTTONDOWN, aVEvt); + + if (eHit == SDRHIT_TEXTEDIT) + { + // Text getroffen + pOLV->MouseButtonDown(aMEvt); + pOLV->MouseMove(aMEvt); + pOLV->MouseButtonUp(aMEvt); +// pOLV->MouseButtonDown(aMEvt); + bNoSel = false; + } + else + { + nAction = ACTION_GOTO_LEFT_CELL; + } + } + + if( bNoSel ) + { + // Move cursor to end of text + ESelection aNewSelection; + + const WritingMode eMode = pTableObj->GetWritingMode(); + if( ((nAction == ACTION_GOTO_LEFT_CELL) || (nAction == ACTION_GOTO_RIGHT_CELL)) && (eMode != WritingMode_TB_RL) ) + { + const bool bLast = ((nAction == ACTION_GOTO_LEFT_CELL) && (eMode == WritingMode_LR_TB)) || + ((nAction == ACTION_GOTO_RIGHT_CELL) && (eMode == WritingMode_RL_TB)); + + if( bLast ) + aNewSelection = ESelection(EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND, EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND); + } + pOLV->SetSelection(aNewSelection); + } + } + } + } +} + +// -------------------------------------------------------------------- + +bool SvxTableController::StopTextEdit() +{ + if(mpView->IsTextEdit()) + { + mpView->SdrEndTextEdit(); + mpView->SetCurrentObj(OBJ_TABLE); + mpView->SetEditMode(SDREDITMODE_EDIT); + return true; + } + else + { + return false; + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::DeleteTable() +{ + // +} + +// -------------------------------------------------------------------- + +void SvxTableController::getSelectedCells( CellPos& rFirst, CellPos& rLast ) +{ + if( mbCellSelectionMode ) + { + checkCell( maCursorFirstPos ); + checkCell( maCursorLastPos ); + + rFirst.mnCol = std::min( maCursorFirstPos.mnCol, maCursorLastPos.mnCol ); + rFirst.mnRow = std::min( maCursorFirstPos.mnRow, maCursorLastPos.mnRow ); + rLast.mnCol = std::max( maCursorFirstPos.mnCol, maCursorLastPos.mnCol ); + rLast.mnRow = std::max( maCursorFirstPos.mnRow, maCursorLastPos.mnRow ); + + bool bExt = false; + if( mxTable.is() ) do + { + bExt = false; + for( sal_Int32 nRow = rFirst.mnRow; nRow <= rLast.mnRow && !bExt; nRow++ ) + { + for( sal_Int32 nCol = rFirst.mnCol; nCol <= rLast.mnCol && !bExt; nCol++ ) + { + Reference< XMergeableCell > xCell( mxTable->getCellByPosition( nCol, nRow ), UNO_QUERY ); + if( !xCell.is() ) + continue; + + if( xCell->isMerged() ) + { + CellPos aPos( nCol, nRow ); + findMergeOrigin( aPos ); + if( (aPos.mnCol < rFirst.mnCol) || (aPos.mnRow < rFirst.mnRow) ) + { + rFirst.mnCol = std::min( rFirst.mnCol, aPos.mnCol ); + rFirst.mnRow = std::min( rFirst.mnRow, aPos.mnRow ); + bExt = true; + } + } + else + { + if( ((nCol + xCell->getColumnSpan() - 1) > rLast.mnCol) || (nRow + xCell->getRowSpan() - 1 ) > rLast.mnRow ) + { + rLast.mnCol = std::max( rLast.mnCol, nCol + xCell->getColumnSpan() - 1 ); + rLast.mnRow = std::max( rLast.mnRow, nRow + xCell->getRowSpan() - 1 ); + bExt = true; + } + } + } + } + } + while(bExt); + } + else if( mpView && mpView->IsTextEdit() ) + { + rFirst = getSelectionStart(); + findMergeOrigin( rFirst ); + rLast = rFirst; + + if( mxTable.is() ) + { + Reference< XMergeableCell > xCell( mxTable->getCellByPosition( rLast.mnCol, rLast.mnRow ), UNO_QUERY ); + if( xCell.is() ) + { + rLast.mnCol += xCell->getColumnSpan() - 1; + rLast.mnRow += xCell->getRowSpan() - 1; + } + } + } + else + { + rFirst.mnCol = 0; + rFirst.mnRow = 0; + if( mxTable.is() ) + { + rLast.mnRow = mxTable->getRowCount()-1; + rLast.mnCol = mxTable->getColumnCount()-1; + } + else + { + rLast.mnRow = 0; + rLast.mnCol = 0; + } + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::StartSelection( const CellPos& rPos ) +{ + StopTextEdit(); + mbCellSelectionMode = true; + maCursorLastPos = maCursorFirstPos = rPos; + mpView->MarkListHasChanged(); +} + +// -------------------------------------------------------------------- + +void SvxTableController::setSelectedCells( const CellPos& rStart, const CellPos& rEnd ) +{ + StopTextEdit(); + mbCellSelectionMode = true; + maCursorFirstPos = rStart; + UpdateSelection( rEnd ); +} + +// -------------------------------------------------------------------- + +void SvxTableController::UpdateSelection( const CellPos& rPos ) +{ + maCursorLastPos = rPos; + mpView->MarkListHasChanged(); +} + +// -------------------------------------------------------------------- + +void SvxTableController::clearSelection() +{ + RemoveSelection(); +} + +// -------------------------------------------------------------------- + +void SvxTableController::selectAll() +{ + if( mxTable.is() ) + { + CellPos aPos1, aPos2( mxTable->getColumnCount()-1, mxTable->getRowCount()-1 ); + if( (aPos2.mnCol >= 0) && (aPos2.mnRow >= 0) ) + { + setSelectedCells( aPos1, aPos2 ); + } + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::RemoveSelection() +{ + if( mbCellSelectionMode ) + { + mbCellSelectionMode = false; + mpView->MarkListHasChanged(); + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::onTableModified() +{ + if( mnUpdateEvent == 0 ) + mnUpdateEvent = Application::PostUserEvent( LINK( this, SvxTableController, UpdateHdl ) ); +} +// -------------------------------------------------------------------- + +void SvxTableController::updateSelectionOverlay() +{ + destroySelectionOverlay(); + if( mbCellSelectionMode ) + { + ::sdr::table::SdrTableObj* pTableObj = dynamic_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + if( pTableObj ) + { + sdr::overlay::OverlayObjectCell::RangeVector aRanges; + + Rectangle aRect; + CellPos aStart,aEnd; + getSelectedCells( aStart, aEnd ); + pTableObj->getCellBounds( aStart, aRect ); + + basegfx::B2DRange a2DRange( basegfx::B2DPoint(aRect.Left(), aRect.Top()) ); + a2DRange.expand( basegfx::B2DPoint(aRect.Right(), aRect.Bottom()) ); + + findMergeOrigin( aEnd ); + pTableObj->getCellBounds( aEnd, aRect ); + a2DRange.expand( basegfx::B2DPoint(aRect.Left(), aRect.Top()) ); + a2DRange.expand( basegfx::B2DPoint(aRect.Right(), aRect.Bottom()) ); + aRanges.push_back( a2DRange ); + + ::Color aHighlight( COL_BLUE ); + OutputDevice* pOutDev = mpView->GetFirstOutputDevice(); + if( pOutDev ) + aHighlight = pOutDev->GetSettings().GetStyleSettings().GetHighlightColor(); + + const sal_uInt32 nCount = mpView->PaintWindowCount(); + for( sal_uInt32 nIndex = 0; nIndex < nCount; nIndex++ ) + { + SdrPaintWindow* pPaintWindow = mpView->GetPaintWindow(nIndex); + if( pPaintWindow ) + { + ::sdr::overlay::OverlayManager* pOverlayManager = pPaintWindow->GetOverlayManager(); + if( pOverlayManager ) + { + // sdr::overlay::CellOverlayType eType = sdr::overlay::CELL_OVERLAY_INVERT; + sdr::overlay::CellOverlayType eType = sdr::overlay::CELL_OVERLAY_TRANSPARENT; + + sdr::overlay::OverlayObjectCell* pOverlay = new sdr::overlay::OverlayObjectCell( eType, aHighlight, aRanges ); + + pOverlayManager->add(*pOverlay); + mpSelectionOverlay = new ::sdr::overlay::OverlayObjectList; + mpSelectionOverlay->append(*pOverlay); + } + } + } + } + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::destroySelectionOverlay() +{ + if( mpSelectionOverlay ) + { + delete mpSelectionOverlay; + mpSelectionOverlay = 0; + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::MergeAttrFromSelectedCells(SfxItemSet& rAttr, bool bOnlyHardAttr) const +{ + if( mxTable.is() ) + { + CellPos aStart, aEnd; + const_cast<SvxTableController&>(*this).getSelectedCells( aStart, aEnd ); + + for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ ) + { + for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() && !xCell->isMerged() ) + { + const SfxItemSet& rSet = xCell->GetItemSet(); + SfxWhichIter aIter(rSet); + sal_uInt16 nWhich(aIter.FirstWhich()); + while(nWhich) + { + if(!bOnlyHardAttr) + { + if(SFX_ITEM_DONTCARE == rSet.GetItemState(nWhich, FALSE)) + rAttr.InvalidateItem(nWhich); + else + rAttr.MergeValue(rSet.Get(nWhich), TRUE); + } + else if(SFX_ITEM_SET == rSet.GetItemState(nWhich, FALSE)) + { + const SfxPoolItem& rItem = rSet.Get(nWhich); + rAttr.MergeValue(rItem, TRUE); + } + + nWhich = aIter.NextWhich(); + } + } + } + } + } + + if( mpView->IsTextEdit() ) + { + } +} + +// -------------------------------------------------------------------- + +const sal_uInt16 CELL_BEFORE = 0x0001; +const sal_uInt16 CELL_LEFT = 0x0002; +const sal_uInt16 CELL_RIGHT = 0x0004; +const sal_uInt16 CELL_AFTER = 0x0008; + +const sal_uInt16 CELL_UPPER = 0x0010; +const sal_uInt16 CELL_TOP = 0x0020; +const sal_uInt16 CELL_BOTTOM = 0x0040; +const sal_uInt16 CELL_LOWER = 0x0080; + +// -------------------------------------------------------------------- + +static void ImplSetLinePreserveColor( SvxBoxItem& rNewFrame, const SvxBorderLine* pNew, USHORT nLine ) +{ + if( pNew ) + { + const SvxBorderLine* pOld = rNewFrame.GetLine(nLine); + if( pOld ) + { + SvxBorderLine aNewLine( *pNew ); + aNewLine.SetColor( pOld->GetColor() ); + rNewFrame.SetLine( &aNewLine, nLine ); + return; + } + } + rNewFrame.SetLine( pNew, nLine ); +} + +// -------------------------------------------------------------------- + +static void ImplApplyBoxItem( sal_uInt16 nCellFlags, const SvxBoxItem* pBoxItem, const SvxBoxInfoItem* pBoxInfoItem, SvxBoxItem& rNewFrame ) +{ + if( (nCellFlags & (CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 ) + { + // current cell is outside the selection + + if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner + { + if( nCellFlags & CELL_UPPER ) + { + if( pBoxInfoItem->IsValid(VALID_TOP) ) + rNewFrame.SetLine(0, BOX_LINE_BOTTOM ); + } + else if( nCellFlags & CELL_LOWER ) + { + if( pBoxInfoItem->IsValid(VALID_BOTTOM) ) + rNewFrame.SetLine( 0, BOX_LINE_TOP ); + } + } + else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner + { + if( nCellFlags & CELL_BEFORE ) + { + if( pBoxInfoItem->IsValid(VALID_LEFT) ) + rNewFrame.SetLine( 0, BOX_LINE_RIGHT ); + } + else if( nCellFlags & CELL_AFTER ) + { + if( pBoxInfoItem->IsValid(VALID_RIGHT) ) + rNewFrame.SetLine( 0, BOX_LINE_LEFT ); + } + } + } + else + { + // current cell is inside the selection + + if( (nCellFlags & CELL_LEFT) ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) ) + rNewFrame.SetLine( (nCellFlags & CELL_LEFT) ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), BOX_LINE_LEFT ); + + if( (nCellFlags & CELL_RIGHT) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) ) + rNewFrame.SetLine( (nCellFlags & CELL_RIGHT) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), BOX_LINE_RIGHT ); + + if( (nCellFlags & CELL_TOP) ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) ) + rNewFrame.SetLine( (nCellFlags & CELL_TOP) ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(), BOX_LINE_TOP ); + + if( (nCellFlags & CELL_BOTTOM) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) ) + rNewFrame.SetLine( (nCellFlags & CELL_BOTTOM) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(), BOX_LINE_BOTTOM ); + + // apply distance to borders + if( pBoxInfoItem->IsValid( VALID_DISTANCE ) ) + for( USHORT nLine = 0; nLine < 4; ++nLine ) + rNewFrame.SetDistance( pBoxItem->GetDistance( nLine ), nLine ); + } +} + +// -------------------------------------------------------------------- + +static void ImplSetLineColor( SvxBoxItem& rNewFrame, USHORT nLine, const Color& rColor ) +{ + const SvxBorderLine* pSourceLine = rNewFrame.GetLine( nLine ); + if( pSourceLine ) + { + SvxBorderLine aLine( *pSourceLine ); + aLine.SetColor( rColor ); + rNewFrame.SetLine( &aLine, nLine ); + } +} + +// -------------------------------------------------------------------- + +static void ImplApplyLineColorItem( sal_uInt16 nCellFlags, const SvxColorItem* pLineColorItem, SvxBoxItem& rNewFrame ) +{ + const Color aColor( pLineColorItem->GetValue() ); + + if( (nCellFlags & (CELL_LOWER|CELL_BEFORE|CELL_AFTER)) == 0 ) + ImplSetLineColor( rNewFrame, BOX_LINE_BOTTOM, aColor ); + + if( (nCellFlags & (CELL_UPPER|CELL_BEFORE|CELL_AFTER)) == 0 ) + ImplSetLineColor( rNewFrame, BOX_LINE_TOP, aColor ); + + if( (nCellFlags & (CELL_UPPER|CELL_LOWER|CELL_AFTER)) == 0 ) + ImplSetLineColor( rNewFrame, BOX_LINE_RIGHT, aColor ); + + if( (nCellFlags & (CELL_UPPER|CELL_LOWER|CELL_BEFORE)) == 0 ) + ImplSetLineColor( rNewFrame, BOX_LINE_LEFT, aColor ); +} + +// -------------------------------------------------------------------- + +static void ImplApplyBorderLineItem( sal_uInt16 nCellFlags, const SvxBorderLine* pBorderLineItem, SvxBoxItem& rNewFrame ) +{ + if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER|CELL_UPPER|CELL_LOWER)) != 0 ) + { + if( (nCellFlags & ( CELL_BEFORE|CELL_AFTER)) == 0 ) // check if its not nw or ne corner + { + if( nCellFlags & CELL_UPPER ) + { + if( rNewFrame.GetBottom() ) + ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_BOTTOM ); + } + else if( nCellFlags & CELL_LOWER ) + { + if( rNewFrame.GetTop() ) + ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_TOP ); + } + } + else if( (nCellFlags & ( CELL_UPPER|CELL_LOWER)) == 0 ) // check if its not sw or se corner + { + if( nCellFlags & CELL_BEFORE ) + { + if( rNewFrame.GetRight() ) + ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_RIGHT ); + } + else if( nCellFlags & CELL_AFTER ) + { + if( rNewFrame.GetLeft() ) + ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_LEFT ); + } + } + } + else + { + if( rNewFrame.GetBottom() ) + ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_BOTTOM ); + if( rNewFrame.GetTop() ) + ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_TOP ); + if( rNewFrame.GetRight() ) + ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_RIGHT ); + if( rNewFrame.GetLeft() ) + ImplSetLinePreserveColor( rNewFrame, pBorderLineItem, BOX_LINE_LEFT ); + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::ApplyBorderAttr( const SfxItemSet& rAttr ) +{ + if( mxTable.is() ) + { + const sal_Int32 nRowCount = mxTable->getRowCount(); + const sal_Int32 nColCount = mxTable->getColumnCount(); + if( nRowCount && nColCount ) + { + const SvxBoxItem* pBoxItem = 0; + if(SFX_ITEM_SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER, FALSE) ) + pBoxItem = dynamic_cast< const SvxBoxItem* >( &rAttr.Get( SDRATTR_TABLE_BORDER ) ); + + const SvxBoxInfoItem* pBoxInfoItem = 0; + if(SFX_ITEM_SET == rAttr.GetItemState(SDRATTR_TABLE_BORDER_INNER, FALSE) ) + pBoxInfoItem = dynamic_cast< const SvxBoxInfoItem* >( &rAttr.Get( SDRATTR_TABLE_BORDER_INNER ) ); + + const SvxColorItem* pLineColorItem = 0; + if(SFX_ITEM_SET == rAttr.GetItemState(SID_FRAME_LINECOLOR, FALSE) ) + pLineColorItem = dynamic_cast< const SvxColorItem* >( &rAttr.Get( SID_FRAME_LINECOLOR ) ); + + const SvxBorderLine* pBorderLineItem = 0; + if(SFX_ITEM_SET == rAttr.GetItemState(SID_FRAME_LINESTYLE, FALSE) ) + pBorderLineItem = ((const SvxLineItem&)rAttr.Get( SID_FRAME_LINESTYLE )).GetLine(); + + if( pBoxInfoItem && !pBoxItem ) + { + const static SvxBoxItem gaEmptyBoxItem( SDRATTR_TABLE_BORDER ); + pBoxItem = &gaEmptyBoxItem; + } + else if( pBoxItem && !pBoxInfoItem ) + { + const static SvxBoxInfoItem gaEmptyBoxInfoItem( SDRATTR_TABLE_BORDER_INNER ); + pBoxInfoItem = &gaEmptyBoxInfoItem; + } + + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + const sal_Int32 nLastRow = std::min( aEnd.mnRow + 2, nRowCount ); + const sal_Int32 nLastCol = std::min( aEnd.mnCol + 2, nColCount ); + + for( sal_Int32 nRow = std::max( aStart.mnRow - 1, (sal_Int32)0 ); nRow < nLastRow; nRow++ ) + { + sal_uInt16 nRowFlags = 0; + nRowFlags |= (nRow == aStart.mnRow) ? CELL_TOP : 0; + nRowFlags |= (nRow == aEnd.mnRow) ? CELL_BOTTOM : 0; + nRowFlags |= (nRow < aStart.mnRow) ? CELL_UPPER : 0; + nRowFlags |= (nRow > aEnd.mnRow) ? CELL_LOWER : 0; + + for( sal_Int32 nCol = std::max( aStart.mnCol - 1, (sal_Int32)0 ); nCol < nLastCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( !xCell.is() ) + continue; + + const SfxItemSet& rSet = xCell->GetItemSet(); + const SvxBoxItem* pOldOuter = (const SvxBoxItem*) &rSet.Get( SDRATTR_TABLE_BORDER ); + + SvxBoxItem aNewFrame( *pOldOuter ); + + sal_uInt16 nCellFlags = nRowFlags; + nCellFlags |= (nCol == aStart.mnCol) ? CELL_LEFT : 0; + nCellFlags |= (nCol == aEnd.mnCol) ? CELL_RIGHT : 0; + nCellFlags |= (nCol < aStart.mnCol) ? CELL_BEFORE : 0; + nCellFlags |= (nCol > aEnd.mnCol) ? CELL_AFTER : 0; + + if( pBoxItem && pBoxInfoItem ) + ImplApplyBoxItem( nCellFlags, pBoxItem, pBoxInfoItem, aNewFrame ); + + if( pLineColorItem ) + ImplApplyLineColorItem( nCellFlags, pLineColorItem, aNewFrame ); + + if( pBorderLineItem ) + ImplApplyBorderLineItem( nCellFlags, pBorderLineItem, aNewFrame ); + + if (aNewFrame != *pOldOuter) + { + SfxItemSet aAttr(*rSet.GetPool(), rSet.GetRanges()); + aAttr.Put(aNewFrame); + xCell->SetMergedItemSetAndBroadcast( aAttr, false ); + } + } + } + } + } +} + +// -------------------------------------------------------------------- + +void SvxTableController::UpdateTableShape() +{ + SdrObject* pTableObj = mxTableObj.get(); + if( pTableObj ) + { + pTableObj->ActionChanged(); + pTableObj->BroadcastObjectChange(); + } + updateSelectionOverlay(); +} + + +// -------------------------------------------------------------------- + +void SvxTableController::SetAttrToSelectedCells(const SfxItemSet& rAttr, bool bReplaceAll) +{ + if( mxTable.is() ) + { + const bool bUndo = mpModel && mpModel->IsUndoEnabled(); + + if( bUndo ) + mpModel->BegUndo( ImpGetResStr(STR_TABLE_NUMFORMAT) ); + + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + SfxItemSet aAttr(*rAttr.GetPool(), rAttr.GetRanges()); + aAttr.Put(rAttr, TRUE); + + const bool bFrame = (rAttr.GetItemState( SDRATTR_TABLE_BORDER ) == SFX_ITEM_SET) || (rAttr.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SFX_ITEM_SET); + + if( bFrame ) + { + aAttr.ClearItem( SDRATTR_TABLE_BORDER ); + aAttr.ClearItem( SDRATTR_TABLE_BORDER_INNER ); + } + + for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ ) + { + for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() ) + { + if( bUndo ) + xCell->AddUndo(); + xCell->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll); + } + } + } + + if( bFrame ) + { + ApplyBorderAttr( rAttr ); + } + + UpdateTableShape(); + + if( bUndo ) + mpModel->EndUndo(); + + } +} + +// -------------------------------------------------------------------- + +bool SvxTableController::GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const +{ + if( mxTableObj.is() && hasSelectedCells() ) + { + MergeAttrFromSelectedCells( rTargetSet, bOnlyHardAttr ); + + if( mpView->IsTextEdit() ) + { + if( mxTableObj->GetOutlinerParaObject() ) + rTargetSet.Put( SvxScriptTypeItem( mxTableObj->GetOutlinerParaObject()->GetTextObject().GetScriptType() ) ); + + OutlinerView* pTextEditOutlinerView = mpView->GetTextEditOutlinerView(); + if(pTextEditOutlinerView) + { + // FALSE= InvalidItems nicht al Default, sondern als "Loecher" betrachten + rTargetSet.Put(pTextEditOutlinerView->GetAttribs(), FALSE); + rTargetSet.Put( SvxScriptTypeItem( pTextEditOutlinerView->GetSelectedScriptType() ), FALSE ); + } + } + + return true; + } + else + { + return false; + } +} + +// -------------------------------------------------------------------- + +bool SvxTableController::SetAttributes(const SfxItemSet& rSet, bool bReplaceAll) +{ + if( mbCellSelectionMode || mpView->IsTextEdit() ) + { + SetAttrToSelectedCells( rSet, bReplaceAll ); + return true; + } + return false; +} + +// -------------------------------------------------------------------- + +bool SvxTableController::GetMarkedObjModel( SdrPage* pNewPage ) +{ + if( mxTableObj.is() && mbCellSelectionMode && pNewPage ) try + { + ::sdr::table::SdrTableObj& rTableObj = *static_cast< ::sdr::table::SdrTableObj* >( mxTableObj.get() ); + + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + SdrTableObj* pNewTableObj = rTableObj.CloneRange( aStart, aEnd ); + + pNewTableObj->SetPage( pNewPage ); + pNewTableObj->SetModel( pNewPage->GetModel() ); + + SdrInsertReason aReason(SDRREASON_VIEWCALL); + pNewPage->InsertObject(pNewTableObj,CONTAINER_APPEND,&aReason); + + return true; + } + catch( Exception& ) + { + DBG_ERROR( "svx::SvxTableController::GetMarkedObjModel(), exception caught!" ); + } + return false; +} + +// -------------------------------------------------------------------- + +bool SvxTableController::PasteObjModel( const SdrModel& rModel ) +{ + if( mxTableObj.is() && mpView && (rModel.GetPageCount() >= 1) ) + { + const SdrPage* pPastePage = rModel.GetPage(0); + if( pPastePage && pPastePage->GetObjCount() == 1 ) + { + SdrTableObj* pPasteTableObj = dynamic_cast< SdrTableObj* >( pPastePage->GetObj(0) ); + if( pPasteTableObj ) + { + return PasteObject( pPasteTableObj ); + } + } + } + + return false; +} + +// -------------------------------------------------------------------- + +bool SvxTableController::PasteObject( SdrTableObj* pPasteTableObj ) +{ + if( !pPasteTableObj ) + return false; + + Reference< XTable > xPasteTable( pPasteTableObj->getTable() ); + if( !xPasteTable.is() ) + return false; + + if( !mxTable.is() ) + return false; + + sal_Int32 nPasteColumns = xPasteTable->getColumnCount(); + sal_Int32 nPasteRows = xPasteTable->getRowCount(); + + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + if( mpView->IsTextEdit() ) + mpView->SdrEndTextEdit(sal_True); + + sal_Int32 nColumns = mxTable->getColumnCount(); + sal_Int32 nRows = mxTable->getRowCount(); + + const sal_Int32 nMissing = nPasteRows - ( nRows - aStart.mnRow ); + if( nMissing > 0 ) + { + Reference< XTableRows > xRows( mxTable->getRows() ); + xRows->insertByIndex( nRows, nMissing ); + nRows = mxTable->getRowCount(); + } + + nPasteRows = std::min( nPasteRows, nRows - aStart.mnRow ); + nPasteColumns = std::min( nPasteColumns, nColumns - aStart.mnCol ); + + // copy cell contents + for( sal_Int32 nRow = 0; nRow < nPasteRows; ++nRow ) + { + for( sal_Int32 nCol = 0; nCol < nPasteColumns; ++nCol ) + { + CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( aStart.mnCol + nCol, aStart.mnRow + nRow ).get() ) ); + if( xTargetCell.is() && !xTargetCell->isMerged() ) + { + xTargetCell->AddUndo(); + xTargetCell->cloneFrom( dynamic_cast< Cell* >( xPasteTable->getCellByPosition( nCol, nRow ).get() ) ); + nCol += xTargetCell->getColumnSpan() - 1; + } + } + } + + UpdateTableShape(); + + return true; +} + +bool SvxTableController::TakeFormatPaintBrush( boost::shared_ptr< SfxItemSet >& /*rFormatSet*/ ) +{ + // SdrView::TakeFormatPaintBrush() is enough + return false; +} + +bool SvxTableController::ApplyFormatPaintBrush( SfxItemSet& rFormatSet, bool bNoCharacterFormats, bool bNoParagraphFormats ) +{ + if( mbCellSelectionMode ) + { + SdrTextObj* pTableObj = dynamic_cast<SdrTextObj*>( mxTableObj.get() ); + if( !pTableObj ) + return false; + + const bool bUndo = mpModel && mpModel->IsUndoEnabled(); + + if( bUndo ) + mpModel->BegUndo( ImpGetResStr(STR_TABLE_NUMFORMAT) ); + + CellPos aStart, aEnd; + getSelectedCells( aStart, aEnd ); + + SfxItemSet aAttr(*rFormatSet.GetPool(), rFormatSet.GetRanges()); + aAttr.Put(rFormatSet, TRUE); + + const bool bFrame = (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER ) == SFX_ITEM_SET) || (rFormatSet.GetItemState( SDRATTR_TABLE_BORDER_INNER ) == SFX_ITEM_SET); + + if( bFrame ) + { + aAttr.ClearItem( SDRATTR_TABLE_BORDER ); + aAttr.ClearItem( SDRATTR_TABLE_BORDER_INNER ); + } + + const USHORT* pRanges = rFormatSet.GetRanges(); + bool bTextOnly = true; + + while( *pRanges ) + { + if( (*pRanges != EE_PARA_START) && (*pRanges != EE_CHAR_START) ) + { + bTextOnly = true; + break; + } + pRanges += 2; + } + + const bool bReplaceAll = false; + for( sal_Int32 nRow = aStart.mnRow; nRow <= aEnd.mnRow; nRow++ ) + { + for( sal_Int32 nCol = aStart.mnCol; nCol <= aEnd.mnCol; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() ) + { + if( bUndo ) + xCell->AddUndo(); + if( !bTextOnly ) + xCell->SetMergedItemSetAndBroadcast(aAttr, bReplaceAll); + + SdrText* pText = static_cast< SdrText* >( xCell.get() ); + mpView->ApplyFormatPaintBrushToText( rFormatSet, *pTableObj, pText, bNoCharacterFormats, bNoParagraphFormats ); + } + } + } + + if( bFrame ) + { + ApplyBorderAttr( rFormatSet ); + } + + UpdateTableShape(); + + if( bUndo ) + mpModel->EndUndo(); + + return true; + + } + return false; +} + + +// -------------------------------------------------------------------- + +IMPL_LINK( SvxTableController, UpdateHdl, void *, EMPTYARG ) +{ + mnUpdateEvent = 0; + + if( mbCellSelectionMode ) + { + CellPos aStart( maCursorFirstPos ); + CellPos aEnd( maCursorLastPos ); + checkCell(aStart); + checkCell(aEnd); + if( aStart != maCursorFirstPos || aEnd != maCursorLastPos ) + { + setSelectedCells( aStart, aEnd ); + } + } + updateSelectionOverlay(); + + return 0; +} + +} } diff --git a/svx/source/table/tablecontroller.hxx b/svx/source/table/tablecontroller.hxx new file mode 100644 index 000000000000..8ced09bc587f --- /dev/null +++ b/svx/source/table/tablecontroller.hxx @@ -0,0 +1,170 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLECONTROLLER_HXX_ +#define _SVX_TABLECONTROLLER_HXX_ + +#include <com/sun/star/util/XModifyListener.hpp> +#include <com/sun/star/table/XTable.hpp> +#include <rtl/ref.hxx> + +#include <svx/sdr/overlay/overlayobjectlist.hxx> +#include <svx/selectioncontroller.hxx> +#include <svx/svdotable.hxx> +#include <svx/svdview.hxx> +#include <tablemodel.hxx> + +class SdrObjEditView; +class SdrObject; +class SfxItemSet; + +namespace sdr { namespace table { + +const sal_Int16 SELTYPE_NONE = 0; +const sal_Int16 SELTYPE_MOUSE = 1; +const sal_Int16 SELTYPE_KEYS = 2; + +class SVX_DLLPUBLIC SvxTableController: public sdr::SelectionController +{ +public: + SVX_DLLPRIVATE SvxTableController( SdrObjEditView* pView, const SdrObject* pObj ); + SVX_DLLPRIVATE virtual ~SvxTableController(); + + // from sdr::SelectionController + SVX_DLLPRIVATE virtual bool onKeyInput(const KeyEvent& rKEvt, Window* pWin); + SVX_DLLPRIVATE virtual bool onMouseButtonDown(const MouseEvent& rMEvt, Window* pWin); + SVX_DLLPRIVATE virtual bool onMouseButtonUp(const MouseEvent& rMEvt, Window* pWin); + SVX_DLLPRIVATE virtual bool onMouseMove(const MouseEvent& rMEvt, Window* pWin); + + SVX_DLLPRIVATE virtual bool DeleteMarked(); + + SVX_DLLPRIVATE virtual void onSelectionHasChanged(); + + SVX_DLLPRIVATE virtual void GetState( SfxItemSet& rSet ); + SVX_DLLPRIVATE virtual void Execute( SfxRequest& rReq ); + + SVX_DLLPRIVATE virtual bool GetStyleSheet( SfxStyleSheet* &rpStyleSheet ) const; + SVX_DLLPRIVATE virtual bool SetStyleSheet( SfxStyleSheet* pStyleSheet, bool bDontRemoveHardAttr ); + + SVX_DLLPRIVATE virtual bool TakeFormatPaintBrush( boost::shared_ptr< SfxItemSet >& rFormatSet ); + SVX_DLLPRIVATE virtual bool ApplyFormatPaintBrush( SfxItemSet& rFormatSet, bool bNoCharacterFormats, bool bNoParagraphFormats ); + + // slots + SVX_DLLPRIVATE void onInsert( sal_uInt16 nSId, const SfxItemSet* pArgs = 0 ); + SVX_DLLPRIVATE void onDelete( sal_uInt16 nSId ); + SVX_DLLPRIVATE void onSelect( sal_uInt16 nSId ); + SVX_DLLPRIVATE void onFormatTable( SfxRequest& rReq ); + SVX_DLLPRIVATE void MergeMarkedCells(); + SVX_DLLPRIVATE void SplitMarkedCells(); + SVX_DLLPRIVATE void DistributeColumns(); + SVX_DLLPRIVATE void DistributeRows(); + SVX_DLLPRIVATE void SetVertical( sal_uInt16 nSId ); + + SVX_DLLPRIVATE static rtl::Reference< sdr::SelectionController > create( SdrObjEditView* pView, const SdrObject* pObj, const rtl::Reference< sdr::SelectionController >& xRefController ); + + SVX_DLLPRIVATE void MergeAttrFromSelectedCells(SfxItemSet& rAttr, bool bOnlyHardAttr) const; + SVX_DLLPRIVATE void SetAttrToSelectedCells(const SfxItemSet& rAttr, bool bReplaceAll); + + SVX_DLLPRIVATE virtual bool GetAttributes(SfxItemSet& rTargetSet, bool bOnlyHardAttr) const; + SVX_DLLPRIVATE virtual bool SetAttributes(const SfxItemSet& rSet, bool bReplaceAll); + + SVX_DLLPRIVATE virtual bool GetMarkedObjModel( SdrPage* pNewPage ); + SVX_DLLPRIVATE virtual bool PasteObjModel( const SdrModel& rModel ); + + SVX_DLLPRIVATE bool hasSelectedCells() const { return mbCellSelectionMode || mpView->IsTextEdit(); } + + void getSelectedCells( CellPos& rFirstPos, CellPos& rLastPos ); + void setSelectedCells( const CellPos& rFirstPos, const CellPos& rLastPos ); + void clearSelection(); + void selectAll(); + + SVX_DLLPRIVATE void onTableModified(); + +private: + SvxTableController(SvxTableController &); // not defined + void operator =(SvxTableController &); // not defined + + // internals + SVX_DLLPRIVATE void ApplyBorderAttr( const SfxItemSet& rAttr ); + SVX_DLLPRIVATE void UpdateTableShape(); + + SVX_DLLPRIVATE void SetTableStyle( const SfxItemSet* pArgs ); + SVX_DLLPRIVATE void SetTableStyleSettings( const SfxItemSet* pArgs ); + + SVX_DLLPRIVATE bool PasteObject( SdrTableObj* pPasteTableObj ); + + SVX_DLLPRIVATE bool checkTableObject(); + SVX_DLLPRIVATE bool updateTableObject(); + SVX_DLLPRIVATE const CellPos& getSelectionStart(); + SVX_DLLPRIVATE void setSelectionStart( const CellPos& rPos ); + SVX_DLLPRIVATE const CellPos& getSelectionEnd(); + SVX_DLLPRIVATE ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellCursor > getSelectionCursor(); + SVX_DLLPRIVATE void checkCell( CellPos& rPos ); + + SVX_DLLPRIVATE void MergeRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ); + + SVX_DLLPRIVATE void EditCell( const CellPos& rPos, ::Window* pWindow, const ::com::sun::star::awt::MouseEvent* pMouseEvent = 0, sal_uInt16 nAction = 0 ); + SVX_DLLPRIVATE bool StopTextEdit(); + + SVX_DLLPRIVATE void DeleteTable(); + + SVX_DLLPRIVATE sal_uInt16 getKeyboardAction( const KeyEvent& rKEvt, Window* pWindow ); + SVX_DLLPRIVATE bool executeAction( sal_uInt16 nAction, bool bSelect, Window* pWindow ); + SVX_DLLPRIVATE void gotoCell( const CellPos& rCell, bool bSelect, Window* pWindow, sal_uInt16 nAction = 0 ); + + SVX_DLLPRIVATE void StartSelection( const CellPos& rPos ); + SVX_DLLPRIVATE void UpdateSelection( const CellPos& rPos ); + SVX_DLLPRIVATE void RemoveSelection(); + SVX_DLLPRIVATE void updateSelectionOverlay(); + SVX_DLLPRIVATE void destroySelectionOverlay(); + + SVX_DLLPRIVATE void findMergeOrigin( CellPos& rPos ); + + DECL_LINK( UpdateHdl, void * ); + + TableModelRef mxTable; + + CellPos maCursorFirstPos; + CellPos maCursorLastPos; + bool mbCellSelectionMode; + CellPos maMouseDownPos; + bool mbLeftButtonDown; + ::sdr::overlay::OverlayObjectList* mpSelectionOverlay; + + SdrView* mpView; + SdrObjectWeakRef mxTableObj; + SdrModel* mpModel; + + ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener > mxModifyListener; + + ULONG mnUpdateEvent; +}; + +} } + +#endif // _SVX_TABLECONTROLLER_HXX_ + diff --git a/svx/source/table/tabledesign.cxx b/svx/source/table/tabledesign.cxx new file mode 100644 index 000000000000..e952425e5c30 --- /dev/null +++ b/svx/source/table/tabledesign.cxx @@ -0,0 +1,808 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/util/XModifyBroadcaster.hpp> +#include <com/sun/star/util/XModifyListener.hpp> +#include <comphelper/serviceinfohelper.hxx> + +#include <osl/mutex.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase6.hxx> +#include <cppuhelper/implbase7.hxx> +#include <cppuhelper/interfacecontainer.h> + +#include "svx/unoprov.hxx" +#include "svx/sdr/table/tabledesign.hxx" +#include "svx/dialmgr.hxx" +#include "svx/dialogs.hrc" + +#include "celltypes.hxx" + +#include <vector> +#include <map> + +#include <boost/bind.hpp> + +// ----------------------------------------------------------------------------- + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::container; + +using ::rtl::OUString; +using ::vos::OGuard; +using ::osl::MutexGuard; +using ::osl::ClearableMutexGuard; +using ::cppu::OInterfaceContainerHelper; + +namespace sdr { namespace table { + +typedef std::map< OUString, sal_Int32 > CellStyleNameMap; + +typedef ::cppu::WeakComponentImplHelper6< XStyle, XNameReplace, XServiceInfo, XIndexAccess, XModifyBroadcaster, XModifyListener > TableDesignStyleBase; + +class TableDesignStyle : private ::cppu::BaseMutex, public TableDesignStyleBase +{ +public: + TableDesignStyle(); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() throw(RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException); + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw(RuntimeException); + + // XStyle + virtual ::sal_Bool SAL_CALL isUserDefined() throw (RuntimeException); + virtual ::sal_Bool SAL_CALL isInUse() throw (RuntimeException); + virtual OUString SAL_CALL getParentStyle() throw (RuntimeException); + virtual void SAL_CALL setParentStyle( const OUString& aParentStyle ) throw (NoSuchElementException, RuntimeException); + + // XNamed + virtual OUString SAL_CALL getName() throw (RuntimeException); + virtual void SAL_CALL setName( const OUString& aName ) throw (RuntimeException); + + // XNameAccess + virtual Any SAL_CALL getByName( const OUString& aName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException); + virtual Sequence< OUString > SAL_CALL getElementNames() throw(RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) throw(RuntimeException); + + // XElementAccess + virtual ::com::sun::star::uno::Type SAL_CALL getElementType() throw(RuntimeException); + virtual sal_Bool SAL_CALL hasElements() throw(RuntimeException); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() throw(RuntimeException) ; + virtual Any SAL_CALL getByIndex( sal_Int32 Index ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException); + + // XNameReplace + virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException); + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( const Reference< XModifyListener >& aListener ) throw (RuntimeException); + virtual void SAL_CALL removeModifyListener( const Reference< XModifyListener >& aListener ) throw (RuntimeException); + + // XModifyListener + virtual void SAL_CALL modified( const ::com::sun::star::lang::EventObject& aEvent ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL disposing( const ::com::sun::star::lang::EventObject& Source ) throw (::com::sun::star::uno::RuntimeException); + + void notifyModifyListener(); + + // this function is called upon disposing the component + virtual void SAL_CALL disposing(); + + static const CellStyleNameMap& getCellStyleNameMap(); + + OUString msName; + Reference< XStyle > maCellStyles[style_count]; +}; + +typedef std::vector< Reference< XStyle > > TableDesignStyleVector; + +class TableDesignFamily : public ::cppu::WeakImplHelper7< XNameContainer, XNamed, XIndexAccess, XSingleServiceFactory, XServiceInfo, XComponent, XPropertySet > +{ +public: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() throw(RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw(RuntimeException); + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw(RuntimeException); + + // XNamed + virtual OUString SAL_CALL getName( ) throw (RuntimeException); + virtual void SAL_CALL setName( const OUString& aName ) throw (RuntimeException); + + // XNameAccess + virtual Any SAL_CALL getByName( const OUString& aName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException); + virtual Sequence< OUString > SAL_CALL getElementNames() throw(RuntimeException); + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) throw(RuntimeException); + + // XElementAccess + virtual Type SAL_CALL getElementType() throw(RuntimeException); + virtual sal_Bool SAL_CALL hasElements() throw(RuntimeException); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount() throw(RuntimeException) ; + virtual Any SAL_CALL getByIndex( sal_Int32 Index ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException); + + // XNameContainer + virtual void SAL_CALL insertByName( const OUString& aName, const Any& aElement ) throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException); + virtual void SAL_CALL removeByName( const OUString& Name ) throw(NoSuchElementException, WrappedTargetException, RuntimeException); + + // XNameReplace + virtual void SAL_CALL replaceByName( const OUString& aName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException); + + // XSingleServiceFactory + virtual Reference< XInterface > SAL_CALL createInstance( ) throw(Exception, RuntimeException); + virtual Reference< XInterface > SAL_CALL createInstanceWithArguments( const Sequence< Any >& aArguments ) throw(Exception, RuntimeException); + + // XComponent + virtual void SAL_CALL dispose( ) throw (RuntimeException); + virtual void SAL_CALL addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException); + virtual void SAL_CALL removeEventListener( const Reference< XEventListener >& aListener ) throw (RuntimeException); + + // XPropertySet + virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() throw (RuntimeException); + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException); + virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference<XPropertyChangeListener>& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException); + virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener>& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName,const Reference<XVetoableChangeListener>&aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException); + + TableDesignStyleVector maDesigns; +}; + +//------------------------------------------------------------------------ +// TableDesignStyle +//------------------------------------------------------------------------ + +TableDesignStyle::TableDesignStyle() +: TableDesignStyleBase(m_aMutex) +{ +} + +const CellStyleNameMap& TableDesignStyle::getCellStyleNameMap() +{ + static CellStyleNameMap aMap; + if( aMap.empty() ) + { + CellStyleNameMap aNewMap; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "first-row" ) ) ] = first_row_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "last-row" ) ) ] = last_row_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "first-column" ) ) ] = first_column_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "last-column" ) ) ] = last_column_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "body" ) ) ] = body_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "even-rows" ) ) ] = even_rows_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "odd-rows" ) ) ] = odd_rows_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "even-columns" ) ) ] = even_columns_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "odd-columns" ) ) ] = odd_columns_style; + aNewMap[ OUString( RTL_CONSTASCII_USTRINGPARAM( "background" ) ) ] = background_style; + aMap.swap( aNewMap ); + } + + return aMap; +} + +// ---------------------------------------------------------- +// XServiceInfo +// ---------------------------------------------------------- + +OUString SAL_CALL TableDesignStyle::getImplementationName() throw(RuntimeException) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM("TableDesignStyle") ); +} + +// ---------------------------------------------------------- + +sal_Bool SAL_CALL TableDesignStyle::supportsService( const OUString& ServiceName ) throw(RuntimeException) +{ + return comphelper::ServiceInfoHelper::supportsService( ServiceName, getSupportedServiceNames() ); +} + +// ---------------------------------------------------------- + +Sequence< OUString > SAL_CALL TableDesignStyle::getSupportedServiceNames() throw(RuntimeException) +{ + OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.style.Style") ); + Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +// ---------------------------------------------------------- +// XStyle +// ---------------------------------------------------------- + +sal_Bool SAL_CALL TableDesignStyle::isUserDefined() throw (RuntimeException) +{ + return sal_False; +} + +// ---------------------------------------------------------- + +sal_Bool SAL_CALL TableDesignStyle::isInUse() throw (RuntimeException) +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + OInterfaceContainerHelper * pContainer = rBHelper.getContainer( XModifyListener::static_type() ); + if( pContainer ) + { + Sequence< Reference< XInterface > > aListener( pContainer->getElements() ); + aGuard.clear(); + + sal_Int32 nIndex = aListener.getLength(); + while( --nIndex >= 0 ) + { + TableDesignUser* pUser = dynamic_cast< TableDesignUser* >( aListener[nIndex].get() ); + if( pUser && pUser->isInUse() ) + return sal_True; + } + } + return sal_False; +} + +// ---------------------------------------------------------- + +OUString SAL_CALL TableDesignStyle::getParentStyle() throw (RuntimeException) +{ + return OUString(); +} + +// ---------------------------------------------------------- + +void SAL_CALL TableDesignStyle::setParentStyle( const OUString& ) throw (NoSuchElementException, RuntimeException) +{ +} + +// ---------------------------------------------------------- +// XNamed +// ---------------------------------------------------------- + +OUString SAL_CALL TableDesignStyle::getName() throw (RuntimeException) +{ + return msName; +} + +// ---------------------------------------------------------- + +void SAL_CALL TableDesignStyle::setName( const OUString& rName ) throw (RuntimeException) +{ + msName = rName; +} + +// ---------------------------------------------------------- +// XNameAccess +// ---------------------------------------------------------- + +Any SAL_CALL TableDesignStyle::getByName( const OUString& rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + const CellStyleNameMap& rMap = getCellStyleNameMap(); + + CellStyleNameMap::const_iterator iter = rMap.find( rName ); + if( iter == rMap.end() ) + throw NoSuchElementException(); + + return Any( maCellStyles[(*iter).second] ); +} + +// ---------------------------------------------------------- + +Sequence< OUString > SAL_CALL TableDesignStyle::getElementNames() throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + const CellStyleNameMap& rMap = getCellStyleNameMap(); + Sequence< OUString > aRet( rMap.size() ); + OUString* pName = aRet.getArray(); + + CellStyleNameMap::const_iterator iter = rMap.begin(); + while( iter != rMap.end() ) + *pName++ = (*iter++).first; + + return aRet; +} + +// ---------------------------------------------------------- + +sal_Bool SAL_CALL TableDesignStyle::hasByName( const OUString& rName ) throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + const CellStyleNameMap& rMap = getCellStyleNameMap(); + + CellStyleNameMap::const_iterator iter = rMap.find( rName ); + return ( iter != rMap.end() ) ? sal_True : sal_False; +} + +// ---------------------------------------------------------- +// XElementAccess +// ---------------------------------------------------------- + +Type SAL_CALL TableDesignStyle::getElementType() throw(RuntimeException) +{ + return XStyle::static_type(); +} + +// ---------------------------------------------------------- + +sal_Bool SAL_CALL TableDesignStyle::hasElements() throw(RuntimeException) +{ + return sal_True; +} + +// ---------------------------------------------------------- +// XIndexAccess +// ---------------------------------------------------------- + +sal_Int32 SAL_CALL TableDesignStyle::getCount() throw(RuntimeException) +{ + return style_count; +} + +// ---------------------------------------------------------- + +Any SAL_CALL TableDesignStyle::getByIndex( sal_Int32 Index ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (Index < 0) || (Index >= style_count) ) + throw IndexOutOfBoundsException(); + + return Any( maCellStyles[Index] ); +} + +// ---------------------------------------------------------- +// XNameReplace +// ---------------------------------------------------------- + +void SAL_CALL TableDesignStyle::replaceByName( const OUString& rName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + const CellStyleNameMap& rMap = getCellStyleNameMap(); + CellStyleNameMap::const_iterator iter = rMap.find( rName ); + if( iter == rMap.end() ) + throw NoSuchElementException(); + + + Reference< XStyle > xNewStyle; + if( !(aElement >>= xNewStyle) ) + throw IllegalArgumentException(); + + const sal_Int32 nIndex = (*iter).second; + + Reference< XStyle > xOldStyle( maCellStyles[nIndex] ); + + if( xNewStyle != xOldStyle ) + { + Reference< XModifyListener > xListener( this ); + + // end listening to old style, if possible + Reference< XModifyBroadcaster > xOldBroadcaster( xOldStyle, UNO_QUERY ); + if( xOldBroadcaster.is() ) + xOldBroadcaster->removeModifyListener( xListener ); + + // start listening to new style, if possible + Reference< XModifyBroadcaster > xNewBroadcaster( xNewStyle, UNO_QUERY ); + if( xNewBroadcaster.is() ) + xNewBroadcaster->addModifyListener( xListener ); + + maCellStyles[nIndex] = xNewStyle; + } +} + +// ---------------------------------------------------------- +// XComponent +// ---------------------------------------------------------- + +void SAL_CALL TableDesignStyle::disposing() +{ + for( sal_Int32 nIndex = 0; nIndex < style_count; nIndex++ ) + maCellStyles[nIndex].clear(); +} + +//------------------------------------------------------------------------ +// XModifyBroadcaster +//------------------------------------------------------------------------ + +void SAL_CALL TableDesignStyle::addModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException) +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + aGuard.clear(); + EventObject aEvt( static_cast< OWeakObject * >( this ) ); + xListener->disposing( aEvt ); + } + else + { + rBHelper.addListener( XModifyListener::static_type(), xListener ); + } +} + +//------------------------------------------------------------------------ + +void SAL_CALL TableDesignStyle::removeModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException) +{ + rBHelper.removeListener( XModifyListener::static_type(), xListener ); +} + +//------------------------------------------------------------------------ + +void TableDesignStyle::notifyModifyListener() +{ + MutexGuard aGuard( rBHelper.rMutex ); + + OInterfaceContainerHelper * pContainer = rBHelper.getContainer( XModifyListener::static_type() ); + if( pContainer ) + { + EventObject aEvt( static_cast< OWeakObject * >( this ) ); + pContainer->forEach<XModifyListener>( boost::bind( &XModifyListener::modified, _1, boost::cref( aEvt ) ) ); + } +} + +//------------------------------------------------------------------------ +// XModifyListener +//------------------------------------------------------------------------ + +// if we get a modify hint from a style, notify all registered XModifyListener +void SAL_CALL TableDesignStyle::modified( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException) +{ + notifyModifyListener(); +} + +//------------------------------------------------------------------------ + +void SAL_CALL TableDesignStyle::disposing( const ::com::sun::star::lang::EventObject& ) throw (::com::sun::star::uno::RuntimeException) +{ +} + +//------------------------------------------------------------------------ +// TableStyle +//------------------------------------------------------------------------ + +// ---------------------------------------------------------- +// XServiceInfo +// ---------------------------------------------------------- + +OUString SAL_CALL TableDesignFamily::getImplementationName() throw(RuntimeException) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM("TableDesignFamily") ); +} + +// ---------------------------------------------------------- + +sal_Bool SAL_CALL TableDesignFamily::supportsService( const OUString& ServiceName ) throw(RuntimeException) +{ + return comphelper::ServiceInfoHelper::supportsService( ServiceName, getSupportedServiceNames() ); +} + +// ---------------------------------------------------------- + +Sequence< OUString > SAL_CALL TableDesignFamily::getSupportedServiceNames() throw(RuntimeException) +{ + OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.style.StyleFamily") ); + Sequence< OUString > aSeq( &aServiceName, 1 ); + return aSeq; +} + +// ---------------------------------------------------------- +// XNamed +// ---------------------------------------------------------- + +OUString SAL_CALL TableDesignFamily::getName() throw (RuntimeException) +{ + return OUString( RTL_CONSTASCII_USTRINGPARAM( "table" ) ); +} + +// ---------------------------------------------------------- + +void SAL_CALL TableDesignFamily::setName( const OUString& ) throw (RuntimeException) +{ +} + +// ---------------------------------------------------------- +// XNameAccess +// ---------------------------------------------------------- + +Any SAL_CALL TableDesignFamily::getByName( const OUString& rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + for( TableDesignStyleVector::iterator iter( maDesigns.begin() ); iter != maDesigns.end(); iter++ ) + { + if( (*iter)->getName() == rName ) + return Any( (*iter) ); + } + + throw NoSuchElementException(); +} + +// ---------------------------------------------------------- + +Sequence< OUString > SAL_CALL TableDesignFamily::getElementNames() throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + Sequence< OUString > aRet( maDesigns.size() ); + OUString* pNames = aRet.getArray(); + + for( TableDesignStyleVector::iterator iter( maDesigns.begin() ); iter != maDesigns.end(); iter++ ) + *pNames++ = (*iter)->getName(); + + return aRet; +} + +// ---------------------------------------------------------- + +sal_Bool SAL_CALL TableDesignFamily::hasByName( const OUString& aName ) throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + for( TableDesignStyleVector::iterator iter( maDesigns.begin() ); iter != maDesigns.end(); iter++ ) + if( (*iter)->getName() == aName ) + return sal_True; + + return sal_False; +} + +// ---------------------------------------------------------- +// XElementAccess +// ---------------------------------------------------------- + +Type SAL_CALL TableDesignFamily::getElementType() throw(RuntimeException) +{ + return XStyle::static_type(); +} + +// ---------------------------------------------------------- + +sal_Bool SAL_CALL TableDesignFamily::hasElements() throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + return maDesigns.empty() ? sal_False : sal_True; +} + +// ---------------------------------------------------------- +// XIndexAccess +// ---------------------------------------------------------- + +sal_Int32 SAL_CALL TableDesignFamily::getCount() throw(RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + return sal::static_int_cast< sal_Int32 >( maDesigns.size() ); +} + +// ---------------------------------------------------------- + +Any SAL_CALL TableDesignFamily::getByIndex( sal_Int32 Index ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (Index >= 0) && (Index < sal::static_int_cast< sal_Int32 >( maDesigns.size() ) ) ) + return Any( maDesigns[Index] ); + + throw IndexOutOfBoundsException(); +} + +// ---------------------------------------------------------- +// XNameContainer +// ---------------------------------------------------------- + +void SAL_CALL TableDesignFamily::insertByName( const OUString& rName, const Any& rElement ) throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + Reference< XStyle > xStyle( rElement, UNO_QUERY ); + if( !xStyle.is() ) + throw IllegalArgumentException(); + + xStyle->setName( rName ); + for( TableDesignStyleVector::iterator iter( maDesigns.begin() ); iter != maDesigns.end(); iter++ ) + if( (*iter)->getName() == rName ) + throw ElementExistException(); + + maDesigns.push_back( xStyle ); +} + +// ---------------------------------------------------------- + +void SAL_CALL TableDesignFamily::removeByName( const OUString& rName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + for( TableDesignStyleVector::iterator iter( maDesigns.begin() ); iter != maDesigns.end(); iter++ ) + { + if( (*iter)->getName() == rName ) + { + maDesigns.erase( iter ); + return; + } + } + + + throw NoSuchElementException(); +} + +// ---------------------------------------------------------- +// XNameReplace +// ---------------------------------------------------------- + +void SAL_CALL TableDesignFamily::replaceByName( const OUString& rName, const Any& aElement ) throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + Reference< XStyle > xStyle( aElement, UNO_QUERY ); + if( !xStyle.is() ) + throw IllegalArgumentException(); + + for( TableDesignStyleVector::iterator iter( maDesigns.begin() ); iter != maDesigns.end(); iter++ ) + { + if( (*iter)->getName() == rName ) + { + (*iter) = xStyle; + xStyle->setName( rName ); + return; + } + } + + throw NoSuchElementException(); +} + +// ---------------------------------------------------------- +// XSingleServiceFactory +// ---------------------------------------------------------- + +Reference< XInterface > SAL_CALL TableDesignFamily::createInstance() throw(Exception, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + return Reference< XInterface >( static_cast< XStyle* >( new TableDesignStyle ) ); +} + +// ---------------------------------------------------------- + +Reference< XInterface > SAL_CALL TableDesignFamily::createInstanceWithArguments( const Sequence< Any >& ) throw(Exception, RuntimeException) +{ + return createInstance(); +} + +// ---------------------------------------------------------- +// XComponent +// ---------------------------------------------------------- + +void SAL_CALL TableDesignFamily::dispose( ) throw (RuntimeException) +{ + TableDesignStyleVector aDesigns; + aDesigns.swap( maDesigns ); + + for( TableDesignStyleVector::iterator iter( aDesigns.begin() ); iter != aDesigns.end(); iter++ ) + { + Reference< XComponent > xComp( (*iter), UNO_QUERY ); + if( xComp.is() ) + xComp->dispose(); + } +} + +// ---------------------------------------------------------- + +void SAL_CALL TableDesignFamily::addEventListener( const Reference< XEventListener >& ) throw (RuntimeException) +{ +} + +// ---------------------------------------------------------- + +void SAL_CALL TableDesignFamily::removeEventListener( const Reference< XEventListener >& ) throw (RuntimeException) +{ +} + +// ---------------------------------------------------------- +// XPropertySet +// ---------------------------------------------------------- + +Reference<XPropertySetInfo> TableDesignFamily::getPropertySetInfo() throw (RuntimeException) +{ + OSL_ENSURE( 0, "###unexpected!" ); + return Reference<XPropertySetInfo>(); +} + +// ---------------------------------------------------------- + +void TableDesignFamily::setPropertyValue( const OUString& , const Any& ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + OSL_ENSURE( 0, "###unexpected!" ); +} + +// ---------------------------------------------------------- + +Any TableDesignFamily::getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("DisplayName") )) + { + OUString sDisplayName( SVX_RESSTR( RID_SVXSTR_STYLEFAMILY_TABLEDESIGN ) ); + return Any( sDisplayName ); + } + else + { + throw UnknownPropertyException( OUString( RTL_CONSTASCII_USTRINGPARAM("unknown property: ") ) + PropertyName, static_cast<OWeakObject *>(this) ); + } +} + +// ---------------------------------------------------------- + +void TableDesignFamily::addPropertyChangeListener( const OUString& , const Reference<XPropertyChangeListener>& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + OSL_ENSURE( 0, "###unexpected!" ); +} + +// ---------------------------------------------------------- + +void TableDesignFamily::removePropertyChangeListener( const OUString& , const Reference<XPropertyChangeListener>& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + OSL_ENSURE( 0, "###unexpected!" ); +} + +// ---------------------------------------------------------- + +void TableDesignFamily::addVetoableChangeListener( const OUString& , const Reference<XVetoableChangeListener>& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + OSL_ENSURE( 0, "###unexpected!" ); +} + +// ---------------------------------------------------------- + +void TableDesignFamily::removeVetoableChangeListener( const OUString& , const Reference<XVetoableChangeListener>& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + OSL_ENSURE( 0, "###unexpected!" ); +} + +// -------------------------------------------------------------------- + + +SVX_DLLPUBLIC Reference< XNameAccess > CreateTableDesignFamily() +{ + return new TableDesignFamily(); +} + +} } diff --git a/svx/source/table/tablehandles.cxx b/svx/source/table/tablehandles.cxx new file mode 100644 index 000000000000..33833f8b81b1 --- /dev/null +++ b/svx/source/table/tablehandles.cxx @@ -0,0 +1,314 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include "tablehandles.hxx" + +#include <vcl/svapp.hxx> +#include <vcl/outdev.hxx> +#include <vcl/salbtype.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/hatch.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <svx/sdr/overlay/overlayobject.hxx> +#include <svx/sdr/overlay/overlaymanager.hxx> +#include <svx/sdrpagewindow.hxx> +#include <sdrpaintwindow.hxx> +#include <svx/svdmrkv.hxx> +#include <svx/svdpagv.hxx> +#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> +#include <svx/sdr/overlay/overlayhatchrect.hxx> +#include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx> + +namespace sdr { namespace table { + +// -------------------------------------------------------------------- + +class OverlayTableEdge : public sdr::overlay::OverlayObject +{ +protected: + basegfx::B2DPolyPolygon maPolyPolygon; + bool mbVisible; + + // geometry creation for OverlayObject + virtual drawinglayer::primitive2d::Primitive2DSequence createOverlayObjectPrimitive2DSequence(); + +public: + OverlayTableEdge( const basegfx::B2DPolyPolygon& rPolyPolygon, bool bVisible ); + virtual ~OverlayTableEdge(); +}; + +// -------------------------------------------------------------------- + +TableEdgeHdl::TableEdgeHdl( const Point& rPnt, bool bHorizontal, sal_Int32 nMin, sal_Int32 nMax, sal_Int32 nEdges ) +: SdrHdl( rPnt, HDL_USER ) +, mbHorizontal( bHorizontal ) +, mnMin( nMin ) +, mnMax( nMax ) +, maEdges(nEdges) +{ +} + +void TableEdgeHdl::SetEdge( sal_Int32 nEdge, sal_Int32 nStart, sal_Int32 nEnd, TableEdgeState eState ) +{ + if( (nEdge >= 0) && (nEdge <= sal::static_int_cast<sal_Int32>(maEdges.size())) ) + { + maEdges[nEdge].mnStart = nStart; + maEdges[nEdge].mnEnd = nEnd; + maEdges[nEdge].meState = eState; + } + else + { + OSL_ENSURE( false, "sdr::table::TableEdgeHdl::SetEdge(), invalid edge!" ); + } +} + +Pointer TableEdgeHdl::GetPointer() const +{ + if( mbHorizontal ) + return POINTER_VSPLIT; + else + return POINTER_HSPLIT; +} + +sal_Int32 TableEdgeHdl::GetValidDragOffset( const SdrDragStat& rDrag ) const +{ + return std::min( std::max( static_cast<sal_Int32>(mbHorizontal ? rDrag.GetDY() : rDrag.GetDX()), mnMin ), mnMax ); +} + +basegfx::B2DPolyPolygon TableEdgeHdl::getSpecialDragPoly(const SdrDragStat& rDrag) const +{ + basegfx::B2DPolyPolygon aVisible; + basegfx::B2DPolyPolygon aInvisible; + + // create and return visible and non-visible parts for drag + getPolyPolygon(aVisible, aInvisible, &rDrag); + aVisible.append(aInvisible); + + return aVisible; +} + +void TableEdgeHdl::getPolyPolygon(basegfx::B2DPolyPolygon& rVisible, basegfx::B2DPolyPolygon& rInvisible, const SdrDragStat* pDrag) const +{ + // changed method to create visible and invisible partial polygons in one run in + // separate PolyPolygons; both kinds are used + basegfx::B2DPoint aOffset(aPos.X(), aPos.Y()); + rVisible.clear(); + rInvisible.clear(); + + if( pDrag ) + { + int n = mbHorizontal ? 1 : 0; + aOffset[n] = aOffset[n] + GetValidDragOffset( *pDrag ); + } + + basegfx::B2DPoint aStart(aOffset), aEnd(aOffset); + int nPos = mbHorizontal ? 0 : 1; + TableEdgeVector::const_iterator aIter( maEdges.begin() ); + + while( aIter != maEdges.end() ) + { + TableEdge aEdge(*aIter++); + + aStart[nPos] = aOffset[nPos] + aEdge.mnStart; + aEnd[nPos] = aOffset[nPos] + aEdge.mnEnd; + + basegfx::B2DPolygon aPolygon; + aPolygon.append( aStart ); + aPolygon.append( aEnd ); + + if(aEdge.meState == Visible) + { + rVisible.append(aPolygon); + } + else + { + rInvisible.append(aPolygon); + } + } +} + +void TableEdgeHdl::CreateB2dIAObject() +{ + GetRidOfIAObject(); + + if(pHdlList && pHdlList->GetView() && !pHdlList->GetView()->areMarkHandlesHidden()) + { + SdrMarkView* pView = pHdlList->GetView(); + SdrPageView* pPageView = pView->GetSdrPageView(); + + if(pPageView) + { + basegfx::B2DPolyPolygon aVisible; + basegfx::B2DPolyPolygon aInvisible; + + // get visible and invisible parts + getPolyPolygon(aVisible, aInvisible, 0); + + if(aVisible.count() || aInvisible.count()) + { + for(sal_uInt32 nWindow = 0; nWindow < pPageView->PageWindowCount(); nWindow++) + { + const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(nWindow); + + if(rPageWindow.GetPaintWindow().OutputToWindow()) + { + if(rPageWindow.GetOverlayManager()) + { + if(aVisible.count()) + { + // create overlay object for visible parts + sdr::overlay::OverlayObject* pOverlayObject = new OverlayTableEdge(aVisible, true); + rPageWindow.GetOverlayManager()->add(*pOverlayObject); + maOverlayGroup.append(*pOverlayObject); + } + + if(aInvisible.count()) + { + // also create overlay object vor invisible parts to allow + // a standard HitTest using the primitives from that overlay object + // (see OverlayTableEdge implementation) + sdr::overlay::OverlayObject* pOverlayObject = new OverlayTableEdge(aInvisible, false); + rPageWindow.GetOverlayManager()->add(*pOverlayObject); + maOverlayGroup.append(*pOverlayObject); + } + } + } + } + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +OverlayTableEdge::OverlayTableEdge( const basegfx::B2DPolyPolygon& rPolyPolygon, bool bVisible ) +: OverlayObject(Color(COL_GRAY)) +, maPolyPolygon( rPolyPolygon ) +, mbVisible(bVisible) +{ +} + +OverlayTableEdge::~OverlayTableEdge() +{ +} + +drawinglayer::primitive2d::Primitive2DSequence OverlayTableEdge::createOverlayObjectPrimitive2DSequence() +{ + drawinglayer::primitive2d::Primitive2DSequence aRetval; + + if(maPolyPolygon.count()) + { + // Discussed with CL. Currently i will leave the transparence out since this + // a little bit expensive. We may check the look with drag polygons later + const drawinglayer::primitive2d::Primitive2DReference aReference( + new drawinglayer::primitive2d::PolyPolygonHairlinePrimitive2D( + maPolyPolygon, + getBaseColor().getBColor())); + + if(mbVisible) + { + // visible, just return as sequence + aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aReference, 1); + } + else + { + // embed in HiddenGeometryPrimitive2D to support HitTest of this invisible + // overlay object + const drawinglayer::primitive2d::Primitive2DSequence aSequence(&aReference, 1); + const drawinglayer::primitive2d::Primitive2DReference aNewReference( + new drawinglayer::primitive2d::HiddenGeometryPrimitive2D(aSequence)); + aRetval = drawinglayer::primitive2d::Primitive2DSequence(&aNewReference, 1); + } + } + + return aRetval; +} + +// ==================================================================== + +TableBorderHdl::TableBorderHdl( const Rectangle& rRect ) +: SdrHdl( rRect.TopLeft(), HDL_MOVE ) +, maRectangle( rRect ) +{ + +} + +Pointer TableBorderHdl::GetPointer() const +{ + return POINTER_MOVE; +} + +// create marker for this kind +void TableBorderHdl::CreateB2dIAObject() +{ + GetRidOfIAObject(); + + if(pHdlList && pHdlList->GetView() && !pHdlList->GetView()->areMarkHandlesHidden()) + { + SdrMarkView* pView = pHdlList->GetView(); + SdrPageView* pPageView = pView->GetSdrPageView(); + + if(pPageView) + { + for(sal_uInt32 nWindow = 0; nWindow < pPageView->PageWindowCount(); nWindow++) + { + // const SdrPageViewWinRec& rPageViewWinRec = rPageViewWinList[b]; + const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(nWindow); + + if(rPageWindow.GetPaintWindow().OutputToWindow()) + { + if(rPageWindow.GetOverlayManager()) + { + const basegfx::B2DRange aRange(vcl::unotools::b2DRectangleFromRectangle(maRectangle)); + sdr::overlay::OverlayObject* pOverlayObject = new sdr::overlay::OverlayHatchRect( + aRange.getMinimum(), + aRange.getMaximum(), + Color(0x80, 0x80, 0x80), + 6.0, + 0.0, + 45 * F_PI180, + 0.0); + + rPageWindow.GetOverlayManager()->add(*pOverlayObject); + maOverlayGroup.append(*pOverlayObject); + } + } + } + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +} // end of namespace table +} // end of namespace sdr diff --git a/svx/source/table/tablehandles.hxx b/svx/source/table/tablehandles.hxx new file mode 100644 index 000000000000..0704e94a84b7 --- /dev/null +++ b/svx/source/table/tablehandles.hxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLEHANDLES_HXX +#define _SVX_TABLEHANDLES_HXX + +#include <svx/sdr/overlay/overlayobject.hxx> + +#include <svx/svdhdl.hxx> + +// -------------------------------------------------------------------- + +namespace sdr { namespace table { + +enum TableEdgeState { Empty, Invisible, Visible }; + +struct TableEdge +{ + sal_Int32 mnStart; + sal_Int32 mnEnd; + TableEdgeState meState; + + TableEdge() : mnStart(0), mnEnd(0), meState(Empty) {} +}; + +typedef std::vector< TableEdge > TableEdgeVector; + +class TableEdgeHdl : public SdrHdl +{ +public: + TableEdgeHdl( const Point& rPnt, bool bHorizontal, sal_Int32 nMin, sal_Int32 nMax, sal_Int32 nEdges ); + + sal_Int32 GetValidDragOffset( const SdrDragStat& rDrag ) const; + + virtual Pointer GetPointer() const; + + void SetEdge( sal_Int32 nEdge, sal_Int32 nStart, sal_Int32 nEnd, TableEdgeState nState ); + + bool IsHorizontalEdge() const { return mbHorizontal; } + + basegfx::B2DPolyPolygon getSpecialDragPoly(const SdrDragStat& rDrag) const; + void getPolyPolygon(basegfx::B2DPolyPolygon& rVisible, basegfx::B2DPolyPolygon& rInvisible, const SdrDragStat* pDrag) const; + +protected: + // create marker for this kind + virtual void CreateB2dIAObject(); + +private: + bool mbHorizontal; + sal_Int32 mnMin, mnMax; + TableEdgeVector maEdges; +}; + +class TableBorderHdl : public SdrHdl +{ +public: + TableBorderHdl( const Rectangle& rRect ); + + virtual Pointer GetPointer() const; + +protected: + // create marker for this kind + virtual void CreateB2dIAObject(); + +private: + Rectangle maRectangle; +}; + +} // end of namespace table +} // end of namespace sdr + +#endif diff --git a/svx/source/table/tablelayouter.cxx b/svx/source/table/tablelayouter.cxx new file mode 100644 index 000000000000..5e13bce7101e --- /dev/null +++ b/svx/source/table/tablelayouter.cxx @@ -0,0 +1,1300 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/table/XMergeableCell.hpp> +#include <com/sun/star/awt/XLayoutConstrains.hpp> +#include <boost/bind.hpp> + +#include "cell.hxx" +#include "cellrange.hxx" +#include "tablemodel.hxx" +#include "tablerow.hxx" +#include "tablerows.hxx" +#include "tablecolumn.hxx" +#include "tablecolumns.hxx" +#include "tablelayouter.hxx" +#include "svx/svdotable.hxx" +#include "editeng/borderline.hxx" +#include "editeng/boxitem.hxx" +#include "svx/svdmodel.hxx" +#include "svdstr.hrc" +#include "svdglob.hxx" + +using ::rtl::OUString; +using ::com::sun::star::awt::XLayoutConstrains; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::text; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- + +static SvxBorderLine gEmptyBorder; + +// ----------------------------------------------------------------------------- + +TableLayouter::TableLayouter( const TableModelRef& xTableModel ) +: mxTable( xTableModel ) +, meWritingMode( WritingMode_LR_TB ) +, msSize( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ) +{ +} + +// ----------------------------------------------------------------------------- + +TableLayouter::~TableLayouter() +{ + ClearBorderLayout(); +} + +// ----------------------------------------------------------------------------- + +basegfx::B2ITuple TableLayouter::getCellSize( const CellPos& rPos ) const +{ + sal_Int32 width = 0; + sal_Int32 height = 0; + + try + { + CellRef xCell( getCell( rPos ) ); + if( xCell.is() && !xCell->isMerged() ) + { + CellPos aPos( rPos ); + + sal_Int32 nRowCount = getRowCount(); + sal_Int32 nRowSpan = std::max( xCell->getRowSpan(), (sal_Int32)1 ); + while( nRowSpan && (aPos.mnRow < nRowCount) ) + { + if( ((sal_Int32)maRows.size()) <= aPos.mnRow ) + break; + + height += maRows[aPos.mnRow++].mnSize; + nRowSpan--; + } + + sal_Int32 nColCount = getColumnCount(); + sal_Int32 nColSpan = std::max( xCell->getColumnSpan(), (sal_Int32)1 ); + while( nColSpan && (aPos.mnCol < nColCount ) ) + { + if( ((sal_Int32)maColumns.size()) <= aPos.mnCol ) + break; + + width += maColumns[aPos.mnCol++].mnSize; + nColSpan--; + } + } + } + catch( Exception& ) + { + DBG_ERROR( "TableLayouter::getCellSize(), exception caught!" ); + } + + return basegfx::B2ITuple( width, height ); +} + +// ----------------------------------------------------------------------------- + +bool TableLayouter::getCellArea( const CellPos& rPos, basegfx::B2IRectangle& rArea ) const +{ + try + { + CellRef xCell( getCell( rPos ) ); + if( xCell.is() && !xCell->isMerged() && isValid(rPos) ) + { + const basegfx::B2ITuple aCellSize( getCellSize( rPos ) ); + + if( (rPos.mnCol < ((sal_Int32)maColumns.size()) && (rPos.mnRow < ((sal_Int32)maRows.size()) ) ) ) + { + const sal_Int32 x = maColumns[rPos.mnCol].mnPos; + const sal_Int32 y = maRows[rPos.mnRow].mnPos; + + rArea = basegfx::B2IRectangle( x, y, x + aCellSize.getX(), y + aCellSize.getY() ); + return true; + } + } + } + catch( Exception& ) + { + DBG_ERROR( "TableLayouter::getCellSize(), exception caught!" ); + } + return false; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableLayouter::getRowHeight( sal_Int32 nRow ) +{ + if( isValidRow(nRow) ) + return maRows[nRow].mnSize; + else + return 0; +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::setRowHeight( sal_Int32 nRow, sal_Int32 nHeight ) +{ + if( isValidRow(nRow) ) + { + maRows[nRow].mnSize = nHeight; + } + else + { + DBG_ERROR( "TableLayouter::setRowHeight(), row out of range!" ); + } +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableLayouter::getColumnWidth( sal_Int32 nColumn ) +{ + if( isValidColumn(nColumn) ) + return maColumns[nColumn].mnSize; + else + return 0; +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::setColumnWidth( sal_Int32 nColumn, sal_Int32 nWidth ) +{ + if( isValidColumn(nColumn) ) + maColumns[nColumn].mnSize = nWidth; + else + DBG_ERROR( "TableLayouter::setColumnWidth(), column out of range!" ); +} + +// ----------------------------------------------------------------------------- + +bool TableLayouter::isEdgeVisible( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal ) const +{ + const BorderLineMap& rMap = bHorizontal ? maHorizontalBorders : maVerticalBorders; + + if( (nEdgeX >= 0) && (nEdgeX < sal::static_int_cast<sal_Int32>(rMap.size())) && + (nEdgeY >= 0) && (nEdgeY < sal::static_int_cast<sal_Int32>(rMap[nEdgeX].size())) ) + { + return rMap[nEdgeX][nEdgeY] != 0; + } + else + { + OSL_ENSURE( false, "sdr::table::TableLayouter::getBorderLine(), invalid edge!" ); + } + + return false; +} + +// ----------------------------------------------------------------------------- + +/** returns the requested borderline in rpBorderLine or a null pointer if there is no border at this edge */ +SvxBorderLine* TableLayouter::getBorderLine( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal )const +{ + SvxBorderLine* pLine = 0; + + const BorderLineMap& rMap = bHorizontal ? maHorizontalBorders : maVerticalBorders; + + if( (nEdgeX >= 0) && (nEdgeX < sal::static_int_cast<sal_Int32>(rMap.size())) && + (nEdgeY >= 0) && (nEdgeY < sal::static_int_cast<sal_Int32>(rMap[nEdgeX].size())) ) + { + pLine = rMap[nEdgeX][nEdgeY]; + if( pLine == &gEmptyBorder ) + pLine = 0; + } + else + { + OSL_ENSURE( false, "sdr::table::TableLayouter::getBorderLine(), invalid edge!" ); + } + + return pLine; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableLayouter::getHorizontalEdge( int nEdgeY, sal_Int32* pnMin /*= 0*/, sal_Int32* pnMax /*= 0*/ ) +{ + sal_Int32 nRet = 0; + if( (nEdgeY >= 0) && (nEdgeY <= getRowCount() ) ) + nRet = maRows[std::min((sal_Int32)nEdgeY,getRowCount()-1)].mnPos; + + if( nEdgeY == getRowCount() ) + nRet += maRows[nEdgeY - 1].mnSize; + + if( pnMin ) + { + if( (nEdgeY > 0) && (nEdgeY <= getRowCount() ) ) + { + *pnMin = maRows[nEdgeY-1].mnPos + 600; // todo + } + else + { + *pnMin = nRet; + } + } + + if( pnMax ) + { + *pnMax = 0x0fffffff; + } + return nRet; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableLayouter::getVerticalEdge( int nEdgeX, sal_Int32* pnMin /*= 0*/, sal_Int32* pnMax /*= 0*/ ) +{ + sal_Int32 nRet = 0; + + const sal_Int32 nColCount = getColumnCount(); + if( (nEdgeX >= 0) && (nEdgeX <= nColCount ) ) + nRet = maColumns[std::min((sal_Int32)nEdgeX,nColCount-1)].mnPos; + + const bool bRTL = meWritingMode == WritingMode_RL_TB; + if( bRTL ) + { + if( (nEdgeX >= 0) && (nEdgeX < nColCount) ) + nRet += maColumns[nEdgeX].mnSize; + } + else + { + if( nEdgeX == getColumnCount() ) + nRet += maColumns[nEdgeX - 1].mnSize; + } + + if( pnMin ) + { + *pnMin = nRet; + if( bRTL ) + { + if( nEdgeX < nColCount ) + *pnMin = nRet - maColumns[nEdgeX].mnSize + getMinimumColumnWidth(nEdgeX); + } + else + { + if( (nEdgeX > 0) && (nEdgeX <= nColCount ) ) + *pnMin = maColumns[nEdgeX-1].mnPos + getMinimumColumnWidth( nEdgeX-1 ); + } + } + + if( pnMax ) + { + *pnMax = 0x0fffffff; // todo + if( bRTL ) + { + if( nEdgeX > 0 ) + *pnMax = nRet + maColumns[nEdgeX-1].mnSize - getMinimumColumnWidth( nEdgeX-1 ); + } + else + { + if( (nEdgeX >= 0) && (nEdgeX < nColCount ) ) + *pnMax = maColumns[nEdgeX].mnPos + maColumns[nEdgeX].mnSize - getMinimumColumnWidth( nEdgeX ); + } + } + + return nRet; +} + +// ----------------------------------------------------------------------------- + +static bool checkMergeOrigin( const TableModelRef& xTable, sal_Int32 nMergedX, sal_Int32 nMergedY, sal_Int32 nCellX, sal_Int32 nCellY, bool& bRunning ) +{ + Reference< XMergeableCell > xCell( xTable->getCellByPosition( nCellX, nCellY ), UNO_QUERY ); + if( xCell.is() && !xCell->isMerged() ) + { + const sal_Int32 nRight = xCell->getColumnSpan() + nCellX; + const sal_Int32 nBottom = xCell->getRowSpan() + nCellY; + if( (nMergedX < nRight) && (nMergedY < nBottom) ) + return true; + + bRunning = false; + } + return false; +} + +/** returns true if the cell(nMergedX,nMergedY) is merged with other cells. + the returned cell( rOriginX, rOriginY ) is the origin( top left cell ) of the merge. +*/ +bool findMergeOrigin( const TableModelRef& xTable, sal_Int32 nMergedX, sal_Int32 nMergedY, sal_Int32& rOriginX, sal_Int32& rOriginY ) +{ + rOriginX = nMergedX; + rOriginY = nMergedY; + + if( xTable.is() ) try + { + // check if this cell already the origin or not merged at all + Reference< XMergeableCell > xCell( xTable->getCellByPosition( nMergedX, nMergedY ), UNO_QUERY_THROW ); + if( !xCell.is() || !xCell->isMerged() ) + return true; + + bool bCheckVert = true; + bool bCheckHorz = true; + + sal_Int32 nMinCol = 0; + sal_Int32 nMinRow = 0; + + sal_Int32 nStep = 1, i; + + sal_Int32 nRow, nCol; + do + { + if( bCheckVert ) + { + nRow = nMergedY - nStep; + if( nRow >= nMinRow ) + { + nCol = nMergedX; + for( i = 0; (i <= nStep) && (nCol >= nMinCol); i++, nCol-- ) + { + if( checkMergeOrigin( xTable, nMergedX, nMergedY, nCol, nRow, bCheckVert ) ) + { + rOriginX = nCol; rOriginY = nRow; + return true; + } + + if( !bCheckVert ) + { + if( nCol == nMergedX ) + { + nMinRow = nRow+1; + } + else + { + bCheckVert = true; + } + break; + } + } + } + else + { + bCheckVert = false; + } + } + + if( bCheckHorz ) + { + nCol = nMergedX - nStep; + if( nCol >= nMinCol ) + { + nRow = nMergedY; + for( i = 0; (i < nStep) && (nRow >= nMinRow); i++, nRow-- ) + { + if( checkMergeOrigin( xTable, nMergedX, nMergedY, nCol, nRow, bCheckHorz ) ) + { + rOriginX = nCol; rOriginY = nRow; + return true; + } + + if( !bCheckHorz ) + { + if( nRow == nMergedY ) + { + nMinCol = nCol+1; + } + else + { + bCheckHorz = true; + } + break; + } + } + } + else + { + bCheckHorz = false; + } + } + nStep++; + } + while( bCheckVert || bCheckHorz ); + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::TableLayouter::findMergeOrigin(), exception caught!"); + } + return false; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableLayouter::getMinimumColumnWidth( sal_Int32 nColumn ) +{ + if( isValidColumn( nColumn ) ) + { + return maColumns[nColumn].mnMinSize; + } + else + { + DBG_ERROR( "TableLayouter::getMinimumColumnWidth(), column out of range!" ); + return 0; + } +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableLayouter::distribute( LayoutVector& rLayouts, sal_Int32 nDistribute ) +{ + // break loops after 100 runs to avoid freezing office due to developer error + sal_Int32 nSafe = 100; + + const sal_Size nCount = rLayouts.size(); + sal_Size nIndex; + + bool bConstrainsBroken = false; + + do + { + // first enforce minimum size constrains on all entities + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + Layout& rLayout = rLayouts[nIndex]; + if( rLayout.mnSize < rLayout.mnMinSize ) + { + nDistribute -= rLayout.mnMinSize - rLayout.mnSize; + rLayout.mnSize = rLayout.mnMinSize; + } + } + + // calculate current width + // if nDistribute is < 0 (shrinking), entities that are already + // at minimum width are not counted + sal_Int32 nCurrentWidth = 0; + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + Layout& rLayout = rLayouts[nIndex]; + if( (nDistribute > 0) || (rLayout.mnSize > rLayout.mnMinSize) ) + nCurrentWidth += rLayout.mnSize; + } + + bConstrainsBroken = false; + + // now distribute over entities + if( (nCurrentWidth != 0) && (nDistribute != 0) ) + { + sal_Int32 nDistributed = nDistribute; + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + Layout& rLayout = rLayouts[nIndex]; + if( (nDistribute > 0) || (rLayout.mnSize > rLayout.mnMinSize) ) + { + sal_Int32 n; + if( nIndex == (nCount-1) ) + n = nDistributed; // for last entitie, use up rest + else + n = (nDistribute * rLayout.mnSize) / nCurrentWidth; // + + nDistributed -= n; + rLayout.mnSize += n; + + if( rLayout.mnSize < rLayout.mnMinSize ) + bConstrainsBroken = true; + } + } + } + } while( bConstrainsBroken && --nSafe ); + + sal_Int32 nSize = 0; + for( nIndex = 0; nIndex < nCount; ++nIndex ) + nSize += rLayouts[nIndex].mnSize; + + return nSize; +} + +// ----------------------------------------------------------------------------- + +typedef std::vector< CellRef > MergeableCellVector; +typedef std::vector< MergeableCellVector > MergeVector; +typedef std::vector< sal_Int32 > Int32Vector; + +// ----------------------------------------------------------------------------- + +void TableLayouter::LayoutTableWidth( Rectangle& rArea, bool bFit ) +{ + const sal_Int32 nColCount = getColumnCount(); + const sal_Int32 nRowCount = getRowCount(); + if( nColCount == 0 ) + return; + + MergeVector aMergedCells( nColCount ); + Int32Vector aOptimalColumns; + + const OUString sOptimalSize( RTL_CONSTASCII_USTRINGPARAM("OptimalSize") ); + + if( sal::static_int_cast< sal_Int32 >( maColumns.size() ) != nColCount ) + maColumns.resize( nColCount ); + + Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_QUERY_THROW ); + + // first calculate current width and initial minimum width per column, + // merged cells will be counted later + sal_Int32 nCurrentWidth = 0; + sal_Int32 nCol = 0, nRow = 0; + for( nCol = 0; nCol < nColCount; nCol++ ) + { + sal_Int32 nMinWidth = 0; + + bool bIsEmpty = true; // check if all cells in this column are merged + + for( nRow = 0; nRow < nRowCount; ++nRow ) + { + CellRef xCell( getCell( CellPos( nCol, nRow ) ) ); + if( xCell.is() && !xCell->isMerged() ) + { + bIsEmpty = false; + + sal_Int32 nColSpan = xCell->getColumnSpan(); + if( nColSpan > 1 ) + { + // merged cells will be evaluated later + aMergedCells[nCol+nColSpan-1].push_back( xCell ); + } + else + { + nMinWidth = std::max( nMinWidth, xCell->getMinimumSize().Width ); + } + } + } + + maColumns[nCol].mnMinSize = nMinWidth; + + if( bIsEmpty ) + { + maColumns[nCol].mnSize = 0; + } + else + { + sal_Int32 nColWidth = 0; + Reference< XPropertySet > xColSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW ); + sal_Bool bOptimal = sal_False; + xColSet->getPropertyValue( sOptimalSize ) >>= bOptimal; + if( bOptimal ) + { + aOptimalColumns.push_back(nCol); + } + else + { + xColSet->getPropertyValue( msSize ) >>= nColWidth; + } + + maColumns[nCol].mnSize = nColWidth; + + if( maColumns[nCol].mnSize < nMinWidth ) + maColumns[nCol].mnSize = nMinWidth; + + nCurrentWidth += maColumns[nCol].mnSize; + } + } + + // if we have optimal sized rows, distribute what is given (left) + if( !bFit && !aOptimalColumns.empty() && (nCurrentWidth < rArea.getWidth()) ) + { + sal_Int32 nLeft = rArea.getWidth() - nCurrentWidth; + sal_Int32 nDistribute = nLeft / aOptimalColumns.size(); + + Int32Vector::iterator iter( aOptimalColumns.begin() ); + while( iter != aOptimalColumns.end() ) + { + sal_Int32 nOptCol = (*iter++); + if( iter == aOptimalColumns.end() ) + nDistribute = nLeft; + + maColumns[nOptCol].mnSize += nDistribute; + nLeft -= nDistribute; + } + + DBG_ASSERT( nLeft == 0, "svx::TableLayouter::LayoutTableWidtht(), layouting failed!" ); + } + + // now check if merged cells fit + for( nCol = 1; nCol < nColCount; ++nCol ) + { + bool bChanges = false; + MergeableCellVector::iterator iter( aMergedCells[nCol].begin() ); + + const sal_Int32 nOldSize = maColumns[nCol].mnSize; + + while( iter != aMergedCells[nCol].end() ) + { + CellRef xCell( (*iter++) ); + sal_Int32 nMinWidth = xCell->getMinimumSize().Width; + + for( sal_Int32 nMCol = nCol - xCell->getColumnSpan() + 1; (nMCol > 0) && (nMCol < nCol); ++nMCol ) + nMinWidth -= maColumns[nMCol].mnSize; + + if( nMinWidth > maColumns[nCol].mnMinSize ) + maColumns[nCol].mnMinSize = nMinWidth; + + if( nMinWidth > maColumns[nCol].mnSize ) + { + maColumns[nCol].mnSize = nMinWidth; + bChanges = true; + } + } + + if( bChanges ) + nCurrentWidth += maColumns[nCol].mnSize - nOldSize; + } + + // now scale if wanted and needed + if( bFit && (nCurrentWidth != rArea.getWidth()) ) + distribute( maColumns, rArea.getWidth() - nCurrentWidth ); + + // last step, update left edges + sal_Int32 nNewWidth = 0; + + const bool bRTL = meWritingMode == WritingMode_RL_TB; + RangeIterator<sal_Int32> coliter( 0, nColCount, !bRTL ); + while( coliter.next(nCol ) ) + { + maColumns[nCol].mnPos = nNewWidth; + nNewWidth += maColumns[nCol].mnSize; + if( bFit ) + { + Reference< XPropertySet > xColSet( xCols->getByIndex(nCol), UNO_QUERY_THROW ); + xColSet->setPropertyValue( msSize, Any( maColumns[nCol].mnSize ) ); + } + } + + rArea.SetSize( Size( nNewWidth, rArea.GetHeight() ) ); + updateCells( rArea ); +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::LayoutTableHeight( Rectangle& rArea, bool bFit ) +{ + const sal_Int32 nColCount = getColumnCount(); + const sal_Int32 nRowCount = getRowCount(); + if( nRowCount == 0 ) + return; + + Reference< XTableRows > xRows( mxTable->getRows() ); + + MergeVector aMergedCells( nRowCount ); + Int32Vector aOptimalRows; + + const OUString sOptimalSize( RTL_CONSTASCII_USTRINGPARAM("OptimalSize") ); + + // first calculate current height and initial minimum size per column, + // merged cells will be counted later + sal_Int32 nCurrentHeight = 0; + sal_Int32 nCol, nRow; + for( nRow = 0; nRow < nRowCount; ++nRow ) + { + sal_Int32 nMinHeight = 0; + + bool bIsEmpty = true; // check if all cells in this row are merged + + for( nCol = 0; nCol < nColCount; ++nCol ) + { + CellRef xCell( getCell( CellPos( nCol, nRow ) ) ); + if( xCell.is() && !xCell->isMerged() ) + { + bIsEmpty = false; + + sal_Int32 nRowSpan = xCell->getRowSpan(); + if( nRowSpan > 1 ) + { + // merged cells will be evaluated later + aMergedCells[nRow+nRowSpan-1].push_back( xCell ); + } + else + { + nMinHeight = std::max( nMinHeight, xCell->getMinimumSize().Height ); + } + } + } + + maRows[nRow].mnMinSize = nMinHeight; + + if( bIsEmpty ) + { + maRows[nRow].mnSize = 0; + } + else + { + sal_Int32 nRowHeight = 0; + Reference< XPropertySet > xRowSet( xRows->getByIndex(nRow), UNO_QUERY_THROW ); + + sal_Bool bOptimal = sal_False; + xRowSet->getPropertyValue( sOptimalSize ) >>= bOptimal; + if( bOptimal ) + { + aOptimalRows.push_back( nRow ); + } + else + { + xRowSet->getPropertyValue( msSize ) >>= nRowHeight; + } + + maRows[nRow].mnSize = nRowHeight; + + if( maRows[nRow].mnSize < nMinHeight ) + maRows[nRow].mnSize = nMinHeight; + + nCurrentHeight += maRows[nRow].mnSize; + } + } + + // if we have optimal sized rows, distribute what is given (left) + if( !bFit && !aOptimalRows.empty() && (nCurrentHeight < rArea.getHeight()) ) + { + sal_Int32 nLeft = rArea.getHeight() - nCurrentHeight; + sal_Int32 nDistribute = nLeft / aOptimalRows.size(); + + Int32Vector::iterator iter( aOptimalRows.begin() ); + while( iter != aOptimalRows.end() ) + { + sal_Int32 nOptRow = (*iter++); + if( iter == aOptimalRows.end() ) + nDistribute = nLeft; + + maRows[nOptRow].mnSize += nDistribute; + nLeft -= nDistribute; + + } + + DBG_ASSERT( nLeft == 0, "svx::TableLayouter::LayoutTableHeight(), layouting failed!" ); + } + + // now check if merged cells fit + for( nRow = 1; nRow < nRowCount; ++nRow ) + { + bool bChanges = false; + sal_Int32 nOldSize = maRows[nRow].mnSize; + + MergeableCellVector::iterator iter( aMergedCells[nRow].begin() ); + while( iter != aMergedCells[nRow].end() ) + { + CellRef xCell( (*iter++) ); + sal_Int32 nMinHeight = xCell->getMinimumSize().Height; + + for( sal_Int32 nMRow = nRow - xCell->getRowSpan() + 1; (nMRow > 0) && (nMRow < nRow); ++nMRow ) + nMinHeight -= maRows[nMRow].mnSize; + + if( nMinHeight > maRows[nRow].mnMinSize ) + maRows[nRow].mnMinSize = nMinHeight; + + if( nMinHeight > maRows[nRow].mnSize ) + { + maRows[nRow].mnSize = nMinHeight; + bChanges = true; + } + } + if( bChanges ) + nCurrentHeight += maRows[nRow].mnSize - nOldSize; + } + + // now scale if wanted and needed + if( bFit && nCurrentHeight != rArea.getHeight() ) + distribute( maRows, rArea.getHeight() - nCurrentHeight ); + + // last step, update left edges + sal_Int32 nNewHeight = 0; + for( nRow = 0; nRow < nRowCount; ++nRow ) + { + maRows[nRow].mnPos = nNewHeight; + nNewHeight += maRows[nRow].mnSize; + + if( bFit ) + { + Reference< XPropertySet > xRowSet( xRows->getByIndex(nRow), UNO_QUERY_THROW ); + xRowSet->setPropertyValue( msSize, Any( maRows[nRow].mnSize ) ); + } + } + + rArea.SetSize( Size( rArea.GetWidth(), nNewHeight ) ); + updateCells( rArea ); +} + +// ----------------------------------------------------------------------------- + +/** try to fit the table into the given rectangle. + If the rectangle is to small, it will be grown to fit the table. */ +void TableLayouter::LayoutTable( Rectangle& rRectangle, bool bFitWidth, bool bFitHeight ) +{ + if( !mxTable.is() ) + return; + + const sal_Int32 nRowCount = mxTable->getRowCount(); + const sal_Int32 nColCount = mxTable->getColumnCount(); + + if( (nRowCount != getRowCount()) || (nColCount != getColumnCount()) ) + { + if( static_cast< sal_Int32 >( maRows.size() ) != nRowCount ) + maRows.resize( nRowCount ); + + Reference< XTableRows > xRows( mxTable->getRows() ); + for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ ) + maRows[nRow].clear(); + + if( static_cast< sal_Int32 >( maColumns.size() ) != nColCount ) + maColumns.resize( nColCount ); + + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) + maColumns[nCol].clear(); + } + + LayoutTableWidth( rRectangle, bFitWidth ); + LayoutTableHeight( rRectangle, bFitHeight ); + UpdateBorderLayout(); +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::updateCells( Rectangle& rRectangle ) +{ + const sal_Int32 nColCount = getColumnCount(); + const sal_Int32 nRowCount = getRowCount(); + + CellPos aPos; + for( aPos.mnRow = 0; aPos.mnRow < nRowCount; aPos.mnRow++ ) + { + for( aPos.mnCol = 0; aPos.mnCol < nColCount; aPos.mnCol++ ) + { + CellRef xCell( getCell( aPos ) ); + if( xCell.is() ) + { + basegfx::B2IRectangle aCellArea; + getCellArea( aPos, aCellArea ); + + Rectangle aCellRect; + aCellRect.nLeft = aCellArea.getMinX(); + aCellRect.nRight = aCellArea.getMaxX(); + aCellRect.nTop = aCellArea.getMinY(); + aCellRect.nBottom = aCellArea.getMaxY(); + aCellRect.Move( rRectangle.nLeft, rRectangle.nTop ); + xCell->setCellRect( aCellRect ); + } + } + } +} + +// ----------------------------------------------------------------------------- + +CellRef TableLayouter::getCell( const CellPos& rPos ) const +{ + CellRef xCell; + if( mxTable.is() ) try + { + xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) ); + } + catch( Exception& ) + { + DBG_ERROR( "sdr::table::TableLayouter::getCell(), exception caught!" ); + } + return xCell; +} + +// ----------------------------------------------------------------------------- + +bool TableLayouter::HasPriority( const SvxBorderLine* pThis, const SvxBorderLine* pOther ) +{ + if (!pThis || ((pThis == &gEmptyBorder) && (pOther != 0))) + return false; + if (!pOther || (pOther == &gEmptyBorder)) + return true; + + USHORT nThisSize = pThis->GetOutWidth() + pThis->GetDistance() + pThis->GetInWidth(); + USHORT nOtherSize = pOther->GetOutWidth() + pOther->GetDistance() + pOther->GetInWidth(); + + if (nThisSize > nOtherSize) + return true; + + else if (nThisSize < nOtherSize) + { + return false; + } + else + { + if ( pOther->GetInWidth() && !pThis->GetInWidth() ) + { + return true; + } + else if ( pThis->GetInWidth() && !pOther->GetInWidth() ) + { + return false; + } + else + { + return true; //! ??? + } + } +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::SetBorder( sal_Int32 nCol, sal_Int32 nRow, bool bHorizontal, const SvxBorderLine* pLine ) +{ + if( pLine == 0 ) + pLine = &gEmptyBorder; + + SvxBorderLine *pOld = bHorizontal ? maHorizontalBorders[nCol][nRow] : maVerticalBorders[nCol][nRow]; + + if( HasPriority( pLine, pOld ) ) + { + if( (pOld != 0) && (pOld != &gEmptyBorder) ) + delete pOld; + + SvxBorderLine* pNew = ( pLine != &gEmptyBorder ) ? new SvxBorderLine(*pLine) : &gEmptyBorder; + + if( bHorizontal ) + maHorizontalBorders[nCol][nRow] = pNew; + else + maVerticalBorders[nCol][nRow] = pNew; + } +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::ClearBorderLayout() +{ + ClearBorderLayout(maHorizontalBorders); + ClearBorderLayout(maVerticalBorders); +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::ClearBorderLayout(BorderLineMap& rMap) +{ + const sal_Int32 nColCount = rMap.size(); + + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) + { + const sal_Int32 nRowCount = rMap[nCol].size(); + for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ ) + { + SvxBorderLine* pLine = rMap[nCol][nRow]; + if( pLine ) + { + if( pLine != &gEmptyBorder ) + delete pLine; + + rMap[nCol][nRow] = 0; + } + } + } +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::ResizeBorderLayout() +{ + ClearBorderLayout(); + ResizeBorderLayout(maHorizontalBorders); + ResizeBorderLayout(maVerticalBorders); +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::ResizeBorderLayout( BorderLineMap& rMap ) +{ + const sal_Int32 nColCount = getColumnCount() + 1; + const sal_Int32 nRowCount = getRowCount() + 1; + + if( sal::static_int_cast<sal_Int32>(rMap.size()) != nColCount ) + rMap.resize( nColCount ); + + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) + { + if( sal::static_int_cast<sal_Int32>(rMap[nCol].size()) != nRowCount ) + rMap[nCol].resize( nRowCount ); + } +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::UpdateBorderLayout() +{ + // make sure old border layout is cleared and border maps have correct size + ResizeBorderLayout(); + + const sal_Int32 nColCount = getColumnCount(); + const sal_Int32 nRowCount = getRowCount(); + + CellPos aPos; + for( aPos.mnRow = 0; aPos.mnRow < nRowCount; aPos.mnRow++ ) + { + for( aPos.mnCol = 0; aPos.mnCol < nColCount; aPos.mnCol++ ) + { + CellRef xCell( getCell( aPos ) ); + if( !xCell.is() || xCell->isMerged() ) + continue; + + const SvxBoxItem* pThisAttr = (const SvxBoxItem*)xCell->GetItemSet().GetItem( SDRATTR_TABLE_BORDER ); + OSL_ENSURE(pThisAttr,"sdr::table::TableLayouter::UpdateBorderLayout(), no border attribute?"); + + if( !pThisAttr ) + continue; + + const sal_Int32 nLastRow = xCell->getRowSpan() + aPos.mnRow; + const sal_Int32 nLastCol = xCell->getColumnSpan() + aPos.mnCol; + + for( sal_Int32 nRow = aPos.mnRow; nRow < nLastRow; nRow++ ) + { + SetBorder( aPos.mnCol, nRow, false, pThisAttr->GetLeft() ); + SetBorder( nLastCol, nRow, false, pThisAttr->GetRight() ); + } + + for( sal_Int32 nCol = aPos.mnCol; nCol < nLastCol; nCol++ ) + { + SetBorder( nCol, aPos.mnRow, true, pThisAttr->GetTop() ); + SetBorder( nCol, nLastRow, true, pThisAttr->GetBottom() ); + } + } + } +} + +// ----------------------------------------------------------------------------- +/* +void TableLayouter::SetLayoutToModel() +{ + const sal_Int32 nRowCount = getRowCount(); + const sal_Int32 nColCount = getColumnCount(); + + try + { + sal_Int32 nOldSize = 0; + + Reference< XIndexAccess > xRows( mxTable->getRows(), UNO_QUERY_THROW ); + for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ ) + { + Reference< XPropertySet > xRowSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW ); + xRowSet->getPropertyValue( msSize ) >>= nOldSize; + if( maRows[nRow].mnSize != nOldSize ) + xRowSet->setPropertyValue( msSize, Any( maRows[nRow].mnSize ) ); + } + + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) + { + Reference< XPropertySet > xColSet( getColumnByIndex( nCol ), UNO_QUERY_THROW ); + xColSet->getPropertyValue( msSize ) >>= nOldSize; + if( maColumns[nCol].mnSize != nOldSize ) + xColSet->setPropertyValue( msSize, Any( maColumns[nCol].mnSize ) ); + } + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::TableLayouter::SetLayoutToModel(), exception caught!"); + } +} +*/ +// ----------------------------------------------------------------------------- + +void TableLayouter::DistributeColumns( ::Rectangle& rArea, sal_Int32 nFirstCol, sal_Int32 nLastCol ) +{ + if( mxTable.is() ) try + { + const sal_Int32 nColCount = getColumnCount(); + + if( (nFirstCol < 0) || (nFirstCol>= nLastCol) || (nLastCol >= nColCount) ) + return; + + sal_Int32 nAllWidth = 0; + for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol ) + nAllWidth += getColumnWidth(nCol); + + sal_Int32 nWidth = nAllWidth / (nLastCol-nFirstCol+1); + + Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_QUERY_THROW ); + + for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol ) + { + if( nCol == nLastCol ) + nWidth = nAllWidth; // last column get round errors + + Reference< XPropertySet > xColSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW ); + xColSet->setPropertyValue( msSize, Any( nWidth ) ); + + nAllWidth -= nWidth; + } + + LayoutTable( rArea, true, false ); + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("sdr::table::TableLayouter::DistributeColumns(), exception caught!"); + } +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::DistributeRows( ::Rectangle& rArea, sal_Int32 nFirstRow, sal_Int32 nLastRow ) +{ + if( mxTable.is() ) try + { + const sal_Int32 nRowCount = mxTable->getRowCount(); + + if( (nFirstRow < 0) || (nFirstRow>= nLastRow) || (nLastRow >= nRowCount) ) + return; + + sal_Int32 nAllHeight = 0; + sal_Int32 nMinHeight = 0; + + for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow ) + { + nMinHeight = std::max( maRows[nRow].mnMinSize, nMinHeight ); + nAllHeight += maRows[nRow].mnSize; + } + + const sal_Int32 nRows = (nLastRow-nFirstRow+1); + sal_Int32 nHeight = nAllHeight / nRows; + + if( nHeight < nMinHeight ) + { + sal_Int32 nNeededHeight = nRows * nMinHeight; + rArea.nBottom += nNeededHeight - nAllHeight; + nHeight = nMinHeight; + nAllHeight = nRows * nMinHeight; + } + + Reference< XTableRows > xRows( mxTable->getRows(), UNO_QUERY_THROW ); + for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow ) + { + if( nRow == nLastRow ) + nHeight = nAllHeight; // last row get round errors + + Reference< XPropertySet > xRowSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW ); + xRowSet->setPropertyValue( msSize, Any( nHeight ) ); + + nAllHeight -= nHeight; + } + + LayoutTable( rArea, false, true ); + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("sdr::table::TableLayouter::DistributeRows(), exception caught!"); + } +} + +// ----------------------------------------------------------------------------- + +void TableLayouter::SetWritingMode( com::sun::star::text::WritingMode eWritingMode ) +{ + meWritingMode = eWritingMode; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableLayouter::getColumnStart( sal_Int32 nColumn ) const +{ + if( isValidColumn(nColumn) ) + return maColumns[nColumn].mnPos; + else + return 0; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableLayouter::getRowStart( sal_Int32 nRow ) const +{ + if( isValidRow(nRow) ) + return maRows[nRow].mnPos; + else + return 0; +} + +// ----------------------------------------------------------------------------- + +/* +sal_Int32 TableLayouter::detectInsertedOrRemovedRows() +{ + sal_Int32 nHeightChange = 0; + + try + { + Reference< XIndexAccess > xRows( mxTable->getRows(), UNO_QUERY_THROW ); + std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > >::iterator oldIter( mxRows.begin() ); + sal_Int32 nCount = xRows->getCount(); + for( sal_Int32 nRow = 0; nRow < nCount; nRow++ ) + { + Reference< XInterface > xRow( xRows->getByIndex(nRow), UNO_QUERY ); + + std::vector< ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > >::iterator searchIter = mxRows.end(); + if( oldIter != mxRows.end() ) + searchIter = std::find( oldIter,mxRows.end(), xRow ); + + if( searchIter == mxRows.end() ) + { + // new row + Reference< XPropertySet > xSet( xRow, UNO_QUERY_THROW ); + sal_Int32 nSize = 0; + xSet->getPropertyValue( msSize ) >>= nSize; + nHeightChange += nSize; + } + else if( searchIter == oldIter ) + { + // no change + oldIter++; + } + else + { + // rows removed + do + { + Reference< XPropertySet > xSet( (*oldIter), UNO_QUERY_THROW ); + sal_Int32 nSize = 0; + xSet->getPropertyValue( msSize ) >>= nSize; + nHeightChange -= nSize; + } + while( oldIter++ != searchIter ); + } + } + + while( oldIter != mxRows.end() ) + { + // rows removed + Reference< XPropertySet > xSet( (*oldIter++), UNO_QUERY_THROW ); + sal_Int32 nSize = 0; + xSet->getPropertyValue( msSize ) >>= nSize; + nHeightChange -= nSize; + } + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("svx::TableLayouter::detectInsertedOrRemovedRows(), exception caught!"); + } + + return nHeightChange; +} +*/ + +// ----------------------------------------------------------------------------- + +} } diff --git a/svx/source/table/tablelayouter.hxx b/svx/source/table/tablelayouter.hxx new file mode 100644 index 000000000000..9c56aafb556f --- /dev/null +++ b/svx/source/table/tablelayouter.hxx @@ -0,0 +1,178 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLE_TABLELAYOUTER_HXX_ +#define _SVX_TABLE_TABLELAYOUTER_HXX_ + +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/text/WritingMode.hpp> +#include <com/sun/star/table/XTable.hpp> +#include <basegfx/range/b2irectangle.hxx> +#include <basegfx/tuple/b2ituple.hxx> +#include <tools/gen.hxx> +#include <boost/shared_ptr.hpp> +#include <vector> +#include <map> + +#include "svx/svdotable.hxx" + +// ----------------------------------------------------------------------------- + +class SvxBorderLine; + +namespace sdr { namespace table { + +/** returns true if the cell(nMergedCol,nMergedRow) is merged with other cells. + the returned cell( rOriginCol, rOriginRow ) is the origin( top left cell ) of the merge. +*/ +bool findMergeOrigin( const TableModelRef& xTable, sal_Int32 nMergedCol, sal_Int32 nMergedRow, sal_Int32& rOriginCol, sal_Int32& rOriginRow ); + +typedef std::vector< SvxBorderLine* > BorderLineVector; +typedef std::vector< BorderLineVector > BorderLineMap; + +// ----------------------------------------------------------------------------- +// TableModel +// ----------------------------------------------------------------------------- + +class TableLayouter +{ +public: + TableLayouter( const TableModelRef& xTableModel ); + virtual ~TableLayouter(); + + /** this checks if new rows are inserted or old rows where removed. + This can be used to grow or shrink the table shape in this case. + @returns + the height difference + sal_Int32 detectInsertedOrRemovedRows(); + */ + + /** try to fit the table into the given rectangle. + If the rectangle is to small, it will be grown to fit the table. + + if bFitWidth or bFitHeight is set, the layouter tries to scale + the rows and/or columns to the given area. The result my be bigger + to fullfill constrains. + + if bFitWidth or bFitHeight is set, the model is changed. + */ + void LayoutTable( ::Rectangle& rRectangle, bool bFitWidth, bool bFitHeight ); + + /** after a call to LayoutTable, this method can be used to set the new + column and row sizes back to the model. */ +// void SetLayoutToModel(); + + void UpdateBorderLayout(); + + basegfx::B2ITuple getCellSize( const CellPos& rPos ) const; + bool getCellArea( const CellRef& xCell, basegfx::B2IRectangle& rArea ) const; + bool getCellArea( const CellPos& rPos, basegfx::B2IRectangle& rArea ) const; + + ::sal_Int32 getRowCount() const { return static_cast< ::sal_Int32 >( maRows.size() ); } + ::sal_Int32 getColumnCount() const { return static_cast< ::sal_Int32 >( maColumns.size() ); } + + sal_Int32 getRowHeight( sal_Int32 nRow ); + + // sets the layout height of the given row hard, LayoutTable must be called directly after calling this method! */ + void setRowHeight( sal_Int32 nRow, sal_Int32 nHeight ); + + sal_Int32 getColumnWidth( sal_Int32 nColumn ); + + // sets the layout width of the given column hard, LayoutTable must be called directly after calling this method! */ + void setColumnWidth( sal_Int32 nColumn, sal_Int32 nWidth ); + + sal_Int32 getMinimumColumnWidth( sal_Int32 nColumn ); + + sal_Int32 getColumnStart( sal_Int32 nColumn ) const; + sal_Int32 getRowStart( sal_Int32 nRow ) const; + + /** checks if the given edge is visible. + Edges between merged cells are not visible. + */ + bool isEdgeVisible( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal ) const; + + /** returns the requested borderline in rpBorderLine or a null pointer if there is no border at this edge */ + SvxBorderLine* getBorderLine( sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal )const; + + void updateCells( ::Rectangle& rRectangle ); + + sal_Int32 getHorizontalEdge( int nEdgeY, sal_Int32* pnMin = 0, sal_Int32* pnMax = 0 ); + sal_Int32 getVerticalEdge( int nEdgeX , sal_Int32* pnMin = 0, sal_Int32* pnMax = 0); + + void DistributeColumns( ::Rectangle& rArea, sal_Int32 nFirstCol, sal_Int32 nLastCol ); + void DistributeRows( ::Rectangle& rArea, sal_Int32 nFirstRow, sal_Int32 nLastRow ); + + com::sun::star::text::WritingMode GetWritingMode() const { return meWritingMode; } + void SetWritingMode( com::sun::star::text::WritingMode eWritingMode ); + +private: + CellRef getCell( const CellPos& rPos ) const; + + void LayoutTableWidth( ::Rectangle& rArea, bool bFit ); + void LayoutTableHeight( ::Rectangle& rArea, bool bFit ); + + inline bool isValidColumn( sal_Int32 nColumn ) const { return (nColumn >= 0) && (nColumn < static_cast<sal_Int32>( maColumns.size())); } + inline bool isValidRow( sal_Int32 nRow ) const { return (nRow >= 0) && (nRow < static_cast<sal_Int32>( maRows.size())); } + inline bool isValid( const CellPos& rPos ) const { return isValidColumn( rPos.mnCol ) && isValidRow( rPos.mnRow ); } + + void ClearBorderLayout(); + void ClearBorderLayout(BorderLineMap& rMap); + void ResizeBorderLayout(); + void ResizeBorderLayout( BorderLineMap& rMap ); + + void SetBorder( sal_Int32 nCol, sal_Int32 nRow, bool bHorizontal, const SvxBorderLine* pLine ); + + static bool HasPriority( const SvxBorderLine* pThis, const SvxBorderLine* pOther ); + + struct Layout + { + sal_Int32 mnPos; + sal_Int32 mnSize; + sal_Int32 mnMinSize; + + Layout() : mnPos( 0 ), mnSize( 0 ), mnMinSize( 0 ) {} + void clear() { mnPos = 0; mnSize = 0; mnMinSize = 0; } + }; + typedef std::vector< Layout > LayoutVector; + + sal_Int32 distribute( LayoutVector& rLayouts, sal_Int32 nDistribute ); + + TableModelRef mxTable; + LayoutVector maRows; + LayoutVector maColumns; + + BorderLineMap maHorizontalBorders; + BorderLineMap maVerticalBorders; + + com::sun::star::text::WritingMode meWritingMode; + + const rtl::OUString msSize; +}; + +} } + +#endif diff --git a/svx/source/table/tablemodel.cxx b/svx/source/table/tablemodel.cxx new file mode 100644 index 000000000000..1c8d0aa60dc8 --- /dev/null +++ b/svx/source/table/tablemodel.cxx @@ -0,0 +1,1258 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/table/XMergeableCell.hpp> + +#include <algorithm> +#include <boost/bind.hpp> + +#include <vcl/svapp.hxx> +#include <vos/mutex.hxx> + +#include "cell.hxx" +#include "cellcursor.hxx" +#include "tablemodel.hxx" +#include "tablerow.hxx" +#include "tablerows.hxx" +#include "tablecolumn.hxx" +#include "tablecolumns.hxx" +#include "tableundo.hxx" +#include "svx/svdotable.hxx" +#include "svx/svdmodel.hxx" +#include "svdstr.hrc" +#include "svdglob.hxx" + +//#define PLEASE_DEBUG_THE_TABLES 1 + +using ::rtl::OUString; +using namespace ::osl; +using namespace ::vos; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- + +// removes the given range from a vector +template< class Vec, class Iter > void remove_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount ) +{ + const sal_Int32 nSize = static_cast<sal_Int32>(rVector.size()); + if( nCount && (nIndex >= 0) && (nIndex < nSize) ) + { + if( (nIndex + nCount) >= nSize ) + { + // remove at end + rVector.resize( nIndex ); + } + else + { + Iter aBegin( rVector.begin() ); + while( nIndex-- ) + aBegin++; + if( nCount == 1 ) + { + rVector.erase( aBegin ); + } + else + { + Iter aEnd( aBegin ); + + while( nCount-- ) + aEnd++; + rVector.erase( aBegin, aEnd ); + } + } + } +} + +// ----------------------------------------------------------------------------- + +/** inserts a range into a vector */ +template< class Vec, class Iter, class Entry > sal_Int32 insert_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount ) +{ + if( nCount ) + { + if( nIndex >= static_cast< sal_Int32 >( rVector.size() ) ) + { + // append at end + nIndex = static_cast< sal_Int32 >( rVector.size() ); // cap to end + rVector.resize( nIndex + nCount ); + } + else + { + // insert + sal_Int32 nFind = nIndex; + Iter aIter( rVector.begin() ); + while( nFind-- ) + aIter++; + + Entry aEmpty; + rVector.insert( aIter, nCount, aEmpty ); + } + } + return nIndex; +} + +// ----------------------------------------------------------------------------- + +TableModel::TableModel( SdrTableObj* pTableObj ) +: TableModelBase( m_aMutex ) +, mpTableObj( pTableObj ) +, mbModified( sal_False ) +, mbNotifyPending( false ) +, mnNotifyLock( 0 ) +{ +} + +TableModel::TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable ) +: TableModelBase( m_aMutex ) +, mpTableObj( pTableObj ) +, mbModified( sal_False ) +, mbNotifyPending( false ) +, mnNotifyLock( 0 ) +{ + if( xSourceTable.is() ) + { + const sal_Int32 nColCount = xSourceTable->getColumnCountImpl(); + const sal_Int32 nRowCount = xSourceTable->getRowCountImpl(); + + init( nColCount, nRowCount ); + + sal_Int32 nRows = nRowCount; + while( nRows-- ) + (*maRows[nRows]) = (*xSourceTable->maRows[nRows]); + + sal_Int32 nColumns = nColCount; + while( nColumns-- ) + (*maColumns[nColumns]) = (*xSourceTable->maColumns[nColumns]); + + // copy cells + for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol ) + { + for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow ) + { + CellRef xTargetCell( getCell( nCol, nRow ) ); + if( xTargetCell.is() ) + xTargetCell->cloneFrom( xSourceTable->getCell( nCol, nRow ) ); + } + } + } +} + +// ----------------------------------------------------------------------------- + +TableModel::~TableModel() +{ +} + +// ----------------------------------------------------------------------------- + +void TableModel::init( sal_Int32 nColumns, sal_Int32 nRows ) +{ + if( nRows < 20 ) + maRows.reserve( 20 ); + + if( nColumns < 20 ) + maColumns.reserve( 20 ); + + if( nRows && nColumns ) + { + maColumns.resize( nColumns ); + maRows.resize( nRows ); + + while( nRows-- ) + maRows[nRows].set( new TableRow( this, nRows, nColumns ) ); + + while( nColumns-- ) + maColumns[nColumns].set( new TableColumn( this, nColumns ) ); + } +} + +// ----------------------------------------------------------------------------- +// ICellRange +// ----------------------------------------------------------------------------- + +sal_Int32 TableModel::getLeft() +{ + return 0; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableModel::getTop() +{ + return 0; +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableModel::getRight() +{ + return getColumnCount(); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableModel::getBottom() +{ + return getRowCount(); +} + +// ----------------------------------------------------------------------------- + +Reference< XTable > TableModel::getTable() +{ + return this; +} + +// ----------------------------------------------------------------------------- + +void TableModel::UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount ) +{ + TableModelNotifyGuard aGuard( this ); + + // remove the rows + remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount ); + updateRows(); + setModified(sal_True); +} + +// ----------------------------------------------------------------------------- + +void TableModel::UndoRemoveRows( sal_Int32 nIndex, RowVector& aRows ) +{ + TableModelNotifyGuard aGuard( this ); + + const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aRows.size() ); + + nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount ); + + for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset ) + maRows[nIndex+nOffset] = aRows[nOffset]; + + updateRows(); + setModified(sal_True); +} + +// ----------------------------------------------------------------------------- + +void TableModel::UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount ) +{ + TableModelNotifyGuard aGuard( this ); + + // now remove the columns + remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount ); + sal_Int32 nRows = getRowCountImpl(); + while( nRows-- ) + maRows[nRows]->removeColumns( nIndex, nCount ); + + updateColumns(); + setModified(sal_True); +} + +// ----------------------------------------------------------------------------- + +void TableModel::UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aCols, CellVector& aCells ) +{ + TableModelNotifyGuard aGuard( this ); + + const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aCols.size() ); + + // assert if there are not enough cells saved + DBG_ASSERT( (aCols.size() * maRows.size()) == aCells.size(), "sdr::table::TableModel::UndoRemoveColumns(), invalid undo data!" ); + + nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount ); + for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset ) + maColumns[nIndex+nOffset] = aCols[nOffset]; + + CellVector::iterator aIter( aCells.begin() ); + + sal_Int32 nRows = getRowCountImpl(); + for( sal_Int32 nRow = 0; nRow < nRows; ++nRow ) + maRows[nRow]->insertColumns( nIndex, nCount, &aIter ); + + updateColumns(); + setModified(sal_True); +} + +// ----------------------------------------------------------------------------- +// XTable +// ----------------------------------------------------------------------------- + +Reference< XCellCursor > SAL_CALL TableModel::createCursor() throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return createCursorByRange( Reference< XCellRange >( this ) ); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellCursor > SAL_CALL TableModel::createCursorByRange( const Reference< XCellRange >& Range ) throw (IllegalArgumentException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + ICellRange* pRange = dynamic_cast< ICellRange* >( Range.get() ); + if( (pRange == 0) || (pRange->getTable().get() != this) ) + throw IllegalArgumentException(); + + TableModelRef xModel( this ); + return new CellCursor( xModel, pRange->getLeft(), pRange->getTop(), pRange->getRight(), pRange->getBottom() ); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL TableModel::getRowCount() throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return getRowCountImpl(); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL TableModel::getColumnCount() throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return getColumnCountImpl(); +} + +// ----------------------------------------------------------------------------- +// XComponent +// ----------------------------------------------------------------------------- + +void TableModel::dispose() throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + TableModelBase::dispose(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException) +{ + TableModelBase::addEventListener( xListener ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::removeEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException) +{ + TableModelBase::removeEventListener( xListener ); +} + +// ----------------------------------------------------------------------------- +// XModifiable +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL TableModel::isModified( ) throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + return mbModified; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::setModified( sal_Bool bModified ) throw (PropertyVetoException, RuntimeException) +{ + { + OGuard aGuard( Application::GetSolarMutex() ); + mbModified = bModified; + } + if( bModified ) + notifyModification(); +} + +// ----------------------------------------------------------------------------- +// XModifyBroadcaster +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException) +{ + rBHelper.addListener( XModifyListener::static_type() , xListener ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::removeModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException) +{ + rBHelper.removeListener( XModifyListener::static_type() , xListener ); +} + +// ----------------------------------------------------------------------------- +// XColumnRowRange +// ----------------------------------------------------------------------------- + +Reference< XTableColumns > SAL_CALL TableModel::getColumns() throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( !mxTableColumns.is() ) + mxTableColumns.set( new TableColumns( this ) ); + return mxTableColumns.get(); +} + +// ----------------------------------------------------------------------------- + +Reference< XTableRows > SAL_CALL TableModel::getRows() throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( !mxTableRows.is() ) + mxTableRows.set( new TableRows( this ) ); + return mxTableRows.get(); +} + +// ----------------------------------------------------------------------------- +// XCellRange +// ----------------------------------------------------------------------------- + +Reference< XCell > SAL_CALL TableModel::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw ( IndexOutOfBoundsException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + CellRef xCell( getCell( nColumn, nRow ) ); + if( xCell.is() ) + return xCell.get(); + + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL TableModel::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + + if( (nLeft >= 0) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) && (nRight < getColumnCountImpl()) && (nBottom < getRowCountImpl() ) ) + { + TableModelRef xModel( this ); + return new CellRange( xModel, nLeft, nTop, nRight, nBottom ); + } + + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException) +{ + return Reference< XCellRange >(); +} + +// ----------------------------------------------------------------------------- +// XPropertySet +// ----------------------------------------------------------------------------- + +Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo( ) throw (RuntimeException) +{ + Reference< XPropertySetInfo > xInfo; + return xInfo; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::setPropertyValue( const ::rtl::OUString& /*aPropertyName*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + return Any(); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::removeVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- +// XFastPropertySet +// ----------------------------------------------------------------------------- + +void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL TableModel::getFastPropertyValue( ::sal_Int32 /*nHandle*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + Any aAny; + return aAny; +} + +// ----------------------------------------------------------------------------- +// internals +// ----------------------------------------------------------------------------- + +sal_Int32 TableModel::getRowCountImpl() const +{ + return static_cast< sal_Int32 >( maRows.size() ); +} + +// ----------------------------------------------------------------------------- + +sal_Int32 TableModel::getColumnCountImpl() const +{ + return static_cast< sal_Int32 >( maColumns.size() ); +} + +// ----------------------------------------------------------------------------- + +void TableModel::disposing() +{ + if( !maRows.empty() ) + { + RowVector::iterator aIter( maRows.begin() ); + while( aIter != maRows.end() ) + (*aIter++)->dispose(); + RowVector().swap(maRows); + } + + if( !maColumns.empty() ) + { + ColumnVector::iterator aIter( maColumns.begin() ); + while( aIter != maColumns.end() ) + (*aIter++)->dispose(); + ColumnVector().swap(maColumns); + } + + if( mxTableColumns.is() ) + { + mxTableColumns->dispose(); + mxTableColumns.clear(); + } + + if( mxTableRows.is() ) + { + mxTableRows->dispose(); + mxTableRows.clear(); + } + + mpTableObj = 0; +} + +// ----------------------------------------------------------------------------- +// XBroadcaster +// ----------------------------------------------------------------------------- + +void TableModel::lockBroadcasts() throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + ++mnNotifyLock; +} +// ----------------------------------------------------------------------------- + +void TableModel::unlockBroadcasts() throw (RuntimeException) +{ + OGuard aGuard( Application::GetSolarMutex() ); + --mnNotifyLock; + if( mnNotifyLock <= 0 ) + { + mnNotifyLock = 0; + if( mbNotifyPending ) + notifyModification(); + } +} + +// ----------------------------------------------------------------------------- +#ifdef PLEASE_DEBUG_THE_TABLES +#include <stdio.h> +#endif + +void TableModel::notifyModification() +{ + ::osl::MutexGuard guard( m_aMutex ); + if( (mnNotifyLock == 0) && mpTableObj && mpTableObj->GetModel() ) + { + mbNotifyPending = false; + + ::cppu::OInterfaceContainerHelper * pModifyListeners = rBHelper.getContainer( XModifyListener::static_type() ); + if( pModifyListeners ) + { + EventObject aSource; + aSource.Source = static_cast< ::cppu::OWeakObject* >(this); + pModifyListeners->notifyEach( &XModifyListener::modified, aSource); + } + } + else + { + mbNotifyPending = true; + } + +#ifdef PLEASE_DEBUG_THE_TABLES + FILE* file = fopen( "c:\\table.xml","w" ); + + const sal_Int32 nColCount = getColumnCountImpl(); + const sal_Int32 nRowCount = getRowCountImpl(); + + fprintf( file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\r" ); + fprintf( file, "<table columns=\"%ld\" rows=\"%ld\" updated=\"%s\">\n\r", nColCount, nRowCount, mbNotifyPending ? "false" : "true"); + + for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol ) + { + fprintf( file, "<column this=\"%lx\"/>\n\r", maColumns[nCol].get() ); + } + + // first check merged cells before and inside the removed rows + for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow ) + { + fprintf( file, "<row this=\"%lx\">\n\r", maRows[nRow].get() ); + for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol ) + { + CellRef xCell( getCell( nCol, nRow ) ); + fprintf( file, "<cell this=\"%lx\"", xCell.get() ); + + sal_Int32 nRowSpan = xCell->getRowSpan(); + sal_Int32 nColSpan = xCell->getColumnSpan(); + sal_Bool bMerged = xCell->isMerged(); + + if( nColSpan != 1 ) + fprintf( file, " column-span=\"%ld\"", nColSpan ); + if( nRowSpan != 1 ) + fprintf( file, " row-span=\"%ld\"", nRowSpan ); + + if( bMerged ) + fprintf( file, " merged=\"true\"" ); + + fprintf( file, "/>" ); + } + fprintf( file, "\n\r</row>\n\r" ); + } + + fprintf( file, "</table>\n\r" ); + fclose( file ); +#endif +} + +// ----------------------------------------------------------------------------- + +CellRef TableModel::getCell( sal_Int32 nCol, sal_Int32 nRow ) const +{ + if( ((nRow >= 0) && (nRow < getRowCountImpl())) && (nCol >= 0) && (nCol < getColumnCountImpl()) ) + { + return maRows[nRow]->maCells[nCol]; + } + else + { + CellRef xRet; + return xRet; + } +} + +// ----------------------------------------------------------------------------- +/* +bool TableModel::getCellPos( const CellRef& xCell, ::sal_Int32& rnCol, ::sal_Int32& rnRow ) const +{ + const sal_Int32 nRowCount = getRowCount(); + const sal_Int32 nColCount = getColumnCount(); + for( rnRow = 0; rnRow < nRowCount; rnRow++ ) + { + for( rnCol = 0; rnCol < nColCount; rnCol++ ) + { + if( maRows[rnRow]->maCells[rnCol] == xCell ) + { + return true; + } + } + } + return false; +} +*/ + +// ----------------------------------------------------------------------------- + +CellRef TableModel::createCell() +{ + CellRef xCell; + if( mpTableObj ) + mpTableObj->createCell( xCell ); + return xCell; +} + +// ----------------------------------------------------------------------------- + +void TableModel::insertColumns( sal_Int32 nIndex, sal_Int32 nCount ) +{ + if( nCount && mpTableObj ) + { + try + { + SdrModel* pModel = mpTableObj->GetModel(); + + TableModelNotifyGuard aGuard( this ); + nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount ); + + sal_Int32 nRows = getRowCountImpl(); + while( nRows-- ) + maRows[nRows]->insertColumns( nIndex, nCount ); + + ColumnVector aNewColumns(nCount); + for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset ) + { + TableColumnRef xNewCol( new TableColumn( this, nIndex+nOffset ) ); + maColumns[nIndex+nOffset] = xNewCol; + aNewColumns[nOffset] = xNewCol; + } + + const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled(); + if( bUndo ) + { + pModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) ); + pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) ); + + TableModelRef xThis( this ); + + nRows = getRowCountImpl(); + CellVector aNewCells( nCount * nRows ); + CellVector::iterator aCellIter( aNewCells.begin() ); + + nRows = getRowCountImpl(); + for( sal_Int32 nRow = 0; nRow < nRows; ++nRow ) + { + for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset ) + (*aCellIter++) = getCell( nIndex + nOffset, nRow ); + } + + pModel->AddUndo( new InsertColUndo( xThis, nIndex, aNewColumns, aNewCells ) ); + } + + const sal_Int32 nRowCount = getRowCountImpl(); + // check if cells merge over new columns + for( sal_Int32 nCol = 0; nCol < nIndex; ++nCol ) + { + for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow ) + { + CellRef xCell( getCell( nCol, nRow ) ); + sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1; + if( (nColSpan != 1) && ((nColSpan + nCol ) > nIndex) ) + { + // cell merges over newly created columns, so add the new columns to the merged cell + const sal_Int32 nRowSpan = xCell->getRowSpan(); + nColSpan += nCount; + merge( nCol, nRow, nColSpan, nRowSpan ); + } + } + } + + if( bUndo ) + pModel->EndUndo(); + + if( pModel ) + pModel->SetChanged(); + + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::TableModel::insertColumns(), exception caught!"); + } + updateColumns(); + setModified(sal_True); + } +} + +// ----------------------------------------------------------------------------- + +void TableModel::removeColumns( sal_Int32 nIndex, sal_Int32 nCount ) +{ + sal_Int32 nColCount = getColumnCountImpl(); + + if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nColCount) ) + { + try + { + TableModelNotifyGuard aGuard( this ); + + // clip removed columns to columns actually avalaible + if( (nIndex + nCount) > nColCount ) + nCount = nColCount - nIndex; + + sal_Int32 nRows = getRowCountImpl(); + + SdrModel* pModel = mpTableObj->GetModel(); + + const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled(); + if( bUndo ) + { + pModel->BegUndo( ImpGetResStr(STR_UNDO_COL_DELETE) ); + pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) ); + + TableModelRef xThis( this ); + ColumnVector aRemovedCols( nCount ); + sal_Int32 nOffset; + for( nOffset = 0; nOffset < nCount; ++nOffset ) + { + aRemovedCols[nOffset] = maColumns[nIndex+nOffset]; + } + + CellVector aRemovedCells( nCount * nRows ); + CellVector::iterator aCellIter( aRemovedCells.begin() ); + for( sal_Int32 nRow = 0; nRow < nRows; ++nRow ) + { + for( nOffset = 0; nOffset < nCount; ++nOffset ) + (*aCellIter++) = getCell( nIndex + nOffset, nRow ); + } + + pModel->AddUndo( new RemoveColUndo( xThis, nIndex, aRemovedCols, aRemovedCells ) ); + } + + // only rows before and inside the removed rows are considered + nColCount = nIndex + nCount + 1; + + const sal_Int32 nRowCount = getRowCountImpl(); + + // first check merged cells before and inside the removed rows + for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol ) + { + for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow ) + { + CellRef xCell( getCell( nCol, nRow ) ); + sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1; + if( nColSpan <= 1 ) + continue; + + if( nCol >= nIndex ) + { + // current cell is inside the removed columns + if( (nCol + nColSpan) > ( nIndex + nCount ) ) + { + // current cells merges with columns after the removed columns + const sal_Int32 nRemove = nCount - nCol + nIndex; + + CellRef xTargetCell( getCell( nIndex + nCount, nRow ) ); + if( xTargetCell.is() ) + { + if( bUndo ) + xTargetCell->AddUndo(); + xTargetCell->merge( nColSpan - nRemove, xCell->getRowSpan() ); + xTargetCell->replaceContentAndFormating( xCell ); + } + } + } + else if( nColSpan > (nIndex - nCol) ) + { + // current cells spans inside the removed columns, so adjust + const sal_Int32 nRemove = ::std::min( nCount, nCol + nColSpan - nIndex ); + if( bUndo ) + xCell->AddUndo(); + xCell->merge( nColSpan - nRemove, xCell->getRowSpan() ); + } + } + } + + // now remove the columns + remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount ); + while( nRows-- ) + maRows[nRows]->removeColumns( nIndex, nCount ); + + if( bUndo ) + pModel->EndUndo(); + + if( pModel ) + pModel->SetChanged(); + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::TableModel::removeColumns(), exception caught!"); + } + + updateColumns(); + setModified(sal_True); + } +} + +// ----------------------------------------------------------------------------- + +void TableModel::insertRows( sal_Int32 nIndex, sal_Int32 nCount ) +{ + if( nCount && mpTableObj ) + { + SdrModel* pModel = mpTableObj->GetModel(); + const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled(); + try + { + TableModelNotifyGuard aGuard( this ); + + nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount ); + + RowVector aNewRows(nCount); + const sal_Int32 nColCount = getColumnCountImpl(); + for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset ) + { + TableRowRef xNewRow( new TableRow( this, nIndex+nOffset, nColCount ) ); + maRows[nIndex+nOffset] = xNewRow; + aNewRows[nOffset] = xNewRow; + } + + if( bUndo ) + { + pModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW) ); + pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) ); + TableModelRef xThis( this ); + pModel->AddUndo( new InsertRowUndo( xThis, nIndex, aNewRows ) ); + } + + // check if cells merge over new columns + for( sal_Int32 nRow = 0; nRow < nIndex; ++nRow ) + { + for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol ) + { + CellRef xCell( getCell( nCol, nRow ) ); + sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1; + if( (nRowSpan > 1) && ((nRowSpan + nRow) > nIndex) ) + { + // cell merges over newly created columns, so add the new columns to the merged cell + const sal_Int32 nColSpan = xCell->getColumnSpan(); + nRowSpan += nCount; + merge( nCol, nRow, nColSpan, nRowSpan ); + } + } + } + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::TableModel::insertRows(), exception caught!"); + } + if( bUndo ) + pModel->EndUndo(); + + if( pModel ) + pModel->SetChanged(); + + updateRows(); + setModified(sal_True); + } +} + +// ----------------------------------------------------------------------------- + +void TableModel::removeRows( sal_Int32 nIndex, sal_Int32 nCount ) +{ + sal_Int32 nRowCount = getRowCountImpl(); + + if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nRowCount) ) + { + SdrModel* pModel = mpTableObj->GetModel(); + const bool bUndo = pModel && mpTableObj->IsInserted()&& pModel->IsUndoEnabled(); + + try + { + TableModelNotifyGuard aGuard( this ); + + // clip removed rows to rows actually avalaible + if( (nIndex + nCount) > nRowCount ) + nCount = nRowCount - nIndex; + + if( bUndo ) + { + pModel->BegUndo( ImpGetResStr(STR_UNDO_ROW_DELETE) ); + pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) ); + + TableModelRef xThis( this ); + + RowVector aRemovedRows( nCount ); + for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset ) + aRemovedRows[nOffset] = maRows[nIndex+nOffset]; + + pModel->AddUndo( new RemoveRowUndo( xThis, nIndex, aRemovedRows ) ); + } + + // only rows before and inside the removed rows are considered + nRowCount = nIndex + nCount + 1; + + const sal_Int32 nColCount = getColumnCountImpl(); + + // first check merged cells before and inside the removed rows + for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow ) + { + for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol ) + { + CellRef xCell( getCell( nCol, nRow ) ); + sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1; + if( nRowSpan <= 1 ) + continue; + + if( nRow >= nIndex ) + { + // current cell is inside the removed rows + if( (nRow + nRowSpan) > (nIndex + nCount) ) + { + // current cells merges with rows after the removed rows + const sal_Int32 nRemove = nCount - nRow + nIndex; + + CellRef xTargetCell( getCell( nCol, nIndex + nCount ) ); + if( xTargetCell.is() ) + { + if( bUndo ) + xTargetCell->AddUndo(); + xTargetCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove ); + xTargetCell->replaceContentAndFormating( xCell ); + } + } + } + else if( nRowSpan > (nIndex - nRow) ) + { + // current cells spans inside the removed rows, so adjust + const sal_Int32 nRemove = ::std::min( nCount, nRow + nRowSpan - nIndex ); + if( bUndo ) + xCell->AddUndo(); + xCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove ); + } + } + } + + // now remove the rows + remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount ); + + if( bUndo ) + pModel->EndUndo(); + + if( pModel ) + pModel->SetChanged(); + } + catch( Exception& ) + { + DBG_ERROR("sdr::table::TableModel::removeRows(), exception caught!"); + } + + updateRows(); + setModified(sal_True); + } +} + +// ----------------------------------------------------------------------------- + +TableRowRef TableModel::getRow( sal_Int32 nRow ) const throw (IndexOutOfBoundsException) +{ + if( (nRow >= 0) && (nRow < getRowCountImpl()) ) + return maRows[nRow]; + + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +TableColumnRef TableModel::getColumn( sal_Int32 nColumn ) const throw (IndexOutOfBoundsException) +{ + if( (nColumn >= 0) && (nColumn < getColumnCountImpl()) ) + return maColumns[nColumn]; + + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +/** deletes rows and columns that are completly merged. Must be called between BegUndo/EndUndo! */ +void TableModel::optimize() +{ + TableModelNotifyGuard aGuard( this ); + + bool bWasModified = false; + + if( !maRows.empty() && !maColumns.empty() ) + { + sal_Int32 nCol = getColumnCountImpl() - 1; + while( nCol > 0 ) + { + bool bEmpty = true; + for( sal_Int32 nRow = 0; (nRow < getRowCountImpl()) && bEmpty; nRow++ ) + { + Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY ); + if( xCell.is() && !xCell->isMerged() ) + bEmpty = false; + } + + if( bEmpty ) + { + if( nCol > 0 ) try + { + const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM("Width") ); + sal_Int32 nWidth1 = 0, nWidth2 = 0; + Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maColumns[nCol].get() ), UNO_QUERY_THROW ); + Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maColumns[nCol-1].get() ), UNO_QUERY_THROW ); + xSet1->getPropertyValue( sWidth ) >>= nWidth1; + xSet2->getPropertyValue( sWidth ) >>= nWidth2; + nWidth1 += nWidth2; + xSet2->setPropertyValue( sWidth, Any( nWidth1 ) ); + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("svx::TableModel::optimize(), exception caught!"); + } + + removeColumns( nCol, 1 ); + bWasModified = true; + } + + nCol--; + } + + sal_Int32 nRow = getRowCountImpl() - 1; + while( nRow > 0 ) + { + bool bEmpty = true; + for( nCol = 0; (nCol < getColumnCountImpl()) && bEmpty; nCol++ ) + { + Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY ); + if( xCell.is() && !xCell->isMerged() ) + bEmpty = false; + } + + if( bEmpty ) + { + if( nRow > 0 ) try + { + const OUString sHeight( RTL_CONSTASCII_USTRINGPARAM("Height") ); + sal_Int32 nHeight1 = 0, nHeight2 = 0; + Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maRows[nRow].get() ), UNO_QUERY_THROW ); + Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maRows[nRow-1].get() ), UNO_QUERY_THROW ); + xSet1->getPropertyValue( sHeight ) >>= nHeight1; + xSet2->getPropertyValue( sHeight ) >>= nHeight2; + nHeight1 += nHeight2; + xSet2->setPropertyValue( sHeight, Any( nHeight1 ) ); + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("svx::TableModel::optimize(), exception caught!"); + } + + removeRows( nRow, 1 ); + bWasModified = true; + } + + nRow--; + } + } + if( bWasModified ) + setModified(sal_True); +} + +// ----------------------------------------------------------------------------- + +void TableModel::merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan ) +{ + SdrModel* pModel = mpTableObj->GetModel(); + + const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled(); + + const sal_Int32 nLastRow = nRow + nRowSpan; + const sal_Int32 nLastCol = nCol + nColSpan; + + if( (nLastRow > getRowCount()) || (nLastCol > getRowCount() ) ) + { + DBG_ERROR("TableModel::merge(), merge beyound the table!"); + } + + // merge first cell + CellRef xOriginCell( dynamic_cast< Cell* >( getCellByPosition( nCol, nRow ).get() ) ); + if( xOriginCell.is() ) + { + if( bUndo ) + xOriginCell->AddUndo(); + xOriginCell->merge( nColSpan, nRowSpan ); + } + + sal_Int32 nTempCol = nCol + 1; + + // merge remaining cells + for( ; nRow < nLastRow; nRow++ ) + { + for( ; nTempCol < nLastCol; nTempCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( getCellByPosition( nTempCol, nRow ).get() ) ); + if( xCell.is() && !xCell->isMerged() ) + { + if( bUndo ) + xCell->AddUndo(); + xCell->setMerged(); + xOriginCell->mergeContent( xCell ); + } + } + nTempCol = nCol; + } +} + + +// ----------------------------------------------------------------------------- + +void TableModel::updateRows() +{ + sal_Int32 nRow = 0; + RowVector::iterator iter = maRows.begin(); + while( iter != maRows.end() ) + { + (*iter++)->mnRow = nRow++; + } +} + +// ----------------------------------------------------------------------------- + +void TableModel::updateColumns() +{ + sal_Int32 nColumn = 0; + ColumnVector::iterator iter = maColumns.begin(); + while( iter != maColumns.end() ) + { + (*iter++)->mnColumn = nColumn++; + } +} + +// ----------------------------------------------------------------------------- + +} } diff --git a/svx/source/table/tablemodel.hxx b/svx/source/table/tablemodel.hxx new file mode 100644 index 000000000000..a1498c0041a6 --- /dev/null +++ b/svx/source/table/tablemodel.hxx @@ -0,0 +1,225 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLE_TABLEMODEL_HXX_ +#define _SVX_TABLE_TABLEMODEL_HXX_ + +#include <com/sun/star/util/XBroadcaster.hpp> +#include <com/sun/star/table/XTable.hpp> +#include <basegfx/range/b2irectangle.hxx> +#include <basegfx/tuple/b2ituple.hxx> +#include <cppuhelper/compbase2.hxx> +#include <comphelper/broadcasthelper.hxx> +#include <comphelper/listenernotification.hxx> +#include <tools/gen.hxx> +#include "celltypes.hxx" + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +class SdrTableObj; + +// ----------------------------------------------------------------------------- +// ICellRange +// ----------------------------------------------------------------------------- + +/** base class for each object implementing an XCellRange */ +class ICellRange +{ +public: + virtual sal_Int32 getLeft() = 0; + virtual sal_Int32 getTop() = 0; + virtual sal_Int32 getRight() = 0; + virtual sal_Int32 getBottom() = 0; + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XTable > getTable() = 0; +}; + +// ----------------------------------------------------------------------------- +// TableModel +// ----------------------------------------------------------------------------- + +typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::table::XTable, ::com::sun::star::util::XBroadcaster > TableModelBase; + +class TableModel : public TableModelBase, + public ::comphelper::OBaseMutex, + public ICellRange +{ + friend class InsertRowUndo; + friend class RemoveRowUndo; + friend class InsertColUndo; + friend class RemoveColUndo; + friend class TableColumnUndo; + friend class TableRowUndo; + friend class TableColumn; + friend class TableRow; + friend class TableRows; + friend class TableColumns; + friend class TableModelNotifyGuard; + +public: + TableModel( SdrTableObj* pTableObj ); + TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable ); + virtual ~TableModel(); + + void init( sal_Int32 nColumns, sal_Int32 nRows ); + + SdrTableObj* getSdrTableObj() const { return mpTableObj; } + + /** deletes rows and columns that are completly merged. Must be called between BegUndo/EndUndo! */ + void optimize(); + + /// merges the cell at the given position with the given span + void merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan ); + + // ICellRange + virtual sal_Int32 getLeft(); + virtual sal_Int32 getTop(); + virtual sal_Int32 getRight(); + virtual sal_Int32 getBottom(); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XTable > getTable(); + + // XTable + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellCursor > SAL_CALL createCursor( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellCursor > SAL_CALL createCursorByRange( const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange >& Range ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL getRowCount() throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Int32 SAL_CALL getColumnCount() 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); + + // XModifiable + virtual ::sal_Bool SAL_CALL isModified( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setModified( ::sal_Bool bModified ) throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException); + + // XModifyBroadcaster + virtual void SAL_CALL addModifyListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeModifyListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XModifyListener >& aListener ) throw (::com::sun::star::uno::RuntimeException); + + // XColumnRowRange + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XTableColumns > SAL_CALL getColumns() throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XTableRows > SAL_CALL getRows() throw (::com::sun::star::uno::RuntimeException); + + // XCellRange + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > SAL_CALL getCellByPosition( ::sal_Int32 nColumn, ::sal_Int32 nRow ) throw ( ::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByPosition( ::sal_Int32 nLeft, ::sal_Int32 nTop, ::sal_Int32 nRight, ::sal_Int32 nBottom ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByName( const ::rtl::OUString& aRange ) throw (::com::sun::star::uno::RuntimeException); + + // XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XFastPropertySet + virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XBroadcaster + virtual void SAL_CALL lockBroadcasts() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL unlockBroadcasts() throw (::com::sun::star::uno::RuntimeException); + +protected: + void notifyModification(); + + void insertColumns( sal_Int32 nIndex, sal_Int32 nCount ); + void removeColumns( sal_Int32 nIndex, sal_Int32 nCount ); + void insertRows( sal_Int32 nIndex, sal_Int32 nCount ); + void removeRows( sal_Int32 nIndex, sal_Int32 nCount ); + + sal_Int32 getRowCountImpl() const; + sal_Int32 getColumnCountImpl() const; + + CellRef createCell(); + CellRef getCell( ::sal_Int32 nCol, ::sal_Int32 nRow ) const; + + void UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount ); + void UndoRemoveRows( sal_Int32 nIndex, RowVector& aNewRows ); + + void UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount ); + void UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells ); + +private: + /** this function is called upon disposing the component + */ + virtual void SAL_CALL disposing(); + + TableRowRef getRow( sal_Int32 nRow ) const throw (::com::sun::star::lang::IndexOutOfBoundsException); + TableColumnRef getColumn( sal_Int32 nColumn ) const throw (::com::sun::star::lang::IndexOutOfBoundsException); + + void updateRows(); + void updateColumns(); + + RowVector maRows; + ColumnVector maColumns; + + TableColumnsRef mxTableColumns; + TableRowsRef mxTableRows; + + SdrTableObj* mpTableObj; + + sal_Bool mbModified; + bool mbNotifyPending; + + sal_Int32 mnNotifyLock; +}; + +class TableModelNotifyGuard +{ +public: + TableModelNotifyGuard( TableModel* pModel ) + : mxBroadcaster( static_cast< ::com::sun::star::util::XBroadcaster* >( pModel ) ) + { + if( mxBroadcaster.is() ) + mxBroadcaster->lockBroadcasts(); + } + + TableModelNotifyGuard( ::com::sun::star::uno::XInterface* pInterface ) + : mxBroadcaster( pInterface, ::com::sun::star::uno::UNO_QUERY ) + { + if( mxBroadcaster.is() ) + mxBroadcaster->lockBroadcasts(); + } + + ~TableModelNotifyGuard() + { + if( mxBroadcaster.is() ) + mxBroadcaster->unlockBroadcasts(); + } + +private: + com::sun::star::uno::Reference< ::com::sun::star::util::XBroadcaster > mxBroadcaster; +}; + +} } + +#endif diff --git a/svx/source/table/tablerow.cxx b/svx/source/table/tablerow.cxx new file mode 100644 index 000000000000..379d4beb37df --- /dev/null +++ b/svx/source/table/tablerow.cxx @@ -0,0 +1,381 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/lang/DisposedException.hpp> + +#include "cell.hxx" +#include "tablerow.hxx" +#include "tableundo.hxx" +#include "svx/svdmodel.hxx" +#include "svx/svdotable.hxx" + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::beans; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +const sal_Int32 Property_Height = 0; +const sal_Int32 Property_OptimalHeight = 1; +const sal_Int32 Property_IsVisible = 2; +const sal_Int32 Property_IsStartOfNewPage = 3; + +// ----------------------------------------------------------------------------- +// TableRow +// ----------------------------------------------------------------------------- + +TableRow::TableRow( const TableModelRef& xTableModel, sal_Int32 nRow, sal_Int32 nColumns ) +: TableRowBase( getStaticPropertySetInfo() ) +, mxTableModel( xTableModel ) +, mnRow( nRow ) +, mnHeight( 0 ) +, mbOptimalHeight( sal_True ) +, mbIsVisible( sal_True ) +, mbIsStartOfNewPage( sal_False ) +{ + if( nColumns < 20 ) + maCells.reserve( 20 ); + + if( nColumns ) + { + maCells.resize( nColumns ); + while( nColumns-- ) + maCells[ nColumns ] = mxTableModel->createCell(); + } +} + +// ----------------------------------------------------------------------------- + +TableRow::~TableRow() +{ +} + +// ----------------------------------------------------------------------------- + +void TableRow::dispose() +{ + mxTableModel.clear(); + if( !maCells.empty() ) + { + CellVector::iterator aIter( maCells.begin() ); + while( aIter != maCells.end() ) + (*aIter++)->dispose(); + CellVector().swap(maCells); + } +} + +// ----------------------------------------------------------------------------- + +void TableRow::throwIfDisposed() const throw (::com::sun::star::uno::RuntimeException) +{ + if( !mxTableModel.is() ) + throw DisposedException(); +} + +// ----------------------------------------------------------------------------- + +TableRow& TableRow::operator=( const TableRow& r ) +{ + mnHeight = r.mnHeight; + mbOptimalHeight = r.mbOptimalHeight; + mbIsVisible = r.mbIsVisible; + mbIsStartOfNewPage = r.mbIsStartOfNewPage; + maName = r.maName; + + return *this; +} + +// ----------------------------------------------------------------------------- + +void TableRow::insertColumns( sal_Int32 nIndex, sal_Int32 nCount, CellVector::iterator* pIter /* = 0 */ ) +{ + throwIfDisposed(); + if( nCount ) + { + if( nIndex >= static_cast< sal_Int32 >( maCells.size() ) ) + nIndex = static_cast< sal_Int32 >( maCells.size() ); + if ( pIter ) + maCells.insert( maCells.begin() + nIndex, *pIter, (*pIter) + nCount ); + else + { + maCells.reserve( maCells.size() + nCount ); + for ( sal_Int32 i = 0; i < nCount; i++ ) + maCells.insert( maCells.begin() + nIndex + i, mxTableModel->createCell() ); + } + } +} + +// ----------------------------------------------------------------------------- + +void TableRow::removeColumns( sal_Int32 nIndex, sal_Int32 nCount ) +{ + throwIfDisposed(); + if( (nCount >= 0) && ( nIndex >= 0) ) + { + if( (nIndex + nCount) < static_cast< sal_Int32 >( maCells.size() ) ) + { + CellVector::iterator aBegin( maCells.begin() ); + while( nIndex-- && (aBegin != maCells.end()) ) + aBegin++; + + if( nCount > 1 ) + { + CellVector::iterator aEnd( aBegin ); + while( nCount-- && (aEnd != maCells.end()) ) + aEnd++; + maCells.erase( aBegin, aEnd ); + } + else + { + maCells.erase( aBegin ); + } + } + else + { + maCells.resize( nIndex ); + } + } +} + +// ----------------------------------------------------------------------------- +// XCellRange +// ----------------------------------------------------------------------------- + +Reference< XCell > SAL_CALL TableRow::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (IndexOutOfBoundsException, RuntimeException) +{ + throwIfDisposed(); + if( nRow != 0 ) + throw IndexOutOfBoundsException(); + + return mxTableModel->getCellByPosition( nColumn, mnRow ); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL TableRow::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException) +{ + throwIfDisposed(); + if( (nLeft >= 0 ) && (nTop == 0) && (nRight >= nLeft) && (nBottom == 0) ) + { + return mxTableModel->getCellRangeByPosition( nLeft, mnRow, nRight, mnRow ); + } + throw IndexOutOfBoundsException(); +} + +// ----------------------------------------------------------------------------- + +Reference< XCellRange > SAL_CALL TableRow::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException) +{ + throwIfDisposed(); + return Reference< XCellRange >(); +} + +// ----------------------------------------------------------------------------- +// XNamed +// ----------------------------------------------------------------------------- + +OUString SAL_CALL TableRow::getName() throw (RuntimeException) +{ + return maName; +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableRow::setName( const OUString& aName ) throw (RuntimeException) +{ + maName = aName; +} + +// ----------------------------------------------------------------------------- +// XFastPropertySet +// ----------------------------------------------------------------------------- + +void SAL_CALL TableRow::setFastPropertyValue( sal_Int32 nHandle, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, RuntimeException) +{ + bool bOk = false; + bool bChange = false; + + TableRowUndo* pUndo = 0; + + SdrModel* pModel = mxTableModel->getSdrTableObj()->GetModel(); + + const bool bUndo = mxTableModel.is() && mxTableModel->getSdrTableObj() && mxTableModel->getSdrTableObj()->IsInserted() && pModel && pModel->IsUndoEnabled(); + + if( bUndo ) + { + TableRowRef xThis( this ); + pUndo = new TableRowUndo( xThis ); + } + + switch( nHandle ) + { + case Property_Height: + { + sal_Int32 nHeight = mnHeight; + bOk = aValue >>= nHeight; + if( bOk && (mnHeight != nHeight) ) + { + mnHeight = nHeight; + mbOptimalHeight = mnHeight == 0; + bChange = true; + } + break; + } + + case Property_OptimalHeight: + { + sal_Bool bOptimalHeight = mbOptimalHeight; + bOk = aValue >>= bOptimalHeight; + if( bOk && (mbOptimalHeight != bOptimalHeight) ) + { + mbOptimalHeight = bOptimalHeight; + if( bOptimalHeight ) + mnHeight = 0; + bChange = true; + } + break; + } + case Property_IsVisible: + { + sal_Bool bIsVisible = mbIsVisible; + bOk = aValue >>= bIsVisible; + if( bOk && (mbIsVisible != bIsVisible) ) + { + mbIsVisible = bIsVisible; + bChange = true; + } + break; + } + + case Property_IsStartOfNewPage: + { + sal_Bool bIsStartOfNewPage = mbIsStartOfNewPage; + bOk = aValue >>= bIsStartOfNewPage; + if( bOk && (mbIsStartOfNewPage != bIsStartOfNewPage) ) + { + mbIsStartOfNewPage = bIsStartOfNewPage; + bChange = true; + } + break; + } + default: + throw UnknownPropertyException(); + } + if( !bOk ) + throw IllegalArgumentException(); + + if( bChange ) + { + if( pUndo ) + { + pModel->AddUndo( pUndo ); + pUndo = 0; + } + mxTableModel->setModified(sal_True); + } + + if( pUndo ) + delete pUndo; +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL TableRow::getFastPropertyValue( sal_Int32 nHandle ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + switch( nHandle ) + { + case Property_Height: return Any( mnHeight ); + case Property_OptimalHeight: return Any( mbOptimalHeight ); + case Property_IsVisible: return Any( mbIsVisible ); + case Property_IsStartOfNewPage: return Any( mbIsStartOfNewPage ); + default: throw UnknownPropertyException(); + } +} + +// ----------------------------------------------------------------------------- + +rtl::Reference< ::comphelper::FastPropertySetInfo > TableRow::getStaticPropertySetInfo() +{ + static rtl::Reference< ::comphelper::FastPropertySetInfo > xInfo; + if( !xInfo.is() ) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if( !xInfo.is() ) + { + comphelper::PropertyVector aProperties(6); + + aProperties[0].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Height" ) ); + aProperties[0].Handle = Property_Height; + aProperties[0].Type = ::getCppuType((const sal_Int32*)0); + aProperties[0].Attributes = 0; + + aProperties[1].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "OptimalHeight" ) ); + aProperties[1].Handle = Property_OptimalHeight; + aProperties[1].Type = ::getBooleanCppuType(); + aProperties[1].Attributes = 0; + + aProperties[2].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsVisible" ) ); + aProperties[2].Handle = Property_IsVisible; + aProperties[2].Type = ::getBooleanCppuType(); + aProperties[2].Attributes = 0; + + aProperties[3].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsStartOfNewPage" ) ); + aProperties[3].Handle = Property_IsStartOfNewPage; + aProperties[3].Type = ::getBooleanCppuType(); + aProperties[3].Attributes = 0; + + aProperties[4].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Size" ) ); + aProperties[4].Handle = Property_Height; + aProperties[4].Type = ::getCppuType((const sal_Int32*)0); + aProperties[4].Attributes = 0; + + aProperties[5].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "OptimalSize" ) ); + aProperties[5].Handle = Property_OptimalHeight; + aProperties[5].Type = ::getBooleanCppuType(); + aProperties[5].Attributes = 0; + + xInfo.set( new ::comphelper::FastPropertySetInfo(aProperties) ); + } + } + + return xInfo; +} + +// ----------------------------------------------------------------------------- + + +} } diff --git a/svx/source/table/tablerow.hxx b/svx/source/table/tablerow.hxx new file mode 100644 index 000000000000..4d1009c8f6b8 --- /dev/null +++ b/svx/source/table/tablerow.hxx @@ -0,0 +1,92 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLEROW_HXX_ +#define _SVX_TABLEROW_HXX_ + +#include <com/sun/star/table/XCellRange.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <cppuhelper/implbase2.hxx> + +#include "propertyset.hxx" +#include "tablemodel.hxx" + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// TableRow +// ----------------------------------------------------------------------------- + +typedef ::cppu::ImplInheritanceHelper2< ::comphelper::FastPropertySet, ::com::sun::star::table::XCellRange, ::com::sun::star::container::XNamed > TableRowBase; + +class TableRow : public TableRowBase +{ + friend class TableModel; + friend class TableRowUndo; +public: + TableRow( const TableModelRef& xTableModel, sal_Int32 nRow, sal_Int32 nColumns ); + virtual ~TableRow(); + + void dispose(); + void throwIfDisposed() const throw (::com::sun::star::uno::RuntimeException); + + TableRow& operator=( const TableRow& ); + + void insertColumns( sal_Int32 nIndex, sal_Int32 nCount, CellVector::iterator* pIter = 0 ); + void removeColumns( sal_Int32 nIndex, sal_Int32 nCount ); + + // XCellRange + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > SAL_CALL getCellRangeByName( const ::rtl::OUString& aRange ) throw (::com::sun::star::uno::RuntimeException); + + // XNamed + virtual ::rtl::OUString SAL_CALL getName() throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setName( const ::rtl::OUString& aName ) throw (::com::sun::star::uno::RuntimeException); + + // XFastPropertySet + virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const ::com::sun::star::uno::Any& aValue ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + +private: + static rtl::Reference< ::comphelper::FastPropertySetInfo > getStaticPropertySetInfo(); + + TableModelRef mxTableModel; + CellVector maCells; + sal_Int32 mnRow; + sal_Int32 mnHeight; + sal_Bool mbOptimalHeight; + sal_Bool mbIsVisible; + sal_Bool mbIsStartOfNewPage; + ::rtl::OUString maName; +}; + +} } + +#endif diff --git a/svx/source/table/tablerows.cxx b/svx/source/table/tablerows.cxx new file mode 100644 index 000000000000..2b995dfa896d --- /dev/null +++ b/svx/source/table/tablerows.cxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <com/sun/star/lang/DisposedException.hpp> + +#include "cell.hxx" +#include "tablerow.hxx" +#include "tablerows.hxx" + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::table; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// TableRows +// ----------------------------------------------------------------------------- + +TableRows::TableRows( const TableModelRef& xTableModel ) +: mxTableModel( xTableModel ) +{ +} + +// ----------------------------------------------------------------------------- + +TableRows::~TableRows() +{ + dispose(); +} + +// ----------------------------------------------------------------------------- + +void TableRows::dispose() +{ + mxTableModel.clear(); +} + +// ----------------------------------------------------------------------------- + +void TableRows::throwIfDisposed() const throw (::com::sun::star::uno::RuntimeException) +{ + if( !mxTableModel.is() ) + throw DisposedException(); +} + +// ----------------------------------------------------------------------------- +// XTableRows +// ----------------------------------------------------------------------------- + +void SAL_CALL TableRows::insertByIndex( sal_Int32 nIndex, sal_Int32 nCount ) throw (RuntimeException) +{ + throwIfDisposed(); + mxTableModel->insertRows( nIndex, nCount ); +} + +// ----------------------------------------------------------------------------- + +void SAL_CALL TableRows::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount ) throw (RuntimeException) +{ + throwIfDisposed(); + mxTableModel->removeRows( nIndex, nCount ); +} + +// ----------------------------------------------------------------------------- +// XIndexAccess +// ----------------------------------------------------------------------------- + +sal_Int32 SAL_CALL TableRows::getCount() throw (RuntimeException) +{ + throwIfDisposed(); + return mxTableModel->getRowCount(); +} + +// ----------------------------------------------------------------------------- + +Any SAL_CALL TableRows::getByIndex( sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException) +{ + throwIfDisposed(); + return Any( Reference< XCellRange >( static_cast< XCellRange* >( mxTableModel->getRow( Index ).get() ) ) ); +} + +// ----------------------------------------------------------------------------- +// XElementAccess +// ----------------------------------------------------------------------------- + +Type SAL_CALL TableRows::getElementType() throw (RuntimeException) +{ + throwIfDisposed(); + return XCellRange::static_type(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool SAL_CALL TableRows::hasElements() throw (RuntimeException) +{ + throwIfDisposed(); + return mxTableModel->getRowCount() != 0; +} + +// ----------------------------------------------------------------------------- + +} } diff --git a/svx/source/table/tablerows.hxx b/svx/source/table/tablerows.hxx new file mode 100644 index 000000000000..47d5b19832f0 --- /dev/null +++ b/svx/source/table/tablerows.hxx @@ -0,0 +1,71 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLEROWS_HXX_ +#define _SVX_TABLEROWS_HXX_ + +#include <com/sun/star/table/XTableRows.hpp> +#include <cppuhelper/implbase1.hxx> + +#include "tablemodel.hxx" + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +// ----------------------------------------------------------------------------- +// TableRows +// ----------------------------------------------------------------------------- + +class TableRows : public ::cppu::WeakAggImplHelper1< ::com::sun::star::table::XTableRows > +{ +public: + TableRows( const TableModelRef& xTableModel ); + virtual ~TableRows(); + + void dispose(); + void throwIfDisposed() const throw (::com::sun::star::uno::RuntimeException); + + // XTableRows + virtual void SAL_CALL insertByIndex( sal_Int32 nIndex, sal_Int32 nCount ) throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeByIndex( sal_Int32 nIndex, sal_Int32 nCount ) throw (::com::sun::star::uno::RuntimeException); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getByIndex( sal_Int32 Index ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // Methods + virtual ::com::sun::star::uno::Type SAL_CALL getElementType() throw (::com::sun::star::uno::RuntimeException); + virtual ::sal_Bool SAL_CALL hasElements() throw (::com::sun::star::uno::RuntimeException); + +private: + TableModelRef mxTableModel; +}; + +} } + +#endif diff --git a/svx/source/table/tablertfexporter.cxx b/svx/source/table/tablertfexporter.cxx new file mode 100644 index 000000000000..d155e084fff8 --- /dev/null +++ b/svx/source/table/tablertfexporter.cxx @@ -0,0 +1,284 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <vector> + +#include <com/sun/star/table/XTable.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> + +#include <tools/stream.hxx> +#include <svtools/rtfkeywd.hxx> +#include <svtools/rtfout.hxx> + +#include <editeng/eeitem.hxx> +#include <svx/sdtaitm.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> + +#include "cell.hxx" +#include "celltypes.hxx" +#include "svx/svdotable.hxx" +#include "svx/svdoutl.hxx" +#include "editeng/editeng.hxx" +#include "editeng/outlobj.hxx" + +//#include <tablertfexporter.hxx> + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; + +namespace sdr { namespace table { + +class SdrTableRtfExporter +{ +public: + SdrTableRtfExporter( SvStream& rStrmP, SdrTableObj& rObj ); + ULONG Write(); + void WriteRow( const Reference< XPropertySet >& xRowSet, sal_Int32 nRow, const std::vector< sal_Int32 >& aColumnStart ); + void WriteCell( sal_Int32 nCol, sal_Int32 nRow ); + +private: + SvStream& mrStrm; + SdrTableObj& mrObj; + Reference< XTable > mxTable; + const OUString msSize; +}; + +void SdrTableObj::ExportAsRTF( SvStream& rStrm, SdrTableObj& rObj ) +{ + SdrTableRtfExporter aEx( rStrm, rObj ); + aEx.Write(); +} + +SdrTableRtfExporter::SdrTableRtfExporter( SvStream& rStrm, SdrTableObj& rObj ) +: mrStrm( rStrm ) +, mrObj( rObj ) +, mxTable( rObj.getTable() ) +, msSize( RTL_CONSTASCII_USTRINGPARAM("Size") ) +{ +} + +long HundMMToTwips( long nIn ) +{ + long nRet = OutputDevice::LogicToLogic( nIn, MAP_100TH_MM, MAP_TWIP ); + return nRet; +} + +ULONG SdrTableRtfExporter::Write() +{ + mrStrm << '{' << OOO_STRING_SVTOOLS_RTF_RTF; + mrStrm << OOO_STRING_SVTOOLS_RTF_ANSI << RTFOutFuncs::sNewLine; + + Reference< XTableColumns > xColumns( mxTable->getColumns() ); + const sal_Int32 nColCount = xColumns->getCount(); + + std::vector< sal_Int32 > aColumnStart; + aColumnStart.reserve( nColCount ); + + // determine right offset of cells + sal_Int32 nPos = 0; + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) try + { + Reference< XPropertySet > xSet( xColumns->getByIndex(nCol), UNO_QUERY_THROW ); + sal_Int32 nWidth = 0; + xSet->getPropertyValue( msSize ) >>= nWidth; + nPos += HundMMToTwips( nWidth ); + aColumnStart.push_back( nPos ); + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("SdrTableRtfExporter::Write(), exception caught!"); + } + + // export rows + Reference< XTableRows > xRows( mxTable->getRows() ); + const sal_Int32 nRowCount = xRows->getCount(); + + for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ ) try + { + Reference< XPropertySet > xRowSet( xRows->getByIndex(nRow), UNO_QUERY_THROW ); + WriteRow( xRowSet, nRow, aColumnStart ); + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("SdrTableRtfExporter::Write(), exception caught!"); + } + + mrStrm << '}' << RTFOutFuncs::sNewLine; + return mrStrm.GetError(); +} + +void SdrTableRtfExporter::WriteRow( const Reference< XPropertySet >& xRowSet, sal_Int32 nRow, const std::vector< sal_Int32 >& aColumnStart ) +{ + sal_Int32 nRowHeight = 0; + xRowSet->getPropertyValue( msSize ) >>= nRowHeight; + + mrStrm << OOO_STRING_SVTOOLS_RTF_TROWD << OOO_STRING_SVTOOLS_RTF_TRGAPH << "30" << OOO_STRING_SVTOOLS_RTF_TRLEFT << "-30"; + mrStrm << OOO_STRING_SVTOOLS_RTF_TRRH << ByteString::CreateFromInt32( nRowHeight ).GetBuffer(); + + const sal_Int32 nColCount = mxTable->getColumnCount(); + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) + { + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + + if( !xCell.is() ) + continue; + +/* + const sal_Bool bIsMerged = xCell->isMerged(); + const sal_Int32 nRowSpan = xCell->getRowSpan(); + const sal_Int32 nColSpan = xCell->getColumnSpan(); + + const sal_Char* pChar; + + if( !bIsMerged && ((nRowSpan > 1) || (nColSpan > 1)) ) + mrStrm << OOO_STRING_SVTOOLS_RTF_CLMGF; // The first cell in a range of table cells to be merged. + + SdrTextVertAdjust eVAdj = xCell->GetTextVerticalAdjust(); + switch( eVAdj ) + { + case SVX_VER_JUSTIFY_TOP: pChar = OOO_STRING_SVTOOLS_RTF_CLVERTALT; break; + case SVX_VER_JUSTIFY_CENTER: pChar = OOO_STRING_SVTOOLS_RTF_CLVERTALC; break; + case SVX_VER_JUSTIFY_BOTTOM: pChar = OOO_STRING_SVTOOLS_RTF_CLVERTALB; break; + case SVX_VER_JUSTIFY_STANDARD: pChar = OOO_STRING_SVTOOLS_RTF_CLVERTALB; break; //! Bottom + default: pChar = NULL; break; + } + if ( pChar ) + mrStrm << pChar; +*/ + mrStrm << OOO_STRING_SVTOOLS_RTF_CELLX << ByteString::CreateFromInt32( aColumnStart[nCol] ).GetBuffer(); + if ( (nCol & 0x0F) == 0x0F ) + mrStrm << RTFOutFuncs::sNewLine; // Zeilen nicht zu lang werden lassen + } + mrStrm << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_PLAIN << OOO_STRING_SVTOOLS_RTF_INTBL << RTFOutFuncs::sNewLine; + + ULONG nStrmPos = mrStrm.Tell(); + for( sal_Int32 nCol = 0; nCol < nColCount; nCol++ ) + { + WriteCell( nCol, nRow ); + if ( mrStrm.Tell() - nStrmPos > 255 ) + { + mrStrm << RTFOutFuncs::sNewLine; + nStrmPos = mrStrm.Tell(); + } + } + mrStrm << OOO_STRING_SVTOOLS_RTF_ROW << RTFOutFuncs::sNewLine; +} + + +void SdrTableRtfExporter::WriteCell( sal_Int32 nCol, sal_Int32 nRow ) +{ + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + + if( !xCell.is() || xCell->isMerged() ) + { + mrStrm << OOO_STRING_SVTOOLS_RTF_CELL; + return ; + } + + String aContent; + + OutlinerParaObject* pParaObj = xCell->GetEditOutlinerParaObject(); + bool bOwnParaObj = pParaObj != 0; + + if( pParaObj == 0 ) + pParaObj = xCell->GetOutlinerParaObject(); + + if(pParaObj) + { + // handle outliner attributes + SdrOutliner& rOutliner = mrObj.ImpGetDrawOutliner(); + rOutliner.SetText(*pParaObj); + + aContent = rOutliner.GetEditEngine().GetText( LINEEND_LF ); + + rOutliner.Clear(); + + if( bOwnParaObj ) + delete pParaObj; + } + + bool bResetPar, bResetAttr; + bResetPar = bResetAttr = FALSE; + + SdrTextHorzAdjust eHAdj = xCell->GetTextHorizontalAdjust(); + + const SfxItemSet& rCellSet = xCell->GetItemSet(); + + const SvxWeightItem& rWeightItem = (const SvxWeightItem&) rCellSet.Get( EE_CHAR_WEIGHT ); + const SvxPostureItem& rPostureItem = (const SvxPostureItem&) rCellSet.Get( EE_CHAR_ITALIC ); + const SvxUnderlineItem& rUnderlineItem = (const SvxUnderlineItem&) rCellSet.Get( EE_CHAR_UNDERLINE ); + + const sal_Char* pChar; + + switch( eHAdj ) + { + case SDRTEXTHORZADJUST_CENTER: pChar = OOO_STRING_SVTOOLS_RTF_QC; break; + case SDRTEXTHORZADJUST_BLOCK: pChar = OOO_STRING_SVTOOLS_RTF_QJ; break; + case SDRTEXTHORZADJUST_RIGHT: pChar = OOO_STRING_SVTOOLS_RTF_QR; break; + case SDRTEXTHORZADJUST_LEFT: + default: pChar = OOO_STRING_SVTOOLS_RTF_QL; break; + } + mrStrm << pChar; + + if ( rWeightItem.GetWeight() >= WEIGHT_BOLD ) + { // bold + bResetAttr = true; + mrStrm << OOO_STRING_SVTOOLS_RTF_B; + } + if ( rPostureItem.GetPosture() != ITALIC_NONE ) + { // italic + bResetAttr = true; + mrStrm << OOO_STRING_SVTOOLS_RTF_I; + } + if ( rUnderlineItem.GetLineStyle() != UNDERLINE_NONE ) + { // underline + bResetAttr = true; + mrStrm << OOO_STRING_SVTOOLS_RTF_UL; + } + + mrStrm << ' '; + RTFOutFuncs::Out_String( mrStrm, aContent ); + mrStrm << OOO_STRING_SVTOOLS_RTF_CELL; + + if ( bResetPar ) + mrStrm << OOO_STRING_SVTOOLS_RTF_PARD << OOO_STRING_SVTOOLS_RTF_INTBL; + if ( bResetAttr ) + mrStrm << OOO_STRING_SVTOOLS_RTF_PLAIN; +} + +} } + diff --git a/svx/source/table/tablertfimporter.cxx b/svx/source/table/tablertfimporter.cxx new file mode 100644 index 000000000000..359089444210 --- /dev/null +++ b/svx/source/table/tablertfimporter.cxx @@ -0,0 +1,447 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include <vector> +#include <boost/shared_ptr.hpp> + +#include <com/sun/star/table/XTable.hpp> + +#include <tools/stream.hxx> +#include <svtools/rtftoken.h> + +#include <editeng/eeitem.hxx> +#include <svx/svdetc.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/outlobj.hxx> + +#include "cell.hxx" +#include "celltypes.hxx" +#include "svx/svdotable.hxx" +#include "svx/svdoutl.hxx" +#include "editeng/editeng.hxx" +#include "editeng/editdata.hxx" +#include "svx/svdmodel.hxx" +#include "editeng/svxrtf.hxx" + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; + +namespace sdr { namespace table { + +struct RTFCellDefault +{ + SfxItemSet maItemSet; + sal_Int32 mnCol; + USHORT mnTwips; // right border of the cell + sal_Int32 mnColSpan; // MergeCell if >1, merged cells if 0 + + RTFCellDefault( SfxItemPool* pPool ) : maItemSet( *pPool ), mnCol(0), mnTwips(0 ), mnColSpan(1) {} +}; + +typedef std::vector< boost::shared_ptr< RTFCellDefault > > RTFCellDefaultVector; + +struct RTFCellInfo +{ + SfxItemSet maItemSet; + sal_Int32 mnStartPara; + sal_Int32 mnParaCount; + sal_Int32 mnColSpan; + + RTFCellInfo( SfxItemPool& rPool ) : maItemSet( rPool ), mnStartPara(0), mnParaCount(0), mnColSpan(0) {} +}; + +typedef boost::shared_ptr< RTFCellInfo > RTFCellInfoPtr; +typedef std::vector< RTFCellInfoPtr > RTFColumnVector; + +typedef boost::shared_ptr< RTFColumnVector > RTFColumnVectorPtr; + +typedef std::vector< RTFColumnVectorPtr > RTFRowVector; + +class SdrTableRTFParser +{ +public: + SdrTableRTFParser( SdrTableObj& rTableObj ); + ~SdrTableRTFParser(); + + void Read( SvStream& rStream ); + + void ProcToken( ImportInfo* pInfo ); + + void NextRow(); + void NextColumn(); + void NewCellRow(); + + void InsertCell( ImportInfo* pInfo ); + + void FillTable(); + + DECL_LINK( RTFImportHdl, ImportInfo* ); + +private: + SdrTableObj& mrTableObj; + SdrOutliner* mpOutliner; + SfxItemPool& mrItemPool; + + RTFCellDefaultVector maDefaultList; + RTFCellDefaultVector::iterator maDefaultIterator; + + int mnLastToken; + sal_Int32 mnLastWidth; + bool mbNewDef; + + USHORT mnStartPara; + + sal_Int32 mnColCnt; + sal_Int32 mnRowCnt; + sal_Int32 mnColMax; + + std::vector< sal_Int32 > maColumnEdges; + + RTFRowVector maRows; + + RTFCellDefault* mpInsDefault; + RTFCellDefault* mpActDefault; + RTFCellDefault* mpDefMerge; + + Reference< XTable > mxTable; +}; + +SdrTableRTFParser::SdrTableRTFParser( SdrTableObj& rTableObj ) +: mrTableObj( rTableObj ) +, mpOutliner( SdrMakeOutliner( OUTLINERMODE_TEXTOBJECT, rTableObj.GetModel() ) ) +, mrItemPool( rTableObj.GetModel()->GetItemPool() ) +, mnLastToken( 0 ) +, mnLastWidth( 0 ) +, mbNewDef( false ) +, mnStartPara( 0 ) +, mnColCnt( 0 ) +, mnRowCnt( 0 ) +, mnColMax( 0 ) +, mpActDefault( 0 ) +, mpDefMerge( 0 ) +, mxTable( rTableObj.getTable() ) +{ + mpOutliner->SetUpdateMode(TRUE); + mpOutliner->SetStyleSheet( 0, mrTableObj.GetStyleSheet() ); + mpInsDefault = new RTFCellDefault( &mrItemPool ); +} + +SdrTableRTFParser::~SdrTableRTFParser() +{ + delete mpOutliner; + delete mpInsDefault; +} + +void SdrTableRTFParser::Read( SvStream& rStream ) +{ + EditEngine& rEdit = const_cast< EditEngine& >( mpOutliner->GetEditEngine() ); + + Link aOldLink( rEdit.GetImportHdl() ); + rEdit.SetImportHdl( LINK( this, SdrTableRTFParser, RTFImportHdl ) ); + mpOutliner->Read( rStream, String(), EE_FORMAT_RTF ); + rEdit.SetImportHdl( aOldLink ); + + FillTable(); +} + +IMPL_LINK( SdrTableRTFParser, RTFImportHdl, ImportInfo*, pInfo ) +{ + switch ( pInfo->eState ) + { + case RTFIMP_NEXTTOKEN: + ProcToken( pInfo ); + break; + case RTFIMP_UNKNOWNATTR: + ProcToken( pInfo ); + break; + case RTFIMP_START: + { + SvxRTFParser* pParser = (SvxRTFParser*) pInfo->pParser; + pParser->SetAttrPool( &mrItemPool ); + RTFPardAttrMapIds& rMap = pParser->GetPardMap(); + rMap.nBox = SDRATTR_TABLE_BORDER; + } + break; + case RTFIMP_END: + if ( pInfo->aSelection.nEndPos ) + { + mpActDefault = NULL; + pInfo->nToken = RTF_PAR; + pInfo->aSelection.nEndPara++; + ProcToken( pInfo ); + } + break; + case RTFIMP_SETATTR: + break; + case RTFIMP_INSERTTEXT: + break; + case RTFIMP_INSERTPARA: + break; + default: + DBG_ERRORFILE("unknown ImportInfo.eState"); + } + return 0; +} + +void SdrTableRTFParser::NextRow() +{ + ++mnRowCnt; +} + +void SdrTableRTFParser::InsertCell( ImportInfo* pInfo ) +{ + sal_Int32 nCol = mpActDefault->mnCol; + + RTFCellInfoPtr xCellInfo( new RTFCellInfo(mrItemPool) ); + + xCellInfo->mnStartPara = mnStartPara; + xCellInfo->mnParaCount = pInfo->aSelection.nEndPara - 1 - mnStartPara; + + if( !maRows.empty() ) + { + RTFColumnVectorPtr xColumn( maRows.back() ); + + if( xColumn->size() <= (size_t)nCol ) + xColumn->resize( nCol+1 ); + + (*xColumn)[nCol] = xCellInfo; + } + + mnStartPara = pInfo->aSelection.nEndPara - 1; +} + +void SdrTableRTFParser::FillTable() +{ + try + { + sal_Int32 nColCount = mxTable->getColumnCount(); + Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_QUERY_THROW ); + + if( nColCount < mnColMax ) + { + xCols->insertByIndex( nColCount, mnColMax - nColCount ); + nColCount = mxTable->getColumnCount(); + } + + const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM("Width") ); + sal_Int32 nCol, nLastEdge = 0; + for( nCol = 0; nCol < nColCount; nCol++ ) + { + Reference< XPropertySet > xSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW ); + sal_Int32 nWidth = maColumnEdges[nCol] - nLastEdge; + + xSet->setPropertyValue( sWidth, Any( nWidth ) ); + nLastEdge += nWidth; + } + + const sal_Int32 nRowCount = mxTable->getRowCount(); + if( nRowCount < mnRowCnt ) + { + Reference< XTableRows > xRows( mxTable->getRows(), UNO_QUERY_THROW ); + xRows->insertByIndex( nRowCount, mnRowCnt - nRowCount ); + } + + for( sal_Int32 nRow = 0; nRow < (sal_Int32)maRows.size(); nRow++ ) + { + RTFColumnVectorPtr xColumn( maRows[nRow] ); + for( nCol = 0; nCol < (sal_Int32)xColumn->size(); nCol++ ) + { + RTFCellInfoPtr xCellInfo( (*xColumn)[nCol] ); + + CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) ); + if( xCell.is() && xCellInfo.get() ) + { + const SfxPoolItem *pPoolItem = 0; + if( xCellInfo->maItemSet.GetItemState(SDRATTR_TABLE_BORDER,FALSE,&pPoolItem)==SFX_ITEM_SET) + xCell->SetMergedItem( *pPoolItem ); + + String sDebug = mpOutliner->GetText( mpOutliner->GetParagraph( xCellInfo->mnStartPara ), xCellInfo->mnParaCount ); + + OutlinerParaObject* pTextObject = mpOutliner->CreateParaObject( (USHORT)xCellInfo->mnStartPara, (USHORT)xCellInfo->mnParaCount ); + if( pTextObject ) + { + SdrOutliner& rOutliner=mrTableObj.ImpGetDrawOutliner(); + rOutliner.SetUpdateMode(TRUE); + rOutliner.SetText( *pTextObject ); + mrTableObj.NbcSetOutlinerParaObjectForText( rOutliner.CreateParaObject(), xCell.get() ); + delete pTextObject; + } + } + } + } + + Rectangle aRect( mrTableObj.GetSnapRect() ); + aRect.nRight = aRect.nLeft + nLastEdge; + mrTableObj.NbcSetSnapRect( aRect ); + + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("sdr::table::SdrTableRTFParser::InsertCell(), exception caught!" ); + } +} + +void SdrTableRTFParser::NewCellRow() +{ + if( mbNewDef ) + { + mbNewDef = FALSE; + + maRows.push_back( RTFColumnVectorPtr( new RTFColumnVector() ) ); + } + mpDefMerge = NULL; + maDefaultIterator = maDefaultList.begin(); + + NextColumn(); + + DBG_ASSERT( mpActDefault, "NewCellRow: pActDefault==0" ); +} + +void SdrTableRTFParser::NextColumn() +{ + if( maDefaultIterator != maDefaultList.end() ) + mpActDefault = (*maDefaultIterator++).get(); + else + mpActDefault = 0; +} + +long TwipsToHundMM( long nIn ) +{ + long nRet = OutputDevice::LogicToLogic( nIn, MAP_TWIP, MAP_100TH_MM ); + return nRet; +} + +void SdrTableRTFParser::ProcToken( ImportInfo* pInfo ) +{ + switch ( pInfo->nToken ) + { + case RTF_TROWD: // denotes table row defauls, before RTF_CELLX + { + mnColCnt = 0; + maDefaultList.clear(); + mpDefMerge = NULL; + mnLastToken = pInfo->nToken; + } + break; + case RTF_CLMGF: // The first cell of cells to be merged + { + mpDefMerge = mpInsDefault; + mnLastToken = pInfo->nToken; + } + break; + case RTF_CLMRG: // A cell to be merged with the preceding cell + { + if ( !mpDefMerge ) + mpDefMerge = maDefaultList.back().get(); + DBG_ASSERT( mpDefMerge, "RTF_CLMRG: pDefMerge==0" ); + if( mpDefMerge ) + mpDefMerge->mnColSpan++; + mpInsDefault->mnColSpan = 0; + mnLastToken = pInfo->nToken; + } + break; + case RTF_CELLX: // closes cell default + { + mbNewDef = TRUE; + mpInsDefault->mnCol = mnColCnt; + maDefaultList.push_back( boost::shared_ptr< RTFCellDefault >( mpInsDefault ) ); + + if( (sal_Int32)maColumnEdges.size() <= mnColCnt ) + maColumnEdges.resize( mnColCnt + 1 ); + + const sal_Int32 nSize = TwipsToHundMM( pInfo->nTokenValue ); + maColumnEdges[mnColCnt] = std::max( maColumnEdges[mnColCnt], nSize ); + + mpInsDefault = new RTFCellDefault( &mrItemPool ); + if ( ++mnColCnt > mnColMax ) + mnColMax = mnColCnt; + mnLastToken = pInfo->nToken; + } + break; + case RTF_INTBL: // before the first RTF_CELL + { + if ( mnLastToken != RTF_INTBL && mnLastToken != RTF_CELL && mnLastToken != RTF_PAR ) + { + NewCellRow(); + mnLastToken = pInfo->nToken; + } + } + break; + case RTF_CELL: // denotes the end of a cell. + { + DBG_ASSERT( mpActDefault, "RTF_CELL: pActDefault==0" ); + if ( mbNewDef || !mpActDefault ) + NewCellRow(); + if ( !mpActDefault ) + mpActDefault = mpInsDefault; + if ( mpActDefault->mnColSpan > 0 ) + { + InsertCell(pInfo); + } + NextColumn(); + mnLastToken = pInfo->nToken; + } + break; + case RTF_ROW: // means the end of a row + { + NextRow(); + mnLastToken = pInfo->nToken; + } + break; + case RTF_PAR: // Paragraph + mnLastToken = pInfo->nToken; + break; + default: + { // do not set nLastToken + switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) ) + { + case RTF_SHADINGDEF: +// ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(pInfo->nToken, mpInsDefault->maItemSet, TRUE ); + break; + case RTF_BRDRDEF: + ((SvxRTFParser*)pInfo->pParser)->ReadBorderAttr(pInfo->nToken, mpInsDefault->maItemSet, TRUE ); + break; + } + } + } +} + +void SdrTableObj::ImportAsRTF( SvStream& rStream, SdrTableObj& rObj ) +{ + SdrTableRTFParser aParser( rObj ); + aParser.Read( rStream ); +} + +} } + diff --git a/svx/source/table/tableundo.cxx b/svx/source/table/tableundo.cxx new file mode 100644 index 000000000000..d57be9f0994d --- /dev/null +++ b/svx/source/table/tableundo.cxx @@ -0,0 +1,559 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include "svx/sdr/properties/textproperties.hxx" +#include "editeng/outlobj.hxx" + +#include "cell.hxx" +#include "tableundo.hxx" +#include "svx/svdotable.hxx" +#include "tablerow.hxx" +#include "tablecolumn.hxx" + + +// ----------------------------------------------------------------------------- + +using ::rtl::OUString; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +CellUndo::CellUndo( const SdrObjectWeakRef& xObjRef, const CellRef& xCell ) +: SdrUndoAction( *xCell->GetModel() ) +, mxObjRef( xObjRef ) +, mxCell( xCell ) +, mbUndo( true ) +{ + if( mxCell.is() && mxObjRef.is() ) + { + getDataFromCell( maUndoData ); + mxObjRef->AddObjectUser( *this ); + } +} + +CellUndo::~CellUndo() +{ + if( mxObjRef.is() ) + mxObjRef->RemoveObjectUser( *this ); + dispose(); +} + +void CellUndo::dispose() +{ + mxCell.clear(); + delete maUndoData.mpProperties; + maUndoData.mpProperties = 0; + delete maRedoData.mpProperties; + maRedoData.mpProperties = 0; + delete maUndoData.mpOutlinerParaObject; + maUndoData.mpOutlinerParaObject = 0; + delete maRedoData.mpOutlinerParaObject; + maRedoData.mpOutlinerParaObject = 0; +} + +void CellUndo::ObjectInDestruction(const SdrObject& ) +{ + dispose(); +} + +void CellUndo::Undo() +{ + if( mxCell.is() && mbUndo ) + { + if( maRedoData.mpProperties == 0 ) + getDataFromCell( maRedoData ); + + setDataToCell( maUndoData ); + mbUndo = false; + } +} + +void CellUndo::Redo() +{ + if( mxCell.is() && !mbUndo ) + { + setDataToCell( maRedoData ); + mbUndo = true; + } +} + +BOOL CellUndo::Merge( SfxUndoAction *pNextAction ) +{ + CellUndo* pNext = dynamic_cast< CellUndo* >( pNextAction ); + if( pNext && pNext->mxCell.get() == mxCell.get() ) + { + return TRUE; + } + else + { + return FALSE; + } +} + +void CellUndo::setDataToCell( const Data& rData ) +{ + delete mxCell->mpProperties; + if( rData.mpProperties ) + mxCell->mpProperties = Cell::CloneProperties( rData.mpProperties, *mxObjRef.get(), *mxCell.get() ); + else + mxCell->mpProperties = 0; + + if( rData.mpOutlinerParaObject ) + mxCell->SetOutlinerParaObject( new OutlinerParaObject(*rData.mpOutlinerParaObject) ); + else + mxCell->RemoveOutlinerParaObject(); + + mxCell->msFormula = rData.msFormula; + mxCell->mfValue = rData.mfValue; + mxCell->mnError = rData.mnError; + mxCell->mbMerged = rData.mbMerged; + mxCell->mnRowSpan = rData.mnRowSpan; + mxCell->mnColSpan = rData.mnColSpan; + + if( mxObjRef.is() ) + mxObjRef->ActionChanged(); +} + +void CellUndo::getDataFromCell( Data& rData ) +{ + if( mxObjRef.is() && mxCell.is() ) + { + if( mxCell->mpProperties ) + rData.mpProperties = mxCell->CloneProperties( *mxObjRef.get(), *mxCell.get()); + + if( mxCell->GetOutlinerParaObject() ) + rData.mpOutlinerParaObject = new OutlinerParaObject(*mxCell->GetOutlinerParaObject()); + else + rData.mpOutlinerParaObject = 0; + + rData.mnCellContentType = mxCell->mnCellContentType; + + rData.msFormula = mxCell->msFormula; + rData.mfValue = mxCell->mfValue; + rData.mnError = mxCell->mnError; + rData.mbMerged = mxCell->mbMerged; + rData.mnRowSpan = mxCell->mnRowSpan; + rData.mnColSpan = mxCell->mnColSpan; + } +} + +// ----------------------------------------------------------------------------- +// class InsertRowUndo : public SdrUndoAction +// ----------------------------------------------------------------------------- + +static void Dispose( RowVector& rRows ) +{ + RowVector::iterator aIter( rRows.begin() ); + while( aIter != rRows.end() ) + (*aIter++)->dispose(); +} + +// ----------------------------------------------------------------------------- + +InsertRowUndo::InsertRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aNewRows ) +: SdrUndoAction( *xTable->getSdrTableObj()->GetModel() ) +, mxTable( xTable ) +, mnIndex( nIndex ) +, mbUndo( true ) +{ + maRows.swap( aNewRows ); +} + +// ----------------------------------------------------------------------------- + +InsertRowUndo::~InsertRowUndo() +{ + if( !mbUndo ) + Dispose( maRows ); +} + +// ----------------------------------------------------------------------------- + +void InsertRowUndo::Undo() +{ + if( mxTable.is() ) + { + mxTable->UndoInsertRows( mnIndex, sal::static_int_cast< sal_Int32 >( maRows.size() ) ); + mbUndo = false; + } +} + +// ----------------------------------------------------------------------------- + +void InsertRowUndo::Redo() +{ + if( mxTable.is() ) + { + mxTable->UndoRemoveRows( mnIndex, maRows ); + mbUndo = true; + } +} + +// ----------------------------------------------------------------------------- +// class RemoveRowUndo : public SdrUndoAction +// ----------------------------------------------------------------------------- + +RemoveRowUndo::RemoveRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aRemovedRows ) +: SdrUndoAction( *xTable->getSdrTableObj()->GetModel() ) +, mxTable( xTable ) +, mnIndex( nIndex ) +, mbUndo( true ) +{ + maRows.swap( aRemovedRows ); +} + +// ----------------------------------------------------------------------------- + +RemoveRowUndo::~RemoveRowUndo() +{ + if( mbUndo ) + Dispose( maRows ); +} + +// ----------------------------------------------------------------------------- + +void RemoveRowUndo::Undo() +{ + if( mxTable.is() ) + { + mxTable->UndoRemoveRows( mnIndex, maRows ); + mbUndo = false; + } +} + +// ----------------------------------------------------------------------------- + +void RemoveRowUndo::Redo() +{ + if( mxTable.is() ) + { + mxTable->UndoInsertRows( mnIndex, sal::static_int_cast< sal_Int32 >( maRows.size() ) ); + mbUndo = true; + } +} + +// ----------------------------------------------------------------------------- +// class InsertColUndo : public SdrUndoAction +// ----------------------------------------------------------------------------- + +static void Dispose( ColumnVector& rCols ) +{ + ColumnVector::iterator aIter( rCols.begin() ); + while( aIter != rCols.end() ) + (*aIter++)->dispose(); +} + +// ----------------------------------------------------------------------------- + +static void Dispose( CellVector& rCells ) +{ + CellVector::iterator aIter( rCells.begin() ); + while( aIter != rCells.end() ) + (*aIter++)->dispose(); +} + +// ----------------------------------------------------------------------------- + +InsertColUndo::InsertColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells ) +: SdrUndoAction( *xTable->getSdrTableObj()->GetModel() ) +, mxTable( xTable ) +, mnIndex( nIndex ) +, mbUndo( true ) +{ + maColumns.swap( aNewCols ); + maCells.swap( aCells ); +} + +// ----------------------------------------------------------------------------- + +InsertColUndo::~InsertColUndo() +{ + if( !mbUndo ) + { + Dispose( maColumns ); + Dispose( maCells ); + } +} + +// ----------------------------------------------------------------------------- + +void InsertColUndo::Undo() +{ + if( mxTable.is() ) + { + mxTable->UndoInsertColumns( mnIndex, sal::static_int_cast< sal_Int32 >( maColumns.size() ) ); + mbUndo = false; + } +} + +// ----------------------------------------------------------------------------- + +void InsertColUndo::Redo() +{ + if( mxTable.is() ) + { + mxTable->UndoRemoveColumns( mnIndex, maColumns, maCells ); + mbUndo = true; + } +} + +// ----------------------------------------------------------------------------- +// class RemoveColUndo : public SdrUndoAction +// ----------------------------------------------------------------------------- + +RemoveColUndo::RemoveColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells ) +: SdrUndoAction( *xTable->getSdrTableObj()->GetModel() ) +, mxTable( xTable ) +, mnIndex( nIndex ) +, mbUndo( true ) +{ + maColumns.swap( aNewCols ); + maCells.swap( aCells ); +} + +// ----------------------------------------------------------------------------- + +RemoveColUndo::~RemoveColUndo() +{ + if( mbUndo ) + { + Dispose( maColumns ); + Dispose( maCells ); + } +} + +// ----------------------------------------------------------------------------- + +void RemoveColUndo::Undo() +{ + if( mxTable.is() ) + { + mxTable->UndoRemoveColumns( mnIndex, maColumns, maCells ); + mbUndo = false; + } +} + +// ----------------------------------------------------------------------------- + +void RemoveColUndo::Redo() +{ + if( mxTable.is() ) + { + mxTable->UndoInsertColumns( mnIndex, sal::static_int_cast< sal_Int32 >( maColumns.size() ) ); + mbUndo = true; + } +} + +// ----------------------------------------------------------------------------- +// class TableColumnUndo : public SdrUndoAction +// ----------------------------------------------------------------------------- + +TableColumnUndo::TableColumnUndo( const TableColumnRef& xCol ) +: SdrUndoAction( *xCol->mxTableModel->getSdrTableObj()->GetModel() ) +, mxCol( xCol ) +, mbHasRedoData( false ) +{ + getData( maUndoData ); +} + +// ----------------------------------------------------------------------------- + +TableColumnUndo::~TableColumnUndo() +{ +} + +// ----------------------------------------------------------------------------- + +void TableColumnUndo::Undo() +{ + if( !mbHasRedoData ) + { + getData( maRedoData ); + mbHasRedoData = true; + } + setData( maUndoData ); +} + +// ----------------------------------------------------------------------------- + +void TableColumnUndo::Redo() +{ + setData( maRedoData ); +} + +// ----------------------------------------------------------------------------- + +BOOL TableColumnUndo::Merge( SfxUndoAction *pNextAction ) +{ + TableColumnUndo* pNext = dynamic_cast< TableColumnUndo* >( pNextAction ); + return pNext && pNext->mxCol == mxCol; +} + +// ----------------------------------------------------------------------------- + +void TableColumnUndo::setData( const Data& rData ) +{ + mxCol->mnColumn = rData.mnColumn; + mxCol->mnWidth = rData.mnWidth; + mxCol->mbOptimalWidth = rData.mbOptimalWidth; + mxCol->mbIsVisible = rData.mbIsVisible; + mxCol->mbIsStartOfNewPage = rData.mbIsStartOfNewPage; + mxCol->maName = rData.maName; +} + +// ----------------------------------------------------------------------------- + +void TableColumnUndo::getData( Data& rData ) +{ + rData.mnColumn = mxCol->mnColumn; + rData.mnWidth = mxCol->mnWidth; + rData.mbOptimalWidth = mxCol->mbOptimalWidth; + rData.mbIsVisible = mxCol->mbIsVisible; + rData.mbIsStartOfNewPage = mxCol->mbIsStartOfNewPage; + rData.maName = mxCol->maName; +} + +// ----------------------------------------------------------------------------- +// class TableRowUndo : public SdrUndoAction +// ----------------------------------------------------------------------------- + +TableRowUndo::TableRowUndo( const TableRowRef& xRow ) +: SdrUndoAction( *xRow->mxTableModel->getSdrTableObj()->GetModel() ) +, mxRow( xRow ) +, mbHasRedoData( false ) +{ + getData( maUndoData ); +} + +// ----------------------------------------------------------------------------- + +TableRowUndo::~TableRowUndo() +{ +} + +// ----------------------------------------------------------------------------- + +void TableRowUndo::Undo() +{ + if( !mbHasRedoData ) + { + getData( maRedoData ); + mbHasRedoData = true; + } + setData( maUndoData ); +} + +// ----------------------------------------------------------------------------- + +void TableRowUndo::Redo() +{ + setData( maRedoData ); +} + +// ----------------------------------------------------------------------------- + +BOOL TableRowUndo::Merge( SfxUndoAction *pNextAction ) +{ + TableRowUndo* pNext = dynamic_cast< TableRowUndo* >( pNextAction ); + return pNext && pNext->mxRow == mxRow; +} + +// ----------------------------------------------------------------------------- + +void TableRowUndo::setData( const Data& rData ) +{ + mxRow->mnRow = rData.mnRow; + mxRow->mnHeight = rData.mnHeight; + mxRow->mbOptimalHeight = rData.mbOptimalHeight; + mxRow->mbIsVisible = rData.mbIsVisible; + mxRow->mbIsStartOfNewPage = rData.mbIsStartOfNewPage; + mxRow->maName = rData.maName; + } + +// ----------------------------------------------------------------------------- + +void TableRowUndo::getData( Data& rData ) +{ + rData.mnRow = mxRow->mnRow; + rData.mnHeight = mxRow->mnHeight; + rData.mbOptimalHeight = mxRow->mbOptimalHeight; + rData.mbIsVisible = mxRow->mbIsVisible; + rData.mbIsStartOfNewPage = mxRow->mbIsStartOfNewPage; + rData.maName = mxRow->maName; +} + +// ----------------------------------------------------------------------------- + +TableStyleUndo::TableStyleUndo( const SdrTableObj& rTableObj ) +: SdrUndoAction( *rTableObj.GetModel() ) +, mxObjRef( const_cast< sdr::table::SdrTableObj*>( &rTableObj ) ) +{ + getData( maUndoData ); +} + +void TableStyleUndo::Undo() +{ + if( !mbHasRedoData ) + { + getData( maRedoData ); + mbHasRedoData = true; + } + setData( maUndoData ); +} + +void TableStyleUndo::Redo() +{ + setData( maRedoData ); +} + +void TableStyleUndo::setData( const Data& rData ) +{ + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxObjRef.get() ); + if( pTableObj ) + { + pTableObj->setTableStyle( rData.mxTableStyle ); + pTableObj->setTableStyleSettings( rData.maSettings ); + } +} + +void TableStyleUndo::getData( Data& rData ) +{ + SdrTableObj* pTableObj = dynamic_cast< SdrTableObj* >( mxObjRef.get() ); + if( pTableObj ) + { + rData.maSettings = pTableObj->getTableStyleSettings(); + rData.mxTableStyle = pTableObj->getTableStyle(); + } +} + +} } diff --git a/svx/source/table/tableundo.hxx b/svx/source/table/tableundo.hxx new file mode 100644 index 000000000000..8bf00c4b0d98 --- /dev/null +++ b/svx/source/table/tableundo.hxx @@ -0,0 +1,259 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_TABLEUNDO_HXX_ +#define _SVX_TABLEUNDO_HXX_ + +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/table/CellContentType.hpp> + +#include "svx/svdotable.hxx" +#include "svx/svdobj.hxx" +#include "svx/svdundo.hxx" + +#include "celltypes.hxx" + +namespace sdr { namespace properties { + class TextProperties; +} } + +class OutlinerParaObject; + +// ----------------------------------------------------------------------------- + +namespace sdr { namespace table { + +class CellUndo : public SdrUndoAction, public sdr::ObjectUser +{ +public: + CellUndo( const SdrObjectWeakRef& xObjRef, const CellRef& xCell ); + virtual ~CellUndo(); + + virtual void Undo(); + virtual void Redo(); + virtual BOOL Merge( SfxUndoAction *pNextAction ); + + void dispose(); + virtual void ObjectInDestruction(const SdrObject& rObject); + +private: + struct Data + { + sdr::properties::TextProperties* mpProperties; + OutlinerParaObject* mpOutlinerParaObject; + + ::com::sun::star::table::CellContentType mnCellContentType; + + ::rtl::OUString msFormula; + double mfValue; + ::sal_Int32 mnError; + ::sal_Bool mbMerged; + ::sal_Int32 mnRowSpan; + ::sal_Int32 mnColSpan; + + Data() : mpProperties(0), mpOutlinerParaObject(0) {}; + }; + + void setDataToCell( const Data& rData ); + void getDataFromCell( Data& rData ); + + SdrObjectWeakRef mxObjRef; + CellRef mxCell; + Data maUndoData; + Data maRedoData; + bool mbUndo; +}; + +// ----------------------------------------------------------------------------- + +class InsertRowUndo : public SdrUndoAction +{ +public: + InsertRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aNewRows ); + virtual ~InsertRowUndo(); + + virtual void Undo(); + virtual void Redo(); + +private: + TableModelRef mxTable; + sal_Int32 mnIndex; + RowVector maRows; + bool mbUndo; +}; + +// ----------------------------------------------------------------------------- + +class RemoveRowUndo : public SdrUndoAction +{ +public: + RemoveRowUndo( const TableModelRef& xTable, sal_Int32 nIndex, RowVector& aRemovedRows ); + virtual ~RemoveRowUndo(); + + virtual void Undo(); + virtual void Redo(); + +private: + TableModelRef mxTable; + sal_Int32 mnIndex; + RowVector maRows; + bool mbUndo; +}; + +// ----------------------------------------------------------------------------- + +class InsertColUndo : public SdrUndoAction +{ +public: + InsertColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells ); + virtual ~InsertColUndo(); + + virtual void Undo(); + virtual void Redo(); + +private: + TableModelRef mxTable; + sal_Int32 mnIndex; + ColumnVector maColumns; + CellVector maCells; + bool mbUndo; +}; + +// ----------------------------------------------------------------------------- + +class RemoveColUndo : public SdrUndoAction +{ +public: + RemoveColUndo( const TableModelRef& xTable, sal_Int32 nIndex, ColumnVector& aNewCols, CellVector& aCells ); + virtual ~RemoveColUndo(); + + virtual void Undo(); + virtual void Redo(); + +private: + TableModelRef mxTable; + sal_Int32 mnIndex; + ColumnVector maColumns; + CellVector maCells; + bool mbUndo; +}; + +// ----------------------------------------------------------------------------- + +class TableColumnUndo : public SdrUndoAction +{ +public: + TableColumnUndo( const TableColumnRef& xCol ); + virtual ~TableColumnUndo(); + + virtual void Undo(); + virtual void Redo(); + virtual BOOL Merge( SfxUndoAction *pNextAction ); + +private: + struct Data + { + sal_Int32 mnColumn; + sal_Int32 mnWidth; + sal_Bool mbOptimalWidth; + sal_Bool mbIsVisible; + sal_Bool mbIsStartOfNewPage; + ::rtl::OUString maName; + }; + + void setData( const Data& rData ); + void getData( Data& rData ); + + TableColumnRef mxCol; + Data maUndoData; + Data maRedoData; + bool mbHasRedoData; +}; + +// ----------------------------------------------------------------------------- + +class TableRowUndo : public SdrUndoAction +{ +public: + TableRowUndo( const TableRowRef& xRow ); + virtual ~TableRowUndo(); + + virtual void Undo(); + virtual void Redo(); + virtual BOOL Merge( SfxUndoAction *pNextAction ); + +private: + struct Data + { + CellVector maCells; + sal_Int32 mnRow; + sal_Int32 mnHeight; + sal_Bool mbOptimalHeight; + sal_Bool mbIsVisible; + sal_Bool mbIsStartOfNewPage; + ::rtl::OUString maName; + }; + + void setData( const Data& rData ); + void getData( Data& rData ); + + TableRowRef mxRow; + Data maUndoData; + Data maRedoData; + bool mbHasRedoData; +}; + +// ----------------------------------------------------------------------------- + +class TableStyleUndo : public SdrUndoAction +{ +public: + TableStyleUndo( const SdrTableObj& rTableObj ); + + virtual void Undo(); + virtual void Redo(); + +private: + SdrObjectWeakRef mxObjRef; + + struct Data + { + TableStyleSettings maSettings; + ::com::sun::star::uno::Reference< ::com::sun::star::container::XIndexAccess > mxTableStyle; + }; + + void setData( const Data& rData ); + void getData( Data& rData ); + + Data maUndoData; + Data maRedoData; + bool mbHasRedoData; +}; + +} } + +#endif diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx new file mode 100644 index 000000000000..63d1066e7149 --- /dev/null +++ b/svx/source/table/viewcontactoftableobj.cxx @@ -0,0 +1,736 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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_svx.hxx" + +#include "viewcontactoftableobj.hxx" +#include <svx/svdotable.hxx> +#include <com/sun/star/table/XTable.hpp> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <drawinglayer/primitive2d/polygonprimitive2d.hxx> +#include <svx/sdr/primitive2d/sdrattributecreator.hxx> +#include <drawinglayer/primitive2d/groupprimitive2d.hxx> +#include <svx/sdr/primitive2d/sdrdecompositiontools.hxx> +#include <svx/sdr/primitive2d/sdrattributecreator.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <svx/sdr/attribute/sdrtextattribute.hxx> +#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx> +#include <editeng/borderline.hxx> +#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx> +#include <svx/sdr/attribute/sdrfilltextattribute.hxx> +#include <drawinglayer/attribute/sdrlineattribute.hxx> +#include <drawinglayer/attribute/sdrshadowattribute.hxx> +#include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include "cell.hxx" +#include "tablelayouter.hxx" + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + class SdrCellPrimitive2D : public BufferedDecompositionPrimitive2D + { + private: + basegfx::B2DHomMatrix maTransform; + attribute::SdrFillTextAttribute maSdrFTAttribute; + + protected: + // local decomposition. + virtual Primitive2DSequence create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const; + + public: + SdrCellPrimitive2D( + const basegfx::B2DHomMatrix& rTransform, + const attribute::SdrFillTextAttribute& rSdrFTAttribute) + : BufferedDecompositionPrimitive2D(), + maTransform(rTransform), + maSdrFTAttribute(rSdrFTAttribute) + { + } + + // data access + const basegfx::B2DHomMatrix& getTransform() const { return maTransform; } + const attribute::SdrFillTextAttribute& getSdrFTAttribute() const { return maSdrFTAttribute; } + + // compare operator + virtual bool operator==(const BasePrimitive2D& rPrimitive) const; + + // provide unique ID + DeclPrimitrive2DIDBlock() + }; + + Primitive2DSequence SdrCellPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*aViewInformation*/) const + { + // prepare unit polygon + Primitive2DSequence aRetval; + const basegfx::B2DPolyPolygon aUnitPolyPolygon(basegfx::tools::createUnitPolygon()); + + // add fill + if(!getSdrFTAttribute().getFill().isDefault()) + { + appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, + createPolyPolygonFillPrimitive( + aUnitPolyPolygon, + getTransform(), + getSdrFTAttribute().getFill(), + getSdrFTAttribute().getFillFloatTransGradient())); + } + else + { + // if no fill create one for HitTest and BoundRect fallback + appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, + createHiddenGeometryPrimitives2D( + true, + aUnitPolyPolygon, + getTransform())); + } + + // add text + if(!getSdrFTAttribute().getText().isDefault()) + { + appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, + createTextPrimitive( + aUnitPolyPolygon, + getTransform(), + getSdrFTAttribute().getText(), + attribute::SdrLineAttribute(), + true, + false, + false)); + } + + return aRetval; + } + + bool SdrCellPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) + { + const SdrCellPrimitive2D& rCompare = (SdrCellPrimitive2D&)rPrimitive; + + return (getTransform() == rCompare.getTransform() + && getSdrFTAttribute() == rCompare.getSdrFTAttribute()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(SdrCellPrimitive2D, PRIMITIVE2D_ID_SDRCELLPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace drawinglayer +{ + namespace primitive2d + { + class SdrBorderlinePrimitive2D : public BufferedDecompositionPrimitive2D + { + private: + basegfx::B2DHomMatrix maTransform; + SvxBorderLine maLeftLine; + SvxBorderLine maBottomLine; + SvxBorderLine maRightLine; + SvxBorderLine maTopLine; + + // bitfield + unsigned mbLeftIsOutside : 1; + unsigned mbBottomIsOutside : 1; + unsigned mbRightIsOutside : 1; + unsigned mbTopIsOutside : 1; + unsigned mbInTwips : 1; + + protected: + // local decomposition. + virtual Primitive2DSequence create2DDecomposition(const geometry::ViewInformation2D& aViewInformation) const; + + public: + SdrBorderlinePrimitive2D( + const basegfx::B2DHomMatrix& rTransform, + const SvxBorderLine& rLeftLine, + const SvxBorderLine& rBottomLine, + const SvxBorderLine& rRightLine, + const SvxBorderLine& rTopLine, + bool bLeftIsOutside, + bool bBottomIsOutside, + bool bRightIsOutside, + bool bTopIsOutside, + bool bInTwips) + : BufferedDecompositionPrimitive2D(), + maTransform(rTransform), + maLeftLine(rLeftLine), + maBottomLine(rBottomLine), + maRightLine(rRightLine), + maTopLine(rTopLine), + mbLeftIsOutside(bLeftIsOutside), + mbBottomIsOutside(bBottomIsOutside), + mbRightIsOutside(bRightIsOutside), + mbTopIsOutside(bTopIsOutside), + mbInTwips(bInTwips) + { + } + + + // data access + const basegfx::B2DHomMatrix& getTransform() const { return maTransform; } + const SvxBorderLine& getLeftLine() const { return maLeftLine; } + const SvxBorderLine& getBottomLine() const { return maBottomLine; } + const SvxBorderLine& getRightLine() const { return maRightLine; } + const SvxBorderLine& getTopLine() const { return maTopLine; } + bool getLeftIsOutside() const { return mbLeftIsOutside; } + bool getBottomIsOutside() const { return mbBottomIsOutside; } + bool getRightIsOutside() const { return mbRightIsOutside; } + bool getTopIsOutside() const { return mbTopIsOutside; } + bool getInTwips() const { return mbInTwips; } + + // compare operator + virtual bool operator==(const BasePrimitive2D& rPrimitive) const; + + // provide unique ID + DeclPrimitrive2DIDBlock() + }; + + sal_uInt16 getBorderLineOutWidth(const SvxBorderLine& rLineA) + { + return (1 == rLineA.GetOutWidth() ? 0 : rLineA.GetOutWidth()); + } + + sal_uInt16 getBorderLineDistance(const SvxBorderLine& rLineA) + { + return (1 == rLineA.GetDistance() ? 0 : rLineA.GetDistance()); + } + + sal_uInt16 getBorderLineInWidth(const SvxBorderLine& rLineA) + { + return (1 == rLineA.GetInWidth() ? 0 : rLineA.GetInWidth()); + } + + sal_uInt16 getBorderLineWidth(const SvxBorderLine& rLineA) + { + return getBorderLineOutWidth(rLineA) + getBorderLineDistance(rLineA) + getBorderLineInWidth(rLineA); + } + + double getInnerExtend(const SvxBorderLine& rLineA, bool bSideToUse) + { + if(!rLineA.isEmpty()) + { + if(rLineA.isDouble()) + { + // reduce to inner edge of associated matching line + return -((getBorderLineWidth(rLineA) / 2.0) - (bSideToUse ? getBorderLineOutWidth(rLineA) : getBorderLineInWidth(rLineA))); + } + else + { + // extend to overlap with single line + return getBorderLineWidth(rLineA) / 2.0; + } + } + + return 0.0; + } + + double getOuterExtend(const SvxBorderLine& rLineA) + { + if(!rLineA.isEmpty()) + { + // extend to overlap with single line + return getBorderLineWidth(rLineA) / 2.0; + } + + return 0.0; + } + + double getChangedValue(sal_uInt16 nValue, bool bChangeToMM) + { + if(1 == nValue) + return 1.0; + + if(bChangeToMM) + return nValue * (127.0 / 72.0); + + return (double)nValue; + } + + Primitive2DSequence SdrBorderlinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*aViewInformation*/) const + { + Primitive2DSequence xRetval(4); + sal_uInt32 nInsert(0); + const double fTwipsToMM(getInTwips() ? (127.0 / 72.0) : 1.0); + + if(!getLeftLine().isEmpty()) + { + // create left line from top to bottom + const basegfx::B2DPoint aStart(getTransform() * basegfx::B2DPoint(0.0, 0.0)); + const basegfx::B2DPoint aEnd(getTransform() * basegfx::B2DPoint(0.0, 1.0)); + + if(!aStart.equal(aEnd)) + { + const double fExtendIS(getInnerExtend(getTopLine(), false)); + const double fExtendIE(getInnerExtend(getBottomLine(), true)); + double fExtendOS(0.0); + double fExtendOE(0.0); + + if(getLeftIsOutside()) + { + if(getTopIsOutside()) + { + fExtendOS = getOuterExtend(getTopLine()); + } + + if(getBottomIsOutside()) + { + fExtendOE = getOuterExtend(getBottomLine()); + } + } + + xRetval[nInsert++] = Primitive2DReference(new BorderLinePrimitive2D( + aStart, + aEnd, + getChangedValue(getLeftLine().GetOutWidth(), getInTwips()), + getChangedValue(getLeftLine().GetDistance(), getInTwips()), + getChangedValue(getLeftLine().GetInWidth(), getInTwips()), + fExtendIS * fTwipsToMM, + fExtendIE * fTwipsToMM, + fExtendOS * fTwipsToMM, + fExtendOE * fTwipsToMM, + true, + getLeftIsOutside(), + getLeftLine().GetColor().getBColor())); + } + } + + if(!getBottomLine().isEmpty()) + { + // create bottom line from left to right + const basegfx::B2DPoint aStart(getTransform() * basegfx::B2DPoint(0.0, 1.0)); + const basegfx::B2DPoint aEnd(getTransform() * basegfx::B2DPoint(1.0, 1.0)); + + if(!aStart.equal(aEnd)) + { + const double fExtendIS(getInnerExtend(getLeftLine(), true)); + const double fExtendIE(getInnerExtend(getRightLine(), false)); + double fExtendOS(0.0); + double fExtendOE(0.0); + + if(getBottomIsOutside()) + { + if(getLeftIsOutside()) + { + fExtendOS = getOuterExtend(getLeftLine()); + } + + if(getRightIsOutside()) + { + fExtendOE = getOuterExtend(getRightLine()); + } + } + + xRetval[nInsert++] = Primitive2DReference(new BorderLinePrimitive2D( + aStart, + aEnd, + getChangedValue(getBottomLine().GetOutWidth(), getInTwips()), + getChangedValue(getBottomLine().GetDistance(), getInTwips()), + getChangedValue(getBottomLine().GetInWidth(), getInTwips()), + fExtendIS * fTwipsToMM, + fExtendIE * fTwipsToMM, + fExtendOS * fTwipsToMM, + fExtendOE * fTwipsToMM, + true, + getBottomIsOutside(), + getBottomLine().GetColor().getBColor())); + } + } + + if(!getRightLine().isEmpty()) + { + // create right line from top to bottom + const basegfx::B2DPoint aStart(getTransform() * basegfx::B2DPoint(1.0, 0.0)); + const basegfx::B2DPoint aEnd(getTransform() * basegfx::B2DPoint(1.0, 1.0)); + + if(!aStart.equal(aEnd)) + { + const double fExtendIS(getInnerExtend(getTopLine(), false)); + const double fExtendIE(getInnerExtend(getBottomLine(), true)); + double fExtendOS(0.0); + double fExtendOE(0.0); + + if(getRightIsOutside()) + { + if(getTopIsOutside()) + { + fExtendOS = getOuterExtend(getTopLine()); + } + + if(getBottomIsOutside()) + { + fExtendOE = getOuterExtend(getBottomLine()); + } + } + + xRetval[nInsert++] = Primitive2DReference(new BorderLinePrimitive2D( + aStart, + aEnd, + getChangedValue(getRightLine().GetOutWidth(), getInTwips()), + getChangedValue(getRightLine().GetDistance(), getInTwips()), + getChangedValue(getRightLine().GetInWidth(), getInTwips()), + fExtendOS * fTwipsToMM, + fExtendOE * fTwipsToMM, + fExtendIS * fTwipsToMM, + fExtendIE * fTwipsToMM, + getRightIsOutside(), + true, + getRightLine().GetColor().getBColor())); + } + } + + if(!getTopLine().isEmpty()) + { + // create top line from left to right + const basegfx::B2DPoint aStart(getTransform() * basegfx::B2DPoint(0.0, 0.0)); + const basegfx::B2DPoint aEnd(getTransform() * basegfx::B2DPoint(1.0, 0.0)); + + if(!aStart.equal(aEnd)) + { + const double fExtendIS(getInnerExtend(getLeftLine(), true)); + const double fExtendIE(getInnerExtend(getRightLine(), false)); + double fExtendOS(0.0); + double fExtendOE(0.0); + + if(getTopIsOutside()) + { + if(getLeftIsOutside()) + { + fExtendOS = getOuterExtend(getLeftLine()); + } + + if(getRightIsOutside()) + { + fExtendOE = getOuterExtend(getRightLine()); + } + } + + xRetval[nInsert++] = Primitive2DReference(new BorderLinePrimitive2D( + aStart, + aEnd, + getChangedValue(getTopLine().GetOutWidth(), getInTwips()), + getChangedValue(getTopLine().GetDistance(), getInTwips()), + getChangedValue(getTopLine().GetInWidth(), getInTwips()), + fExtendOS * fTwipsToMM, + fExtendOE * fTwipsToMM, + fExtendIS * fTwipsToMM, + fExtendIE * fTwipsToMM, + getTopIsOutside(), + true, + getTopLine().GetColor().getBColor())); + } + } + + xRetval.realloc(nInsert); + return xRetval; + } + + bool SdrBorderlinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const + { + if(BufferedDecompositionPrimitive2D::operator==(rPrimitive)) + { + const SdrBorderlinePrimitive2D& rCompare = (SdrBorderlinePrimitive2D&)rPrimitive; + + return (getTransform() == rCompare.getTransform() + && getLeftLine() == rCompare.getLeftLine() + && getBottomLine() == rCompare.getBottomLine() + && getRightLine() == rCompare.getRightLine() + && getTopLine() == rCompare.getTopLine() + && getLeftIsOutside() == rCompare.getLeftIsOutside() + && getBottomIsOutside() == rCompare.getBottomIsOutside() + && getRightIsOutside() == rCompare.getRightIsOutside() + && getTopIsOutside() == rCompare.getTopIsOutside() + && getInTwips() == rCompare.getInTwips()); + } + + return false; + } + + // provide unique ID + ImplPrimitrive2DIDBlock(SdrBorderlinePrimitive2D, PRIMITIVE2D_ID_SDRBORDERLINEPRIMITIVE2D) + + } // end of namespace primitive2d +} // end of namespace drawinglayer + +////////////////////////////////////////////////////////////////////////////// + +namespace sdr +{ + namespace contact + { + void impGetLine(SvxBorderLine& aLine, const sdr::table::TableLayouter& rLayouter, sal_Int32 nX, sal_Int32 nY, bool bHorizontal, sal_Int32 nColCount, sal_Int32 nRowCount, bool bIsRTL) + { + if(nX >= 0 && nX <= nColCount && nY >= 0 && nY <= nRowCount) + { + const SvxBorderLine* pLine = rLayouter.getBorderLine(nX, nY, bHorizontal); + + if(pLine) + { + // copy line content + aLine = *pLine; + + // check for mirroring. This shall always be done when it is + // not a top- or rightmost line + bool bMirror(aLine.isDouble()); + + if(bMirror) + { + if(bHorizontal) + { + // mirror all bottom lines + bMirror = (0 != nY); + } + else + { + // mirror all left lines + bMirror = (bIsRTL ? 0 != nX : nX != nColCount); + } + } + + if(bMirror) + { + aLine.SetOutWidth(pLine->GetInWidth()); + aLine.SetInWidth(pLine->GetOutWidth()); + } + + return; + } + } + + // no success, copy empty line + const SvxBorderLine aEmptyLine; + aLine = aEmptyLine; + } + + drawinglayer::primitive2d::Primitive2DSequence ViewContactOfTableObj::createViewIndependentPrimitive2DSequence() const + { + const sdr::table::SdrTableObj& rTableObj = GetTableObj(); + const uno::Reference< com::sun::star::table::XTable > xTable = rTableObj.getTable(); + + if(xTable.is()) + { + // create primitive representation for table + drawinglayer::primitive2d::Primitive2DSequence xRetval; + const sal_Int32 nRowCount(xTable->getRowCount()); + const sal_Int32 nColCount(xTable->getColumnCount()); + const sal_Int32 nAllCount(nRowCount * nColCount); + + if(nAllCount) + { + const sdr::table::TableLayouter& rTableLayouter = rTableObj.getTableLayouter(); + const bool bIsRTL(com::sun::star::text::WritingMode_RL_TB == rTableObj.GetWritingMode()); + sdr::table::CellPos aCellPos; + sdr::table::CellRef xCurrentCell; + basegfx::B2IRectangle aCellArea; + + // create range using the model data directly. This is in SdrTextObj::aRect which i will access using + // GetGeoRect() to not trigger any calculations. It's the unrotated geometry. + const Rectangle& rObjectRectangle(rTableObj.GetGeoRect()); + const basegfx::B2DRange aObjectRange(rObjectRectangle.Left(), rObjectRectangle.Top(), rObjectRectangle.Right(), rObjectRectangle.Bottom()); + + // for each cell we need potentially a cell primitive and a border primitive + // (e.g. single cell). Prepare sequences and input counters + drawinglayer::primitive2d::Primitive2DSequence xCellSequence(nAllCount); + drawinglayer::primitive2d::Primitive2DSequence xBorderSequence(nAllCount); + sal_uInt32 nCellInsert(0); + sal_uInt32 nBorderInsert(0); + + // variables for border lines + SvxBorderLine aLeftLine; + SvxBorderLine aBottomLine; + SvxBorderLine aRightLine; + SvxBorderLine aTopLine; + + // create single primitives per cell + for(aCellPos.mnRow = 0; aCellPos.mnRow < nRowCount; aCellPos.mnRow++) + { + for(aCellPos.mnCol = 0; aCellPos.mnCol < nColCount; aCellPos.mnCol++) + { + xCurrentCell.set(dynamic_cast< sdr::table::Cell* >(xTable->getCellByPosition(aCellPos.mnCol, aCellPos.mnRow).get())); + + if(xCurrentCell.is() && !xCurrentCell->isMerged()) + { + if(rTableLayouter.getCellArea(aCellPos, aCellArea)) + { + // create cell transformation matrix + basegfx::B2DHomMatrix aCellMatrix; + aCellMatrix.set(0, 0, (double)aCellArea.getWidth()); + aCellMatrix.set(1, 1, (double)aCellArea.getHeight()); + aCellMatrix.set(0, 2, (double)aCellArea.getMinX() + aObjectRange.getMinX()); + aCellMatrix.set(1, 2, (double)aCellArea.getMinY() + aObjectRange.getMinY()); + + // handle cell fillings and text + const SfxItemSet& rCellItemSet = xCurrentCell->GetItemSet(); + const sal_uInt32 nTextIndex(nColCount * aCellPos.mnRow + aCellPos.mnCol); + const SdrText* pSdrText = rTableObj.getText(nTextIndex); + drawinglayer::attribute::SdrFillTextAttribute aAttribute; + + if(pSdrText) + { + // #i101508# take cell's local text frame distances into account + const sal_Int32 nLeft(xCurrentCell->GetTextLeftDistance()); + const sal_Int32 nRight(xCurrentCell->GetTextRightDistance()); + const sal_Int32 nUpper(xCurrentCell->GetTextUpperDistance()); + const sal_Int32 nLower(xCurrentCell->GetTextLowerDistance()); + + aAttribute = drawinglayer::primitive2d::createNewSdrFillTextAttribute( + rCellItemSet, + pSdrText, + &nLeft, + &nUpper, + &nRight, + &nLower); + } + else + { + aAttribute = drawinglayer::primitive2d::createNewSdrFillTextAttribute( + rCellItemSet, + pSdrText); + } + + // always create cell primitives for BoundRect and HitTest + { + const drawinglayer::primitive2d::Primitive2DReference xCellReference( + new drawinglayer::primitive2d::SdrCellPrimitive2D( + aCellMatrix, aAttribute)); + xCellSequence[nCellInsert++] = xCellReference; + } + + // handle cell borders + const sal_Int32 nX(bIsRTL ? nColCount - aCellPos.mnCol : aCellPos.mnCol); + const sal_Int32 nY(aCellPos.mnRow); + + // get access values for X,Y at the cell's end + const sal_Int32 nXSpan(xCurrentCell->getColumnSpan()); + const sal_Int32 nYSpan(xCurrentCell->getRowSpan()); + const sal_Int32 nXRight(bIsRTL ? nX - nXSpan : nX + nXSpan); + const sal_Int32 nYBottom(nY + nYSpan); + + // get basic lines + impGetLine(aLeftLine, rTableLayouter, nX, nY, false, nColCount, nRowCount, bIsRTL); + impGetLine(aBottomLine, rTableLayouter, nX, nYBottom, true, nColCount, nRowCount, bIsRTL); + impGetLine(aRightLine, rTableLayouter, nXRight, nY, false, nColCount, nRowCount, bIsRTL); + impGetLine(aTopLine, rTableLayouter, nX, nY, true, nColCount, nRowCount, bIsRTL); + + // create the primtive containing all data for one cell with borders + xBorderSequence[nBorderInsert++] = drawinglayer::primitive2d::Primitive2DReference( + new drawinglayer::primitive2d::SdrBorderlinePrimitive2D( + aCellMatrix, + aLeftLine, + aBottomLine, + aRightLine, + aTopLine, + bIsRTL ? nX == nColCount : 0 == nX, + nRowCount == nYBottom, + bIsRTL ? 0 == nXRight : nXRight == nColCount, + 0 == nY, + true)); + } + } + } + } + + // no empty references; reallocate sequences by used count + xCellSequence.realloc(nCellInsert); + xBorderSequence.realloc(nBorderInsert); + + // append to target. We want fillings and text first + xRetval = xCellSequence; + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, xBorderSequence); + } + + if(xRetval.hasElements()) + { + // check and create evtl. shadow for created content + const SfxItemSet& rObjectItemSet = rTableObj.GetMergedItemSet(); + const drawinglayer::attribute::SdrShadowAttribute aNewShadowAttribute( + drawinglayer::primitive2d::createNewSdrShadowAttribute(rObjectItemSet)); + + if(!aNewShadowAttribute.isDefault()) + { + xRetval = drawinglayer::primitive2d::createEmbeddedShadowPrimitive(xRetval, aNewShadowAttribute); + } + } + + return xRetval; + } + else + { + // take unrotated snap rect (direct model data) for position and size + const Rectangle& rRectangle = rTableObj.GetGeoRect(); + const basegfx::B2DRange aObjectRange( + rRectangle.Left(), rRectangle.Top(), + rRectangle.Right(), rRectangle.Bottom()); + + // create object matrix + const GeoStat& rGeoStat(rTableObj.GetGeoStat()); + const double fShearX(rGeoStat.nShearWink ? tan((36000 - rGeoStat.nShearWink) * F_PI18000) : 0.0); + const double fRotate(rGeoStat.nDrehWink ? (36000 - rGeoStat.nDrehWink) * F_PI18000 : 0.0); + const basegfx::B2DHomMatrix aObjectMatrix(basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix( + aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate, + aObjectRange.getMinX(), aObjectRange.getMinY())); + + // credate an invisible outline for the cases where no visible content exists + const drawinglayer::primitive2d::Primitive2DReference xReference( + drawinglayer::primitive2d::createHiddenGeometryPrimitives2D( + false, + aObjectMatrix)); + + return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); + } + } + + ViewContactOfTableObj::ViewContactOfTableObj(::sdr::table::SdrTableObj& rTableObj) + : ViewContactOfSdrObj(rTableObj) + { + } + + ViewContactOfTableObj::~ViewContactOfTableObj() + { + } + } // end of namespace contact +} // end of namespace sdr + +////////////////////////////////////////////////////////////////////////////// +// eof diff --git a/svx/source/table/viewcontactoftableobj.hxx b/svx/source/table/viewcontactoftableobj.hxx new file mode 100644 index 000000000000..733f28be0d3e --- /dev/null +++ b/svx/source/table/viewcontactoftableobj.hxx @@ -0,0 +1,72 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * 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 _SDR_CONTACT_VIEWCONTACTOFTABLEOBJ_HXX +#define _SDR_CONTACT_VIEWCONTACTOFTABLEOBJ_HXX + +#include <svx/sdr/contact/viewcontactofsdrobj.hxx> + +////////////////////////////////////////////////////////////////////////////// +// predeclarations + +////////////////////////////////////////////////////////////////////////////// + +namespace sdr +{ + namespace table + { + class SdrTableObj; + } + + namespace contact + { + class ViewContactOfTableObj : public ViewContactOfSdrObj + { + protected: + // internal access to SdrTextObj + ::sdr::table::SdrTableObj& GetTableObj() const + { + return (::sdr::table::SdrTableObj&)GetSdrObject(); + } + + // This method is responsible for creating the graphical visualisation data derived ONLY from + // the model data + virtual drawinglayer::primitive2d::Primitive2DSequence createViewIndependentPrimitive2DSequence() const; + + public: + // basic constructor, used from SdrObject. + ViewContactOfTableObj(::sdr::table::SdrTableObj& rTextObj); + virtual ~ViewContactOfTableObj(); + }; + } // end of namespace contact +} // end of namespace sdr + +////////////////////////////////////////////////////////////////////////////// + +#endif + +// eof |