LibreOffice Module oox (master) 1
vmldrawing.cxx
Go to the documentation of this file.
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
21
22#include <algorithm>
23#include <com/sun/star/beans/XPropertySet.hpp>
24#include <com/sun/star/drawing/XControlShape.hpp>
25#include <com/sun/star/drawing/XDrawPage.hpp>
26#include <com/sun/star/drawing/XShapes.hpp>
27#include <com/sun/star/lang/XMultiServiceFactory.hpp>
28#include <com/sun/star/text/HoriOrientation.hpp>
29#include <com/sun/star/text/RelOrientation.hpp>
30#include <com/sun/star/text/VertOrientation.hpp>
31#include <osl/diagnose.h>
32#include <rtl/ustring.hxx>
33#include <sal/log.hxx>
36#include <oox/ole/axcontrol.hxx>
37#include <oox/vml/vmlshape.hxx>
39#include <tools/diagnose_ex.h>
40#include <tools/gen.hxx>
41#include <o3tl/string_view.hxx>
42
43namespace oox::vml {
44
45using namespace ::com::sun::star;
46using namespace ::com::sun::star::awt;
47using namespace ::com::sun::star::beans;
48using namespace ::com::sun::star::drawing;
49using namespace ::com::sun::star::lang;
50using namespace ::com::sun::star::text;
51using namespace ::com::sun::star::uno;
52
53using ::oox::core::XmlFilterBase;
54
55namespace {
56
58OUString lclGetShapeId( sal_Int32 nShapeId )
59{
60 // identifier consists of a literal NUL character, a lowercase 's', and the id
61 static constexpr OUStringLiteral aStr = u"\0s";
62 return aStr + OUString::number( nShapeId );
63}
64
66sal_Int32 lclGetShapeId( const OUString& rShapeId )
67{
68 // identifier consists of a literal NUL character, a lowercase 's', and the id
69 return ((rShapeId.getLength() >= 3) && (rShapeId[ 0 ] == '\0') && (rShapeId[ 1 ] == 's')) ? o3tl::toInt32(rShapeId.subView( 2 )) : -1;
70}
71
72} // namespace
73
75 mbAutoLoad( false ),
76 mbDmlShape( bDmlShape )
77{
78}
79
80void OleObjectInfo::setShapeId( sal_Int32 nShapeId )
81{
82 maShapeId = lclGetShapeId( nShapeId );
83}
84
86 : mbTextContentShape(false)
87{
88}
89
90void ControlInfo::setShapeId( sal_Int32 nShapeId )
91{
92 maShapeId = lclGetShapeId(nShapeId);
93}
94
95Drawing::Drawing( XmlFilterBase& rFilter, const Reference< XDrawPage >& rxDrawPage, DrawingType eType ) :
96 mrFilter( rFilter ),
97 mxDrawPage( rxDrawPage ),
98 mxShapes( new ShapeContainer( *this ) ),
99 meType( eType )
100{
101 OSL_ENSURE( mxDrawPage.is(), "Drawing::Drawing - missing UNO draw page" );
102}
103
105{
106}
107
109{
110 if (!mxCtrlForm)
111 mxCtrlForm.reset( new ::oox::ole::EmbeddedForm(
113 return *mxCtrlForm;
114}
115
116void Drawing::registerBlockId( sal_Int32 nBlockId )
117{
118 OSL_ENSURE( nBlockId > 0, "Drawing::registerBlockId - invalid block index" );
119 if( nBlockId > 0 )
120 {
121 // lower_bound() returns iterator pointing to element equal to nBlockId, if existing
122 BlockIdVector::iterator aIt = ::std::lower_bound( maBlockIds.begin(), maBlockIds.end(), nBlockId );
123 if( (aIt == maBlockIds.end()) || (nBlockId != *aIt) )
124 maBlockIds.insert( aIt, nBlockId );
125 }
126}
127
129{
130 OSL_ENSURE( !rOleObject.maShapeId.isEmpty(), "Drawing::registerOleObject - missing OLE object shape id" );
131 OSL_ENSURE( maOleObjects.count( rOleObject.maShapeId ) == 0, "Drawing::registerOleObject - OLE object already registered" );
132 maOleObjects.emplace( rOleObject.maShapeId, rOleObject );
133}
134
136{
137 OSL_ENSURE( !rControl.maShapeId.isEmpty(), "Drawing::registerControl - missing form control shape id" );
138 OSL_ENSURE( !rControl.maName.isEmpty(), "Drawing::registerControl - missing form control name" );
139 OSL_ENSURE( maControls.count( rControl.maShapeId ) == 0, "Drawing::registerControl - form control already registered" );
140 maControls.emplace( rControl.maShapeId, rControl );
141}
142
144{
145 mxShapes->finalizeFragmentImport();
146}
147
149{
150 Reference< XShapes > xShapes( mxDrawPage );
151 mxShapes->convertAndInsert( xShapes );
152
153 // Group together form control radio buttons that are in the same groupBox
154 std::map<OUString, tools::Rectangle> GroupBoxMap;
155 std::map<Reference< XPropertySet >, tools::Rectangle> RadioButtonMap;
156 for ( sal_Int32 i = 0; i < xShapes->getCount(); ++i )
157 {
158 try
159 {
160 Reference< XControlShape > xCtrlShape( xShapes->getByIndex(i), UNO_QUERY );
161 if (!xCtrlShape.is())
162 continue;
163 Reference< XControlModel > xCtrlModel( xCtrlShape->getControl(), UNO_SET_THROW );
164 Reference< XServiceInfo > xModelSI (xCtrlModel, UNO_QUERY_THROW );
165 Reference< XPropertySet > aProps( xCtrlModel, UNO_QUERY_THROW );
166
167 OUString sName;
168 aProps->getPropertyValue("Name") >>= sName;
169 const ::Point aPoint( xCtrlShape->getPosition().X, xCtrlShape->getPosition().Y );
170 const ::Size aSize( xCtrlShape->getSize().Width, xCtrlShape->getSize().Height );
171 const tools::Rectangle aRect( aPoint, aSize );
172 if ( !sName.isEmpty()
173 && xModelSI->supportsService("com.sun.star.awt.UnoControlGroupBoxModel") )
174 {
175 GroupBoxMap[sName] = aRect;
176 }
177 else if ( xModelSI->supportsService("com.sun.star.awt.UnoControlRadioButtonModel") )
178 {
179 OUString sGroupName;
180 aProps->getPropertyValue("GroupName") >>= sGroupName;
181 // only Form Controls are affected by Group Boxes - see drawingfragment.cxx
182 if ( sGroupName == "autoGroup_formControl" )
183 RadioButtonMap[aProps] = aRect;
184 }
185 }
186 catch (uno::Exception&)
187 {
188 DBG_UNHANDLED_EXCEPTION("oox.vml");
189 }
190 }
191 for ( const auto& BoxItr : GroupBoxMap )
192 {
193 const uno::Any aGroup( "autoGroup_" + BoxItr.first );
194 for ( auto RadioItr = RadioButtonMap.begin(); RadioItr != RadioButtonMap.end(); )
195 {
196 if ( BoxItr.second.Contains(RadioItr->second) )
197 {
198 RadioItr->first->setPropertyValue("GroupName", aGroup );
199 // If conflict, first created GroupBox wins
200 RadioItr = RadioButtonMap.erase(RadioItr);
201 }
202 else
203 ++RadioItr;
204 }
205 }
206
207}
208
209sal_Int32 Drawing::getLocalShapeIndex( const OUString& rShapeId ) const
210{
211 sal_Int32 nShapeId = lclGetShapeId( rShapeId );
212 if( nShapeId <= 0 ) return -1;
213
214 /* Shapes in a drawing are counted per registered shape identifier blocks
215 as stored in the o:idmap element. The contents of this element have
216 been stored in our member maBlockIds. Each block represents 1024 shape
217 identifiers, starting with identifier 1 for the block #0. This means,
218 block #0 represents the identifiers 1-1024, block #1 represents the
219 identifiers 1025-2048, and so on. The local shape index has to be
220 calculated according to all blocks registered for this drawing.
221
222 Example:
223 Registered for this drawing are blocks #1 and #3 (shape identifiers
224 1025-2048 and 3073-4096).
225 Shape identifier 1025 -> local shape index 1.
226 Shape identifier 1026 -> local shape index 2.
227 ...
228 Shape identifier 2048 -> local shape index 1024.
229 Shape identifier 3073 -> local shape index 1025.
230 ...
231 Shape identifier 4096 -> local shape index 2048.
232 */
233
234 // get block id from shape id and find its index in the list of used blocks
235 sal_Int32 nBlockId = (nShapeId - 1) / 1024;
236 BlockIdVector::iterator aIt = ::std::lower_bound( maBlockIds.begin(), maBlockIds.end(), nBlockId );
237 sal_Int32 nIndex = static_cast< sal_Int32 >( aIt - maBlockIds.begin() );
238
239 // block id not found in set -> register it now (value of nIndex remains valid)
240 if( (aIt == maBlockIds.end()) || (*aIt != nBlockId) )
241 maBlockIds.insert( aIt, nBlockId );
242
243 // get one-based offset of shape id in its block
244 sal_Int32 nBlockOffset = (nShapeId - 1) % 1024 + 1;
245
246 // calculate the local shape index
247 return 1024 * nIndex + nBlockOffset;
248}
249
250const OleObjectInfo* Drawing::getOleObjectInfo( const OUString& rShapeId ) const
251{
253}
254
255const ControlInfo* Drawing::getControlInfo( const OUString& rShapeId ) const
256{
257 return ContainerHelper::getMapElement( maControls, rShapeId );
258}
259
260Reference< XShape > Drawing::createAndInsertXShape( const OUString& rService,
261 const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect ) const
262{
263 OSL_ENSURE( !rService.isEmpty(), "Drawing::createAndInsertXShape - missing UNO shape service name" );
264 OSL_ENSURE( rxShapes.is(), "Drawing::createAndInsertXShape - missing XShapes container" );
265 Reference< XShape > xShape;
266 if( !rService.isEmpty() && rxShapes.is() ) try
267 {
268 Reference< XMultiServiceFactory > xModelFactory( mrFilter.getModelFactory(), UNO_SET_THROW );
269 xShape.set( xModelFactory->createInstance( rService ), UNO_QUERY_THROW );
270 if ( rService != "com.sun.star.text.TextFrame" )
271 {
272 // insert shape into passed shape collection (maybe drawpage or group shape)
273 rxShapes->add( xShape );
274 xShape->setPosition( awt::Point( rShapeRect.X, rShapeRect.Y ) );
275 }
276 else
277 {
278 Reference< XPropertySet > xPropSet( xShape, UNO_QUERY_THROW );
279 xPropSet->setPropertyValue( "HoriOrient", Any( HoriOrientation::NONE ) );
280 xPropSet->setPropertyValue( "VertOrient", Any( VertOrientation::NONE ) );
281 xPropSet->setPropertyValue( "HoriOrientPosition", Any( rShapeRect.X ) );
282 xPropSet->setPropertyValue( "VertOrientPosition", Any( rShapeRect.Y ) );
283 xPropSet->setPropertyValue( "HoriOrientRelation", Any( RelOrientation::FRAME ) );
284 xPropSet->setPropertyValue( "VertOrientRelation", Any( RelOrientation::FRAME ) );
285 }
286 xShape->setSize( awt::Size( rShapeRect.Width, rShapeRect.Height ) );
287 }
288 catch( const Exception& )
289 {
290 TOOLS_WARN_EXCEPTION( "oox", "Drawing::createAndInsertXShape - error during shape object creation" );
291 }
292 OSL_ENSURE( xShape.is(), "Drawing::createAndInsertXShape - cannot instantiate shape object" );
293 return xShape;
294}
295
296Reference< XShape > Drawing::createAndInsertXControlShape( const ::oox::ole::EmbeddedControl& rControl,
297 const Reference< XShapes >& rxShapes, const awt::Rectangle& rShapeRect, sal_Int32& rnCtrlIndex ) const
298{
299 Reference< XShape > xShape;
300 try
301 {
302 // create control model and insert it into the form of the draw page
303 Reference< XControlModel > xCtrlModel( getControlForm().convertAndInsert( rControl, rnCtrlIndex ), UNO_SET_THROW );
304
305 // create the control shape
306 xShape = createAndInsertXShape( "com.sun.star.drawing.ControlShape", rxShapes, rShapeRect );
307
308 // set the control model at the shape
309 Reference< XControlShape >( xShape, UNO_QUERY_THROW )->setControl( xCtrlModel );
310 }
311 catch (Exception const&)
312 {
313 TOOLS_WARN_EXCEPTION("oox", "exception inserting Shape");
314 }
315 return xShape;
316}
317
318bool Drawing::isShapeSupported( const ShapeBase& /*rShape*/ ) const
319{
320 return true;
321}
322
323OUString Drawing::getShapeBaseName( const ShapeBase& /*rShape*/ ) const
324{
325 return OUString();
326}
327
328bool Drawing::convertClientAnchor( awt::Rectangle& /*orShapeRect*/, const OUString& /*rShapeAnchor*/ ) const
329{
330 return false;
331}
332
333Reference< XShape > Drawing::createAndInsertClientXShape( const ShapeBase& /*rShape*/,
334 const Reference< XShapes >& /*rxShapes*/, const awt::Rectangle& /*rShapeRect*/ ) const
335{
336 return Reference< XShape >();
337}
338
339void Drawing::notifyXShapeInserted( const Reference< XShape >& /*rxShape*/,
340 const awt::Rectangle& /*rShapeRect*/, const ShapeBase& /*rShape*/, bool /*bGroupChild*/ )
341{
342}
343
344} // namespace oox::vml
345
346/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static const MapType::mapped_type * getMapElement(const MapType &rMap, const typename MapType::key_type &rKey)
Returns the pointer to an existing element of the passed map, or a null pointer, if an element with t...
const css::uno::Reference< css::frame::XModel > & getModel() const
Returns the document model (always existing).
Definition: filterbase.cxx:220
const css::uno::Reference< css::lang::XMultiServiceFactory > & getModelFactory() const
Returns the service factory provided by the document model (always existing).
Definition: filterbase.cxx:225
GraphicHelper & getGraphicHelper() const
Returns a helper for the handling of graphics and graphic objects.
Definition: filterbase.cxx:346
A wrapper for a control form embedded directly in a draw page.
Definition: axcontrol.hxx:960
const ControlInfo * getControlInfo(const OUString &rShapeId) const
Returns the registered info structure for a form control, if extant.
Definition: vmldrawing.cxx:255
css::uno::Reference< css::drawing::XShape > createAndInsertXShape(const OUString &rService, const css::uno::Reference< css::drawing::XShapes > &rxShapes, const css::awt::Rectangle &rShapeRect) const
Creates a new UNO shape object, inserts it into the passed UNO shape container, and sets the shape po...
Definition: vmldrawing.cxx:260
virtual bool convertClientAnchor(css::awt::Rectangle &orShapeRect, const OUString &rShapeAnchor) const
Derived classes may calculate the shape rectangle from a non-standard anchor information string.
Definition: vmldrawing.cxx:328
void registerOleObject(const OleObjectInfo &rOleObject)
Registers the passed embedded OLE object.
Definition: vmldrawing.cxx:128
void finalizeFragmentImport()
Final processing after import of the fragment.
Definition: vmldrawing.cxx:143
::oox::ole::EmbeddedForm & getControlForm() const
Returns the form object used to process ActiveX form controls.
Definition: vmldrawing.cxx:108
void registerControl(const ControlInfo &rControl)
Registers the passed embedded form control.
Definition: vmldrawing.cxx:135
std::unique_ptr<::oox::ole::EmbeddedForm > mxCtrlForm
The control form used to process embedded controls.
Definition: vmldrawing.hxx:193
ControlInfoMap maControls
Info about all embedded form controls, mapped by control name.
Definition: vmldrawing.hxx:197
::oox::core::XmlFilterBase & mrFilter
Filter object that imports/exports the VML drawing.
Definition: vmldrawing.hxx:190
void convertAndInsert() const
Creates and inserts all UNO shapes into the draw page.
Definition: vmldrawing.cxx:148
BlockIdVector maBlockIds
Block identifiers used by this drawing.
Definition: vmldrawing.hxx:194
virtual void notifyXShapeInserted(const css::uno::Reference< css::drawing::XShape > &rxShape, const css::awt::Rectangle &rShapeRect, const ShapeBase &rShape, bool bGroupChild)
Derived classes may want to know that a UNO shape has been inserted.
Definition: vmldrawing.cxx:339
OleObjectInfoMap maOleObjects
Info about all embedded OLE objects, mapped by shape id.
Definition: vmldrawing.hxx:196
Drawing(::oox::core::XmlFilterBase &rFilter, const css::uno::Reference< css::drawing::XDrawPage > &rxDrawPage, DrawingType eType)
Definition: vmldrawing.cxx:95
sal_Int32 getLocalShapeIndex(const OUString &rShapeId) const
Returns the local shape index from the passed global shape identifier.
Definition: vmldrawing.cxx:209
virtual bool isShapeSupported(const ShapeBase &rShape) const
Derived classes may disable conversion of specific shapes.
Definition: vmldrawing.cxx:318
virtual css::uno::Reference< css::drawing::XShape > createAndInsertClientXShape(const ShapeBase &rShape, const css::uno::Reference< css::drawing::XShapes > &rxShapes, const css::awt::Rectangle &rShapeRect) const
Derived classes create a UNO shape according to the passed shape model.
Definition: vmldrawing.cxx:333
std::unique_ptr< ShapeContainer > mxShapes
All shapes and shape templates.
Definition: vmldrawing.hxx:195
void registerBlockId(sal_Int32 nBlockId)
Registers a block of shape identifiers reserved by this drawing.
Definition: vmldrawing.cxx:116
css::uno::Reference< css::drawing::XShape > createAndInsertXControlShape(const ::oox::ole::EmbeddedControl &rControl, const css::uno::Reference< css::drawing::XShapes > &rxShapes, const css::awt::Rectangle &rShapeRect, sal_Int32 &rnCtrlIndex) const
Creates a new UNO shape object for a form control, inserts the control model into the form,...
Definition: vmldrawing.cxx:296
const OleObjectInfo * getOleObjectInfo(const OUString &rShapeId) const
Returns the registered info structure for an OLE object, if extant.
Definition: vmldrawing.cxx:250
virtual ~Drawing()
Definition: vmldrawing.cxx:104
css::uno::Reference< css::drawing::XDrawPage > mxDrawPage
UNO draw page used to insert the shapes.
Definition: vmldrawing.hxx:192
virtual OUString getShapeBaseName(const ShapeBase &rShape) const
Derived classes may return additional base names for automatic shape name creation.
Definition: vmldrawing.cxx:323
A shape object that is part of a drawing.
Definition: vmlshape.hxx:241
Container that holds a list of shapes and shape templates.
PropType meType
Definition: dffdumper.cxx:161
#define TOOLS_WARN_EXCEPTION(area, stream)
#define DBG_UNHANDLED_EXCEPTION(...)
OString sName
Definition: drawingml.cxx:3916
float u
DocumentType eType
sal_Int32 nIndex
aStr
@ Exception
sal_Int32 toInt32(std::u16string_view str, sal_Int16 radix=10)
DrawingType
Enumerates different types of VML drawings.
Definition: vmldrawing.hxx:54
const PowerPointImport & mrFilter
Definition: pptimport.cxx:264
uno::Reference< drawing::XDrawPage > mxDrawPage
Contains information about a form control embedded in a draw page.
Definition: vmldrawing.hxx:79
OUString maName
Programmatical name of the form control.
Definition: vmldrawing.hxx:82
void setShapeId(sal_Int32 nShapeId)
Sets the string representation of the passed numeric shape identifier.
Definition: vmldrawing.cxx:90
OUString maShapeId
Shape identifier for shape lookup.
Definition: vmldrawing.hxx:80
Contains information about an OLE object embedded in a draw page.
Definition: vmldrawing.hxx:63
void setShapeId(sal_Int32 nShapeId)
Sets the string representation of the passed numeric shape identifier.
Definition: vmldrawing.cxx:80
OUString maShapeId
Shape identifier for shape lookup.
Definition: vmldrawing.hxx:64