1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "XMLTableShapeImportHelper.hxx"
21 #include "xmlimprt.hxx"
22 #include <drwlayer.hxx>
23 #include "xmlannoi.hxx"
24 #include <rangeutl.hxx>
25 #include <userdat.hxx>
26 #include <docuno.hxx>
27 #include <sheetdata.hxx>
28 #include <xmloff/namespacemap.hxx>
29 #include <xmloff/xmlnamespace.hxx>
30 #include <xmloff/xmluconv.hxx>
31 #include <xmloff/xmltoken.hxx>
32 #include <svx/unoshape.hxx>
33 #include <com/sun/star/drawing/XShape.hpp>
34 #include <com/sun/star/drawing/XShapes.hpp>
35 
36 #define SC_LAYERID "LayerID"
37 
38 using namespace ::com::sun::star;
39 using namespace xmloff::token;
40 
XMLTableShapeImportHelper(ScXMLImport & rImp)41 XMLTableShapeImportHelper::XMLTableShapeImportHelper( ScXMLImport& rImp ) :
42     XMLShapeImportHelper(rImp, rImp.GetModel(), nullptr ),
43     pAnnotationContext(nullptr),
44     bOnTable(false)
45 {
46 }
47 
~XMLTableShapeImportHelper()48 XMLTableShapeImportHelper::~XMLTableShapeImportHelper()
49 {
50 }
51 
SetLayer(const uno::Reference<drawing::XShape> & rShape,SdrLayerID nLayerID,std::u16string_view sType)52 void XMLTableShapeImportHelper::SetLayer(const uno::Reference<drawing::XShape>& rShape, SdrLayerID nLayerID, std::u16string_view sType)
53 {
54     if ( sType == u"com.sun.star.drawing.ControlShape" )
55         nLayerID = SC_LAYER_CONTROLS;
56     if (nLayerID != SDRLAYER_NOTFOUND)
57     {
58         uno::Reference< beans::XPropertySet > xShapeProp( rShape, uno::UNO_QUERY );
59         if( xShapeProp.is() )
60             xShapeProp->setPropertyValue( SC_LAYERID, uno::makeAny<sal_uInt16>(sal_uInt8(nLayerID)) );
61     }
62 }
63 
64 // Attempt to find the topmost parent of the group, this is the one we apply
65 // offsets to
lcl_getTopLevelParent(const uno::Reference<drawing::XShape> & rShape)66 static uno::Reference< drawing::XShape > lcl_getTopLevelParent( const uno::Reference< drawing::XShape >& rShape )
67 {
68     uno::Reference< container::XChild > xChild( rShape, uno::UNO_QUERY );
69     uno::Reference< drawing::XShape > xParent( xChild->getParent(), uno::UNO_QUERY );
70     if ( xParent.is() )
71         return lcl_getTopLevelParent( xParent );
72     return rShape;
73 }
74 
finishShape(uno::Reference<drawing::XShape> & rShape,const uno::Reference<xml::sax::XFastAttributeList> & xAttrList,uno::Reference<drawing::XShapes> & rShapes)75 void XMLTableShapeImportHelper::finishShape(
76     uno::Reference< drawing::XShape >& rShape,
77     const uno::Reference< xml::sax::XFastAttributeList >& xAttrList,
78     uno::Reference< drawing::XShapes >& rShapes )
79 {
80     bool bNote = false;
81     XMLShapeImportHelper::finishShape( rShape, xAttrList, rShapes );
82     static_cast<ScXMLImport&>(mrImporter).LockSolarMutex();
83     ScMyTables& rTables = static_cast<ScXMLImport&>(mrImporter).GetTables();
84     if (rShapes == rTables.GetCurrentXShapes())
85     {
86         if (!pAnnotationContext)
87         {
88             ScDrawObjData aAnchor;
89             aAnchor.maStart = aStartCell;
90             awt::Point aStartPoint(rShape->getPosition());
91             aAnchor.maStartOffset = Point(aStartPoint.X, aStartPoint.Y);
92             aAnchor.mbResizeWithCell = false;
93 
94             sal_Int32 nEndX(-1);
95             sal_Int32 nEndY(-1);
96             std::optional<OUString> xRangeList;
97             SdrLayerID nLayerID = SDRLAYER_NOTFOUND;
98             for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
99             {
100                 switch(aIter.getToken())
101                 {
102                     case XML_ELEMENT(TABLE, XML_END_CELL_ADDRESS):
103                     {
104                         sal_Int32 nOffset(0);
105                         ScDocument* pDoc = static_cast<ScXMLImport&>(mrImporter).GetDocument();
106                         assert(pDoc);
107                         ScRangeStringConverter::GetAddressFromString(aAnchor.maEnd, aIter.toString(), *pDoc, ::formula::FormulaGrammar::CONV_OOO, nOffset);
108                         // When the cell end address is set, we let the shape resize with the cell
109                         aAnchor.mbResizeWithCell = true;
110                         break;
111                     }
112                     case XML_ELEMENT(TABLE, XML_END_X):
113                     {
114                         static_cast<ScXMLImport&>(mrImporter).
115                             GetMM100UnitConverter().convertMeasureToCore(
116                                     nEndX, aIter.toView());
117                         aAnchor.maEndOffset.setX( nEndX );
118                         break;
119                     }
120                     case XML_ELEMENT(TABLE, XML_END_Y):
121                     {
122                         static_cast<ScXMLImport&>(mrImporter).
123                             GetMM100UnitConverter().convertMeasureToCore(
124                                     nEndY, aIter.toView());
125                         aAnchor.maEndOffset.setY( nEndY );
126                         break;
127                     }
128                     case XML_ELEMENT(TABLE, XML_TABLE_BACKGROUND):
129                         if (IsXMLToken(aIter, XML_TRUE))
130                             nLayerID = SC_LAYER_BACK;
131                         break;
132                     case XML_ELEMENT(DRAW, XML_NOTIFY_ON_UPDATE_OF_RANGES):
133                         xRangeList = aIter.toString();
134                         break;
135                     default: ;
136                 }
137             }
138             SetLayer(rShape, nLayerID, rShape->getShapeType());
139 
140             if (SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(rShape))
141             {
142                 if (!bOnTable)
143                     ScDrawLayer::SetCellAnchored(*pSdrObj, aAnchor);
144                 else
145                     ScDrawLayer::SetPageAnchored(*pSdrObj);
146             }
147 
148             if (xRangeList)
149             {
150                 // #i78086# If there are notification ranges, the ChartListener must be created
151                 // also when anchored to the sheet
152                 // -> call AddOLE with invalid cell position (checked in ScMyShapeResizer::ResizeShapes)
153 
154                 if (ScMyTables::IsOLE(rShape))
155                     rTables.AddOLE(rShape, *xRangeList);
156             }
157         }
158         else // shape is annotation
159         {
160             // get the style names for stream copying
161             OUString aStyleName;
162             OUString aTextStyle;
163             for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
164             {
165                 const OUString sValue = aIter.toString();
166                 switch (aIter.getToken())
167                 {
168                     case XML_ELEMENT(DRAW, XML_STYLE_NAME):
169                         aStyleName = sValue;
170                         break;
171                     case XML_ELEMENT(DRAW, XML_TEXT_STYLE_NAME):
172                         aTextStyle = sValue;
173                         break;
174                     default:;
175                 }
176             }
177 
178             pAnnotationContext->SetShape(rShape, rShapes, aStyleName, aTextStyle);
179             bNote = true;
180         }
181     }
182     else //this are grouped shapes which should also get the layerid
183     {
184         uno::Reference< drawing::XShapes > xGroup( rShape, uno::UNO_QUERY );
185         // ignore the group ( within group ) object if it exists
186         if ( !bOnTable && !xGroup.is() )
187         {
188             // For cell anchored grouped shape we need to set the start
189             // position from the most top and left positioned shape(s) within
190             // the group
191             Point aStartPoint( rShape->getPosition().X,rShape->getPosition().Y );
192             uno::Reference< drawing::XShape > xChild( rShapes, uno::UNO_QUERY );
193             if (xChild)
194             {
195                 if (SdrObject *pSdrObj = SdrObject::getSdrObjectFromXShape(lcl_getTopLevelParent(xChild)))
196                 {
197                     if ( ScDrawObjData* pAnchor = ScDrawLayer::GetObjData( pSdrObj ) )
198                     {
199                        if ( pAnchor->maStartOffset.getX() == 0 && pAnchor->maStartOffset.getY() == 0 )
200                             pAnchor->maStartOffset = aStartPoint;
201                        if ( aStartPoint.getX() < pAnchor->maStartOffset.getX() )
202                              pAnchor->maStartOffset.setX( aStartPoint.getX() );
203                        if ( aStartPoint.getY() < pAnchor->maStartOffset.getY() )
204                            pAnchor->maStartOffset.setY( aStartPoint.getY() );
205                     }
206                 }
207             }
208         }
209         SdrLayerID nLayerID = SDRLAYER_NOTFOUND;
210         for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
211         {
212             if (aIter.getToken() == XML_ELEMENT(TABLE, XML_TABLE_BACKGROUND))
213             {
214                 if (IsXMLToken(aIter, XML_TRUE))
215                     nLayerID = SC_LAYER_BACK;
216                 break;
217             }
218         }
219         SetLayer(rShape, nLayerID, rShape->getShapeType());
220     }
221 
222     if (!bNote)
223     {
224         // any shape other than a note prevents copying the sheet
225         ScSheetSaveData* pSheetData = comphelper::getUnoTunnelImplementation<ScModelObj>(mrImporter.GetModel())->GetSheetSaveData();
226         pSheetData->BlockSheet( rTables.GetCurrentSheet() );
227     }
228 
229     static_cast<ScXMLImport&>(mrImporter).UnlockSolarMutex();
230 }
231 
232 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
233