Adjust includes
[LibreOffice.git] / svx / source / table / viewcontactoftableobj.cxx
blob2f818e5ee7f288efc67b04037715de66db7f91d3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "viewcontactoftableobj.hxx"
22 #include <svx/svdotable.hxx>
23 #include <com/sun/star/table/XTable.hpp>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
27 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
28 #include <drawinglayer/primitive2d/groupprimitive2d.hxx>
29 #include <svx/sdr/primitive2d/sdrdecompositiontools.hxx>
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 #include <svx/sdr/attribute/sdrtextattribute.hxx>
32 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
33 #include <editeng/borderline.hxx>
34 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
35 #include <sdr/attribute/sdrfilltextattribute.hxx>
36 #include <drawinglayer/attribute/sdrlineattribute.hxx>
37 #include <drawinglayer/attribute/sdrshadowattribute.hxx>
38 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
39 #include <basegfx/matrix/b2dhommatrixtools.hxx>
40 #include <svx/framelink.hxx>
42 #include <cell.hxx>
43 #include "tablelayouter.hxx"
46 using editeng::SvxBorderLine;
47 using namespace com::sun::star;
50 namespace drawinglayer
52 namespace primitive2d
54 class SdrCellPrimitive2D : public BufferedDecompositionPrimitive2D
56 private:
57 basegfx::B2DHomMatrix maTransform;
58 attribute::SdrFillTextAttribute maSdrFTAttribute;
60 protected:
61 // local decomposition.
62 virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
64 public:
65 SdrCellPrimitive2D(
66 const basegfx::B2DHomMatrix& rTransform,
67 const attribute::SdrFillTextAttribute& rSdrFTAttribute)
68 : BufferedDecompositionPrimitive2D(),
69 maTransform(rTransform),
70 maSdrFTAttribute(rSdrFTAttribute)
74 // data access
75 const basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
76 const attribute::SdrFillTextAttribute& getSdrFTAttribute() const { return maSdrFTAttribute; }
78 // compare operator
79 virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
81 // provide unique ID
82 DeclPrimitive2DIDBlock()
85 void SdrCellPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
87 // prepare unit polygon
88 const basegfx::B2DPolyPolygon aUnitPolyPolygon(basegfx::utils::createUnitPolygon());
90 // add fill
91 if(!getSdrFTAttribute().getFill().isDefault())
93 basegfx::B2DPolyPolygon aTransformed(aUnitPolyPolygon);
95 aTransformed.transform(getTransform());
96 rContainer.push_back(
97 createPolyPolygonFillPrimitive(
98 aTransformed,
99 getSdrFTAttribute().getFill(),
100 getSdrFTAttribute().getFillFloatTransGradient()));
102 else
104 // if no fill create one for HitTest and BoundRect fallback
105 rContainer.push_back(
106 createHiddenGeometryPrimitives2D(
107 true,
108 aUnitPolyPolygon,
109 getTransform()));
112 // add text
113 if(!getSdrFTAttribute().getText().isDefault())
115 rContainer.push_back(
116 createTextPrimitive(
117 aUnitPolyPolygon,
118 getTransform(),
119 getSdrFTAttribute().getText(),
120 attribute::SdrLineAttribute(),
121 true,
122 false));
126 bool SdrCellPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
128 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
130 const SdrCellPrimitive2D& rCompare = static_cast<const SdrCellPrimitive2D&>(rPrimitive);
132 return (getTransform() == rCompare.getTransform()
133 && getSdrFTAttribute() == rCompare.getSdrFTAttribute());
136 return false;
139 // provide unique ID
140 ImplPrimitive2DIDBlock(SdrCellPrimitive2D, PRIMITIVE2D_ID_SDRCELLPRIMITIVE2D)
142 } // end of namespace primitive2d
143 } // end of namespace drawinglayer
145 namespace sdr
147 namespace contact
149 svx::frame::Style impGetLineStyle(
150 const sdr::table::TableLayouter& rLayouter,
151 sal_Int32 nX,
152 sal_Int32 nY,
153 bool bHorizontal,
154 sal_Int32 nColCount,
155 sal_Int32 nRowCount,
156 bool bIsRTL)
158 if(nX >= 0 && nX <= nColCount && nY >= 0 && nY <= nRowCount)
160 const SvxBorderLine* pLine = rLayouter.getBorderLine(nX, nY, bHorizontal);
162 if(pLine)
164 // copy line content
165 SvxBorderLine aLine(*pLine);
167 // check for mirroring. This shall always be done when it is
168 // not a top- or rightmost line
169 bool bMirror(aLine.isDouble());
171 if(bMirror)
173 if(bHorizontal)
175 // mirror all bottom lines
176 bMirror = (0 != nY);
178 else
180 // mirror all left lines
181 bMirror = (bIsRTL ? 0 != nX : nX != nColCount);
185 if(bMirror)
187 aLine.SetMirrorWidths( );
190 const double fTwipsToMM(127.0 / 72.0);
191 return svx::frame::Style(&aLine, fTwipsToMM);
195 // no success, copy empty line
196 return svx::frame::Style();
199 void createForVector(bool bHor, drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX,
200 const svx::frame::Style& rLine,
201 const svx::frame::Style& rLeftA, const svx::frame::Style& rLeftB, const svx::frame::Style& rLeftC,
202 const svx::frame::Style& rRightA, const svx::frame::Style& rRightB, const svx::frame::Style& rRightC)
204 /// top-left and bottom-right Style Tables
205 const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX));
207 /// Fill top-left Style Table
208 svx::frame::StyleVectorTable aStart;
210 aStart.add(rLeftA, rX, -aY, bHor); // bHor ? true : false));
211 aStart.add(rLeftB, rX, -rX, true); // bHor ? true : true));
212 aStart.add(rLeftC, rX, aY, !bHor); // bHor ? false : true));
213 aStart.sort();
215 /// Fill bottom-right Style Table
216 svx::frame::StyleVectorTable aEnd;
217 const basegfx::B2DVector aAxis(-rX);
219 aEnd.add(rRightA, aAxis, -aY, bHor); // bHor ? true : false));
220 aEnd.add(rRightB, aAxis, rX, false); // bHor ? false : false));
221 aEnd.add(rRightC, aAxis, aY, !bHor); // bHor ? false : true));
222 aEnd.sort();
224 CreateBorderPrimitives(
225 rContainer,
226 rOrigin,
228 rLine,
229 aStart,
230 aEnd,
231 nullptr
235 drawinglayer::primitive2d::Primitive2DContainer ViewContactOfTableObj::createViewIndependentPrimitive2DSequence() const
237 const sdr::table::SdrTableObj& rTableObj = static_cast<const sdr::table::SdrTableObj&>(GetSdrObject());
238 const uno::Reference< css::table::XTable > xTable = rTableObj.getTable();
240 if(xTable.is())
242 // create primitive representation for table. Cell info goes
243 // directly to aRetval, Border info to aBorderSequence and added
244 // later to get the correct overlapping
245 drawinglayer::primitive2d::Primitive2DContainer aRetval;
246 const sal_Int32 nRowCount(xTable->getRowCount());
247 const sal_Int32 nColCount(xTable->getColumnCount());
248 const sal_Int32 nAllCount(nRowCount * nColCount);
250 if(nAllCount)
252 const sdr::table::TableLayouter& rTableLayouter = rTableObj.getTableLayouter();
253 const bool bIsRTL(css::text::WritingMode_RL_TB == rTableObj.GetWritingMode());
254 sdr::table::CellPos aCellPos;
255 sdr::table::CellRef xCurrentCell;
256 basegfx::B2IRectangle aCellArea;
258 // create range using the model data directly. This is in SdrTextObj::aRect which i will access using
259 // GetGeoRect() to not trigger any calculations. It's the unrotated geometry.
260 const tools::Rectangle& rObjectRectangle(rTableObj.GetGeoRect());
261 const basegfx::B2DRange aObjectRange(rObjectRectangle.Left(), rObjectRectangle.Top(), rObjectRectangle.Right(), rObjectRectangle.Bottom());
263 // for each cell we need potentially a cell primitive and a border primitive
264 // (e.g. single cell). Prepare sequences and input counters
265 drawinglayer::primitive2d::Primitive2DContainer aBorderSequence;
267 // create single primitives per cell
268 for(aCellPos.mnRow = 0; aCellPos.mnRow < nRowCount; aCellPos.mnRow++)
270 for(aCellPos.mnCol = 0; aCellPos.mnCol < nColCount; aCellPos.mnCol++)
272 xCurrentCell.set(dynamic_cast< sdr::table::Cell* >(xTable->getCellByPosition(aCellPos.mnCol, aCellPos.mnRow).get()));
274 if(xCurrentCell.is() && !xCurrentCell->isMerged())
276 if(rTableLayouter.getCellArea(xCurrentCell, aCellPos, aCellArea))
278 // create cell transformation matrix
279 basegfx::B2DHomMatrix aCellMatrix;
280 aCellMatrix.set(0, 0, (double)aCellArea.getWidth());
281 aCellMatrix.set(1, 1, (double)aCellArea.getHeight());
282 aCellMatrix.set(0, 2, (double)aCellArea.getMinX() + aObjectRange.getMinX());
283 aCellMatrix.set(1, 2, (double)aCellArea.getMinY() + aObjectRange.getMinY());
285 // handle cell fillings and text
286 const SfxItemSet& rCellItemSet = xCurrentCell->GetItemSet();
287 const sal_uInt32 nTextIndex(nColCount * aCellPos.mnRow + aCellPos.mnCol);
288 const SdrText* pSdrText = rTableObj.getText(nTextIndex);
289 drawinglayer::attribute::SdrFillTextAttribute aAttribute;
291 if(pSdrText)
293 // #i101508# take cell's local text frame distances into account
294 const sal_Int32 nLeft(xCurrentCell->GetTextLeftDistance());
295 const sal_Int32 nRight(xCurrentCell->GetTextRightDistance());
296 const sal_Int32 nUpper(xCurrentCell->GetTextUpperDistance());
297 const sal_Int32 nLower(xCurrentCell->GetTextLowerDistance());
299 aAttribute = drawinglayer::primitive2d::createNewSdrFillTextAttribute(
300 rCellItemSet,
301 pSdrText,
302 &nLeft,
303 &nUpper,
304 &nRight,
305 &nLower);
307 else
309 aAttribute = drawinglayer::primitive2d::createNewSdrFillTextAttribute(
310 rCellItemSet,
311 pSdrText);
314 // always create cell primitives for BoundRect and HitTest
316 const drawinglayer::primitive2d::Primitive2DReference xCellReference(
317 new drawinglayer::primitive2d::SdrCellPrimitive2D(
318 aCellMatrix, aAttribute));
319 aRetval.append(xCellReference);
322 // handle cell borders
323 const sal_Int32 nX(bIsRTL ? nColCount - aCellPos.mnCol : aCellPos.mnCol);
324 const sal_Int32 nY(aCellPos.mnRow);
326 // get access values for X,Y at the cell's end
327 const sal_Int32 nXSpan(xCurrentCell->getColumnSpan());
328 const sal_Int32 nYSpan(xCurrentCell->getRowSpan());
329 const sal_Int32 nXRight(bIsRTL ? nX - nXSpan : nX + nXSpan);
330 const sal_Int32 nYBottom(nY + nYSpan);
332 // get basic lines
333 const svx::frame::Style aLeftLine(impGetLineStyle(rTableLayouter, nX, nY, false, nColCount, nRowCount, bIsRTL));
334 //To resolve the bug fdo#59117
335 //In RTL table as BottomLine & TopLine are drawn from Left Side to Right, nX should be nX-1
336 const svx::frame::Style aBottomLine(impGetLineStyle(rTableLayouter, bIsRTL?nX-1:nX, nYBottom, true, nColCount, nRowCount, bIsRTL));
337 const svx::frame::Style aRightLine(impGetLineStyle(rTableLayouter, nXRight, nY, false, nColCount, nRowCount, bIsRTL));
338 const svx::frame::Style aTopLine(impGetLineStyle(rTableLayouter, bIsRTL?nX-1:nX, nY, true, nColCount, nRowCount, bIsRTL));
340 if(aLeftLine.IsUsed() || aBottomLine.IsUsed() || aRightLine.IsUsed() || aTopLine.IsUsed())
342 // get the neighbor cells' borders
343 const svx::frame::Style aLeftFromTLine(impGetLineStyle(rTableLayouter, nX, nY - 1, false, nColCount, nRowCount, bIsRTL));
344 const svx::frame::Style aLeftFromBLine(impGetLineStyle(rTableLayouter, nX, nYBottom + 1, false, nColCount, nRowCount, bIsRTL));
345 const svx::frame::Style aRightFromTLine(impGetLineStyle(rTableLayouter, nXRight, nY - 1, false, nColCount, nRowCount, bIsRTL));
346 const svx::frame::Style aRightFromBLine(impGetLineStyle(rTableLayouter, nXRight, nYBottom + 1, false, nColCount, nRowCount, bIsRTL));
347 const svx::frame::Style aTopFromLLine(impGetLineStyle(rTableLayouter, nX - 1, nY, true, nColCount, nRowCount, bIsRTL));
348 const svx::frame::Style aTopFromRLine(impGetLineStyle(rTableLayouter, nXRight + 1, nY, true, nColCount, nRowCount, bIsRTL));
349 const svx::frame::Style aBottomFromLLine(impGetLineStyle(rTableLayouter, nX - 1, nYBottom, true, nColCount, nRowCount, bIsRTL));
350 const svx::frame::Style aBottomFromRLine(impGetLineStyle(rTableLayouter, nXRight + 1, nYBottom, true, nColCount, nRowCount, bIsRTL));
352 // get cell coordinate system
353 const basegfx::B2DPoint aOrigin(aCellMatrix * basegfx::B2DPoint(0.0, 0.0));
354 const basegfx::B2DVector aX(aCellMatrix * basegfx::B2DVector(1.0, 0.0));
355 const basegfx::B2DVector aY(aCellMatrix * basegfx::B2DVector(0.0, 1.0));
357 if(aLeftLine.IsUsed())
359 createForVector(false, aBorderSequence, aOrigin, aY, aLeftLine,
360 aTopLine, aLeftFromTLine, aTopFromLLine,
361 aBottomLine, aLeftFromBLine, aBottomFromLLine);
364 if(aBottomLine.IsUsed())
366 createForVector(true, aBorderSequence, aOrigin + aY, aX, aBottomLine,
367 aLeftLine, aBottomFromLLine, aLeftFromBLine,
368 aRightLine, aBottomFromRLine, aRightFromBLine);
371 if(aRightLine.IsUsed())
373 createForVector(false, aBorderSequence, aOrigin + aX, aY, aRightLine,
374 aTopFromRLine, aRightFromTLine, aTopLine,
375 aBottomFromRLine, aRightFromBLine, aBottomLine);
378 if(aTopLine.IsUsed())
380 createForVector(true, aBorderSequence, aOrigin, aX, aTopLine,
381 aLeftFromTLine, aTopFromLLine, aLeftLine,
382 aRightFromTLine, aTopFromRLine, aRightLine);
390 // append Border info to target. We want fillings and text first
391 aRetval.append(aBorderSequence);
394 if(!aRetval.empty())
396 // check and create evtl. shadow for created content
397 const SfxItemSet& rObjectItemSet = rTableObj.GetMergedItemSet();
398 const drawinglayer::attribute::SdrShadowAttribute aNewShadowAttribute(
399 drawinglayer::primitive2d::createNewSdrShadowAttribute(rObjectItemSet));
401 if(!aNewShadowAttribute.isDefault())
403 aRetval = drawinglayer::primitive2d::createEmbeddedShadowPrimitive(aRetval, aNewShadowAttribute);
407 return aRetval;
409 else
411 // take unrotated snap rect (direct model data) for position and size
412 const tools::Rectangle& rRectangle = rTableObj.GetGeoRect();
413 const basegfx::B2DRange aObjectRange(
414 rRectangle.Left(), rRectangle.Top(),
415 rRectangle.Right(), rRectangle.Bottom());
417 // create object matrix
418 const GeoStat& rGeoStat(rTableObj.GetGeoStat());
419 const double fShearX(rGeoStat.nShearAngle ? tan((36000 - rGeoStat.nShearAngle) * F_PI18000) : 0.0);
420 const double fRotate(rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle) * F_PI18000 : 0.0);
421 const basegfx::B2DHomMatrix aObjectMatrix(basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
422 aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate,
423 aObjectRange.getMinX(), aObjectRange.getMinY()));
425 // created an invisible outline for the cases where no visible content exists
426 const drawinglayer::primitive2d::Primitive2DReference xReference(
427 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
428 aObjectMatrix));
430 return drawinglayer::primitive2d::Primitive2DContainer { xReference };
434 ViewContactOfTableObj::ViewContactOfTableObj(sdr::table::SdrTableObj& rTableObj)
435 : ViewContactOfSdrObj(rTableObj)
439 ViewContactOfTableObj::~ViewContactOfTableObj()
442 } // end of namespace contact
443 } // end of namespace sdr
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */