[PATCH 1/2] fix bad import positions of shapes & controls fdo#49430

Noel Power noel.power at novell.com
Fri May 4 01:48:27 PDT 2012


---
 oox/inc/oox/xls/drawingbase.hxx    |   10 ++-
 oox/source/token/properties.txt    |    3 +
 oox/source/xls/drawingbase.cxx     |   40 ++++++++++
 oox/source/xls/drawingfragment.cxx |    9 ++-
 sc/inc/global.hxx                  |   19 +++++
 sc/source/core/data/global.cxx     |  147 +++++++++++++++++++++++++++++++++++-
 sc/source/ui/unoobj/docuno.cxx     |   17 ++++
 sc/source/ui/view/viewdata.cxx     |    7 +-
 8 files changed, 246 insertions(+), 6 deletions(-)

diff --git a/oox/inc/oox/xls/drawingbase.hxx b/oox/inc/oox/xls/drawingbase.hxx
index c79eb7a..95fae46 100644
--- a/oox/inc/oox/xls/drawingbase.hxx
+++ b/oox/inc/oox/xls/drawingbase.hxx
@@ -32,6 +32,9 @@
 #include "oox/drawingml/drawingmltypes.hxx"
 #include "oox/xls/worksheethelper.hxx"
 
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/table/XCell.hpp>
+
 namespace oox {
 namespace xls {
 
@@ -108,7 +111,12 @@ public:
     /** Calculates the resulting shape anchor in 1/100 mm. */
     ::com::sun::star::awt::Rectangle calcAnchorRectHmm(
                             const ::com::sun::star::awt::Size& rPageSizeHmm ) const;
-
+    /** Returns the 'to' cell if it exists */
+    ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > getToCell() const;
+    /** Returns the 'from' cell if it exists */
+    ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > getFromCell() const;
+    /** Applies Cell Anchor to an XShape if needed*/
+    void applyToXShape( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape>& rxShape );
 private:
     /** Converts the passed anchor to an absolute position in EMUs. */
     ::oox::drawingml::EmuPoint calcCellAnchorEmu( const CellAnchorModel& rModel ) const;
diff --git a/oox/source/token/properties.txt b/oox/source/token/properties.txt
index 9127c38..176ae08 100644
--- a/oox/source/token/properties.txt
+++ b/oox/source/token/properties.txt
@@ -9,6 +9,7 @@ AdjustLuminance
 AdjustmentValues
 Address
 Align
+Anchor
 AnchorPosition
 ApplyFormDesignMode
 AreaLinks
@@ -217,6 +218,7 @@ HelpText
 HideInactiveSelection
 HoriJustify
 HoriJustifyMethod
+HoriOrientPosition
 HorizontalSplitMode
 HorizontalSplitPositionTwips
 IgnoreBlankCells
@@ -495,6 +497,7 @@ VertJustifyMethod
 VerticalAlign
 VerticalSplitMode
 VerticalSplitPositionTwips
+VertOrientPosition
 ViewBox
 Visible
 VisibleFlag
diff --git a/oox/source/xls/drawingbase.cxx b/oox/source/xls/drawingbase.cxx
index 3369ba9..e740c39 100644
--- a/oox/source/xls/drawingbase.cxx
+++ b/oox/source/xls/drawingbase.cxx
@@ -32,6 +32,7 @@
 #include "oox/helper/attributelist.hxx"
 #include "oox/helper/binaryinputstream.hxx"
 #include "oox/xls/unitconverter.hxx"
+#include "oox/helper/propertyset.hxx"
 
 namespace oox {
 namespace xls {
@@ -170,6 +171,7 @@ void ShapeAnchor::setCellPos( sal_Int32 nElement, sal_Int32 nParentContext, cons
 void ShapeAnchor::importVmlAnchor( const OUString& rAnchor )
 {
     meAnchorType = ANCHOR_VML;
+    meCellAnchorType = CELLANCHOR_PIXEL;
 
     ::std::vector< OUString > aTokens;
     sal_Int32 nIndex = 0;
@@ -281,6 +283,44 @@ Rectangle ShapeAnchor::calcAnchorRectHmm( const Size& rPageSizeHmm ) const
     return Rectangle( lclEmuToHmm( aAnchorRect.X ), lclEmuToHmm( aAnchorRect.Y ), lclEmuToHmm( aAnchorRect.Width ), lclEmuToHmm( aAnchorRect.Height ) );
 }
 
+::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >
+ShapeAnchor::getToCell() const
+{
+    CellAddress aAddress;
+    aAddress.Sheet = getSheetIndex();
+    aAddress.Row = maTo.mnRow;
+    aAddress.Column = maTo.mnCol;
+    return getCell( aAddress );
+}
+::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >
+ShapeAnchor::getFromCell() const
+{
+    CellAddress aAddress;
+    aAddress.Sheet = getSheetIndex();
+    aAddress.Row = maFrom.mnRow;
+    aAddress.Column = maFrom.mnCol;
+    return getCell( aAddress );
+}
+
+void
+ShapeAnchor::applyToXShape( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape>& rxShape )
+{
+    if ( ( meAnchorType == ANCHOR_VML || meAnchorType == ANCHOR_TWOCELL || meAnchorType ==  ANCHOR_ONECELL ) && getFromCell().is() )
+    {
+        PropertySet aShapeProp( rxShape );
+        CellAnchorModel offSets;
+        offSets.mnColOffset = maFrom.mnColOffset;
+        offSets.mnRowOffset = maFrom.mnRowOffset;
+        EmuPoint aPos = calcCellAnchorEmu( offSets );
+
+        Point aZeroZero;
+        rxShape->setPosition( aZeroZero );
+        aShapeProp.setProperty( PROP_HoriOrientPosition, lclEmuToHmm( aPos.X ) );
+        aShapeProp.setProperty( PROP_VertOrientPosition, lclEmuToHmm( aPos.Y ) );
+        aShapeProp.setProperty( PROP_Anchor, getFromCell() );
+    }
+}
+
 // private --------------------------------------------------------------------
 
 EmuPoint ShapeAnchor::calcCellAnchorEmu( const CellAnchorModel& rModel ) const
diff --git a/oox/source/xls/drawingfragment.cxx b/oox/source/xls/drawingfragment.cxx
index 64f0164..5cd6d2b 100644
--- a/oox/source/xls/drawingfragment.cxx
+++ b/oox/source/xls/drawingfragment.cxx
@@ -290,7 +290,8 @@ void DrawingFragment::onEndElement()
 
                     basegfx::B2DHomMatrix aTransformation;
                     mxShape->addShape( getOoxFilter(), &getTheme(), mxDrawPage, aTransformation, &aShapeRectEmu32 );
-
+                    // apply Cell anchoring if necessary
+                    mxAnchor->applyToXShape( mxShape->getXShape() );
                     /*  Collect all shape positions in the WorksheetHelper base
                         class. But first, scale EMUs to 1/100 mm. */
                     Rectangle aShapeRectHmm(
@@ -631,6 +632,12 @@ Reference< XShape > VmlDrawing::createAndInsertClientXShape( const ::oox::vml::S
                 }
             }
 
+            if ( pClientData->maAnchor.getLength() )
+            {
+                ShapeAnchor aAnchor( *this );
+                aAnchor.importVmlAnchor( pClientData->maAnchor );
+                aAnchor.applyToXShape( xShape );
+            }
             return xShape;
         }
     }
diff --git a/sc/inc/global.hxx b/sc/inc/global.hxx
index ac10094..c431598 100644
--- a/sc/inc/global.hxx
+++ b/sc/inc/global.hxx
@@ -34,9 +34,11 @@
 #include <tools/stream.hxx>
 #include <osl/endian.h>
 #include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/table/CellAddress.hpp>
 #include "scdllapi.h"
 
 #include <boost/unordered_map.hpp>
+#include <vector>
 
 class ImageList;
 class Bitmap;
@@ -497,12 +499,27 @@ namespace com { namespace sun { namespace star {
     namespace i18n {
         class XOrdinalSuffix;
     }
+    namespace frame {
+        class XModel;
+    }
+    namespace drawing {
+        class XShape;
+    }
 }}}
 namespace utl {
     class TransliterationWrapper;
 }
 
 #ifndef _SCALC_EXE
+struct SC_DLLPUBLIC OrientationInfo
+{
+    OrientationInfo() : mnVert( 0 ), mnHori( 0 ) {}
+    ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > mxShape;
+    ::com::sun::star::table::CellAddress maAddress;
+    sal_Int32 mnVert;
+    sal_Int32 mnHori;
+};
+
 class ScGlobal
 {
     static SvxSearchItem*   pSearchItem;
@@ -695,6 +712,8 @@ SC_DLLPUBLIC    static const sal_Unicode* FindUnquoted( const sal_Unicode* pStri
 
     /** Obtain the ordinal suffix for a number according to the system locale */
     static String           GetOrdinalSuffix( sal_Int32 nNumber);
+    SC_DLLPUBLIC static void CaptureShapeOrientationInfo( std::vector< OrientationInfo >& infos, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& rxModel );
+    SC_DLLPUBLIC static void ApplyShapeOrientationInfo( std::vector< OrientationInfo >& infos, const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& rxModel, ScDocument& rDoc );
 };
 #endif
 
diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx
index c43a853..a5a9c0e 100644
--- a/sc/source/core/data/global.cxx
+++ b/sc/source/core/data/global.cxx
@@ -63,6 +63,15 @@
 #include <unotools/calendarwrapper.hxx>
 #include <unotools/collatorwrapper.hxx>
 #include <com/sun/star/i18n/CollatorOptions.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/document/XViewDataSupplier.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/table/XCell.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XCellAddressable.hpp>
 #include <unotools/intlwrapper.hxx>
 #include <unotools/syslocale.hxx>
 #include <unotools/transliterationwrapper.hxx>
@@ -87,11 +96,15 @@
 #include "sc.hrc"
 #include "scmod.hxx"
 #include "appoptio.hxx"
-
+#include "unonames.hxx"
+#include "drawview.hxx"
+#include "drawutil.hxx"
+#include "viewdata.hxx"
 // -----------------------------------------------------------------------
 
 using ::rtl::OUString;
 using ::rtl::OUStringBuffer;
+using namespace ::com::sun::star;
 
 #define CLIPST_AVAILABLE    0
 #define CLIPST_CAPTURED     1
@@ -1180,5 +1193,137 @@ IntlWrapper*         ScGlobal::GetScIntlWrapper()
     }
     return pLocale;
 }
+void ScGlobal::CaptureShapeOrientationInfo( std::vector< OrientationInfo >& infos, const uno::Reference<frame::XModel >& rxModel )
+{
+    rtl::OUString sHori( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_HORIPOS ) );
+    rtl::OUString sVert( RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_VERTPOS ) );
+    uno::Reference<drawing::XDrawPagesSupplier> xDrwSupp( rxModel, uno::UNO_QUERY );
+    uno::Reference<container::XIndexAccess> xPages( xDrwSupp.is() ? xDrwSupp->getDrawPages() : NULL, uno::UNO_QUERY );
+    if ( xPages.is() )
+    {
+        for ( sal_Int32 nIndex = 0, nPages = xPages->getCount(); nIndex < nPages; ++nIndex )
+        {
+            uno::Reference<container::XIndexAccess> xShapes( xPages->getByIndex( nIndex ), uno::UNO_QUERY );
+            for ( sal_Int32 nShapeIndex = 0, nShapes = xShapes->getCount(); nShapeIndex < nShapes; ++nShapeIndex )
+            {
+                uno::Reference< beans::XPropertySet > xShape( xShapes->getByIndex( nShapeIndex ), uno::UNO_QUERY );
+                uno::Reference< table::XCell > xCell( xShape->getPropertyValue( rtl::OUString(  RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_ANCHOR  ) ) ), uno::UNO_QUERY );
+                uno::Reference< sheet::XSpreadsheetDocument > xSpreadSheet( rxModel, uno::UNO_QUERY );
+                uno::Reference< container::XIndexAccess > xSheets( xSpreadSheet.is() ? xSpreadSheet->getSheets() : NULL, uno::UNO_QUERY );
+                uno::Reference< sheet::XSpreadsheet > xSheet;
+                uno::Reference< sheet::XCellAddressable > xAddressable( xCell, uno::UNO_QUERY );
+                if ( xSheets.is() && xAddressable.is() && xSpreadSheet.is() )
+                    xSheet.set( xSheets->getByIndex( xAddressable->getCellAddress().Sheet ), uno::UNO_QUERY );
+                // only capture orientation if the shape is anchored to cell
+                if ( xShape.is() && xCell.is() && xAddressable.is() && xSheet.is() )
+                {
+                    uno::Reference< beans::XPropertySetInfo > xShapePropInfo = xShape->getPropertySetInfo();
+                    if ( xShapePropInfo.is() && xShapePropInfo->hasPropertyByName( sHori ) && xShapePropInfo->hasPropertyByName( sVert ) )
+                    {
+                        OrientationInfo aShape;
+                        aShape.mxShape.set( xShape, uno::UNO_QUERY );
+                        xShape->getPropertyValue( sHori ) >>= aShape.mnHori;
+                        xShape->getPropertyValue( sVert ) >>= aShape.mnVert;
+                        aShape.maAddress = xAddressable->getCellAddress();
+                        infos.push_back( aShape );
+                        // Remove temporary cell anchor. Ideally we should
+                        // preserve the cell anchoring but the drawing layer
+                        // and the ScGridWindow don't calcuate positions in the
+                        // same way. This means unfortunately ( especially if
+                        // row heights above the shape are not uniform ) that
+                        // the shape anchor position and the shape position
+                        // can be quite skewed. The only alterative
+                        // unfortunately is to position the shape absolutely
+                        // rather than relative to a cell address :-(
+                        xShape->setPropertyValue( rtl::OUString(  RTL_CONSTASCII_USTRINGPARAM( SC_UNONAME_ANCHOR ) ), uno::makeAny( xSheet ) );
+                    }
+                }
+            }
+        }
+    }
+}
+
+// Note: this method is only expected to be called when importing an alien
+// document.
+void ScGlobal::ApplyShapeOrientationInfo( std::vector< OrientationInfo >& infos, const uno::Reference< frame::XModel >& rxModel, ScDocument& rDoc )
+{
+    // For each shape previously anchored to a cell calculate the shape
+    // position ( as the view would ) based on the available zoom and scaling.
+    // This prevents the shape being being drawn in an unexpected postion due to
+    // a) differences in the calculation of shape position by drawinglayer and
+    //    the postion of the actual rows drawn by ScGridwin
+    // b) affect of UpdateAllRowHeights
+    for ( std::vector< OrientationInfo >::iterator it = infos.begin(), it_end = infos.end(); it != it_end; ++it )
+    {
+        OutputDevice* pDevice = Application::GetDefaultDevice();
+        if ( pDevice )
+        {
+            uno::Reference< document::XViewDataSupplier > xViewSup( rxModel, uno::UNO_QUERY );
+            uno::Reference< container::XIndexAccess > xIndexAccess;
+            if ( xViewSup.is() )
+                xIndexAccess = xViewSup->getViewData();
+            uno::Sequence< beans::PropertyValue > aSeq;
+            // set up partial view data to calculate zoom, pptx & ppty values
+            ScViewData aViewData( NULL, NULL );
+            aViewData.InitData( &rDoc );
+            // support initialising view data from binary import
+            if ( ScExtDocOptions* pDocOptions = rDoc.GetExtDocOptions() )
+            {
+                aViewData.ReadExtOptions( *pDocOptions );
+            }
+            else // or from the view data from the model ( oox import )
+            {
+                if ( xIndexAccess.is() && xIndexAccess->getCount() )
+                    xIndexAccess->getByIndex(0) >>= aSeq;
+                aViewData.ReadUserDataSequence( aSeq );
+            }
+
+            aViewData.SetTabNo( it->maAddress.Sheet );
+
+            long nHeight = 0;
+            long nWidth = 0;
+
+            MapMode aTmpMode( MAP_TWIP );
+            // get postion of shape based on the start anchor
+            for ( int i = 0; i < it->maAddress.Column; ++i )
+            {
+                long nTwip =  aViewData.GetDocument()->GetColWidth(  i, it->maAddress.Sheet );
+                nWidth += ( nTwip * aViewData.GetPPTX() );
+            }
+            for ( int i = 0; i < it->maAddress.Row; ++i )
+            {
+                long nTwip =  aViewData.GetDocument()->GetRowHeight(  i, it->maAddress.Sheet );
+                nHeight += ( nTwip * aViewData.GetPPTY() );
+            }
+
+            // determine the scale that will be used by the view
+            Fraction aScaleX;
+            Fraction aScaleY;
+            SCROW nEndRow = it->maAddress.Row;
+            SCCOL nEndCol = it->maAddress.Column;
+            aViewData.GetDocument()->GetTableArea( aViewData.GetTabNo(), nEndCol, nEndRow );
+            if (nEndCol<20)
+                nEndCol = 20;
+           if (nEndRow<20)
+                nEndRow = 20;
+
+            ScDrawUtil::CalcScale( aViewData.GetDocument(), aViewData.GetTabNo(), 0,0, nEndCol,nEndRow, pDevice,aViewData.GetZoomX(),aViewData.GetZoomY(),aViewData.GetPPTX(),aViewData.GetPPTY(), aScaleX,aScaleY );
+
+            // finally calculate and apply the position of shape ( including
+            // any vertical and horizontal offsets )
+            Point aTmpPos( nWidth, nHeight);
+            aTmpMode = MapMode ( MAP_100TH_MM );
+            aTmpMode.SetScaleX(aScaleX);
+            aTmpMode.SetScaleY(aScaleY);
+
+            aTmpPos = pDevice->PixelToLogic( aTmpPos, aTmpMode );
+            if ( it->mxShape.is() )
+            {
+                com::sun::star::awt::Point aUnoPos( aTmpPos.X() + it->mnHori, aTmpPos.Y() +  it->mnVert );
+                it->mxShape->setPosition( aUnoPos );
+            }
+        }
+    }
+}
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
index b9be493..d8851fc 100644
--- a/sc/source/ui/unoobj/docuno.cxx
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -1692,7 +1692,24 @@ void SAL_CALL ScModelObj::setPropertyValue(
             {
                 pDoc->EnableAdjustHeight( bAdjustHeightEnabled );
                 if( bAdjustHeightEnabled )
+                {
+                    // during import ( e.g. oox ) shapes anchored by cell lose
+                    // any additional Hori/Vert orientation ( which offsets the
+                    // shape position relative to the cell ) when
+                    // UpdateAllRowHeights is called. Here we save Hori/Vert
+                    // values before calling UpdateAllRowHeights. Also due to
+                    // differences between the drawing layer and gridwindow
+                    // position calculations we actually can't reliably use cell
+                    // anchoring so we need to remove the cell anchoring, custom
+                    // calculate where the view would position the shape and
+                    // then position the shape absolutely at the newly
+                    // calculated postion.
+                    std::vector< OrientationInfo > savedOrientations;
+                    uno::Reference< frame::XModel > xModel( this );
+                    ScGlobal::CaptureShapeOrientationInfo( savedOrientations, xModel );
                     pDocShell->UpdateAllRowHeights();
+                    ScGlobal::ApplyShapeOrientationInfo( savedOrientations, xModel, *pDoc );
+                }
             }
         }
         else if ( aString.EqualsAscii( SC_UNO_ISEXECUTELINKENABLED ) )
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index 26c6346..875889e 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -2480,7 +2480,8 @@ void ScViewData::ReadExtOptions( const ScExtDocOptions& rDocOpt )
     /*  Width of the tabbar, relative to frame window width. We do not have the
         correct width of the frame window here -> store in ScTabView, which sets
         the size in the next resize. */
-    pView->SetPendingRelTabBarWidth( rDocSett.mfTabBarWidth );
+    if ( pView )
+        pView->SetPendingRelTabBarWidth( rDocSett.mfTabBarWidth );
 
     // sheet settings
     for( SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabData.size()); ++nTab )
@@ -2780,12 +2781,12 @@ void ScViewData::ReadUserDataSequence(const uno::Sequence <beans::PropertyValue>
                     nTabNo = nTab;
             }
         }
-        else if (sName.compareToAscii(SC_HORIZONTALSCROLLBARWIDTH) == 0)
+        else if (pView && sName.compareToAscii(SC_HORIZONTALSCROLLBARWIDTH) == 0)
         {
             if (rSettings[i].Value >>= nTemp32)
                 pView->SetTabBarWidth(nTemp32);
         }
-        else if (sName.compareToAscii(SC_RELHORIZONTALTABBARWIDTH) == 0)
+        else if (pView && sName.compareToAscii(SC_RELHORIZONTALTABBARWIDTH) == 0)
         {
             double fWidth = 0.0;
             if (rSettings[i].Value >>= fWidth)
-- 
1.7.3.4


--------------060806050201050307000309--


More information about the LibreOffice mailing list