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