LibreOffice Module svx (master)  1
viewcontactoftableobj.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 
20 
22 #include <svx/svdotable.hxx>
23 #include <com/sun/star/table/XTable.hpp>
33 #include <editeng/borderline.hxx>
41 #include <svx/framelink.hxx>
42 #include <svx/framelinkarray.hxx>
43 #include <vcl/canvastools.hxx>
44 
45 #include <cell.hxx>
46 #include "tablelayouter.hxx"
47 
48 
50 using namespace com::sun::star;
51 
52 
53 namespace drawinglayer
54 {
55  namespace primitive2d
56  {
57  namespace {
58 
59  class SdrCellPrimitive2D : public BufferedDecompositionPrimitive2D
60  {
61  private:
63  attribute::SdrFillTextAttribute const maSdrFTAttribute;
64 
65  protected:
66  // local decomposition.
67  virtual void create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& aViewInformation) const override;
68 
69  public:
70  SdrCellPrimitive2D(
71  const basegfx::B2DHomMatrix& rTransform,
72  const attribute::SdrFillTextAttribute& rSdrFTAttribute)
73  : BufferedDecompositionPrimitive2D(),
74  maTransform(rTransform),
75  maSdrFTAttribute(rSdrFTAttribute)
76  {
77  }
78 
79  // data access
80  const basegfx::B2DHomMatrix& getTransform() const { return maTransform; }
81  const attribute::SdrFillTextAttribute& getSdrFTAttribute() const { return maSdrFTAttribute; }
82 
83  // compare operator
84  virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
85 
86  // provide unique ID
88  };
89 
90  }
91 
92  void SdrCellPrimitive2D::create2DDecomposition(Primitive2DContainer& rContainer, const geometry::ViewInformation2D& /*aViewInformation*/) const
93  {
94  // prepare unit polygon
96 
97  // add fill
98  if(!getSdrFTAttribute().getFill().isDefault())
99  {
100  basegfx::B2DPolyPolygon aTransformed(aUnitPolyPolygon);
101 
102  aTransformed.transform(getTransform());
103  rContainer.push_back(
105  aTransformed,
106  getSdrFTAttribute().getFill(),
107  getSdrFTAttribute().getFillFloatTransGradient()));
108  }
109  else
110  {
111  // if no fill create one for HitTest and BoundRect fallback
112  rContainer.push_back(
114  true,
115  aUnitPolyPolygon,
116  getTransform()));
117  }
118 
119  // add text
120  if(!getSdrFTAttribute().getText().isDefault())
121  {
122  rContainer.push_back(
124  aUnitPolyPolygon,
125  getTransform(),
126  getSdrFTAttribute().getText(),
127  attribute::SdrLineAttribute(),
128  true,
129  false));
130  }
131  }
132 
133  bool SdrCellPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
134  {
135  if(BufferedDecompositionPrimitive2D::operator==(rPrimitive))
136  {
137  const SdrCellPrimitive2D& rCompare = static_cast<const SdrCellPrimitive2D&>(rPrimitive);
138 
139  return (getTransform() == rCompare.getTransform()
140  && getSdrFTAttribute() == rCompare.getSdrFTAttribute());
141  }
142 
143  return false;
144  }
145 
146  // provide unique ID
148 
149  } // end of namespace primitive2d
150 } // end of namespace drawinglayer
151 
152 namespace sdr
153 {
154  namespace contact
155  {
157  const sdr::table::TableLayouter& rLayouter,
158  sal_Int32 nX,
159  sal_Int32 nY,
160  bool bHorizontal,
161  sal_Int32 nColCount,
162  sal_Int32 nRowCount,
163  bool bIsRTL)
164  {
165  if(nX >= 0 && nX <= nColCount && nY >= 0 && nY <= nRowCount)
166  {
167  const SvxBorderLine* pLine = rLayouter.getBorderLine(nX, nY, bHorizontal);
168 
169  if(pLine)
170  {
171  // copy line content
172  SvxBorderLine aLine(*pLine);
173 
174  // check for mirroring. This shall always be done when it is
175  // not a top- or rightmost line
176  bool bMirror(aLine.isDouble());
177 
178  if(bMirror)
179  {
180  if(bHorizontal)
181  {
182  // mirror all bottom lines
183  bMirror = (0 != nY);
184  }
185  else
186  {
187  // mirror all left lines
188  bMirror = (bIsRTL ? 0 != nX : nX != nColCount);
189  }
190  }
191 
192  if(bMirror)
193  {
194  aLine.SetMirrorWidths( );
195  }
196 
197  const double fTwipsToMM(127.0 / 72.0);
198  return svx::frame::Style(&aLine, fTwipsToMM);
199  }
200  }
201 
202  // no success, copy empty line
203  return svx::frame::Style();
204  }
205 
206  drawinglayer::primitive2d::Primitive2DContainer ViewContactOfTableObj::createViewIndependentPrimitive2DSequence() const
207  {
208  const sdr::table::SdrTableObj& rTableObj = static_cast<const sdr::table::SdrTableObj&>(GetSdrObject());
209  const uno::Reference< css::table::XTable > xTable = rTableObj.getTable();
210 
211  if(xTable.is())
212  {
213  // create primitive representation for table. Cell info goes
214  // directly to aRetval, Border info to aBorderSequence and added
215  // later to get the correct overlapping
217  const sal_Int32 nRowCount(xTable->getRowCount());
218  const sal_Int32 nColCount(xTable->getColumnCount());
219  const sal_Int32 nAllCount(nRowCount * nColCount);
220 
221  if(nAllCount)
222  {
223  const sdr::table::TableLayouter& rTableLayouter(rTableObj.getTableLayouter());
224  const bool bIsRTL(css::text::WritingMode_RL_TB == rTableObj.GetWritingMode());
225  sdr::table::CellPos aCellPos;
226  sdr::table::CellRef xCurrentCell;
227  basegfx::B2IRectangle aCellArea;
228 
229  // create range using the model data directly. This is in SdrTextObj::aRect which i will access using
230  // GetGeoRect() to not trigger any calculations. It's the unrotated geometry.
232 
233  // To create the CellBorderPrimitives, use the tolling from svx::frame::Array
234  // which is capable of creating the needed visualization. Fill it during the
235  // anyways needed run over the table.
236  svx::frame::Array aArray;
237 
238  // initialize CellBorderArray for primitive creation
239  aArray.Initialize(nColCount, nRowCount);
240 
241  // create single primitives per cell
242  for(aCellPos.mnRow = 0; aCellPos.mnRow < nRowCount; aCellPos.mnRow++)
243  {
244  // add RowHeight to CellBorderArray for primitive creation
245  aArray.SetRowHeight(aCellPos.mnRow, rTableLayouter.getRowHeight(aCellPos.mnRow));
246 
247  for(aCellPos.mnCol = 0; aCellPos.mnCol < nColCount; aCellPos.mnCol++)
248  {
249  // add ColWidth to CellBorderArray for primitive creation, only
250  // needs to be done in the 1st run
251  if(0 == aCellPos.mnRow)
252  {
253  aArray.SetColWidth(aCellPos.mnCol, rTableLayouter.getColumnWidth(aCellPos.mnCol));
254  }
255 
256  // access the cell
257  xCurrentCell.set(dynamic_cast< sdr::table::Cell* >(xTable->getCellByPosition(aCellPos.mnCol, aCellPos.mnRow).get()));
258 
259  if(xCurrentCell.is())
260  {
261  // copy styles for current cell to CellBorderArray for primitive creation
262  aArray.SetCellStyleLeft(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow, false, nColCount, nRowCount, bIsRTL));
263  aArray.SetCellStyleRight(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol + 1, aCellPos.mnRow, false, nColCount, nRowCount, bIsRTL));
264  aArray.SetCellStyleTop(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow, true, nColCount, nRowCount, bIsRTL));
265  aArray.SetCellStyleBottom(aCellPos.mnCol, aCellPos.mnRow, impGetLineStyle(rTableLayouter, aCellPos.mnCol, aCellPos.mnRow + 1, true, nColCount, nRowCount, bIsRTL));
266 
267  // ignore merged cells (all except the top-left of a merged cell)
268  if(!xCurrentCell->isMerged())
269  {
270  // check if we are the top-left of a merged cell
271  const sal_Int32 nXSpan(xCurrentCell->getColumnSpan());
272  const sal_Int32 nYSpan(xCurrentCell->getRowSpan());
273 
274  if(nXSpan > 1 || nYSpan > 1)
275  {
276  // if merged, set so at CellBorderArray for primitive creation
277  aArray.SetMergedRange(aCellPos.mnCol, aCellPos.mnRow, aCellPos.mnCol + nXSpan - 1, aCellPos.mnRow + nYSpan - 1);
278  }
279  }
280  }
281 
282  if(xCurrentCell.is() && !xCurrentCell->isMerged())
283  {
284  if(rTableLayouter.getCellArea(xCurrentCell, aCellPos, aCellArea))
285  {
286  // create cell transformation matrix
287  basegfx::B2DHomMatrix aCellMatrix;
288  aCellMatrix.set(0, 0, static_cast<double>(aCellArea.getWidth()));
289  aCellMatrix.set(1, 1, static_cast<double>(aCellArea.getHeight()));
290  aCellMatrix.set(0, 2, static_cast<double>(aCellArea.getMinX()) + aObjectRange.getMinX());
291  aCellMatrix.set(1, 2, static_cast<double>(aCellArea.getMinY()) + aObjectRange.getMinY());
292 
293  // handle cell fillings and text
294  const SfxItemSet& rCellItemSet = xCurrentCell->GetItemSet();
295  const sal_uInt32 nTextIndex(nColCount * aCellPos.mnRow + aCellPos.mnCol);
296  const SdrText* pSdrText = rTableObj.getText(nTextIndex);
298 
299  if(pSdrText)
300  {
301  // #i101508# take cell's local text frame distances into account
302  const sal_Int32 nLeft(xCurrentCell->GetTextLeftDistance());
303  const sal_Int32 nRight(xCurrentCell->GetTextRightDistance());
304  const sal_Int32 nUpper(xCurrentCell->GetTextUpperDistance());
305  const sal_Int32 nLower(xCurrentCell->GetTextLowerDistance());
306 
308  rCellItemSet,
309  pSdrText,
310  &nLeft,
311  &nUpper,
312  &nRight,
313  &nLower);
314  }
315  else
316  {
318  rCellItemSet,
319  pSdrText);
320  }
321 
322  // always create cell primitives for BoundRect and HitTest
323  {
325  new drawinglayer::primitive2d::SdrCellPrimitive2D(
326  aCellMatrix, aAttribute));
327  aRetval.append(xCellReference);
328  }
329  }
330  }
331  }
332  }
333 
334  // now create all CellBorderPrimitives
335  const drawinglayer::primitive2d::Primitive2DContainer aCellBorderPrimitives(aArray.CreateB2DPrimitiveArray());
336 
337  if(!aCellBorderPrimitives.empty())
338  {
339  // this is already scaled (due to Table in non-uniform coordinates), so
340  // first transform removing scale
341  basegfx::B2DHomMatrix aTransform(
343  1.0 / aObjectRange.getWidth(),
344  1.0 / aObjectRange.getHeight()));
345 
346  // If RTL, mirror the whole unified table in X and move right.
347  // This is much easier than taking this into account for the whole
348  // index calculations
349  if(bIsRTL)
350  {
351  aTransform.scale(-1.0, 1.0);
352  aTransform.translate(1.0, 0.0);
353  }
354 
355  // create object matrix
356  const GeoStat& rGeoStat(rTableObj.GetGeoStat());
357  const double fShearX(rGeoStat.nShearAngle ? tan((36000 - rGeoStat.nShearAngle) * F_PI18000) : 0.0);
358  const double fRotate(rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle) * F_PI18000 : 0.0);
360  aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate,
361  aObjectRange.getMinX(), aObjectRange.getMinY()));
362 
363  // add object matrix to transform. By doing so theoretically
364  // CellBorders could be also rotated/sheared for the first time ever.
365  // To completely make that work, the primitives already created in
366  // aRetval would also have to be based on ObjectMatrix, not only on
367  // ObjectRange as it currently is.
368  aTransform *= aObjectMatrix;
369 
370  // create a transform primitive with this and embed CellBorders
371  // and append to retval
372  aRetval.append(
374  aTransform,
375  aCellBorderPrimitives));
376  }
377  }
378 
379  if(!aRetval.empty())
380  {
381  // check and create evtl. shadow for created content
382  const SfxItemSet& rObjectItemSet = rTableObj.GetMergedItemSet();
383  const drawinglayer::attribute::SdrShadowAttribute aNewShadowAttribute(
385 
386  if(!aNewShadowAttribute.isDefault())
387  {
388  aRetval = drawinglayer::primitive2d::createEmbeddedShadowPrimitive(aRetval, aNewShadowAttribute);
389  }
390  }
391 
392  return aRetval;
393  }
394  else
395  {
396  // take unrotated snap rect (direct model data) for position and size
398 
399  // create object matrix
400  const GeoStat& rGeoStat(rTableObj.GetGeoStat());
401  const double fShearX(rGeoStat.nShearAngle ? tan((36000 - rGeoStat.nShearAngle) * F_PI18000) : 0.0);
402  const double fRotate(rGeoStat.nRotationAngle ? (36000 - rGeoStat.nRotationAngle) * F_PI18000 : 0.0);
404  aObjectRange.getWidth(), aObjectRange.getHeight(), fShearX, fRotate,
405  aObjectRange.getMinX(), aObjectRange.getMinY()));
406 
407  // created an invisible outline for the cases where no visible content exists
410  aObjectMatrix));
411 
413  }
414  }
415 
416  ViewContactOfTableObj::ViewContactOfTableObj(sdr::table::SdrTableObj& rTableObj)
417  : ViewContactOfSdrObj(rTableObj)
418  {
419  }
420 
422  {
423  }
424  } // end of namespace contact
425 } // end of namespace sdr
426 
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const int nColCount
css::uno::Reference< css::table::XTable > getTable() const
Definition: svdotable.cxx:910
static svx::frame::Style impGetLineStyle(const sdr::table::TableLayouter &rLayouter, sal_Int32 nX, sal_Int32 nY, bool bHorizontal, sal_Int32 nColCount, sal_Int32 nRowCount, bool bIsRTL)
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
double getHeight() const
B2DPolygon const & createUnitPolygon()
attribute::SdrFillTextAttribute const maSdrFTAttribute
#define DeclPrimitive2DIDBlock()
sal_Int32 getMinY() const
#define PRIMITIVE2D_ID_SDRCELLPRIMITIVE2D
ImplPrimitive2DIDBlock(LazyControlCreationPrimitive2D, PRIMITIVE2D_ID_SDRCONTROLPRIMITIVE2D) ViewObjectContactOfUnoControl
editeng::SvxBorderLine * getBorderLine(sal_Int32 nEdgeX, sal_Int32 nEdgeY, bool bHorizontal) const
returns the requested borderline in rpBorderLine or a null pointer if there is no border at this edge...
virtual SdrText * getText(sal_Int32 nIndex) const override
Returns the nth available text.
Definition: svdotable.cxx:1317
double getWidth() const
B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fShearX, double fRadiant, double fTranslateX, double fTranslateY)
The transformation of a rectangle into a polygon, by using angle parameters from GeoStat.
Definition: svdtrans.hxx:214
Primitive2DReference createPolyPolygonFillPrimitive(const basegfx::B2DPolyPolygon &rPolyPolygon, const attribute::SdrFillAttribute &rFill, const attribute::FillGradientAttribute &rFillGradient)
const GeoStat & GetGeoStat() const
Definition: svdotext.hxx:399
Primitive2DReference createTextPrimitive(const basegfx::B2DPolyPolygon &rUnitPolyPolygon, const basegfx::B2DHomMatrix &rObjectTransform, const attribute::SdrTextAttribute &rText, const attribute::SdrLineAttribute &rStroke, bool bCellText, bool bWordWrap)
sal_Int64 getWidth() const
void scale(double fX, double fY)
virtual void append(const Primitive2DReference &) override
void Initialize(size_t nWidth, size_t nHeight)
Reinitializes the array with the specified size.
sal_Int32 getMinX() const
css::text::WritingMode GetWritingMode() const
Definition: svdotable.cxx:2035
basegfx::B2DRange b2DRectangleFromRectangle(const ::tools::Rectangle &rRect)
basegfx::B2DHomMatrix const maTransform
double getMinY() const
sal_Int64 getHeight() const
bool isDouble() const
attribute::SdrShadowAttribute createNewSdrShadowAttribute(const SfxItemSet &rSet)
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1911
Primitive2DReference createHiddenGeometryPrimitives2D(const basegfx::B2DHomMatrix &rMatrix)
#define F_PI18000
Contains the widths of primary and secondary line of a frame style.
Definition: framelink.hxx:101
attribute::SdrFillTextAttribute createNewSdrFillTextAttribute(const SfxItemSet &rSet, const SdrText *pText, const sal_Int32 *pLeft, const sal_Int32 *pUpper, const sal_Int32 *pRight, const sal_Int32 *pLower)
css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference
void translate(double fX, double fY)
Primitive2DContainer createEmbeddedShadowPrimitive(const Primitive2DContainer &rContent, const attribute::SdrShadowAttribute &rShadow)
double getMinX() const
Stores frame styles of an array of cells, supports merged ranges.
bool operator==(const ScCsvLayoutData &rData1, const ScCsvLayoutData &rData2)
const tools::Rectangle & GetGeoRect() const
Definition: svdotext.cxx:1467
const TableLayouter & getTableLayouter() const
Definition: svdotable.cxx:1388