LibreOffice Module svx (master) 1
framelinkarray.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 <math.h>
23#include <vector>
24#include <set>
25#include <algorithm>
26#include <tools/debug.hxx>
27#include <tools/gen.hxx>
28#include <vcl/canvastools.hxx>
32
33//#define OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
34#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
37#endif
38
39namespace svx::frame {
40
41namespace {
42
43class Cell
44{
45private:
52
53 basegfx::B2DHomMatrix HelperCreateB2DHomMatrixFromB2DRange(
54 const basegfx::B2DRange& rRange ) const;
55
56public:
57 sal_Int32 mnAddLeft;
58 sal_Int32 mnAddRight;
59 sal_Int32 mnAddTop;
60 sal_Int32 mnAddBottom;
61
64
68
69public:
70 explicit Cell();
71
72 void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; }
73 void SetStyleRight(const Style& rStyle) { maRight = rStyle; }
74 void SetStyleTop(const Style& rStyle) { maTop = rStyle; }
75 void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; }
76 void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; }
77 void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; }
78
79 const Style& GetStyleLeft() const { return maLeft; }
80 const Style& GetStyleRight() const { return maRight; }
81 const Style& GetStyleTop() const { return maTop; }
82 const Style& GetStyleBottom() const { return maBottom; }
83 const Style& GetStyleTLBR() const { return maTLBR; }
84 const Style& GetStyleBLTR() const { return maBLTR; }
85
86 bool IsMerged() const { return mbMergeOrig || mbOverlapX || mbOverlapY; }
87 bool IsRotated() const { return mfOrientation != 0.0; }
88
89 void MirrorSelfX();
90
91 basegfx::B2DHomMatrix CreateCoordinateSystemSingleCell(
92 const Array& rArray, sal_Int32 nCol, sal_Int32 nRow ) const;
93 basegfx::B2DHomMatrix CreateCoordinateSystemMergedCell(
94 const Array& rArray, sal_Int32 nColLeft, sal_Int32 nRowTop, sal_Int32 nColRight, sal_Int32 nRowBottom ) const;
95};
96
97}
98
99typedef std::vector< Cell > CellVec;
100
101basegfx::B2DHomMatrix Cell::HelperCreateB2DHomMatrixFromB2DRange(
102 const basegfx::B2DRange& rRange ) const
103{
104 if( rRange.isEmpty() )
105 return basegfx::B2DHomMatrix();
106
107 basegfx::B2DPoint aOrigin(rRange.getMinimum());
108 basegfx::B2DVector aX(rRange.getWidth(), 0.0);
109 basegfx::B2DVector aY(0.0, rRange.getHeight());
110
112 {
113 // when rotated, adapt values. Get Skew (cos/sin == 1/tan)
114 const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation)));
115
116 switch (meRotMode)
117 {
119 // shear Y-Axis
120 aY.setX(-fSkew);
121 break;
123 // shear origin half, Y full
124 aOrigin.setX(aOrigin.getX() + (fSkew * 0.5));
125 aY.setX(-fSkew);
126 break;
128 // shear origin full, Y full
129 aOrigin.setX(aOrigin.getX() + fSkew);
130 aY.setX(-fSkew);
131 break;
132 default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above
133 break;
134 }
135 }
136
137 // use column vectors as coordinate axes, homogen column for translation
138 return basegfx::utils::createCoordinateSystemTransform( aOrigin, aX, aY );
139}
140
141basegfx::B2DHomMatrix Cell::CreateCoordinateSystemSingleCell(
142 const Array& rArray, sal_Int32 nCol, sal_Int32 nRow) const
143{
144 const Point aPoint( rArray.GetColPosition( nCol ), rArray.GetRowPosition( nRow ) );
145 const Size aSize( rArray.GetColWidth( nCol, nCol ) + 1, rArray.GetRowHeight( nRow, nRow ) + 1 );
147
148 return HelperCreateB2DHomMatrixFromB2DRange( aRange );
149}
150
151basegfx::B2DHomMatrix Cell::CreateCoordinateSystemMergedCell(
152 const Array& rArray, sal_Int32 nColLeft, sal_Int32 nRowTop, sal_Int32 nColRight, sal_Int32 nRowBottom) const
153{
154 basegfx::B2DRange aRange( rArray.GetB2DRange(
155 nColLeft, nRowTop, nColRight, nRowBottom ) );
156
157 // adjust rectangle for partly visible merged cells
158 if( IsMerged() )
159 {
160 // not *sure* what exactly this is good for,
161 // it is just a hard set extension at merged cells,
162 // probably *should* be included in the above extended
163 // GetColPosition/GetColWidth already. This might be
164 // added due to GetColPosition/GetColWidth not working
165 // correctly over PageChanges (if used), but not sure.
166 aRange.expand(
168 aRange.getMinX() - mnAddLeft,
169 aRange.getMinY() - mnAddTop,
170 aRange.getMaxX() + mnAddRight,
171 aRange.getMaxY() + mnAddBottom ) );
172 }
173
174 return HelperCreateB2DHomMatrixFromB2DRange( aRange );
175}
176
177Cell::Cell() :
178 mnAddLeft( 0 ),
179 mnAddRight( 0 ),
180 mnAddTop( 0 ),
181 mnAddBottom( 0 ),
183 mfOrientation( 0.0 ),
184 mbMergeOrig( false ),
185 mbOverlapX( false ),
186 mbOverlapY( false )
187{
188}
189
190void Cell::MirrorSelfX()
191{
192 std::swap( maLeft, maRight );
193 std::swap( mnAddLeft, mnAddRight );
194 maLeft.MirrorSelf();
195 maRight.MirrorSelf();
197}
198
199
200static void lclRecalcCoordVec( std::vector<sal_Int32>& rCoords, const std::vector<sal_Int32>& rSizes )
201{
202 DBG_ASSERT( rCoords.size() == rSizes.size() + 1, "lclRecalcCoordVec - inconsistent vectors" );
203 auto aCIt = rCoords.begin();
204 for( const auto& rSize : rSizes )
205 {
206 *(aCIt + 1) = *aCIt + rSize;
207 ++aCIt;
208 }
209}
210
211static void lclSetMergedRange( CellVec& rCells, sal_Int32 nWidth, sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
212{
213 for( sal_Int32 nCol = nFirstCol; nCol <= nLastCol; ++nCol )
214 {
215 for( sal_Int32 nRow = nFirstRow; nRow <= nLastRow; ++nRow )
216 {
217 Cell& rCell = rCells[ nRow * nWidth + nCol ];
218 rCell.mbMergeOrig = false;
219 rCell.mbOverlapX = nCol > nFirstCol;
220 rCell.mbOverlapY = nRow > nFirstRow;
221 }
222 }
223 rCells[ nFirstRow * nWidth + nFirstCol ].mbMergeOrig = true;
224}
225
226
229
231{
233 std::vector<sal_Int32> maWidths;
234 std::vector<sal_Int32> maHeights;
235 mutable std::vector<sal_Int32> maXCoords;
236 mutable std::vector<sal_Int32> maYCoords;
237 sal_Int32 mnWidth;
238 sal_Int32 mnHeight;
239 sal_Int32 mnFirstClipCol;
240 sal_Int32 mnFirstClipRow;
241 sal_Int32 mnLastClipCol;
242 sal_Int32 mnLastClipRow;
243 mutable bool mbXCoordsDirty;
244 mutable bool mbYCoordsDirty;
246
247 explicit ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight );
248
249 bool IsValidPos( sal_Int32 nCol, sal_Int32 nRow ) const
250 { return (nCol < mnWidth) && (nRow < mnHeight); }
251 sal_Int32 GetIndex( sal_Int32 nCol, sal_Int32 nRow ) const
252 { return nRow * mnWidth + nCol; }
253
254 const Cell& GetCell( sal_Int32 nCol, sal_Int32 nRow ) const;
255 Cell& GetCellAcc( sal_Int32 nCol, sal_Int32 nRow );
256
257 sal_Int32 GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const;
258 sal_Int32 GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const;
259 sal_Int32 GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const;
260 sal_Int32 GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const;
261
262 const Cell& GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const;
263 const Cell& GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const;
264
265 bool IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const;
266 bool IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const;
267 bool IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const;
268 bool IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const;
269
270 bool IsInClipRange( sal_Int32 nCol, sal_Int32 nRow ) const;
271 bool IsColInClipRange( sal_Int32 nCol ) const;
272 bool IsRowInClipRange( sal_Int32 nRow ) const;
273
274 bool OverlapsClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) const;
275
276 sal_Int32 GetMirrorCol( sal_Int32 nCol ) const { return mnWidth - nCol - 1; }
277
278 sal_Int32 GetColPosition( sal_Int32 nCol ) const;
279 sal_Int32 GetRowPosition( sal_Int32 nRow ) const;
280
281 bool HasCellRotation() const;
282};
283
284ArrayImpl::ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight ) :
285 mnWidth( nWidth ),
286 mnHeight( nHeight ),
287 mnFirstClipCol( 0 ),
288 mnFirstClipRow( 0 ),
289 mnLastClipCol( nWidth - 1 ),
290 mnLastClipRow( nHeight - 1 ),
291 mbXCoordsDirty( false ),
292 mbYCoordsDirty( false ),
293 mbMayHaveCellRotation( false )
294{
295 // default-construct all vectors
296 maCells.resize( mnWidth * mnHeight );
297 maWidths.resize( mnWidth, 0 );
298 maHeights.resize( mnHeight, 0 );
299 maXCoords.resize( mnWidth + 1, 0 );
300 maYCoords.resize( mnHeight + 1, 0 );
301}
302
303const Cell& ArrayImpl::GetCell( sal_Int32 nCol, sal_Int32 nRow ) const
304{
305 return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : OBJ_CELL_NONE;
306}
307
308Cell& ArrayImpl::GetCellAcc( sal_Int32 nCol, sal_Int32 nRow )
309{
310 static Cell aDummy;
311 return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : aDummy;
312}
313
314sal_Int32 ArrayImpl::GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const
315{
316 sal_Int32 nFirstCol = nCol;
317 while( (nFirstCol > 0) && GetCell( nFirstCol, nRow ).mbOverlapX ) --nFirstCol;
318 return nFirstCol;
319}
320
321sal_Int32 ArrayImpl::GetMergedFirstRow( sal_Int32 nCol, sal_Int32 nRow ) const
322{
323 sal_Int32 nFirstRow = nRow;
324 while( (nFirstRow > 0) && GetCell( nCol, nFirstRow ).mbOverlapY ) --nFirstRow;
325 return nFirstRow;
326}
327
328sal_Int32 ArrayImpl::GetMergedLastCol( sal_Int32 nCol, sal_Int32 nRow ) const
329{
330 sal_Int32 nLastCol = nCol + 1;
331 while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow ).mbOverlapX ) ++nLastCol;
332 return nLastCol - 1;
333}
334
335sal_Int32 ArrayImpl::GetMergedLastRow( sal_Int32 nCol, sal_Int32 nRow ) const
336{
337 sal_Int32 nLastRow = nRow + 1;
338 while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow ).mbOverlapY ) ++nLastRow;
339 return nLastRow - 1;
340}
341
342const Cell& ArrayImpl::GetMergedOriginCell( sal_Int32 nCol, sal_Int32 nRow ) const
343{
344 return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) );
345}
346
347const Cell& ArrayImpl::GetMergedLastCell( sal_Int32 nCol, sal_Int32 nRow ) const
348{
349 return GetCell( GetMergedLastCol( nCol, nRow ), GetMergedLastRow( nCol, nRow ) );
350}
351
352bool ArrayImpl::IsMergedOverlappedLeft( sal_Int32 nCol, sal_Int32 nRow ) const
353{
354 const Cell& rCell = GetCell( nCol, nRow );
355 return rCell.mbOverlapX || (rCell.mnAddLeft > 0);
356}
357
358bool ArrayImpl::IsMergedOverlappedRight( sal_Int32 nCol, sal_Int32 nRow ) const
359{
360 return GetCell( nCol + 1, nRow ).mbOverlapX || (GetCell( nCol, nRow ).mnAddRight > 0);
361}
362
363bool ArrayImpl::IsMergedOverlappedTop( sal_Int32 nCol, sal_Int32 nRow ) const
364{
365 const Cell& rCell = GetCell( nCol, nRow );
366 return rCell.mbOverlapY || (rCell.mnAddTop > 0);
367}
368
369bool ArrayImpl::IsMergedOverlappedBottom( sal_Int32 nCol, sal_Int32 nRow ) const
370{
371 return GetCell( nCol, nRow + 1 ).mbOverlapY || (GetCell( nCol, nRow ).mnAddBottom > 0);
372}
373
374bool ArrayImpl::IsColInClipRange( sal_Int32 nCol ) const
375{
376 return (mnFirstClipCol <= nCol) && (nCol <= mnLastClipCol);
377}
378
379bool ArrayImpl::IsRowInClipRange( sal_Int32 nRow ) const
380{
381 return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow);
382}
383
384bool ArrayImpl::OverlapsClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow ) const
385{
386 if(nLastCol < mnFirstClipCol)
387 return false;
388
389 if(nFirstCol > mnLastClipCol)
390 return false;
391
392 if(nLastRow < mnFirstClipRow)
393 return false;
394
395 if(nFirstRow > mnLastClipRow)
396 return false;
397
398 return true;
399}
400
401bool ArrayImpl::IsInClipRange( sal_Int32 nCol, sal_Int32 nRow ) const
402{
403 return IsColInClipRange( nCol ) && IsRowInClipRange( nRow );
404}
405
406sal_Int32 ArrayImpl::GetColPosition( sal_Int32 nCol ) const
407{
408 if( mbXCoordsDirty )
409 {
411 mbXCoordsDirty = false;
412 }
413 return maXCoords[ nCol ];
414}
415
416sal_Int32 ArrayImpl::GetRowPosition( sal_Int32 nRow ) const
417{
418 if( mbYCoordsDirty )
419 {
421 mbYCoordsDirty = false;
422 }
423 return maYCoords[ nRow ];
424}
425
427{
428 // check cell array
429 for (const auto& aCell : maCells)
430 {
431 if (aCell.IsRotated())
432 {
433 return true;
434 }
435 }
436
437 return false;
438}
439
440namespace {
441
442class MergedCellIterator
443{
444public:
445 explicit MergedCellIterator( const Array& rArray, sal_Int32 nCol, sal_Int32 nRow );
446
447 bool Is() const { return (mnCol <= mnLastCol) && (mnRow <= mnLastRow); }
448 sal_Int32 Col() const { return mnCol; }
449 sal_Int32 Row() const { return mnRow; }
450
451 MergedCellIterator& operator++();
452
453private:
454 sal_Int32 mnFirstCol;
455 sal_Int32 mnFirstRow;
456 sal_Int32 mnLastCol;
457 sal_Int32 mnLastRow;
458 sal_Int32 mnCol;
459 sal_Int32 mnRow;
460};
461
462}
463
464MergedCellIterator::MergedCellIterator( const Array& rArray, sal_Int32 nCol, sal_Int32 nRow )
465{
466 DBG_ASSERT( rArray.IsMerged( nCol, nRow ), "svx::frame::MergedCellIterator::MergedCellIterator - not in merged range" );
467 rArray.GetMergedRange( mnFirstCol, mnFirstRow, mnLastCol, mnLastRow, nCol, nRow );
470}
471
472MergedCellIterator& MergedCellIterator::operator++()
473{
474 DBG_ASSERT( Is(), "svx::frame::MergedCellIterator::operator++() - already invalid" );
475 if( ++mnCol > mnLastCol )
476 {
478 ++mnRow;
479 }
480 return *this;
481}
482
483
484#define DBG_FRAME_CHECK( cond, funcname, error ) DBG_ASSERT( cond, "svx::frame::Array::" funcname " - " error )
485#define DBG_FRAME_CHECK_COL( col, funcname ) DBG_FRAME_CHECK( (col) < GetColCount(), funcname, "invalid column index" )
486#define DBG_FRAME_CHECK_ROW( row, funcname ) DBG_FRAME_CHECK( (row) < GetRowCount(), funcname, "invalid row index" )
487#define DBG_FRAME_CHECK_COLROW( col, row, funcname ) DBG_FRAME_CHECK( ((col) < GetColCount()) && ((row) < GetRowCount()), funcname, "invalid cell index" )
488#define DBG_FRAME_CHECK_COL_1( col, funcname ) DBG_FRAME_CHECK( (col) <= GetColCount(), funcname, "invalid column index" )
489#define DBG_FRAME_CHECK_ROW_1( row, funcname ) DBG_FRAME_CHECK( (row) <= GetRowCount(), funcname, "invalid row index" )
490
491
492#define CELL( col, row ) mxImpl->GetCell( col, row )
493#define CELLACC( col, row ) mxImpl->GetCellAcc( col, row )
494#define ORIGCELL( col, row ) mxImpl->GetMergedOriginCell( col, row )
495#define LASTCELL( col, row ) mxImpl->GetMergedLastCell( col, row )
496
497
499{
500 Initialize( 0, 0 );
501}
502
504{
505}
506
507// array size and column/row indexes
508void Array::Initialize( sal_Int32 nWidth, sal_Int32 nHeight )
509{
510 mxImpl.reset( new ArrayImpl( nWidth, nHeight ) );
511}
512
513sal_Int32 Array::GetColCount() const
514{
515 return mxImpl->mnWidth;
516}
517
518sal_Int32 Array::GetRowCount() const
519{
520 return mxImpl->mnHeight;
521}
522
523sal_Int32 Array::GetCellCount() const
524{
525 return mxImpl->maCells.size();
526}
527
528sal_Int32 Array::GetCellIndex( sal_Int32 nCol, sal_Int32 nRow, bool bRTL ) const
529{
530 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetCellIndex" );
531 if (bRTL)
532 nCol = mxImpl->GetMirrorCol(nCol);
533 return mxImpl->GetIndex( nCol, nRow );
534}
535
536// cell border styles
537void Array::SetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
538{
539 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" );
540 CELLACC( nCol, nRow ).SetStyleLeft(rStyle);
541}
542
543void Array::SetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
544{
545 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" );
546 CELLACC( nCol, nRow ).SetStyleRight(rStyle);
547}
548
549void Array::SetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
550{
551 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" );
552 CELLACC( nCol, nRow ).SetStyleTop(rStyle);
553}
554
555void Array::SetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
556{
557 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" );
558 CELLACC( nCol, nRow ).SetStyleBottom(rStyle);
559}
560
561void Array::SetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
562{
563 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" );
564 CELLACC( nCol, nRow ).SetStyleTLBR(rStyle);
565}
566
567void Array::SetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow, const Style& rStyle )
568{
569 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" );
570 CELLACC( nCol, nRow ).SetStyleBLTR(rStyle);
571}
572
573void Array::SetCellStyleDiag( sal_Int32 nCol, sal_Int32 nRow, const Style& rTLBR, const Style& rBLTR )
574{
575 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" );
576 Cell& rCell = CELLACC( nCol, nRow );
577 rCell.SetStyleTLBR(rTLBR);
578 rCell.SetStyleBLTR(rBLTR);
579}
580
581void Array::SetColumnStyleLeft( sal_Int32 nCol, const Style& rStyle )
582{
583 DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleLeft" );
584 for( sal_Int32 nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
585 SetCellStyleLeft( nCol, nRow, rStyle );
586}
587
588void Array::SetColumnStyleRight( sal_Int32 nCol, const Style& rStyle )
589{
590 DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleRight" );
591 for( sal_Int32 nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
592 SetCellStyleRight( nCol, nRow, rStyle );
593}
594
595void Array::SetRowStyleTop( sal_Int32 nRow, const Style& rStyle )
596{
597 DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleTop" );
598 for( sal_Int32 nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
599 SetCellStyleTop( nCol, nRow, rStyle );
600}
601
602void Array::SetRowStyleBottom( sal_Int32 nRow, const Style& rStyle )
603{
604 DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleBottom" );
605 for( sal_Int32 nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
606 SetCellStyleBottom( nCol, nRow, rStyle );
607}
608
609void Array::SetCellRotation(sal_Int32 nCol, sal_Int32 nRow, SvxRotateMode eRotMode, double fOrientation)
610{
611 DBG_FRAME_CHECK_COLROW(nCol, nRow, "SetCellRotation");
612 Cell& rTarget = CELLACC(nCol, nRow);
613 rTarget.meRotMode = eRotMode;
614 rTarget.mfOrientation = fOrientation;
615
616 if (!mxImpl->mbMayHaveCellRotation)
617 {
618 // activate once when a cell gets actually rotated to allow fast
619 // answering HasCellRotation() calls
620 mxImpl->mbMayHaveCellRotation = rTarget.IsRotated();
621 }
622}
623
625{
626 if (!mxImpl->mbMayHaveCellRotation)
627 {
628 // never set, no need to check
629 return false;
630 }
631
632 return mxImpl->HasCellRotation();
633}
634
635const Style& Array::GetCellStyleLeft( sal_Int32 nCol, sal_Int32 nRow ) const
636{
637 // outside clipping rows or overlapped in merged cells: invisible
638 if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedLeft( nCol, nRow ) )
639 return OBJ_STYLE_NONE;
640 // left clipping border: always own left style
641 if( nCol == mxImpl->mnFirstClipCol )
642 return ORIGCELL( nCol, nRow ).GetStyleLeft();
643 // right clipping border: always right style of left neighbor cell
644 if( nCol == mxImpl->mnLastClipCol + 1 )
645 return ORIGCELL( nCol - 1, nRow ).GetStyleRight();
646 // outside clipping columns: invisible
647 if( !mxImpl->IsColInClipRange( nCol ) )
648 return OBJ_STYLE_NONE;
649 // inside clipping range: maximum of own left style and right style of left neighbor cell
650 return std::max( ORIGCELL( nCol, nRow ).GetStyleLeft(), ORIGCELL( nCol - 1, nRow ).GetStyleRight() );
651}
652
653const Style& Array::GetCellStyleRight( sal_Int32 nCol, sal_Int32 nRow ) const
654{
655 // outside clipping rows or overlapped in merged cells: invisible
656 if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedRight( nCol, nRow ) )
657 return OBJ_STYLE_NONE;
658 // left clipping border: always left style of right neighbor cell
659 if( nCol + 1 == mxImpl->mnFirstClipCol )
660 return ORIGCELL( nCol + 1, nRow ).GetStyleLeft();
661 // right clipping border: always own right style
662 if( nCol == mxImpl->mnLastClipCol )
663 return LASTCELL( nCol, nRow ).GetStyleRight();
664 // outside clipping columns: invisible
665 if( !mxImpl->IsColInClipRange( nCol ) )
666 return OBJ_STYLE_NONE;
667 // inside clipping range: maximum of own right style and left style of right neighbor cell
668 return std::max( ORIGCELL( nCol, nRow ).GetStyleRight(), ORIGCELL( nCol + 1, nRow ).GetStyleLeft() );
669}
670
671const Style& Array::GetCellStyleTop( sal_Int32 nCol, sal_Int32 nRow ) const
672{
673 // outside clipping columns or overlapped in merged cells: invisible
674 if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedTop( nCol, nRow ) )
675 return OBJ_STYLE_NONE;
676 // top clipping border: always own top style
677 if( nRow == mxImpl->mnFirstClipRow )
678 return ORIGCELL( nCol, nRow ).GetStyleTop();
679 // bottom clipping border: always bottom style of top neighbor cell
680 if( nRow == mxImpl->mnLastClipRow + 1 )
681 return ORIGCELL( nCol, nRow - 1 ).GetStyleBottom();
682 // outside clipping rows: invisible
683 if( !mxImpl->IsRowInClipRange( nRow ) )
684 return OBJ_STYLE_NONE;
685 // inside clipping range: maximum of own top style and bottom style of top neighbor cell
686 return std::max( ORIGCELL( nCol, nRow ).GetStyleTop(), ORIGCELL( nCol, nRow - 1 ).GetStyleBottom() );
687}
688
689const Style& Array::GetCellStyleBottom( sal_Int32 nCol, sal_Int32 nRow ) const
690{
691 // outside clipping columns or overlapped in merged cells: invisible
692 if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedBottom( nCol, nRow ) )
693 return OBJ_STYLE_NONE;
694 // top clipping border: always top style of bottom neighbor cell
695 if( nRow + 1 == mxImpl->mnFirstClipRow )
696 return ORIGCELL( nCol, nRow + 1 ).GetStyleTop();
697 // bottom clipping border: always own bottom style
698 if( nRow == mxImpl->mnLastClipRow )
699 return LASTCELL( nCol, nRow ).GetStyleBottom();
700 // outside clipping rows: invisible
701 if( !mxImpl->IsRowInClipRange( nRow ) )
702 return OBJ_STYLE_NONE;
703 // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell
704 return std::max( ORIGCELL( nCol, nRow ).GetStyleBottom(), ORIGCELL( nCol, nRow + 1 ).GetStyleTop() );
705}
706
707const Style& Array::GetCellStyleTLBR( sal_Int32 nCol, sal_Int32 nRow ) const
708{
709 return CELL( nCol, nRow ).GetStyleTLBR();
710}
711
712const Style& Array::GetCellStyleBLTR( sal_Int32 nCol, sal_Int32 nRow ) const
713{
714 return CELL( nCol, nRow ).GetStyleBLTR();
715}
716
717const Style& Array::GetCellStyleTL( sal_Int32 nCol, sal_Int32 nRow ) const
718{
719 // not in clipping range: always invisible
720 if( !mxImpl->IsInClipRange( nCol, nRow ) )
721 return OBJ_STYLE_NONE;
722 // return style only for top-left cell
723 sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
724 sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
725 return ((nCol == nFirstCol) && (nRow == nFirstRow)) ?
726 CELL( nFirstCol, nFirstRow ).GetStyleTLBR() : OBJ_STYLE_NONE;
727}
728
729const Style& Array::GetCellStyleBR( sal_Int32 nCol, sal_Int32 nRow ) const
730{
731 // not in clipping range: always invisible
732 if( !mxImpl->IsInClipRange( nCol, nRow ) )
733 return OBJ_STYLE_NONE;
734 // return style only for bottom-right cell
735 sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
736 sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
737 return ((nCol == nLastCol) && (nRow == nLastRow)) ?
738 CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleTLBR() : OBJ_STYLE_NONE;
739}
740
741const Style& Array::GetCellStyleBL( sal_Int32 nCol, sal_Int32 nRow ) const
742{
743 // not in clipping range: always invisible
744 if( !mxImpl->IsInClipRange( nCol, nRow ) )
745 return OBJ_STYLE_NONE;
746 // return style only for bottom-left cell
747 sal_Int32 nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
748 sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
749 return ((nCol == nFirstCol) && (nRow == nLastRow)) ?
750 CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleBLTR() : OBJ_STYLE_NONE;
751}
752
753const Style& Array::GetCellStyleTR( sal_Int32 nCol, sal_Int32 nRow ) const
754{
755 // not in clipping range: always invisible
756 if( !mxImpl->IsInClipRange( nCol, nRow ) )
757 return OBJ_STYLE_NONE;
758 // return style only for top-right cell
759 sal_Int32 nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
760 sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
761 return ((nCol == nLastCol) && (nRow == nFirstRow)) ?
762 CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).GetStyleBLTR() : OBJ_STYLE_NONE;
763}
764
765// cell merging
766void Array::SetMergedRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
767{
768 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetMergedRange" );
769 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetMergedRange" );
770#if OSL_DEBUG_LEVEL >= 2
771 {
772 bool bFound = false;
773 for( sal_Int32 nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol )
774 for( sal_Int32 nCurrRow = nFirstRow; !bFound && (nCurrRow <= nLastRow); ++nCurrRow )
775 bFound = CELL( nCurrCol, nCurrRow ).IsMerged();
776 DBG_FRAME_CHECK( !bFound, "SetMergedRange", "overlapping merged ranges" );
777 }
778#endif
779 if( mxImpl->IsValidPos( nFirstCol, nFirstRow ) && mxImpl->IsValidPos( nLastCol, nLastRow ) )
780 lclSetMergedRange( mxImpl->maCells, mxImpl->mnWidth, nFirstCol, nFirstRow, nLastCol, nLastRow );
781}
782
783void Array::SetAddMergedLeftSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
784{
785 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedLeftSize" );
786 DBG_FRAME_CHECK( mxImpl->GetMergedFirstCol( nCol, nRow ) == 0, "SetAddMergedLeftSize", "additional border inside array" );
787 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
788 CELLACC( aIt.Col(), aIt.Row() ).mnAddLeft = nAddSize;
789}
790
791void Array::SetAddMergedRightSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
792{
793 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedRightSize" );
794 DBG_FRAME_CHECK( mxImpl->GetMergedLastCol( nCol, nRow ) + 1 == mxImpl->mnWidth, "SetAddMergedRightSize", "additional border inside array" );
795 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
796 CELLACC( aIt.Col(), aIt.Row() ).mnAddRight = nAddSize;
797}
798
799void Array::SetAddMergedTopSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
800{
801 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedTopSize" );
802 DBG_FRAME_CHECK( mxImpl->GetMergedFirstRow( nCol, nRow ) == 0, "SetAddMergedTopSize", "additional border inside array" );
803 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
804 CELLACC( aIt.Col(), aIt.Row() ).mnAddTop = nAddSize;
805}
806
807void Array::SetAddMergedBottomSize( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize )
808{
809 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedBottomSize" );
810 DBG_FRAME_CHECK( mxImpl->GetMergedLastRow( nCol, nRow ) + 1 == mxImpl->mnHeight, "SetAddMergedBottomSize", "additional border inside array" );
811 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt )
812 CELLACC( aIt.Col(), aIt.Row() ).mnAddBottom = nAddSize;
813}
814
815bool Array::IsMerged( sal_Int32 nCol, sal_Int32 nRow ) const
816{
817 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" );
818 return CELL( nCol, nRow ).IsMerged();
819}
820
821void Array::GetMergedOrigin( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow, sal_Int32 nCol, sal_Int32 nRow ) const
822{
823 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetMergedOrigin" );
824 rnFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
825 rnFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
826}
827
828void Array::GetMergedRange( sal_Int32& rnFirstCol, sal_Int32& rnFirstRow,
829 sal_Int32& rnLastCol, sal_Int32& rnLastRow, sal_Int32 nCol, sal_Int32 nRow ) const
830{
831 GetMergedOrigin( rnFirstCol, rnFirstRow, nCol, nRow );
832 rnLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
833 rnLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
834}
835
836// clipping
837void Array::SetClipRange( sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow )
838{
839 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetClipRange" );
840 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetClipRange" );
841 mxImpl->mnFirstClipCol = nFirstCol;
842 mxImpl->mnFirstClipRow = nFirstRow;
843 mxImpl->mnLastClipCol = nLastCol;
844 mxImpl->mnLastClipRow = nLastRow;
845}
846
847// cell coordinates
848void Array::SetXOffset( sal_Int32 nXOffset )
849{
850 mxImpl->maXCoords[ 0 ] = nXOffset;
851 mxImpl->mbXCoordsDirty = true;
852}
853
854void Array::SetYOffset( sal_Int32 nYOffset )
855{
856 mxImpl->maYCoords[ 0 ] = nYOffset;
857 mxImpl->mbYCoordsDirty = true;
858}
859
860void Array::SetColWidth( sal_Int32 nCol, sal_Int32 nWidth )
861{
862 DBG_FRAME_CHECK_COL( nCol, "SetColWidth" );
863 mxImpl->maWidths[ nCol ] = nWidth;
864 mxImpl->mbXCoordsDirty = true;
865}
866
867void Array::SetRowHeight( sal_Int32 nRow, sal_Int32 nHeight )
868{
869 DBG_FRAME_CHECK_ROW( nRow, "SetRowHeight" );
870 mxImpl->maHeights[ nRow ] = nHeight;
871 mxImpl->mbYCoordsDirty = true;
872}
873
874void Array::SetAllColWidths( sal_Int32 nWidth )
875{
876 std::fill( mxImpl->maWidths.begin(), mxImpl->maWidths.end(), nWidth );
877 mxImpl->mbXCoordsDirty = true;
878}
879
880void Array::SetAllRowHeights( sal_Int32 nHeight )
881{
882 std::fill( mxImpl->maHeights.begin(), mxImpl->maHeights.end(), nHeight );
883 mxImpl->mbYCoordsDirty = true;
884}
885
886sal_Int32 Array::GetColPosition( sal_Int32 nCol ) const
887{
888 DBG_FRAME_CHECK_COL_1( nCol, "GetColPosition" );
889 return mxImpl->GetColPosition( nCol );
890}
891
892sal_Int32 Array::GetRowPosition( sal_Int32 nRow ) const
893{
894 DBG_FRAME_CHECK_ROW_1( nRow, "GetRowPosition" );
895 return mxImpl->GetRowPosition( nRow );
896}
897
898sal_Int32 Array::GetColWidth( sal_Int32 nFirstCol, sal_Int32 nLastCol ) const
899{
900 DBG_FRAME_CHECK_COL( nFirstCol, "GetColWidth" );
901 DBG_FRAME_CHECK_COL( nLastCol, "GetColWidth" );
902 return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol );
903}
904
905sal_Int32 Array::GetRowHeight( sal_Int32 nFirstRow, sal_Int32 nLastRow ) const
906{
907 DBG_FRAME_CHECK_ROW( nFirstRow, "GetRowHeight" );
908 DBG_FRAME_CHECK_ROW( nLastRow, "GetRowHeight" );
909 return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow );
910}
911
912sal_Int32 Array::GetWidth() const
913{
914 return GetColPosition( mxImpl->mnWidth ) - GetColPosition( 0 );
915}
916
917sal_Int32 Array::GetHeight() const
918{
919 return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 );
920}
921
922basegfx::B2DRange Array::GetCellRange( sal_Int32 nCol, sal_Int32 nRow ) const
923{
924 // get the Range of the fully expanded cell (if merged)
925 const sal_Int32 nFirstCol(mxImpl->GetMergedFirstCol( nCol, nRow ));
926 const sal_Int32 nFirstRow(mxImpl->GetMergedFirstRow( nCol, nRow ));
927 const sal_Int32 nLastCol(mxImpl->GetMergedLastCol( nCol, nRow ));
928 const sal_Int32 nLastRow(mxImpl->GetMergedLastRow( nCol, nRow ));
929 const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
930 const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
931 tools::Rectangle aRect(aPoint, aSize);
932
933 // adjust rectangle for partly visible merged cells
934 const Cell& rCell = CELL( nCol, nRow );
935
936 if( rCell.IsMerged() )
937 {
938 // not *sure* what exactly this is good for,
939 // it is just a hard set extension at merged cells,
940 // probably *should* be included in the above extended
941 // GetColPosition/GetColWidth already. This might be
942 // added due to GetColPosition/GetColWidth not working
943 // correctly over PageChanges (if used), but not sure.
944 aRect.AdjustLeft( -(rCell.mnAddLeft) );
945 aRect.AdjustRight(rCell.mnAddRight );
946 aRect.AdjustTop( -(rCell.mnAddTop) );
947 aRect.AdjustBottom(rCell.mnAddBottom );
948 }
949
951}
952
953// return output range of given row/col range in logical coordinates
954basegfx::B2DRange Array::GetB2DRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow) const
955{
956 const Point aPoint( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) );
957 const Size aSize( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 );
958
960}
961
962// mirroring
964{
965 CellVec aNewCells;
966 aNewCells.reserve( GetCellCount() );
967
968 sal_Int32 nCol, nRow;
969 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
970 {
971 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
972 {
973 aNewCells.push_back( CELL( mxImpl->GetMirrorCol( nCol ), nRow ) );
974 aNewCells.back().MirrorSelfX();
975 }
976 }
977 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow )
978 {
979 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol )
980 {
981 if( CELL( nCol, nRow ).mbMergeOrig )
982 {
983 sal_Int32 nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
984 sal_Int32 nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
985 lclSetMergedRange( aNewCells, mxImpl->mnWidth,
986 mxImpl->GetMirrorCol( nLastCol ), nRow,
987 mxImpl->GetMirrorCol( nCol ), nLastRow );
988 }
989 }
990 }
991 mxImpl->maCells.swap( aNewCells );
992
993 std::reverse( mxImpl->maWidths.begin(), mxImpl->maWidths.end() );
994 mxImpl->mbXCoordsDirty = true;
995}
996
997// drawing
999 const Array& rArray,
1000 const Style& rStyle,
1001 sal_Int32 col,
1002 sal_Int32 row,
1003 const basegfx::B2DPoint& rOrigin,
1004 const basegfx::B2DVector& rX,
1005 const basegfx::B2DVector& rY,
1007 bool bUpper,
1008 const Color* pForceColor)
1009{
1010 // prepare SdrFrameBorderData
1011 rData.emplace_back(
1012 bUpper ? rOrigin : basegfx::B2DPoint(rOrigin + rY),
1013 rX,
1014 rStyle,
1015 pForceColor);
1017
1018 // get involved styles at start
1019 const Style& rStartFromTR(rArray.GetCellStyleBL( col, row - 1 ));
1020 const Style& rStartLFromT(rArray.GetCellStyleLeft( col, row - 1 ));
1021 const Style& rStartLFromL(rArray.GetCellStyleTop( col - 1, row ));
1022 const Style& rStartLFromB(rArray.GetCellStyleLeft( col, row ));
1023 const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
1024
1025 rInstance.addSdrConnectStyleData(true, rStartFromTR, rX - rY, false);
1026 rInstance.addSdrConnectStyleData(true, rStartLFromT, -rY, true);
1027 rInstance.addSdrConnectStyleData(true, rStartLFromL, -rX, true);
1028 rInstance.addSdrConnectStyleData(true, rStartLFromB, rY, false);
1029 rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false);
1030
1031 // get involved styles at end
1032 const Style& rEndFromTL(rArray.GetCellStyleBR( col, row - 1 ));
1033 const Style& rEndRFromT(rArray.GetCellStyleRight( col, row - 1 ));
1034 const Style& rEndRFromR(rArray.GetCellStyleTop( col + 1, row ));
1035 const Style& rEndRFromB(rArray.GetCellStyleRight( col, row ));
1036 const Style& rEndFromBL(rArray.GetCellStyleTR( col, row ));
1037
1038 rInstance.addSdrConnectStyleData(false, rEndFromTL, -rX - rY, true);
1039 rInstance.addSdrConnectStyleData(false, rEndRFromT, -rY, true);
1040 rInstance.addSdrConnectStyleData(false, rEndRFromR, rX, false);
1041 rInstance.addSdrConnectStyleData(false, rEndRFromB, rY, false);
1042 rInstance.addSdrConnectStyleData(false, rEndFromBL, rY - rX, true);
1043}
1044
1046 const Array& rArray,
1047 const Style& rStyle,
1048 sal_Int32 col,
1049 sal_Int32 row,
1050 const basegfx::B2DPoint& rOrigin,
1051 const basegfx::B2DVector& rX,
1052 const basegfx::B2DVector& rY,
1054 bool bLeft,
1055 const Color* pForceColor)
1056{
1057 // prepare SdrFrameBorderData
1058 rData.emplace_back(
1059 bLeft ? rOrigin : basegfx::B2DPoint(rOrigin + rX),
1060 rY,
1061 rStyle,
1062 pForceColor);
1064
1065 // get involved styles at start
1066 const Style& rStartFromBL(rArray.GetCellStyleTR( col - 1, row ));
1067 const Style& rStartTFromL(rArray.GetCellStyleTop( col - 1, row ));
1068 const Style& rStartTFromT(rArray.GetCellStyleLeft( col, row - 1 ));
1069 const Style& rStartTFromR(rArray.GetCellStyleTop( col, row ));
1070 const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
1071
1072 rInstance.addSdrConnectStyleData(true, rStartFromBR, rX + rY, false);
1073 rInstance.addSdrConnectStyleData(true, rStartTFromR, rX, false);
1074 rInstance.addSdrConnectStyleData(true, rStartTFromT, -rY, true);
1075 rInstance.addSdrConnectStyleData(true, rStartTFromL, -rX, true);
1076 rInstance.addSdrConnectStyleData(true, rStartFromBL, rY - rX, true);
1077
1078 // get involved styles at end
1079 const Style& rEndFromTL(rArray.GetCellStyleBR( col - 1, row ));
1080 const Style& rEndBFromL(rArray.GetCellStyleBottom( col - 1, row ));
1081 const Style& rEndBFromB(rArray.GetCellStyleLeft( col, row + 1 ));
1082 const Style& rEndBFromR(rArray.GetCellStyleBottom( col, row ));
1083 const Style& rEndFromTR(rArray.GetCellStyleBL( col, row ));
1084
1085 rInstance.addSdrConnectStyleData(false, rEndFromTR, rX - rY, false);
1086 rInstance.addSdrConnectStyleData(false, rEndBFromR, rX, false);
1087 rInstance.addSdrConnectStyleData(false, rEndBFromB, rY, false);
1088 rInstance.addSdrConnectStyleData(false, rEndBFromL, -rX, true);
1089 rInstance.addSdrConnectStyleData(false, rEndFromTL, -rY - rX, true);
1090}
1091
1092static void HelperClipLine(
1093 basegfx::B2DPoint& rStart,
1094 basegfx::B2DVector& rDirection,
1095 const basegfx::B2DRange& rClipRange)
1096{
1097 basegfx::B2DPolygon aLine({rStart, rStart + rDirection});
1098 const basegfx::B2DPolyPolygon aResultPP(
1100 aLine,
1101 rClipRange,
1102 true, // bInside
1103 true)); // bStroke
1104
1105 if(aResultPP.count() > 0)
1106 {
1107 const basegfx::B2DPolygon aResultP(aResultPP.getB2DPolygon(0));
1108
1109 if(aResultP.count() > 0)
1110 {
1111 const basegfx::B2DPoint aResultStart(aResultP.getB2DPoint(0));
1112 const basegfx::B2DPoint aResultEnd(aResultP.getB2DPoint(aResultP.count() - 1));
1113
1114 if(aResultStart != aResultEnd)
1115 {
1116 rStart = aResultStart;
1117 rDirection = aResultEnd - aResultStart;
1118 }
1119 }
1120 }
1121}
1122
1124 const Array& rArray,
1125 const Style& rStyle,
1127 const basegfx::B2DPoint& rOrigin,
1128 const basegfx::B2DVector& rX,
1129 const basegfx::B2DVector& rY,
1130 sal_Int32 nColLeft,
1131 sal_Int32 nColRight,
1132 sal_Int32 nRowTop,
1133 sal_Int32 nRowBottom,
1134 const Color* pForceColor,
1135 const basegfx::B2DRange* pClipRange)
1136{
1137 if(rStyle.IsUsed())
1138 {
1140 basegfx::B2DPoint aStart(rOrigin);
1142
1144 if(nullptr != pClipRange)
1145 {
1146 HelperClipLine(aStart, aDirection, *pClipRange);
1147 }
1148
1150 rData.emplace_back(
1151 aStart,
1152 aDirection,
1153 rStyle,
1154 pForceColor);
1156
1158 const Style& rTLFromRight(rArray.GetCellStyleTop(nColLeft, nRowTop));
1159 const Style& rTLFromBottom(rArray.GetCellStyleLeft(nColLeft, nRowTop));
1160
1161 rInstance.addSdrConnectStyleData(true, rTLFromRight, rX, false);
1162 rInstance.addSdrConnectStyleData(true, rTLFromBottom, rY, false);
1163
1165 const Style& rBRFromBottom(rArray.GetCellStyleRight(nColRight, nRowBottom));
1166 const Style& rBRFromLeft(rArray.GetCellStyleBottom(nColRight, nRowBottom));
1167
1168 rInstance.addSdrConnectStyleData(false, rBRFromBottom, -rY, true);
1169 rInstance.addSdrConnectStyleData(false, rBRFromLeft, -rX, true);
1170 }
1171}
1172
1174 const Array& rArray,
1175 const Style& rStyle,
1177 const basegfx::B2DPoint& rOrigin,
1178 const basegfx::B2DVector& rX,
1179 const basegfx::B2DVector& rY,
1180 sal_Int32 nColLeft,
1181 sal_Int32 nColRight,
1182 sal_Int32 nRowTop,
1183 sal_Int32 nRowBottom,
1184 const Color* pForceColor,
1185 const basegfx::B2DRange* pClipRange)
1186{
1187 if(rStyle.IsUsed())
1188 {
1190 basegfx::B2DPoint aStart(rOrigin + rY);
1192
1194 if(nullptr != pClipRange)
1195 {
1196 HelperClipLine(aStart, aDirection, *pClipRange);
1197 }
1198
1200 rData.emplace_back(
1201 aStart,
1202 aDirection,
1203 rStyle,
1204 pForceColor);
1206
1208 const Style& rBLFromTop(rArray.GetCellStyleLeft(nColLeft, nRowBottom));
1209 const Style& rBLFromBottom(rArray.GetCellStyleBottom(nColLeft, nRowBottom));
1210
1211 rInstance.addSdrConnectStyleData(true, rBLFromTop, -rY, true);
1212 rInstance.addSdrConnectStyleData(true, rBLFromBottom, rX, false);
1213
1215 const Style& rTRFromLeft(rArray.GetCellStyleTop(nColRight, nRowTop));
1216 const Style& rTRFromBottom(rArray.GetCellStyleRight(nColRight, nRowTop));
1217
1218 rInstance.addSdrConnectStyleData(false, rTRFromLeft, -rX, true);
1219 rInstance.addSdrConnectStyleData(false, rTRFromBottom, rY, false);
1220 }
1221}
1222
1224 sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow,
1225 const Color* pForceColor ) const
1226{
1227 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "CreateB2DPrimitiveRange" );
1228 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "CreateB2DPrimitiveRange" );
1229
1230#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
1231 std::vector<basegfx::B2DRange> aClipRanges;
1232#endif
1233
1234 // It may be necessary to extend the loop ranges by one cell to the outside,
1235 // when possible. This is needed e.g. when there is in Calc a Cell with an
1236 // upper CellBorder using DoubleLine and that is right/left connected upwards
1237 // to also DoubleLine. These upper DoubleLines will be extended to meet the
1238 // lower of the upper CellBorder and thus have graphical parts that are
1239 // displayed one cell below and right/left of the target cell - analog to
1240 // other examples in all other directions.
1241 // It would be possible to explicitly test this (if possible by indices at all)
1242 // looping and testing the styles in the outer cells to detect this, but since
1243 // for other usages (e.g. UI) usually nFirstRow==0 and nLastRow==GetRowCount()-1
1244 // (and analog for Col) it is okay to just expand the range when available.
1245 // Do *not* change nFirstRow/nLastRow due to these needed to the boolean tests
1246 // below (!)
1247 // Checked usages, this method is used in Calc EditView/Print/Export stuff and
1248 // in UI (Dialog), not for Writer Tables and Draw/Impress tables. All usages
1249 // seem okay with this change, so I will add it.
1250 const sal_Int32 nStartRow(nFirstRow > 0 ? nFirstRow - 1 : nFirstRow);
1251 const sal_Int32 nEndRow(nLastRow < GetRowCount() - 1 ? nLastRow + 1 : nLastRow);
1252 const sal_Int32 nStartCol(nFirstCol > 0 ? nFirstCol - 1 : nFirstCol);
1253 const sal_Int32 nEndCol(nLastCol < GetColCount() - 1 ? nLastCol + 1 : nLastCol);
1254
1255 // prepare SdrFrameBorderDataVector
1256 std::shared_ptr<drawinglayer::primitive2d::SdrFrameBorderDataVector> aData(
1257 std::make_shared<drawinglayer::primitive2d::SdrFrameBorderDataVector>());
1258
1259 // remember for which merged cells crossed lines were already created. To
1260 // do so, hold the sal_Int32 cell index in a set for fast check
1261 std::set< sal_Int32 > aMergedCells;
1262
1263 for (sal_Int32 nRow(nStartRow); nRow <= nEndRow; ++nRow)
1264 {
1265 for (sal_Int32 nCol(nStartCol); nCol <= nEndCol; ++nCol)
1266 {
1267 // get Cell and CoordinateSystem (*only* for this Cell, do *not* expand for
1268 // merged cells (!)), check if used (non-empty vectors)
1269 const Cell& rCell(CELL(nCol, nRow));
1270 basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystemSingleCell(*this, nCol, nRow));
1271 basegfx::B2DVector aX(basegfx::utils::getColumn(aCoordinateSystem, 0));
1272 basegfx::B2DVector aY(basegfx::utils::getColumn(aCoordinateSystem, 1));
1273
1274 // get needed local values
1275 basegfx::B2DPoint aOrigin(basegfx::utils::getColumn(aCoordinateSystem, 2));
1276 const bool bOverlapX(rCell.mbOverlapX);
1277 const bool bFirstCol(nCol == nFirstCol);
1278
1279 // handle rotation: If cell is rotated, handle lower/right edge inside
1280 // this local geometry due to the created CoordinateSystem already representing
1281 // the needed transformations.
1282 const bool bRotated(rCell.IsRotated());
1283
1284 // Additionally avoid double-handling by suppressing handling when self not rotated,
1285 // but above/left is rotated and thus already handled. Two directly connected
1286 // rotated will paint/create both edges, they might be rotated differently.
1287 const bool bSuppressLeft(!bRotated && nCol > nFirstCol && CELL(nCol - 1, nRow).IsRotated());
1288 const bool bSuppressAbove(!bRotated && nRow > nFirstRow && CELL(nCol, nRow - 1).IsRotated());
1289
1290 if(!aX.equalZero() && !aY.equalZero())
1291 {
1292 // additionally needed local values
1293 const bool bOverlapY(rCell.mbOverlapY);
1294 const bool bLastCol(nCol == nLastCol);
1295 const bool bFirstRow(nRow == nFirstRow);
1296 const bool bLastRow(nRow == nLastRow);
1297
1298 // create upper line for this Cell
1299 if ((!bOverlapY // true for first line in merged cells or cells
1300 || bFirstRow) // true for non_Calc usages of this tooling
1301 && !bSuppressAbove) // true when above is not rotated, so edge is already handled (see bRotated)
1302 {
1303 // get CellStyle - method will take care to get the correct one, e.g.
1304 // for merged cells (it uses ORIGCELL that works with topLeft's of these)
1305 const Style& rTop(GetCellStyleTop(nCol, nRow));
1306
1307 if(rTop.IsUsed())
1308 {
1309 HelperCreateHorizontalEntry(*this, rTop, nCol, nRow, aOrigin, aX, aY, *aData, true, pForceColor);
1310 }
1311 }
1312
1313 // create lower line for this Cell
1314 if (bLastRow // true for non_Calc usages of this tooling
1315 || bRotated) // true if cell is rotated, handle lower edge in local geometry
1316 {
1317 const Style& rBottom(GetCellStyleBottom(nCol, nRow));
1318
1319 if(rBottom.IsUsed())
1320 {
1321 HelperCreateHorizontalEntry(*this, rBottom, nCol, nRow + 1, aOrigin, aX, aY, *aData, false, pForceColor);
1322 }
1323 }
1324
1325 // create left line for this Cell
1326 if ((!bOverlapX // true for first column in merged cells or cells
1327 || bFirstCol) // true for non_Calc usages of this tooling
1328 && !bSuppressLeft) // true when left is not rotated, so edge is already handled (see bRotated)
1329 {
1330 const Style& rLeft(GetCellStyleLeft(nCol, nRow));
1331
1332 if(rLeft.IsUsed())
1333 {
1334 HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, *aData, true, pForceColor);
1335 }
1336 }
1337
1338 // create right line for this Cell
1339 if (bLastCol // true for non_Calc usages of this tooling
1340 || bRotated) // true if cell is rotated, handle right edge in local geometry
1341 {
1342 const Style& rRight(GetCellStyleRight(nCol, nRow));
1343
1344 if(rRight.IsUsed())
1345 {
1346 HelperCreateVerticalEntry(*this, rRight, nCol + 1, nRow, aOrigin, aX, aY, *aData, false, pForceColor);
1347 }
1348 }
1349
1350 // tdf#126269 check for crossed lines, these need special treatment, especially
1351 // for merged cells (see comments in task). Separate treatment of merged and
1352 // non-merged cells to allow better handling of both types
1353 if(rCell.IsMerged())
1354 {
1355 // first check if this merged cell was already handled. To do so,
1356 // calculate and use the index of the TopLeft cell
1357 sal_Int32 nColLeft(nCol), nRowTop(nRow), nColRight(nCol), nRowBottom(nRow);
1358 GetMergedRange(nColLeft, nRowTop, nColRight, nRowBottom, nCol, nRow);
1359 const sal_Int32 nIndexOfMergedCell(mxImpl->GetIndex(nColLeft, nRowTop));
1360
1361 if(aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell))
1362 {
1363 // not found, so not yet handled. Add now to mark as handled
1364 aMergedCells.insert(nIndexOfMergedCell);
1365
1366 // Get and check if diagonal styles are used
1367 // Note: For GetCellStyleBLTR below I tried to use nRowBottom
1368 // as Y-value what seemed more logical, but that
1369 // is wrong. Despite defining a line starting at
1370 // bottom-left, the Style is defined in the cell at top-left
1371 const Style& rTLBR(GetCellStyleTLBR(nColLeft, nRowTop));
1372 const Style& rBLTR(GetCellStyleBLTR(nColLeft, nRowTop));
1373
1374 if(rTLBR.IsUsed() || rBLTR.IsUsed())
1375 {
1376 // test if merged cell overlaps ClipRange at all (needs visualization)
1377 if(mxImpl->OverlapsClipRange(nColLeft, nRowTop, nColRight, nRowBottom))
1378 {
1379 // when merged, get extended coordinate system and derived values
1380 // for the full range of this merged cell. Only work with rMergedCell
1381 // (which is the top-left single cell of the merged cell) from here on
1382 const Cell& rMergedCell(CELL(nColLeft, nRowTop));
1383 aCoordinateSystem = rMergedCell.CreateCoordinateSystemMergedCell(
1384 *this, nColLeft, nRowTop, nColRight, nRowBottom);
1385 aX = basegfx::utils::getColumn(aCoordinateSystem, 0);
1386 aY = basegfx::utils::getColumn(aCoordinateSystem, 1);
1387 aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2);
1388
1389 // check if clip is needed
1390 basegfx::B2DRange aClipRange;
1391
1392 // first use row/col ClipTest for raw check
1393 bool bNeedToClip(
1394 !mxImpl->IsColInClipRange(nColLeft) ||
1395 !mxImpl->IsRowInClipRange(nRowTop) ||
1396 !mxImpl->IsColInClipRange(nColRight) ||
1397 !mxImpl->IsRowInClipRange(nRowBottom));
1398
1399 if(bNeedToClip)
1400 {
1401 // now get ClipRange and CellRange in logical coordinates
1402 aClipRange = GetB2DRange(
1403 mxImpl->mnFirstClipCol, mxImpl->mnFirstClipRow,
1404 mxImpl->mnLastClipCol, mxImpl->mnLastClipRow);
1405
1406 basegfx::B2DRange aCellRange(
1408 nColLeft, nRowTop,
1409 nColRight, nRowBottom));
1410
1411 // intersect these to get the target ClipRange, ensure
1412 // that clip is needed
1413 aClipRange.intersect(aCellRange);
1414 bNeedToClip = !aClipRange.isEmpty();
1415
1416#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
1417 aClipRanges.push_back(aClipRange);
1418#endif
1419 }
1420
1421 // create top-left to bottom-right geometry
1422 HelperCreateTLBREntry(*this, rTLBR, *aData, aOrigin, aX, aY,
1423 nColLeft, nRowTop, nColRight, nRowBottom, pForceColor,
1424 bNeedToClip ? &aClipRange : nullptr);
1425
1426 // create bottom-left to top-right geometry
1427 HelperCreateBLTREntry(*this, rBLTR, *aData, aOrigin, aX, aY,
1428 nColLeft, nRowTop, nColRight, nRowBottom, pForceColor,
1429 bNeedToClip ? &aClipRange : nullptr);
1430 }
1431 }
1432 }
1433 }
1434 else
1435 {
1436 // must be in clipping range: else not visible. This
1437 // already clips completely for non-merged cells
1438 if( mxImpl->IsInClipRange( nCol, nRow ) )
1439 {
1440 // get and check if diagonal styles are used
1441 const Style& rTLBR(GetCellStyleTLBR(nCol, nRow));
1442 const Style& rBLTR(GetCellStyleBLTR(nCol, nRow));
1443
1444 if(rTLBR.IsUsed() || rBLTR.IsUsed())
1445 {
1446 HelperCreateTLBREntry(*this, rTLBR, *aData, aOrigin, aX, aY,
1447 nCol, nRow, nCol, nRow, pForceColor, nullptr);
1448
1449 HelperCreateBLTREntry(*this, rBLTR, *aData, aOrigin, aX, aY,
1450 nCol, nRow, nCol, nRow, pForceColor, nullptr);
1451 }
1452 }
1453 }
1454 }
1455 else if(!aY.equalZero())
1456 {
1457 // cell has height, but no width. Create left vertical line for this Cell
1458 if ((!bOverlapX // true for first column in merged cells or cells
1459 || bFirstCol) // true for non_Calc usages of this tooling
1460 && !bSuppressLeft) // true when left is not rotated, so edge is already handled (see bRotated)
1461 {
1462 const Style& rLeft(GetCellStyleLeft(nCol, nRow));
1463
1464 if (rLeft.IsUsed())
1465 {
1466 HelperCreateVerticalEntry(*this, rLeft, nCol, nRow, aOrigin, aX, aY, *aData, true, pForceColor);
1467 }
1468 }
1469 }
1470 else
1471 {
1472 // Cell has *no* size, thus no visualization
1473 }
1474 }
1475 }
1476
1477 // create instance of SdrFrameBorderPrimitive2D if
1478 // SdrFrameBorderDataVector is used
1480
1481 if(!aData->empty())
1482 {
1483 aSequence.append(
1486 aData,
1487 true))); // force visualization to minimal one discrete unit (pixel)
1488 }
1489
1490#ifdef OPTICAL_CHECK_CLIPRANGE_FOR_MERGED_CELL
1491 for(auto const& rClipRange : aClipRanges)
1492 {
1493 // draw ClipRange in yellow to allow simple interactive optical control in office
1494 aSequence.append(
1498 basegfx::BColor(1.0, 1.0, 0.0))));
1499 }
1500#endif
1501
1502 return aSequence;
1503}
1504
1506{
1508
1509 if (mxImpl->mnWidth && mxImpl->mnHeight)
1510 {
1511 aPrimitives = CreateB2DPrimitiveRange(0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, nullptr);
1512 }
1513
1514 return aPrimitives;
1515}
1516
1517#undef ORIGCELL
1518#undef LASTCELL
1519#undef CELLACC
1520#undef CELL
1521#undef DBG_FRAME_CHECK_ROW_1
1522#undef DBG_FRAME_CHECK_COL_1
1523#undef DBG_FRAME_CHECK_COLROW
1524#undef DBG_FRAME_CHECK_ROW
1525#undef DBG_FRAME_CHECK_COL
1526#undef DBG_FRAME_CHECK
1527
1528}
1529
1530/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
sal_uInt32 count() const
B2DPoint getMinimum() const
TYPE getWidth() const
void intersect(const Range2D &rRange)
bool isEmpty() const
TYPE getHeight() const
bool equalZero() const
TYPE getX() const
TYPE getY() const
void setX(TYPE fX)
void append(const Primitive2DReference &)
void addSdrConnectStyleData(bool bStart, const svx::frame::Style &rStyle, const basegfx::B2DVector &rNormalizedPerpendicular, bool bStyleMirrored)
Stores frame styles of an array of cells, supports merged ranges.
void SetAddMergedLeftSize(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize)
Sets an additional left width for the merged range that contains (nCol,nRow).
const Style & GetCellStyleTL(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top-left to bottom-right frame style of the cell (nCol,nRow).
std::unique_ptr< ArrayImpl > mxImpl
~Array()
Destructs the array.
const Style & GetCellStyleLeft(sal_Int32 nCol, sal_Int32 nRow) const
Returns the left frame style of the cell (nCol,nRow).
const Style & GetCellStyleTLBR(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top-left to bottom-right frame style of the cell (nCol,nRow).
sal_Int32 GetCellCount() const
Returns the number of cells in the array.
const Style & GetCellStyleTop(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top frame style of the cell (nCol,nRow).
bool IsMerged(sal_Int32 nCol, sal_Int32 nRow) const
Returns true, if the cell (nCol,nRow) is part of a merged range.
drawinglayer::primitive2d::Primitive2DContainer CreateB2DPrimitiveRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow, const Color *pForceColor) const
Draws the part of the specified range, that is inside the clipping range.
void SetRowHeight(sal_Int32 nRow, sal_Int32 nHeight)
Sets the output height of the specified row.
sal_Int32 GetColWidth(sal_Int32 nFirstCol, sal_Int32 nLastCol) const
Returns the output width of the specified range of columns.
void SetMergedRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow)
Inserts a new merged cell range.
void SetCellStyleBottom(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the bottom frame style of the specified cell (nCol,nRow).
void SetAddMergedBottomSize(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize)
Sets an additional bottom height for the merged range that contains (nCol,nRow).
bool HasCellRotation() const
Check if at least one cell is rotated.
void SetCellStyleTLBR(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the top-left to bottom-right frame style of the cell (nCol,nRow).
const Style & GetCellStyleBR(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top-left to bottom-right frame style of the cell (nCol,nRow).
void SetCellStyleLeft(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the left frame style of the cell (nCol,nRow).
void SetCellStyleRight(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the right frame style of the cell (nCol,nRow).
void SetAddMergedRightSize(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize)
Sets an additional right width for the merged range that contains (nCol,nRow).
void SetColWidth(sal_Int32 nCol, sal_Int32 nWidth)
Sets the output width of the specified column.
void SetXOffset(sal_Int32 nXOffset)
Sets the X output coordinate of the left column.
sal_Int32 GetWidth() const
Returns the output width of the entire array.
basegfx::B2DRange GetB2DRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow) const
const Style & GetCellStyleTR(sal_Int32 nCol, sal_Int32 nRow) const
Returns the bottom-left to top-right frame style of the cell (nCol,nRow).
basegfx::B2DRange GetCellRange(sal_Int32 nCol, sal_Int32 nRow) const
Returns the output range of the cell (nCol,nRow).
Array()
Constructs an empty array.
const Style & GetCellStyleBLTR(sal_Int32 nCol, sal_Int32 nRow) const
Returns the bottom-left to top-right frame style of the cell (nCol,nRow).
void Initialize(sal_Int32 nWidth, sal_Int32 nHeight)
Reinitializes the array with the specified size.
void SetColumnStyleLeft(sal_Int32 nCol, const Style &rStyle)
Sets the left frame style of the specified column.
void GetMergedRange(sal_Int32 &rnFirstCol, sal_Int32 &rnFirstRow, sal_Int32 &rnLastCol, sal_Int32 &rnLastRow, sal_Int32 nCol, sal_Int32 nRow) const
Returns the top-left and bottom-right address of the merged range that contains (nCol,...
void SetRowStyleTop(sal_Int32 nRow, const Style &rStyle)
Sets the top frame style of the specified row.
void SetYOffset(sal_Int32 nYOffset)
Sets the Y output coordinate of the top row.
sal_Int32 GetRowHeight(sal_Int32 nFirstRow, sal_Int32 nLastRow) const
Returns the output height of the specified range of rows.
const Style & GetCellStyleBottom(sal_Int32 nCol, sal_Int32 nRow) const
Returns the top frame style of the cell (nCol,nRow).
const Style & GetCellStyleRight(sal_Int32 nCol, sal_Int32 nRow) const
Returns the right frame style of the cell (nCol,nRow).
void SetCellStyleDiag(sal_Int32 nCol, sal_Int32 nRow, const Style &rTLBR, const Style &rBLTR)
Sets both diagonal frame styles of the specified cell (nCol,nRow).
drawinglayer::primitive2d::Primitive2DContainer CreateB2DPrimitiveArray() const
Draws the part of the array, that is inside the clipping range.
void GetMergedOrigin(sal_Int32 &rnFirstCol, sal_Int32 &rnFirstRow, sal_Int32 nCol, sal_Int32 nRow) const
Returns the address of the top-left cell of the merged range that contains (nCol,nRow).
sal_Int32 GetHeight() const
Returns the output height of the entire array.
void SetAddMergedTopSize(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nAddSize)
Sets an additional top height for the merged range that contains (nCol,nRow).
const Style & GetCellStyleBL(sal_Int32 nCol, sal_Int32 nRow) const
Returns the bottom-left to top-right frame style of the cell (nCol,nRow).
void SetAllColWidths(sal_Int32 nWidth)
Sets the same output width for all columns.
sal_Int32 GetColPosition(sal_Int32 nCol) const
Returns the X output coordinate of the left border of the specified column.
void SetCellStyleBLTR(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the bottom-left to top-right frame style of the cell (nCol,nRow).
void SetRowStyleBottom(sal_Int32 nRow, const Style &rStyle)
Sets the bottom frame style of the specified row.
sal_Int32 GetColCount() const
Returns the number of columns in the array.
void SetColumnStyleRight(sal_Int32 nCol, const Style &rStyle)
Sets the right frame style of the specified column.
sal_Int32 GetRowPosition(sal_Int32 nRow) const
Returns the Y output coordinate of the top border of the specified row.
void SetClipRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow)
Sets a clipping range.
void SetAllRowHeights(sal_Int32 nHeight)
Sets the same output height for all rows.
sal_Int32 GetCellIndex(sal_Int32 nCol, sal_Int32 nRow, bool bRTL) const
Returns the cell index from the cell address (nCol,nRow).
void MirrorSelfX()
Mirrors the entire array horizontally.
void SetCellRotation(sal_Int32 nCol, sal_Int32 nRow, SvxRotateMode eRotMode, double fOrientation)
Sets the rotation parameters of the cell (nCol,nRow).
void SetCellStyleTop(sal_Int32 nCol, sal_Int32 nRow, const Style &rStyle)
Sets the top frame style of the cell (nCol,nRow).
sal_Int32 GetRowCount() const
Returns the number of rows in the array.
Contains the widths of primary and secondary line of a frame style.
Definition: framelink.hxx:99
bool IsUsed() const
Check if this style is used - this depends on it having any width definition.
Definition: framelink.hxx:136
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
#define DBG_ASSERT(sCon, aError)
FilterGroup & rTarget
SotClipboardFormatId & operator++(SotClipboardFormatId &eFormat)
sal_Int32 mnAddRight
double mfOrientation
#define LASTCELL(col, row)
#define DBG_FRAME_CHECK_COLROW(col, row, funcname)
bool mbOverlapX
#define DBG_FRAME_CHECK_COL(col, funcname)
Style maLeft
sal_Int32 mnAddTop
#define DBG_FRAME_CHECK_ROW_1(row, funcname)
sal_Int32 mnFirstCol
bool mbOverlapY
#define ORIGCELL(col, row)
sal_Int32 mnLastCol
Style maTLBR
Style maBLTR
#define CELL(col, row)
sal_Int32 mnRow
#define DBG_FRAME_CHECK_COL_1(col, funcname)
bool mbMergeOrig
sal_Int32 mnCol
Style maTop
#define DBG_FRAME_CHECK(cond, funcname, error)
#define DBG_FRAME_CHECK_ROW(row, funcname)
#define CELLACC(col, row)
sal_Int32 mnAddLeft
sal_Int32 mnAddBottom
Style maRight
sal_Int32 mnFirstRow
Style maBottom
SvxRotateMode meRotMode
sal_Int32 mnLastRow
const ContentProperties & rData
constexpr OUStringLiteral aData
B2DHomMatrix createCoordinateSystemTransform(const B2DPoint &rOrigin, const B2DVector &rX, const B2DVector &rY)
B2DPolygon createPolygonFromRect(const B2DRectangle &rRect, double fRadiusX, double fRadiusY)
B2DTuple getColumn(const B2DHomMatrix &rMatrix, sal_uInt16 nCol)
B2DPolyPolygon clipPolygonOnRange(const B2DPolygon &rCandidate, const B2DRange &rRange, bool bInside, bool bStroke)
std::vector< SdrFrameBorderData > SdrFrameBorderDataVector
static void HelperCreateHorizontalEntry(const Array &rArray, const Style &rStyle, sal_Int32 col, sal_Int32 row, const basegfx::B2DPoint &rOrigin, const basegfx::B2DVector &rX, const basegfx::B2DVector &rY, drawinglayer::primitive2d::SdrFrameBorderDataVector &rData, bool bUpper, const Color *pForceColor)
static void HelperCreateBLTREntry(const Array &rArray, const Style &rStyle, drawinglayer::primitive2d::SdrFrameBorderDataVector &rData, const basegfx::B2DPoint &rOrigin, const basegfx::B2DVector &rX, const basegfx::B2DVector &rY, sal_Int32 nColLeft, sal_Int32 nColRight, sal_Int32 nRowTop, sal_Int32 nRowBottom, const Color *pForceColor, const basegfx::B2DRange *pClipRange)
const Style OBJ_STYLE_NONE
static void HelperCreateTLBREntry(const Array &rArray, const Style &rStyle, drawinglayer::primitive2d::SdrFrameBorderDataVector &rData, const basegfx::B2DPoint &rOrigin, const basegfx::B2DVector &rX, const basegfx::B2DVector &rY, sal_Int32 nColLeft, sal_Int32 nColRight, sal_Int32 nRowTop, sal_Int32 nRowBottom, const Color *pForceColor, const basegfx::B2DRange *pClipRange)
static void lclRecalcCoordVec(std::vector< sal_Int32 > &rCoords, const std::vector< sal_Int32 > &rSizes)
static void lclSetMergedRange(CellVec &rCells, sal_Int32 nWidth, sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow)
static void HelperCreateVerticalEntry(const Array &rArray, const Style &rStyle, sal_Int32 col, sal_Int32 row, const basegfx::B2DPoint &rOrigin, const basegfx::B2DVector &rX, const basegfx::B2DVector &rY, drawinglayer::primitive2d::SdrFrameBorderDataVector &rData, bool bLeft, const Color *pForceColor)
static void HelperClipLine(basegfx::B2DPoint &rStart, basegfx::B2DVector &rDirection, const basegfx::B2DRange &rClipRange)
std::vector< Cell > CellVec
const Cell OBJ_CELL_NONE
bool IsRotated(const OUString &rsCommandName, const OUString &rsModuleName)
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
SvxRotateMode
Definition: rotmodit.hxx:30
@ SVX_ROTATE_MODE_BOTTOM
Definition: rotmodit.hxx:34
@ SVX_ROTATE_MODE_STANDARD
Definition: rotmodit.hxx:31
@ SVX_ROTATE_MODE_CENTER
Definition: rotmodit.hxx:33
@ SVX_ROTATE_MODE_TOP
Definition: rotmodit.hxx:32
double mnWidth
double mnHeight
bool IsMergedOverlappedRight(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetMergedFirstCol(sal_Int32 nCol, sal_Int32 nRow) const
std::vector< sal_Int32 > maXCoords
bool IsMergedOverlappedTop(sal_Int32 nCol, sal_Int32 nRow) const
bool OverlapsClipRange(sal_Int32 nFirstCol, sal_Int32 nFirstRow, sal_Int32 nLastCol, sal_Int32 nLastRow) const
const Cell & GetMergedLastCell(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetMergedLastRow(sal_Int32 nCol, sal_Int32 nRow) const
bool IsRowInClipRange(sal_Int32 nRow) const
bool IsMergedOverlappedLeft(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetMirrorCol(sal_Int32 nCol) const
sal_Int32 GetMergedFirstRow(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetRowPosition(sal_Int32 nRow) const
std::vector< sal_Int32 > maYCoords
const Cell & GetMergedOriginCell(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetIndex(sal_Int32 nCol, sal_Int32 nRow) const
sal_Int32 GetMergedLastCol(sal_Int32 nCol, sal_Int32 nRow) const
std::vector< sal_Int32 > maWidths
bool IsColInClipRange(sal_Int32 nCol) const
sal_Int32 GetColPosition(sal_Int32 nCol) const
bool IsInClipRange(sal_Int32 nCol, sal_Int32 nRow) const
Cell & GetCellAcc(sal_Int32 nCol, sal_Int32 nRow)
std::vector< sal_Int32 > maHeights
bool IsValidPos(sal_Int32 nCol, sal_Int32 nRow) const
const Cell & GetCell(sal_Int32 nCol, sal_Int32 nRow) const
bool HasCellRotation() const
bool IsMergedOverlappedBottom(sal_Int32 nCol, sal_Int32 nRow) const
css::drawing::Direction3D aDirection
Cell
Definition: svdotable.hxx:95