1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 #include "XMLTableShapeResizer.hxx"
27 #include "unonames.hxx"
28 #include "document.hxx"
29 #include "xmlimprt.hxx"
30 #include "chartlis.hxx"
31 #include "XMLConverter.hxx"
32 #include "rangeutl.hxx"
33 #include "reftokenhelper.hxx"
34 #include <tools/debug.hxx>
35 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
36 #include <com/sun/star/table/XColumnRowRange.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38
39 #include <memory>
40 #include <vector>
41
42 using namespace ::com::sun::star;
43 using ::std::auto_ptr;
44 using ::std::vector;
45 using ::rtl::OUString;
46
ScMyShapeResizer(ScXMLImport & rTempImport)47 ScMyShapeResizer::ScMyShapeResizer(ScXMLImport& rTempImport)
48 : rImport(rTempImport),
49 aShapes(),
50 pCollection(NULL)
51 {
52 }
53
~ScMyShapeResizer()54 ScMyShapeResizer::~ScMyShapeResizer()
55 {
56 }
57
IsOLE(uno::Reference<drawing::XShape> & rShape) const58 sal_Bool ScMyShapeResizer::IsOLE(uno::Reference< drawing::XShape >& rShape) const
59 {
60 return rShape->getShapeType().equals(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.OLE2Shape")));
61 }
62
CreateChartListener(ScDocument * pDoc,const rtl::OUString & rName,const rtl::OUString * pRangeList)63 void ScMyShapeResizer::CreateChartListener(ScDocument* pDoc,
64 const rtl::OUString& rName,
65 const rtl::OUString* pRangeList)
66 {
67 if (!pDoc || !pRangeList)
68 // These are minimum required.
69 return;
70
71 if (!pRangeList->getLength())
72 {
73 pDoc->AddOLEObjectToCollection(rName);
74 return;
75 }
76
77 OUString aRangeStr;
78 ScRangeStringConverter::GetStringFromXMLRangeString(aRangeStr, *pRangeList, pDoc);
79 if (!aRangeStr.getLength())
80 {
81 pDoc->AddOLEObjectToCollection(rName);
82 return;
83 }
84
85 if (!pCollection)
86 pCollection = pDoc->GetChartListenerCollection();
87
88 if (!pCollection)
89 return;
90
91 auto_ptr< vector<ScSharedTokenRef> > pRefTokens(new vector<ScSharedTokenRef>);
92 ScRefTokenHelper::compileRangeRepresentation(*pRefTokens, aRangeStr, pDoc);
93 if (!pRefTokens->empty())
94 {
95 ScChartListener* pCL(new ScChartListener(rName, pDoc, pRefTokens.release()));
96
97 //for loading binary files e.g.
98 //if we have the flat filter we need to set the dirty flag thus the visible charts get repainted
99 //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
100 if( (rImport.getImportFlags() & IMPORT_ALL) == IMPORT_ALL )
101 pCL->SetDirty( sal_True );
102 else
103 {
104 // #i104899# If a formula cell is already dirty, further changes aren't propagated.
105 // This can happen easily now that row heights aren't updated for all sheets.
106 pDoc->InterpretDirtyCells( *pCL->GetRangeList() );
107 }
108
109 pCollection->Insert( pCL );
110 pCL->StartListeningTo();
111 }
112 }
113
AddShape(uno::Reference<drawing::XShape> & rShape,rtl::OUString * pRangeList,table::CellAddress & rStartAddress,table::CellAddress & rEndAddress,sal_Int32 nEndX,sal_Int32 nEndY)114 void ScMyShapeResizer::AddShape(uno::Reference <drawing::XShape>& rShape,
115 rtl::OUString* pRangeList,
116 table::CellAddress& rStartAddress, table::CellAddress& rEndAddress,
117 sal_Int32 nEndX, sal_Int32 nEndY)
118 {
119 ScMyToResizeShape aShape;
120 aShape.xShape.set(rShape);
121 aShape.pRangeList = pRangeList;
122 aShape.aEndCell = rEndAddress;
123 aShape.aStartCell = rStartAddress;
124 aShape.nEndY = nEndY;
125 aShape.nEndX = nEndX;
126 aShapes.push_back(aShape);
127 }
128
GetNewShapeSizePos(ScDocument * pDoc,const Rectangle & rStartRect,const table::CellAddress & rEndCell,awt::Point & rPoint,awt::Size & rSize,sal_Int32 & rEndX,sal_Int32 & rEndY) const129 void ScMyShapeResizer::GetNewShapeSizePos(ScDocument* pDoc, const Rectangle& rStartRect,
130 const table::CellAddress& rEndCell,
131 awt::Point& rPoint, awt::Size& rSize,
132 sal_Int32& rEndX, sal_Int32& rEndY) const
133 {
134 awt::Point aRefPoint;
135 sal_Bool bNegativePage(pDoc->IsNegativePage(rEndCell.Sheet));
136 if (bNegativePage)
137 aRefPoint.X = rStartRect.Right();
138 else
139 aRefPoint.X = rStartRect.Left();
140 aRefPoint.Y = rStartRect.Top();
141 Rectangle aRect(pDoc->GetMMRect(
142 static_cast<SCCOL>(rEndCell.Column), static_cast<SCROW>(rEndCell.Row),
143 static_cast<SCCOL>(rEndCell.Column), static_cast<SCROW>(rEndCell.Row), rEndCell.Sheet ));
144 if (bNegativePage)
145 rEndX = -rEndX + aRect.Right();
146 else
147 rEndX += aRect.Left();
148 rEndY += aRect.Top();
149 rPoint.X += aRefPoint.X;
150 if (bNegativePage)
151 {
152 if (rPoint.X < rStartRect.Left())
153 rPoint.X = rStartRect.Left() + 2; // increment by 2 100th_mm because the cellwidth is internal in twips
154 }
155 else
156 {
157 if (rPoint.X > rStartRect.Right())
158 rPoint.X = rStartRect.Right() - 2; // decrement by 2 100th_mm because the cellwidth is internal in twips
159 }
160 rPoint.Y += aRefPoint.Y;
161 if (rPoint.Y > rStartRect.Bottom())
162 rPoint.Y = rStartRect.Bottom() - 2; // decrement by 2 100th_mm because the cellheight is internal in twips
163 if (bNegativePage)
164 {
165 rSize.Width = -(rEndX - rPoint.X);
166 }
167 else
168 rSize.Width = rEndX - rPoint.X;
169 rSize.Height = rEndY - rPoint.Y;
170 }
171
ResizeShapes()172 void ScMyShapeResizer::ResizeShapes()
173 {
174 if (!aShapes.empty() && rImport.GetModel().is())
175 {
176 rtl::OUString sRowHeight(RTL_CONSTASCII_USTRINGPARAM(SC_UNONAME_CELLHGT));
177 rtl::OUString sPersistName (RTL_CONSTASCII_USTRINGPARAM("PersistName"));
178 rtl::OUString sCaptionPoint( RTL_CONSTASCII_USTRINGPARAM( "CaptionPoint" ));
179 rtl::OUString sConnectorShape( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.ConnectorShape") );
180 rtl::OUString sCaptionShape( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.drawing.CaptionShape") );
181 rtl::OUString sStartShape(RTL_CONSTASCII_USTRINGPARAM("StartShape"));
182 rtl::OUString sEndShape(RTL_CONSTASCII_USTRINGPARAM("EndShape"));
183 rtl::OUString sStartPosition(RTL_CONSTASCII_USTRINGPARAM("StartPosition"));
184 rtl::OUString sEndPosition(RTL_CONSTASCII_USTRINGPARAM("EndPosition"));
185 uno::Reference<table::XCellRange> xTableRow;
186 uno::Reference<sheet::XSpreadsheet> xSheet;
187 uno::Reference<table::XTableRows> xTableRows;
188 sal_Int32 nOldRow(-1);
189 sal_Int32 nOldSheet(-1);
190 ScMyToResizeShapes::iterator aItr(aShapes.begin());
191 ScMyToResizeShapes::iterator aEndItr(aShapes.end());
192 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( rImport.GetModel(), uno::UNO_QUERY );
193 if ( xSpreadDoc.is() )
194 {
195 uno::Reference<container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
196 ScDocument* pDoc(rImport.GetDocument());
197 if ( pDoc && xIndex.is() )
198 {
199 rImport.LockSolarMutex();
200 while (aItr != aEndItr)
201 {
202 // #i78086# invalid cell position is used to call CreateChartListener only
203 if ( aItr->aEndCell.Sheet >= 0 )
204 {
205 if ((nOldSheet != aItr->aEndCell.Sheet) || !xSheet.is())
206 {
207 nOldSheet = aItr->aEndCell.Sheet;
208 xSheet.set(xIndex->getByIndex(nOldSheet), uno::UNO_QUERY);
209 if (xSheet.is())
210 {
211 uno::Reference<table::XColumnRowRange> xColumnRowRange (xSheet, uno::UNO_QUERY);
212 if (xColumnRowRange.is())
213 xTableRows = xColumnRowRange->getRows();
214 }
215 }
216 if (xTableRows.is())
217 {
218 if (nOldRow != aItr->aEndCell.Row || !xTableRow.is())
219 {
220 nOldRow = aItr->aEndCell.Row;
221 xTableRows->getByIndex(nOldRow) >>= xTableRow;
222 }
223 if (xTableRow.is())
224 {
225 uno::Reference <beans::XPropertySet> xRowProperties(xTableRow, uno::UNO_QUERY);
226 if (xRowProperties.is())
227 {
228 sal_Int32 nHeight;
229 if (xRowProperties->getPropertyValue(sRowHeight) >>= nHeight)
230 {
231 Rectangle aRec = pDoc->GetMMRect(static_cast<SCCOL>(aItr->aStartCell.Column), static_cast<SCROW>(aItr->aStartCell.Row),
232 static_cast<SCCOL>(aItr->aStartCell.Column), static_cast<SCROW>(aItr->aStartCell.Row), aItr->aStartCell.Sheet);
233 awt::Point aPoint(aItr->xShape->getPosition());
234 awt::Size aSize(aItr->xShape->getSize());
235 if (pDoc->IsNegativePage(static_cast<SCTAB>(nOldSheet)))
236 aPoint.X += aSize.Width;
237 if (aItr->nEndY >= 0 && aItr->nEndX >= 0)
238 {
239 if (aItr->xShape->getShapeType().equals(sConnectorShape))
240 {
241 //#103122#; handle connected Connectorshapes
242 uno::Reference<beans::XPropertySet> xShapeProps (aItr->xShape, uno::UNO_QUERY);
243 if(xShapeProps.is())
244 {
245 uno::Reference<drawing::XShape> xStartShape(xShapeProps->getPropertyValue( sStartShape ), uno::UNO_QUERY);
246 uno::Reference<drawing::XShape> xEndShape(xShapeProps->getPropertyValue( sEndShape ), uno::UNO_QUERY);
247 if (!xStartShape.is() && !xEndShape.is())
248 {
249 awt::Size aOldSize(aSize);
250 GetNewShapeSizePos(pDoc, aRec, aItr->aEndCell, aPoint, aSize, aItr->nEndX, aItr->nEndY);
251 aItr->xShape->setPosition(aPoint);
252 if( (aSize.Width != aOldSize.Width) ||
253 (aSize.Height != aOldSize.Height) )
254 aItr->xShape->setSize(aSize);
255 }
256 else if (xStartShape.is() && xEndShape.is())
257 {
258 // do nothing, because they are connected
259 }
260 else
261 {
262 // only one point is connected, the other should be moved
263
264 rtl::OUString sProperty;
265 if (xStartShape.is())
266 {
267 awt::Point aEndPoint;
268 xShapeProps->getPropertyValue(sEndPosition) >>= aEndPoint;
269 aPoint.X = aRec.Left() + aEndPoint.X;
270 aPoint.Y = aRec.Top() + aEndPoint.Y;
271 sProperty = sEndPosition;
272 }
273 else
274 {
275 awt::Point aStartPoint;
276 xShapeProps->getPropertyValue(sStartPosition) >>= aStartPoint;
277 aPoint.X = aRec.Left() + aStartPoint.X;
278 aPoint.Y = aRec.Top() + aStartPoint.Y;
279 sProperty = sStartPosition;
280 }
281 xShapeProps->setPropertyValue(sProperty, uno::makeAny(aPoint));
282 }
283 }
284 }
285 else
286 {
287 awt::Size aOldSize(aSize);
288 GetNewShapeSizePos(pDoc, aRec, aItr->aEndCell, aPoint, aSize, aItr->nEndX, aItr->nEndY);
289 if (pDoc->IsNegativePage(static_cast<SCTAB>(nOldSheet)))
290 aPoint.X -= aSize.Width;
291 aItr->xShape->setPosition(aPoint);
292 if( (aSize.Width != aOldSize.Width) ||
293 (aSize.Height != aOldSize.Height) )
294 aItr->xShape->setSize(aSize);
295 }
296 }
297 else
298 {
299 if (aItr->xShape->getShapeType().equals(sCaptionShape))
300 {
301 Rectangle aRectangle(aPoint.X, aPoint.Y, aPoint.X + aSize.Width, aPoint.Y + aSize.Height);
302
303 awt::Point aCaptionPoint;
304 uno::Reference< beans::XPropertySet > xShapeProps(aItr->xShape, uno::UNO_QUERY);
305 if (xShapeProps.is())
306 {
307 try
308 {
309 xShapeProps->getPropertyValue( sCaptionPoint ) >>= aCaptionPoint;
310 }
311 catch ( uno::Exception& )
312 {
313 DBG_ERROR("This Captionshape has no CaptionPoint property.");
314 }
315 }
316 Point aCorePoint(aPoint.X, aPoint.Y);
317 Point aCoreCaptionPoint(aCaptionPoint.X, aCaptionPoint.Y);
318 aCoreCaptionPoint += aCorePoint;
319 aRectangle.Union(Rectangle(aCoreCaptionPoint, aCoreCaptionPoint));
320
321 Point aBeforeRightBottomPoint(aRectangle.BottomRight());
322
323 aRectangle += aRec.TopLeft();
324 if (aRectangle.Left() > aRec.Right())
325 aRectangle -= (Point(aRectangle.Left() - aRec.Right() + 2, 0));
326 if (aRectangle.Top() > aRec.Bottom())
327 aRectangle -= (Point(0, aRectangle.Top() - aRec.Bottom() + 2));
328
329 Point aDifferencePoint(aRectangle.BottomRight() - aBeforeRightBottomPoint);
330 aPoint.X += aDifferencePoint.X();
331 aPoint.Y += aDifferencePoint.Y();
332
333 aItr->xShape->setPosition(aPoint);
334 }
335 else
336 {
337 // #96159# it is possible, that shapes have a negative position
338 // this is now handled here
339 DBG_ERROR("no or negative end address of this shape");
340 awt::Point aRefPoint;
341 aRefPoint.X = aRec.Left();
342 aRefPoint.Y = aRec.Top();
343 aPoint.X += aRefPoint.X;
344 if (aPoint.X > aRec.Right())
345 aPoint.X = aRec.Right() - 2; // decrement by 2 100th_mm because the cellheight is internal in twips
346 aPoint.Y += aRefPoint.Y;
347 if (aPoint.Y > aRec.Bottom())
348 aPoint.Y = aRec.Bottom() - 2; // decrement by 2 100th_mm because the cellheight is internal in twips
349 aItr->xShape->setPosition(aPoint);
350 }
351 }
352 }
353 }
354 }
355 }
356 else
357 {
358 DBG_ERROR("something wents wrong");
359 }
360 }
361 // #i78086# call CreateChartListener also for invalid position (anchored to sheet)
362 if (IsOLE(aItr->xShape))
363 {
364 uno::Reference < beans::XPropertySet > xShapeProps ( aItr->xShape, uno::UNO_QUERY );
365 uno::Reference < beans::XPropertySetInfo > xShapeInfo(xShapeProps->getPropertySetInfo());
366 rtl::OUString sName;
367 if (xShapeProps.is() && xShapeInfo.is() && xShapeInfo->hasPropertyByName(sPersistName) &&
368 (xShapeProps->getPropertyValue(sPersistName) >>= sName))
369 CreateChartListener(pDoc, sName, aItr->pRangeList);
370 }
371 if (aItr->pRangeList)
372 delete aItr->pRangeList;
373 aItr = aShapes.erase(aItr);
374 }
375 rImport.UnlockSolarMutex();
376 // if (pCollection)
377 // pDoc->SetChartListenerCollection(pCollection);
378 }
379 }
380 }
381 }
382