| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sc.hxx" |
| #include "XMLTableShapeResizer.hxx" |
| #include "unonames.hxx" |
| #include "document.hxx" |
| #include "xmlimprt.hxx" |
| #include "chartlis.hxx" |
| #include "XMLConverter.hxx" |
| #include "rangeutl.hxx" |
| #include "reftokenhelper.hxx" |
| #include <tools/debug.hxx> |
| #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> |
| #include <com/sun/star/table/XColumnRowRange.hpp> |
| #include <com/sun/star/beans/XPropertySet.hpp> |
| |
| #include <memory> |
| #include <vector> |
| |
| using namespace ::com::sun::star; |
| using ::std::auto_ptr; |
| using ::std::vector; |
| using ::rtl::OUString; |
| |
| ScMyShapeResizer::ScMyShapeResizer(ScXMLImport& rTempImport) |
| : rImport(rTempImport), |
| aShapes(), |
| pCollection(NULL) |
| { |
| } |
| |
| ScMyShapeResizer::~ScMyShapeResizer() |
| { |
| } |
| |
| sal_Bool ScMyShapeResizer::IsOLE(uno::Reference< drawing::XShape >& rShape) const |
| { |
| return rShape->getShapeType().equals(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.OLE2Shape"))); |
| } |
| |
| void ScMyShapeResizer::CreateChartListener(ScDocument* pDoc, |
| const rtl::OUString& rName, |
| const rtl::OUString* pRangeList) |
| { |
| if (!pDoc || !pRangeList) |
| // These are minimum required. |
| return; |
| |
| if (!pRangeList->getLength()) |
| { |
| pDoc->AddOLEObjectToCollection(rName); |
| return; |
| } |
| |
| OUString aRangeStr; |
| ScRangeStringConverter::GetStringFromXMLRangeString(aRangeStr, *pRangeList, pDoc); |
| if (!aRangeStr.getLength()) |
| { |
| pDoc->AddOLEObjectToCollection(rName); |
| return; |
| } |
| |
| if (!pCollection) |
| pCollection = pDoc->GetChartListenerCollection(); |
| |
| if (!pCollection) |
| return; |
| |
| auto_ptr< vector<ScSharedTokenRef> > pRefTokens(new vector<ScSharedTokenRef>); |
| ScRefTokenHelper::compileRangeRepresentation(*pRefTokens, aRangeStr, pDoc); |
| if (!pRefTokens->empty()) |
| { |
| ScChartListener* pCL(new ScChartListener(rName, pDoc, pRefTokens.release())); |
| |
| //for loading binary files e.g. |
| //if we have the flat filter we need to set the dirty flag thus the visible charts get repainted |
| //otherwise the charts keep their first visual representation which was created at a moment where the calc itself was not loaded completly and is incorect therefor |
| if( (rImport.getImportFlags() & IMPORT_ALL) == IMPORT_ALL ) |
| pCL->SetDirty( sal_True ); |
| else |
| { |
| // #i104899# If a formula cell is already dirty, further changes aren't propagated. |
| // This can happen easily now that row heights aren't updated for all sheets. |
| pDoc->InterpretDirtyCells( *pCL->GetRangeList() ); |
| } |
| |
| pCollection->Insert( pCL ); |
| pCL->StartListeningTo(); |
| } |
| } |
| |
| void ScMyShapeResizer::AddShape(uno::Reference <drawing::XShape>& rShape, |
| rtl::OUString* pRangeList, |
| table::CellAddress& rStartAddress, table::CellAddress& rEndAddress, |
| sal_Int32 nEndX, sal_Int32 nEndY) |
| { |
| ScMyToResizeShape aShape; |
| aShape.xShape.set(rShape); |
| aShape.pRangeList = pRangeList; |
| aShape.aEndCell = rEndAddress; |
| aShape.aStartCell = rStartAddress; |
| aShape.nEndY = nEndY; |
| aShape.nEndX = nEndX; |
| aShapes.push_back(aShape); |
| } |
| |
| void ScMyShapeResizer::GetNewShapeSizePos(ScDocument* pDoc, const Rectangle& rStartRect, |
| const table::CellAddress& rEndCell, |
| awt::Point& rPoint, awt::Size& rSize, |
| sal_Int32& rEndX, sal_Int32& rEndY) const |
| { |
| awt::Point aRefPoint; |
| sal_Bool bNegativePage(pDoc->IsNegativePage(rEndCell.Sheet)); |
| if (bNegativePage) |
| aRefPoint.X = rStartRect.Right(); |
| else |
| aRefPoint.X = rStartRect.Left(); |
| aRefPoint.Y = rStartRect.Top(); |
| Rectangle aRect(pDoc->GetMMRect( |
| static_cast<SCCOL>(rEndCell.Column), static_cast<SCROW>(rEndCell.Row), |
| static_cast<SCCOL>(rEndCell.Column), static_cast<SCROW>(rEndCell.Row), rEndCell.Sheet )); |
| if (bNegativePage) |
| rEndX = -rEndX + aRect.Right(); |
| else |
| rEndX += aRect.Left(); |
| rEndY += aRect.Top(); |
| rPoint.X += aRefPoint.X; |
| if (bNegativePage) |
| { |
| if (rPoint.X < rStartRect.Left()) |
| rPoint.X = rStartRect.Left() + 2; // increment by 2 100th_mm because the cellwidth is internal in twips |
| } |
| else |
| { |
| if (rPoint.X > rStartRect.Right()) |
| rPoint.X = rStartRect.Right() - 2; // decrement by 2 100th_mm because the cellwidth is internal in twips |
| } |
| rPoint.Y += aRefPoint.Y; |
| if (rPoint.Y > rStartRect.Bottom()) |
| rPoint.Y = rStartRect.Bottom() - 2; // decrement by 2 100th_mm because the cellheight is internal in twips |
| if (bNegativePage) |
| { |
| rSize.Width = -(rEndX - rPoint.X); |
| } |
| else |
| rSize.Width = rEndX - rPoint.X; |
| rSize.Height = rEndY - rPoint.Y; |
| } |
| |
| void ScMyShapeResizer::ResizeShapes() |
| { |
| if (!aShapes.empty() && rImport.GetModel().is()) |
| { |
| rtl::OUString sRowHeight(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CELLHGT)); |
| rtl::OUString sPersistName (RTL_CONSTASCII_USTRINGPARAM("PersistName")); |
| rtl::OUString sCaptionPoint( RTL_CONSTASCII_USTRINGPARAM( "CaptionPoint" )); |
| rtl::OUString sConnectorShape( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.ConnectorShape") ); |
| rtl::OUString sCaptionShape( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.CaptionShape") ); |
| rtl::OUString sStartShape(RTL_CONSTASCII_USTRINGPARAM("StartShape")); |
| rtl::OUString sEndShape(RTL_CONSTASCII_USTRINGPARAM("EndShape")); |
| rtl::OUString sStartPosition(RTL_CONSTASCII_USTRINGPARAM("StartPosition")); |
| rtl::OUString sEndPosition(RTL_CONSTASCII_USTRINGPARAM("EndPosition")); |
| uno::Reference<table::XCellRange> xTableRow; |
| uno::Reference<sheet::XSpreadsheet> xSheet; |
| uno::Reference<table::XTableRows> xTableRows; |
| sal_Int32 nOldRow(-1); |
| sal_Int32 nOldSheet(-1); |
| ScMyToResizeShapes::iterator aItr(aShapes.begin()); |
| ScMyToResizeShapes::iterator aEndItr(aShapes.end()); |
| uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( rImport.GetModel(), uno::UNO_QUERY ); |
| if ( xSpreadDoc.is() ) |
| { |
| uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY ); |
| ScDocument* pDoc(rImport.GetDocument()); |
| if ( pDoc && xIndex.is() ) |
| { |
| rImport.LockSolarMutex(); |
| while (aItr != aEndItr) |
| { |
| // #i78086# invalid cell position is used to call CreateChartListener only |
| if ( aItr->aEndCell.Sheet >= 0 ) |
| { |
| if ((nOldSheet != aItr->aEndCell.Sheet) || !xSheet.is()) |
| { |
| nOldSheet = aItr->aEndCell.Sheet; |
| xSheet.set(xIndex->getByIndex(nOldSheet), uno::UNO_QUERY); |
| if (xSheet.is()) |
| { |
| uno::Reference<table::XColumnRowRange> xColumnRowRange (xSheet, uno::UNO_QUERY); |
| if (xColumnRowRange.is()) |
| xTableRows = xColumnRowRange->getRows(); |
| } |
| } |
| if (xTableRows.is()) |
| { |
| if (nOldRow != aItr->aEndCell.Row || !xTableRow.is()) |
| { |
| nOldRow = aItr->aEndCell.Row; |
| xTableRows->getByIndex(nOldRow) >>= xTableRow; |
| } |
| if (xTableRow.is()) |
| { |
| uno::Reference <beans::XPropertySet> xRowProperties(xTableRow, uno::UNO_QUERY); |
| if (xRowProperties.is()) |
| { |
| sal_Int32 nHeight; |
| if (xRowProperties->getPropertyValue(sRowHeight) >>= nHeight) |
| { |
| Rectangle aRec = pDoc->GetMMRect(static_cast<SCCOL>(aItr->aStartCell.Column), static_cast<SCROW>(aItr->aStartCell.Row), |
| static_cast<SCCOL>(aItr->aStartCell.Column), static_cast<SCROW>(aItr->aStartCell.Row), aItr->aStartCell.Sheet); |
| awt::Point aPoint(aItr->xShape->getPosition()); |
| awt::Size aSize(aItr->xShape->getSize()); |
| if (pDoc->IsNegativePage(static_cast<SCTAB>(nOldSheet))) |
| aPoint.X += aSize.Width; |
| if (aItr->nEndY >= 0 && aItr->nEndX >= 0) |
| { |
| if (aItr->xShape->getShapeType().equals(sConnectorShape)) |
| { |
| //#103122#; handle connected Connectorshapes |
| uno::Reference<beans::XPropertySet> xShapeProps (aItr->xShape, uno::UNO_QUERY); |
| if(xShapeProps.is()) |
| { |
| uno::Reference<drawing::XShape> xStartShape(xShapeProps->getPropertyValue( sStartShape ), uno::UNO_QUERY); |
| uno::Reference<drawing::XShape> xEndShape(xShapeProps->getPropertyValue( sEndShape ), uno::UNO_QUERY); |
| if (!xStartShape.is() && !xEndShape.is()) |
| { |
| awt::Size aOldSize(aSize); |
| GetNewShapeSizePos(pDoc, aRec, aItr->aEndCell, aPoint, aSize, aItr->nEndX, aItr->nEndY); |
| aItr->xShape->setPosition(aPoint); |
| if( (aSize.Width != aOldSize.Width) || |
| (aSize.Height != aOldSize.Height) ) |
| aItr->xShape->setSize(aSize); |
| } |
| else if (xStartShape.is() && xEndShape.is()) |
| { |
| // do nothing, because they are connected |
| } |
| else |
| { |
| // only one point is connected, the other should be moved |
| |
| rtl::OUString sProperty; |
| if (xStartShape.is()) |
| { |
| awt::Point aEndPoint; |
| xShapeProps->getPropertyValue(sEndPosition) >>= aEndPoint; |
| aPoint.X = aRec.Left() + aEndPoint.X; |
| aPoint.Y = aRec.Top() + aEndPoint.Y; |
| sProperty = sEndPosition; |
| } |
| else |
| { |
| awt::Point aStartPoint; |
| xShapeProps->getPropertyValue(sStartPosition) >>= aStartPoint; |
| aPoint.X = aRec.Left() + aStartPoint.X; |
| aPoint.Y = aRec.Top() + aStartPoint.Y; |
| sProperty = sStartPosition; |
| } |
| xShapeProps->setPropertyValue(sProperty, uno::makeAny(aPoint)); |
| } |
| } |
| } |
| else |
| { |
| awt::Size aOldSize(aSize); |
| GetNewShapeSizePos(pDoc, aRec, aItr->aEndCell, aPoint, aSize, aItr->nEndX, aItr->nEndY); |
| if (pDoc->IsNegativePage(static_cast<SCTAB>(nOldSheet))) |
| aPoint.X -= aSize.Width; |
| aItr->xShape->setPosition(aPoint); |
| if( (aSize.Width != aOldSize.Width) || |
| (aSize.Height != aOldSize.Height) ) |
| aItr->xShape->setSize(aSize); |
| } |
| } |
| else |
| { |
| if (aItr->xShape->getShapeType().equals(sCaptionShape)) |
| { |
| Rectangle aRectangle(aPoint.X, aPoint.Y, aPoint.X + aSize.Width, aPoint.Y + aSize.Height); |
| |
| awt::Point aCaptionPoint; |
| uno::Reference< beans::XPropertySet > xShapeProps(aItr->xShape, uno::UNO_QUERY); |
| if (xShapeProps.is()) |
| { |
| try |
| { |
| xShapeProps->getPropertyValue( sCaptionPoint ) >>= aCaptionPoint; |
| } |
| catch ( uno::Exception& ) |
| { |
| DBG_ERROR("This Captionshape has no CaptionPoint property."); |
| } |
| } |
| Point aCorePoint(aPoint.X, aPoint.Y); |
| Point aCoreCaptionPoint(aCaptionPoint.X, aCaptionPoint.Y); |
| aCoreCaptionPoint += aCorePoint; |
| aRectangle.Union(Rectangle(aCoreCaptionPoint, aCoreCaptionPoint)); |
| |
| Point aBeforeRightBottomPoint(aRectangle.BottomRight()); |
| |
| aRectangle += aRec.TopLeft(); |
| if (aRectangle.Left() > aRec.Right()) |
| aRectangle -= (Point(aRectangle.Left() - aRec.Right() + 2, 0)); |
| if (aRectangle.Top() > aRec.Bottom()) |
| aRectangle -= (Point(0, aRectangle.Top() - aRec.Bottom() + 2)); |
| |
| Point aDifferencePoint(aRectangle.BottomRight() - aBeforeRightBottomPoint); |
| aPoint.X += aDifferencePoint.X(); |
| aPoint.Y += aDifferencePoint.Y(); |
| |
| aItr->xShape->setPosition(aPoint); |
| } |
| else |
| { |
| // #96159# it is possible, that shapes have a negative position |
| // this is now handled here |
| DBG_ERROR("no or negative end address of this shape"); |
| awt::Point aRefPoint; |
| aRefPoint.X = aRec.Left(); |
| aRefPoint.Y = aRec.Top(); |
| aPoint.X += aRefPoint.X; |
| if (aPoint.X > aRec.Right()) |
| aPoint.X = aRec.Right() - 2; // decrement by 2 100th_mm because the cellheight is internal in twips |
| aPoint.Y += aRefPoint.Y; |
| if (aPoint.Y > aRec.Bottom()) |
| aPoint.Y = aRec.Bottom() - 2; // decrement by 2 100th_mm because the cellheight is internal in twips |
| aItr->xShape->setPosition(aPoint); |
| } |
| } |
| } |
| } |
| } |
| } |
| else |
| { |
| DBG_ERROR("something wents wrong"); |
| } |
| } |
| // #i78086# call CreateChartListener also for invalid position (anchored to sheet) |
| if (IsOLE(aItr->xShape)) |
| { |
| uno::Reference < beans::XPropertySet > xShapeProps ( aItr->xShape, uno::UNO_QUERY ); |
| uno::Reference < beans::XPropertySetInfo > xShapeInfo(xShapeProps->getPropertySetInfo()); |
| rtl::OUString sName; |
| if (xShapeProps.is() && xShapeInfo.is() && xShapeInfo->hasPropertyByName(sPersistName) && |
| (xShapeProps->getPropertyValue(sPersistName) >>= sName)) |
| CreateChartListener(pDoc, sName, aItr->pRangeList); |
| } |
| if (aItr->pRangeList) |
| delete aItr->pRangeList; |
| aItr = aShapes.erase(aItr); |
| } |
| rImport.UnlockSolarMutex(); |
| // if (pCollection) |
| // pDoc->SetChartListenerCollection(pCollection); |
| } |
| } |
| } |
| } |