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