Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "drawingbase.hxx"
30 : :
31 : : #include <com/sun/star/awt/Rectangle.hpp>
32 : : #include "oox/helper/attributelist.hxx"
33 : : #include "oox/helper/binaryinputstream.hxx"
34 : : #include "unitconverter.hxx"
35 : : #include "oox/helper/propertyset.hxx"
36 : : #include "oox/token/properties.hxx"
37 : :
38 : : namespace oox {
39 : : namespace xls {
40 : :
41 : : // ============================================================================
42 : :
43 : : using namespace ::com::sun::star::awt;
44 : : using namespace ::com::sun::star::table;
45 : : using namespace ::oox::drawingml;
46 : :
47 : : using ::rtl::OUString;
48 : :
49 : : // ============================================================================
50 : :
51 : : namespace {
52 : :
53 : : /** Converts the passed 32-bit integer value from 1/100 mm to EMUs. */
54 : 36 : inline sal_Int64 lclHmmToEmu( sal_Int32 nValue )
55 : : {
56 [ + - ]: 36 : return (nValue < 0) ? -1 : convertHmmToEmu( nValue );
57 : : }
58 : :
59 : : /** Converts the passed 64-bit integer value from EMUs to 1/100 mm. */
60 : 24 : inline sal_Int32 lclEmuToHmm( sal_Int64 nValue )
61 : : {
62 [ + - ]: 24 : return (nValue < 0) ? -1 : convertEmuToHmm( nValue );
63 : : }
64 : :
65 : : } // namespace
66 : :
67 : : // ============================================================================
68 : :
69 : 12 : CellAnchorModel::CellAnchorModel() :
70 : : mnCol( -1 ),
71 : : mnRow( -1 ),
72 : : mnColOffset( 0 ),
73 : 12 : mnRowOffset( 0 )
74 : : {
75 : 12 : }
76 : :
77 : : // ----------------------------------------------------------------------------
78 : :
79 : 6 : AnchorClientDataModel::AnchorClientDataModel() :
80 : : mbLocksWithSheet( true ),
81 : 6 : mbPrintsWithSheet( true )
82 : : {
83 : 6 : }
84 : :
85 : : // ============================================================================
86 : :
87 : 6 : ShapeAnchor::ShapeAnchor( const WorksheetHelper& rHelper ) :
88 : : WorksheetHelper( rHelper ),
89 : : meAnchorType( ANCHOR_INVALID ),
90 : : meCellAnchorType( CELLANCHOR_EMU ),
91 : 6 : mnEditAs( XML_twoCell )
92 : : {
93 : 6 : }
94 : :
95 : 0 : void ShapeAnchor::importAnchor( sal_Int32 nElement, const AttributeList& rAttribs )
96 : : {
97 [ # # # # ]: 0 : switch( nElement )
98 : : {
99 : : case XDR_TOKEN( absoluteAnchor ):
100 : 0 : meAnchorType = ANCHOR_ABSOLUTE;
101 : 0 : break;
102 : : case XDR_TOKEN( oneCellAnchor ):
103 : 0 : meAnchorType = ANCHOR_ONECELL;
104 : 0 : break;
105 : : case XDR_TOKEN( twoCellAnchor ):
106 : 0 : meAnchorType = ANCHOR_TWOCELL;
107 : 0 : mnEditAs = rAttribs.getToken( XML_editAs, XML_twoCell );
108 : 0 : break;
109 : : default:
110 : : OSL_ENSURE( false, "ShapeAnchor::importAnchor - unexpected element" );
111 : : }
112 : 0 : meCellAnchorType = CELLANCHOR_EMU;
113 : 0 : }
114 : :
115 : 0 : void ShapeAnchor::importPos( const AttributeList& rAttribs )
116 : : {
117 : : OSL_ENSURE( meAnchorType == ANCHOR_ABSOLUTE, "ShapeAnchor::importPos - unexpected 'xdr:pos' element" );
118 : 0 : maPos.X = rAttribs.getHyper( XML_x, 0 );
119 : 0 : maPos.Y = rAttribs.getHyper( XML_y, 0 );
120 : 0 : }
121 : :
122 : 0 : void ShapeAnchor::importExt( const AttributeList& rAttribs )
123 : : {
124 : : OSL_ENSURE( (meAnchorType == ANCHOR_ABSOLUTE) || (meAnchorType == ANCHOR_ONECELL), "ShapeAnchor::importExt - unexpected 'xdr:ext' element" );
125 : 0 : maSize.Width = rAttribs.getHyper( XML_cx, 0 );
126 : 0 : maSize.Height = rAttribs.getHyper( XML_cy, 0 );
127 : 0 : }
128 : :
129 : 0 : void ShapeAnchor::importClientData( const AttributeList& rAttribs )
130 : : {
131 : 0 : maClientData.mbLocksWithSheet = rAttribs.getBool( XML_fLocksWithSheet, true );
132 : 0 : maClientData.mbPrintsWithSheet = rAttribs.getBool( XML_fPrintsWithSheet, true );
133 : 0 : }
134 : :
135 : 0 : void ShapeAnchor::setCellPos( sal_Int32 nElement, sal_Int32 nParentContext, const OUString& rValue )
136 : : {
137 : 0 : CellAnchorModel* pCellAnchor = 0;
138 [ # # # ]: 0 : switch( nParentContext )
139 : : {
140 : : case XDR_TOKEN( from ):
141 : : OSL_ENSURE( (meAnchorType == ANCHOR_ONECELL) || (meAnchorType == ANCHOR_TWOCELL), "ShapeAnchor::setCellPos - unexpected 'xdr:from' element" );
142 : 0 : pCellAnchor = &maFrom;
143 : 0 : break;
144 : : case XDR_TOKEN( to ):
145 : : OSL_ENSURE( meAnchorType == ANCHOR_TWOCELL, "ShapeAnchor::setCellPos - unexpected 'xdr:to' element" );
146 : 0 : pCellAnchor = &maTo;
147 : 0 : break;
148 : : default:
149 : : OSL_ENSURE( false, "ShapeAnchor::setCellPos - unexpected parent element" );
150 : : }
151 [ # # ][ # # : 0 : if( pCellAnchor ) switch( nElement )
# # # ]
152 : : {
153 : 0 : case XDR_TOKEN( col ): pCellAnchor->mnCol = rValue.toInt32(); break;
154 : 0 : case XDR_TOKEN( row ): pCellAnchor->mnRow = rValue.toInt32(); break;
155 : 0 : case XDR_TOKEN( colOff ): pCellAnchor->mnColOffset = rValue.toInt64(); break;
156 : 0 : case XDR_TOKEN( rowOff ): pCellAnchor->mnRowOffset = rValue.toInt64(); break;
157 : : default: OSL_ENSURE( false, "ShapeAnchor::setCellPos - unexpected element" );
158 : : }
159 : 0 : }
160 : :
161 : 6 : void ShapeAnchor::importVmlAnchor( const OUString& rAnchor )
162 : : {
163 : 6 : meAnchorType = ANCHOR_VML;
164 : 6 : meCellAnchorType = CELLANCHOR_PIXEL;
165 : :
166 [ + - ]: 6 : ::std::vector< OUString > aTokens;
167 : 6 : sal_Int32 nIndex = 0;
168 [ + + ]: 54 : while( nIndex >= 0 )
169 [ + - ]: 48 : aTokens.push_back( rAnchor.getToken( 0, ',', nIndex ).trim() );
170 : :
171 : : OSL_ENSURE( aTokens.size() >= 8, "ShapeAnchor::importVmlAnchor - missing anchor tokens" );
172 [ + - ]: 6 : if( aTokens.size() >= 8 )
173 : : {
174 : 6 : maFrom.mnCol = aTokens[ 0 ].toInt32();
175 : 6 : maFrom.mnColOffset = aTokens[ 1 ].toInt32();
176 : 6 : maFrom.mnRow = aTokens[ 2 ].toInt32();
177 : 6 : maFrom.mnRowOffset = aTokens[ 3 ].toInt32();
178 : 6 : maTo.mnCol = aTokens[ 4 ].toInt32();
179 : 6 : maTo.mnColOffset = aTokens[ 5 ].toInt32();
180 : 6 : maTo.mnRow = aTokens[ 6 ].toInt32();
181 : 6 : maTo.mnRowOffset = aTokens[ 7 ].toInt32();
182 : 6 : }
183 : 6 : }
184 : :
185 : 6 : EmuRectangle ShapeAnchor::calcAnchorRectEmu( const Size& rPageSizeHmm ) const
186 : : {
187 [ + - ]: 6 : AddressConverter& rAddrConv = getAddressConverter();
188 : 6 : EmuSize aPageSize( lclHmmToEmu( rPageSizeHmm.Width ), lclHmmToEmu( rPageSizeHmm.Height ) );
189 : 6 : EmuRectangle aAnchorRect( -1, -1, -1, -1 );
190 : :
191 : : // calculate shape position
192 [ - + - - ]: 6 : switch( meAnchorType )
193 : : {
194 : : case ANCHOR_ABSOLUTE:
195 : : OSL_ENSURE( maPos.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
196 [ # # ][ # # ]: 0 : if( maPos.isValid() && (maPos.X < aPageSize.Width) && (maPos.Y < aPageSize.Height) )
[ # # ][ # # ]
197 : 0 : aAnchorRect.setPos( maPos );
198 : 0 : break;
199 : : case ANCHOR_ONECELL:
200 : : case ANCHOR_TWOCELL:
201 : : case ANCHOR_VML:
202 : : OSL_ENSURE( maFrom.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
203 [ + - ][ + - ]: 6 : if( maFrom.isValid() && rAddrConv.checkCol( maFrom.mnCol, true ) && rAddrConv.checkRow( maFrom.mnRow, true ) )
[ + - ][ + - ]
[ + - ][ + - ]
204 : : {
205 [ + - ]: 6 : EmuPoint aPoint = calcCellAnchorEmu( maFrom );
206 [ + - ][ + - ]: 6 : if( (aPoint.X < aPageSize.Width) && (aPoint.Y < aPageSize.Height) )
207 : 6 : aAnchorRect.setPos( aPoint );
208 : : }
209 : 6 : break;
210 : : case ANCHOR_INVALID:
211 : : OSL_ENSURE( false, "ShapeAnchor::calcAnchorRectEmu - invalid anchor" );
212 : 0 : break;
213 : : }
214 : :
215 : : // calculate shape size
216 [ + - ][ + - ]: 6 : if( (aAnchorRect.X >= 0) && (aAnchorRect.Y >= 0) ) switch( meAnchorType )
[ - + - - ]
217 : : {
218 : : case ANCHOR_ABSOLUTE:
219 : : case ANCHOR_ONECELL:
220 : : OSL_ENSURE( maSize.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid size" );
221 [ # # ]: 0 : if( maSize.isValid() )
222 : : {
223 [ # # ]: 0 : aAnchorRect.Width = ::std::min< sal_Int64 >( maSize.Width, aPageSize.Width - aAnchorRect.X );
224 [ # # ]: 0 : aAnchorRect.Height = ::std::min< sal_Int64 >( maSize.Height, aPageSize.Height - aAnchorRect.Y );
225 : : }
226 : 0 : break;
227 : : case ANCHOR_TWOCELL:
228 : : case ANCHOR_VML:
229 : : OSL_ENSURE( maTo.isValid(), "ShapeAnchor::calcAnchorRectEmu - invalid position" );
230 [ + - ]: 6 : if( maTo.isValid() )
231 : : {
232 : : /* Pass a valid cell address to calcCellAnchorEmu(), otherwise
233 : : nothing useful is returned, even if either row or column is valid. */
234 [ + - ][ + - ]: 6 : CellAddress aToCell = rAddrConv.createValidCellAddress( BinAddress( maTo.mnCol, maTo.mnRow ), getSheetIndex(), true );
235 : 6 : CellAnchorModel aValidTo = maTo;
236 : 6 : aValidTo.mnCol = aToCell.Column;
237 : 6 : aValidTo.mnRow = aToCell.Row;
238 [ + - ]: 6 : EmuPoint aPoint = calcCellAnchorEmu( aValidTo );
239 : : // width (if column index is valid, use the calculated offset, otherwise stretch to maximum available X position)
240 : 6 : aAnchorRect.Width = aPageSize.Width - aAnchorRect.X;
241 [ + - ]: 6 : if( aToCell.Column == maTo.mnCol )
242 [ + - ]: 6 : aAnchorRect.Width = ::std::min< sal_Int64 >( aPoint.X - aAnchorRect.X + 1, aAnchorRect.Width );
243 : : // height (if row index is valid, use the calculated offset, otherwise stretch to maximum available Y position)
244 : 6 : aAnchorRect.Height = aPageSize.Height - aAnchorRect.Y;
245 [ + - ]: 6 : if( aToCell.Row == maTo.mnRow )
246 [ + - ]: 6 : aAnchorRect.Height = ::std::min< sal_Int64 >( aPoint.Y - aAnchorRect.Y + 1, aAnchorRect.Height );
247 : : }
248 : 6 : break;
249 : : case ANCHOR_INVALID:
250 : 6 : break;
251 : : }
252 : :
253 : : // add 0.75 mm (27,000 EMUs) in X direction to correct display error
254 [ + - ]: 6 : if( aAnchorRect.X >= 0 )
255 : 6 : aAnchorRect.X += 27000;
256 : : // remove 0.25 mm (9,000 EMUs) in Y direction to correct display error
257 [ + + ]: 6 : if( aAnchorRect.Y >= 9000 )
258 : 6 : aAnchorRect.Y -= 9000;
259 : :
260 : 6 : return aAnchorRect;
261 : : }
262 : :
263 : 6 : Rectangle ShapeAnchor::calcAnchorRectHmm( const Size& rPageSizeHmm ) const
264 : : {
265 [ + - ]: 6 : EmuRectangle aAnchorRect = calcAnchorRectEmu( rPageSizeHmm );
266 [ + - ][ + - ]: 6 : return Rectangle( lclEmuToHmm( aAnchorRect.X ), lclEmuToHmm( aAnchorRect.Y ), lclEmuToHmm( aAnchorRect.Width ), lclEmuToHmm( aAnchorRect.Height ) );
[ + - ][ + - ]
267 : : }
268 : :
269 : 12 : EmuPoint ShapeAnchor::calcCellAnchorEmu( const CellAnchorModel& rModel ) const
270 : : {
271 : : // calculate position of top-left edge of the cell
272 [ + - ]: 12 : Point aPoint = getCellPosition( rModel.mnCol, rModel.mnRow );
273 : 12 : EmuPoint aEmuPoint( lclHmmToEmu( aPoint.X ), lclHmmToEmu( aPoint.Y ) );
274 : :
275 : : // add the offset inside the cell
276 [ - + - - ]: 12 : switch( meCellAnchorType )
277 : : {
278 : : case CELLANCHOR_EMU:
279 : 0 : aEmuPoint.X += rModel.mnColOffset;
280 : 0 : aEmuPoint.Y += rModel.mnRowOffset;
281 : 0 : break;
282 : :
283 : : case CELLANCHOR_PIXEL:
284 : : {
285 [ + - ]: 12 : const UnitConverter& rUnitConv = getUnitConverter();
286 [ + - ]: 12 : aEmuPoint.X += static_cast< sal_Int64 >( rUnitConv.scaleValue( static_cast< double >( rModel.mnColOffset ), UNIT_SCREENX, UNIT_EMU ) );
287 [ + - ]: 12 : aEmuPoint.Y += static_cast< sal_Int64 >( rUnitConv.scaleValue( static_cast< double >( rModel.mnRowOffset ), UNIT_SCREENY, UNIT_EMU ) );
288 : : }
289 : 12 : break;
290 : :
291 : : case CELLANCHOR_COLROW:
292 : : {
293 [ # # ]: 0 : Size aCellSize = getCellSize( rModel.mnCol, rModel.mnRow );
294 : 0 : EmuSize aEmuSize( lclHmmToEmu( aCellSize.Width ), lclHmmToEmu( aCellSize.Height ) );
295 : : // X offset is given in 1/1024 of column width
296 [ # # ]: 0 : aEmuPoint.X += static_cast< sal_Int64 >( aEmuSize.Width * getLimitedValue< double >( static_cast< double >( rModel.mnColOffset ) / 1024.0, 0.0, 1.0 ) + 0.5 );
297 : : // Y offset is given in 1/256 of row height
298 [ # # ]: 0 : aEmuPoint.Y += static_cast< sal_Int64 >( aEmuSize.Height * getLimitedValue< double >( static_cast< double >( rModel.mnRowOffset ) / 256.0, 0.0, 1.0 ) + 0.5 );
299 : : }
300 : 12 : break;
301 : : }
302 : :
303 : 12 : return aEmuPoint;
304 : : }
305 : :
306 : : // ============================================================================
307 : :
308 : : } // namespace xls
309 [ + - ][ + - ]: 24 : } // namespace oox
310 : :
311 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|