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 #include <tuple>
21 #include <utility>
22 #include <memory>
23 #include <vector>
24 #include <algorithm>
25 #include <limits>
26
27 #include <comphelper/interfacecontainer4.hxx>
28 #include <o3tl/any.hxx>
29 #include <o3tl/safeint.hxx>
30 #include <tools/UnitConversion.hxx>
31 #include <editeng/memberids.h>
32 #include <float.h>
33 #include <swtypes.hxx>
34 #include <cmdid.h>
35 #include <unocoll.hxx>
36 #include <unomid.h>
37 #include <unomap.hxx>
38 #include <unotbl.hxx>
39 #include <unosection.hxx>
40 #include <section.hxx>
41 #include <unocrsr.hxx>
42 #include <hints.hxx>
43 #include <swtblfmt.hxx>
44 #include <doc.hxx>
45 #include <IDocumentUndoRedo.hxx>
46 #include <IDocumentContentOperations.hxx>
47 #include <IDocumentFieldsAccess.hxx>
48 #include <IDocumentRedlineAccess.hxx>
49 #include <IDocumentState.hxx>
50 #include <IDocumentLayoutAccess.hxx>
51 #include <shellres.hxx>
52 #include <docary.hxx>
53 #include <ndole.hxx>
54 #include <ndtxt.hxx>
55 #include <frame.hxx>
56 #include <vcl/svapp.hxx>
57 #include <fmtfsize.hxx>
58 #include <tblafmt.hxx>
59 #include <tabcol.hxx>
60 #include <cellatr.hxx>
61 #include <fmtpdsc.hxx>
62 #include <pagedesc.hxx>
63 #include <viewsh.hxx>
64 #include <rootfrm.hxx>
65 #include <tabfrm.hxx>
66 #include <redline.hxx>
67 #include <unoport.hxx>
68 #include <unocrsrhelper.hxx>
69 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
70 #include <com/sun/star/text/WrapTextMode.hpp>
71 #include <com/sun/star/text/TextContentAnchorType.hpp>
72 #include <com/sun/star/text/TableColumnSeparator.hpp>
73 #include <com/sun/star/text/VertOrientation.hpp>
74 #include <com/sun/star/text/XTextSection.hpp>
75 #include <com/sun/star/table/TableBorder.hpp>
76 #include <com/sun/star/table/TableBorder2.hpp>
77 #include <com/sun/star/table/BorderLine2.hpp>
78 #include <com/sun/star/table/TableBorderDistances.hpp>
79 #include <com/sun/star/beans/PropertyAttribute.hpp>
80 #include <com/sun/star/chart/XChartDataChangeEventListener.hpp>
81 #include <com/sun/star/chart/ChartDataChangeEvent.hpp>
82 #include <com/sun/star/table/CellContentType.hpp>
83 #include <unotextrange.hxx>
84 #include <unotextcursor.hxx>
85 #include <unoparagraph.hxx>
86 #include <svl/numformat.hxx>
87 #include <svl/zforlist.hxx>
88 #include <editeng/formatbreakitem.hxx>
89 #include <editeng/shaditem.hxx>
90 #include <editeng/lrspitem.hxx>
91 #include <editeng/ulspitem.hxx>
92 #include <fmtornt.hxx>
93 #include <editeng/keepitem.hxx>
94 #include <fmtlsplt.hxx>
95 #include <swundo.hxx>
96 #include <SwStyleNameMapper.hxx>
97 #include <frmatr.hxx>
98 #include <sortopt.hxx>
99 #include <sal/log.hxx>
100 #include <editeng/frmdiritem.hxx>
101 #include <comphelper/servicehelper.hxx>
102 #include <comphelper/string.hxx>
103 #include <cppuhelper/supportsservice.hxx>
104 #include <comphelper/sequence.hxx>
105 #include <comphelper/sequenceashashmap.hxx>
106 #include <swtable.hxx>
107 #include <docsh.hxx>
108 #include <fesh.hxx>
109 #include <itabenum.hxx>
110 #include <frameformats.hxx>
111 #include <o3tl/string_view.hxx>
112
113 using namespace ::com::sun::star;
114 using ::editeng::SvxBorderLine;
115
116 namespace
117 {
118 template<typename Tcoretype, typename Tunotype>
119 struct FindUnoInstanceHint final : SfxHint
120 {
FindUnoInstanceHint__anon95baa6450111::FindUnoInstanceHint121 FindUnoInstanceHint(Tcoretype* pCore) : m_pCore(pCore), m_pResult(nullptr) {};
122 const Tcoretype* const m_pCore;
123 mutable rtl::Reference<Tunotype> m_pResult;
124 };
lcl_EnsureCoreConnected(SwFrameFormat * pFormat,cppu::OWeakObject * pObject)125 SwFrameFormat* lcl_EnsureCoreConnected(SwFrameFormat* pFormat, cppu::OWeakObject* pObject)
126 {
127 if(!pFormat)
128 throw uno::RuntimeException(u"Lost connection to core objects"_ustr, pObject);
129 return pFormat;
130 }
lcl_EnsureTableNotComplex(SwTable * pTable,cppu::OWeakObject * pObject)131 SwTable* lcl_EnsureTableNotComplex(SwTable* pTable, cppu::OWeakObject* pObject)
132 {
133 if(pTable->IsTableComplex())
134 throw uno::RuntimeException(u"Table too complex"_ustr, pObject);
135 return pTable;
136 }
137
createChartEvent(uno::Reference<uno::XInterface> const & xSource)138 chart::ChartDataChangeEvent createChartEvent(uno::Reference<uno::XInterface> const& xSource)
139 {
140 //TODO: find appropriate settings of the Event
141 chart::ChartDataChangeEvent event;
142 event.Source = xSource;
143 event.Type = chart::ChartDataChangeType_ALL;
144 event.StartColumn = 0;
145 event.EndColumn = 1;
146 event.StartRow = 0;
147 event.EndRow = 1;
148 return event;
149 }
150
lcl_SendChartEvent(std::unique_lock<std::mutex> & rGuard,uno::Reference<uno::XInterface> const & xSource,::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> & rListeners)151 void lcl_SendChartEvent(std::unique_lock<std::mutex>& rGuard,
152 uno::Reference<uno::XInterface> const& xSource,
153 ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> & rListeners)
154 {
155 if (rListeners.getLength(rGuard))
156 rListeners.notifyEach(rGuard,
157 &chart::XChartDataChangeEventListener::chartDataChanged,
158 createChartEvent(xSource));
159 }
160 }
161
162 #define UNO_TABLE_COLUMN_SUM 10000
163
164
lcl_LineToSvxLine(const table::BorderLine & rLine,SvxBorderLine & rSvxLine)165 static bool lcl_LineToSvxLine(const table::BorderLine& rLine, SvxBorderLine& rSvxLine)
166 {
167 rSvxLine.SetColor(Color(ColorTransparency, rLine.Color));
168
169 rSvxLine.GuessLinesWidths( SvxBorderLineStyle::NONE,
170 o3tl::toTwips(rLine.OuterLineWidth, o3tl::Length::mm100),
171 o3tl::toTwips(rLine.InnerLineWidth, o3tl::Length::mm100),
172 o3tl::toTwips(rLine.LineDistance, o3tl::Length::mm100) );
173
174 return rLine.InnerLineWidth > 0 || rLine.OuterLineWidth > 0;
175 }
176
177 /// @throws lang::IllegalArgumentException
178 /// @throws uno::RuntimeException
lcl_SetSpecialProperty(SwFrameFormat * pFormat,const SfxItemPropertyMapEntry * pEntry,const uno::Any & aValue)179 static void lcl_SetSpecialProperty(SwFrameFormat* pFormat,
180 const SfxItemPropertyMapEntry* pEntry,
181 const uno::Any& aValue)
182 {
183 // special treatment for "non-items"
184 switch(pEntry->nWID)
185 {
186 case FN_TABLE_HEADLINE_REPEAT:
187 case FN_TABLE_HEADLINE_COUNT:
188 {
189 SwTable* pTable = SwTable::FindTable( pFormat );
190 UnoActionContext aAction(pFormat->GetDoc());
191 if( pEntry->nWID == FN_TABLE_HEADLINE_REPEAT)
192 {
193 pFormat->GetDoc()->SetRowsToRepeat( *pTable, aValue.get<bool>() ? 1 : 0 );
194 }
195 else
196 {
197 sal_Int32 nRepeat = 0;
198 aValue >>= nRepeat;
199 if( nRepeat >= 0 && nRepeat < SAL_MAX_UINT16 )
200 pFormat->GetDoc()->SetRowsToRepeat( *pTable, o3tl::narrowing<sal_uInt16>(nRepeat) );
201 }
202 }
203 break;
204
205 case FN_TABLE_IS_RELATIVE_WIDTH:
206 case FN_TABLE_WIDTH:
207 case FN_TABLE_RELATIVE_WIDTH:
208 {
209 SwFormatFrameSize aSz( pFormat->GetFrameSize() );
210 if(FN_TABLE_WIDTH == pEntry->nWID)
211 {
212 sal_Int32 nWidth = 0;
213 aValue >>= nWidth;
214 aSz.SetWidthPercent(0);
215 aSz.SetWidth ( o3tl::toTwips(nWidth, o3tl::Length::mm100) );
216 }
217 else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID)
218 {
219 sal_Int16 nSet = 0;
220 aValue >>= nSet;
221 if(nSet && nSet <=100)
222 aSz.SetWidthPercent( static_cast<sal_uInt8>(nSet) );
223 }
224 else if(FN_TABLE_IS_RELATIVE_WIDTH == pEntry->nWID)
225 {
226 if(!aValue.get<bool>())
227 aSz.SetWidthPercent(0);
228 else
229 {
230 throw lang::IllegalArgumentException(u"relative width cannot be switched on with this property"_ustr, nullptr, 0);
231 }
232 }
233 pFormat->GetDoc()->SetAttr(aSz, *pFormat);
234 }
235 break;
236
237 case RES_PAGEDESC:
238 {
239 OUString sPageStyle;
240 aValue >>= sPageStyle;
241 const SwPageDesc* pDesc = nullptr;
242 if (!sPageStyle.isEmpty())
243 {
244 SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc);
245 pDesc = SwPageDesc::GetByName(*pFormat->GetDoc(), sPageStyle);
246 }
247 SwFormatPageDesc aDesc( pDesc );
248 pFormat->GetDoc()->SetAttr(aDesc, *pFormat);
249 }
250 break;
251
252 default:
253 throw lang::IllegalArgumentException();
254 }
255 }
256
lcl_GetSpecialProperty(SwFrameFormat * pFormat,const SfxItemPropertyMapEntry * pEntry)257 static uno::Any lcl_GetSpecialProperty(SwFrameFormat* pFormat, const SfxItemPropertyMapEntry* pEntry )
258 {
259 switch(pEntry->nWID)
260 {
261 case FN_TABLE_HEADLINE_REPEAT:
262 case FN_TABLE_HEADLINE_COUNT:
263 {
264 SwTable* pTable = SwTable::FindTable( pFormat );
265 const sal_uInt16 nRepeat = pTable->GetRowsToRepeat();
266 if(pEntry->nWID == FN_TABLE_HEADLINE_REPEAT)
267 return uno::Any(nRepeat > 0);
268 return uno::Any(sal_Int32(nRepeat));
269 }
270
271 case FN_TABLE_WIDTH:
272 case FN_TABLE_IS_RELATIVE_WIDTH:
273 case FN_TABLE_RELATIVE_WIDTH:
274 {
275 uno::Any aRet;
276 const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
277 if(FN_TABLE_WIDTH == pEntry->nWID)
278 rSz.QueryValue(aRet, MID_FRMSIZE_WIDTH|CONVERT_TWIPS);
279 else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID)
280 rSz.QueryValue(aRet, MID_FRMSIZE_REL_WIDTH);
281 else
282 aRet <<= (0 != rSz.GetWidthPercent());
283 return aRet;
284 }
285
286 case RES_PAGEDESC:
287 {
288 const SfxItemSet& rSet = pFormat->GetAttrSet();
289 if(const SwFormatPageDesc* pItem = rSet.GetItemIfSet(RES_PAGEDESC, false))
290 {
291 const SwPageDesc* pDsc = pItem->GetPageDesc();
292 if(pDsc)
293 return uno::Any(SwStyleNameMapper::GetProgName(pDsc->GetName(), SwGetPoolIdFromName::PageDesc ));
294 }
295 return uno::Any(OUString());
296 }
297
298 case RES_ANCHOR:
299 return uno::Any(text::TextContentAnchorType_AT_PARAGRAPH);
300
301 case FN_UNO_ANCHOR_TYPES:
302 {
303 uno::Sequence<text::TextContentAnchorType> aTypes{text::TextContentAnchorType_AT_PARAGRAPH};
304 return uno::Any(aTypes);
305 }
306
307 case FN_UNO_WRAP :
308 return uno::Any(text::WrapTextMode_NONE);
309
310 case FN_PARAM_LINK_DISPLAY_NAME :
311 return uno::Any(pFormat->GetName());
312
313 case FN_UNO_REDLINE_NODE_START:
314 case FN_UNO_REDLINE_NODE_END:
315 {
316 SwTable* pTable = SwTable::FindTable( pFormat );
317 SwNode* pTableNode = pTable->GetTableNode();
318 if(FN_UNO_REDLINE_NODE_END == pEntry->nWID)
319 pTableNode = pTableNode->EndOfSectionNode();
320 for(const SwRangeRedline* pRedline : pFormat->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable())
321 {
322 const SwNode& rRedPointNode = pRedline->GetPointNode();
323 const SwNode& rRedMarkNode = pRedline->GetMarkNode();
324 if(rRedPointNode == *pTableNode || rRedMarkNode == *pTableNode)
325 {
326 const SwNode& rStartOfRedline = SwNodeIndex(rRedPointNode) <= SwNodeIndex(rRedMarkNode) ?
327 rRedPointNode : rRedMarkNode;
328 bool bIsStart = &rStartOfRedline == pTableNode;
329 return uno::Any(SwXRedlinePortion::CreateRedlineProperties(*pRedline, bIsStart));
330 }
331 }
332 }
333 }
334 return uno::Any();
335 }
336
337 /** get position of a cell with a given name
338 *
339 * If everything was OK, the indices for column and row are changed (both >= 0).
340 * In case of errors, at least one of them is < 0.
341 *
342 * Also since the implementations of tables does not really have columns using
343 * this function is appropriate only for tables that are not complex (i.e.
344 * where IsTableComplex() returns false).
345 *
346 * @param rCellName e.g. A1..Z1, a1..z1, AA1..AZ1, Aa1..Az1, BA1..BZ1, Ba1..Bz1, ...
347 * @param [IN,OUT] o_rColumn (0-based)
348 * @param [IN,OUT] o_rRow (0-based)
349 */
350 //TODO: potential for throwing proper exceptions instead of having every caller to check for errors
GetCellPosition(std::u16string_view aCellName,sal_Int32 & o_rColumn,sal_Int32 & o_rRow)351 void SwXTextTable::GetCellPosition(std::u16string_view aCellName, sal_Int32& o_rColumn, sal_Int32& o_rRow)
352 {
353 o_rColumn = o_rRow = -1; // default return values indicating failure
354 const sal_Int32 nLen = aCellName.size();
355 if(!nLen)
356 {
357 SAL_WARN("sw.uno", "failed to get column or row index");
358 return;
359 }
360 sal_Int32 nRowPos = 0;
361 while (nRowPos<nLen)
362 {
363 if (aCellName[nRowPos]>='0' && aCellName[nRowPos]<='9')
364 {
365 break;
366 }
367 ++nRowPos;
368 }
369 if (nRowPos<=0 || nRowPos>=nLen)
370 return;
371
372 sal_Int32 nColIdx = 0;
373 for (sal_Int32 i = 0; i < nRowPos; ++i)
374 {
375 nColIdx *= 52;
376 if (i < nRowPos - 1)
377 ++nColIdx;
378 const sal_Unicode cChar = aCellName[i];
379 if ('A' <= cChar && cChar <= 'Z')
380 nColIdx += cChar - 'A';
381 else if ('a' <= cChar && cChar <= 'z')
382 nColIdx += 26 + cChar - 'a';
383 else
384 {
385 nColIdx = -1; // sth failed
386 break;
387 }
388 }
389
390 o_rColumn = nColIdx;
391 o_rRow = o3tl::toInt32(aCellName.substr(nRowPos)) - 1; // - 1 because indices ought to be 0 based
392 }
393
394 /** compare position of two cells (check rows first)
395 *
396 * @note this function probably also make sense only
397 * for cell names of non-complex tables
398 *
399 * @param rCellName1 e.g. "A1" (non-empty string with valid cell name)
400 * @param rCellName2 e.g. "A1" (non-empty string with valid cell name)
401 * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2
402 */
sw_CompareCellsByRowFirst(std::u16string_view aCellName1,std::u16string_view aCellName2)403 int sw_CompareCellsByRowFirst( std::u16string_view aCellName1, std::u16string_view aCellName2 )
404 {
405 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
406 SwXTextTable::GetCellPosition( aCellName1, nCol1, nRow1 );
407 SwXTextTable::GetCellPosition( aCellName2, nCol2, nRow2 );
408
409 if (nRow1 < nRow2 || (nRow1 == nRow2 && nCol1 < nCol2))
410 return -1;
411 else if (nCol1 == nCol2 && nRow1 == nRow2)
412 return 0;
413 else
414 return +1;
415 }
416
417 /** compare position of two cells (check columns first)
418 *
419 * @note this function probably also make sense only
420 * for cell names of non-complex tables
421 *
422 * @param rCellName1 e.g. "A1" (non-empty string with valid cell name)
423 * @param rCellName2 e.g. "A1" (non-empty string with valid cell name)
424 * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2
425 */
sw_CompareCellsByColFirst(std::u16string_view aCellName1,std::u16string_view aCellName2)426 int sw_CompareCellsByColFirst( std::u16string_view aCellName1, std::u16string_view aCellName2 )
427 {
428 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
429 SwXTextTable::GetCellPosition( aCellName1, nCol1, nRow1 );
430 SwXTextTable::GetCellPosition( aCellName2, nCol2, nRow2 );
431
432 if (nCol1 < nCol2 || (nCol1 == nCol2 && nRow1 < nRow2))
433 return -1;
434 else if (nRow1 == nRow2 && nCol1 == nCol2)
435 return 0;
436 else
437 return +1;
438 }
439
440 /** compare position of two cell ranges
441 *
442 * @note this function probably also make sense only
443 * for cell names of non-complex tables
444 *
445 * @param rRange1StartCell e.g. "A1" (non-empty string with valid cell name)
446 * @param rRange1EndCell e.g. "A1" (non-empty string with valid cell name)
447 * @param rRange2StartCell e.g. "A1" (non-empty string with valid cell name)
448 * @param rRange2EndCell e.g. "A1" (non-empty string with valid cell name)
449 * @param bCmpColsFirst if <true> position in columns will be compared first before rows
450 *
451 * @return -1 if cell_range_1 < cell_range_2; 0 if both cell ranges are equal; +1 if cell_range_1 > cell_range_2
452 */
sw_CompareCellRanges(std::u16string_view aRange1StartCell,std::u16string_view aRange1EndCell,std::u16string_view aRange2StartCell,std::u16string_view aRange2EndCell,bool bCmpColsFirst)453 int sw_CompareCellRanges(
454 std::u16string_view aRange1StartCell, std::u16string_view aRange1EndCell,
455 std::u16string_view aRange2StartCell, std::u16string_view aRange2EndCell,
456 bool bCmpColsFirst )
457 {
458 int (*pCompareCells)( std::u16string_view, std::u16string_view ) =
459 bCmpColsFirst ? &sw_CompareCellsByColFirst : &sw_CompareCellsByRowFirst;
460
461 int nCmpResStartCells = pCompareCells( aRange1StartCell, aRange2StartCell );
462 if ((-1 == nCmpResStartCells ) ||
463 ( 0 == nCmpResStartCells &&
464 -1 == pCompareCells( aRange1EndCell, aRange2EndCell ) ))
465 return -1;
466 else if (0 == nCmpResStartCells &&
467 0 == pCompareCells( aRange1EndCell, aRange2EndCell ))
468 return 0;
469 else
470 return +1;
471 }
472
473 /** get cell name at a specified coordinate
474 *
475 * @param nColumn column index (0-based)
476 * @param nRow row index (0-based)
477 * @return the cell name
478 */
sw_GetCellName(sal_Int32 nColumn,sal_Int32 nRow)479 OUString sw_GetCellName( sal_Int32 nColumn, sal_Int32 nRow )
480 {
481 if (nColumn < 0 || nRow < 0)
482 return OUString();
483 OUString sCellName;
484 sw_GetTableBoxColStr( static_cast< sal_uInt16 >(nColumn), sCellName );
485 return sCellName + OUString::number( nRow + 1 );
486 }
487
488 /** Find the top left or bottom right corner box in given table.
489 Consider nested lines when finding the box.
490
491 @param rTableLines the table
492 @param i_bTopLeft if true, find top left box, otherwise find bottom
493 right box
494 */
lcl_FindCornerTableBox(const SwTableLines & rTableLines,const bool i_bTopLeft)495 static const SwTableBox* lcl_FindCornerTableBox(const SwTableLines& rTableLines, const bool i_bTopLeft)
496 {
497 const SwTableLines* pLines(&rTableLines);
498 while(true)
499 {
500 assert(!pLines->empty());
501 if(pLines->empty())
502 return nullptr;
503 const SwTableLine* pLine(i_bTopLeft ? pLines->front() : pLines->back());
504 assert(pLine);
505 const SwTableBoxes& rBoxes(pLine->GetTabBoxes());
506 assert(!rBoxes.empty());
507 const SwTableBox* pBox = i_bTopLeft ? rBoxes.front() : rBoxes.back();
508 assert(pBox);
509 if (pBox->GetSttNd())
510 return pBox;
511 pLines = &pBox->GetTabLines();
512 }
513 }
514
515 /** cleanup order in a range
516 *
517 * Sorts the input to a uniform format. I.e. for the four possible representation
518 * A1:C5, C5:A1, A5:C1, C1:A5
519 * the result will be always A1:C5.
520 *
521 * @param [IN,OUT] rCell1 cell name (will be modified to upper-left corner), e.g. "A1" (non-empty string with valid cell name)
522 * @param [IN,OUT] rCell2 cell name (will be modified to lower-right corner), e.g. "A1" (non-empty string with valid cell name)
523 */
sw_NormalizeRange(OUString & rCell1,OUString & rCell2)524 void sw_NormalizeRange(OUString &rCell1, OUString &rCell2)
525 {
526 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
527 SwXTextTable::GetCellPosition( rCell1, nCol1, nRow1 );
528 SwXTextTable::GetCellPosition( rCell2, nCol2, nRow2 );
529 if (nCol2 < nCol1 || nRow2 < nRow1)
530 {
531 rCell1 = sw_GetCellName( std::min(nCol1, nCol2), std::min(nRow1, nRow2) );
532 rCell2 = sw_GetCellName( std::max(nCol1, nCol2), std::max(nRow1, nRow2) );
533 }
534 }
535
Normalize()536 void SwRangeDescriptor::Normalize()
537 {
538 if (nTop > nBottom)
539 std::swap(nBottom, nTop);
540 if (nLeft > nRight)
541 std::swap(nLeft, nRight);
542 }
543
lcl_CreateXCell(SwFrameFormat * pFormat,sal_Int32 nColumn,sal_Int32 nRow)544 static rtl::Reference<SwXCell> lcl_CreateXCell(SwFrameFormat* pFormat, sal_Int32 nColumn, sal_Int32 nRow)
545 {
546 const OUString sCellName = sw_GetCellName(nColumn, nRow);
547 SwTable* pTable = SwTable::FindTable(pFormat);
548 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
549 if(!pBox)
550 return nullptr;
551 return SwXCell::CreateXCell(pFormat, pBox, pTable);
552 }
553
lcl_InspectLines(SwTableLines & rLines,std::vector<OUString> & rAllNames)554 static void lcl_InspectLines(SwTableLines& rLines, std::vector<OUString>& rAllNames)
555 {
556 for(auto pLine : rLines)
557 {
558 for(auto pBox : pLine->GetTabBoxes())
559 {
560 if(!pBox->GetName().isEmpty() && pBox->getRowSpan() > 0)
561 rAllNames.push_back(pBox->GetName());
562 SwTableLines& rBoxLines = pBox->GetTabLines();
563 if(!rBoxLines.empty())
564 lcl_InspectLines(rBoxLines, rAllNames);
565 }
566 }
567 }
568
lcl_FormatTable(SwFrameFormat const * pTableFormat)569 static bool lcl_FormatTable(SwFrameFormat const * pTableFormat)
570 {
571 bool bHasFrames = false;
572 SwIterator<SwFrame,SwFormat> aIter( *pTableFormat );
573 for(SwFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
574 {
575 vcl::RenderContext* pRenderContext = pFrame->getRootFrame()->GetCurrShell()->GetOut();
576 // mba: no TYPEINFO for SwTabFrame
577 if(!pFrame->IsTabFrame())
578 continue;
579 DisableCallbackAction a(*pFrame->getRootFrame());
580 SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pFrame);
581 if(pTabFrame->isFrameAreaDefinitionValid())
582 pTabFrame->InvalidatePos();
583 pTabFrame->SetONECalcLowers();
584 pTabFrame->Calc(pRenderContext);
585 bHasFrames = true;
586 }
587 return bHasFrames;
588 }
589
lcl_CursorSelect(SwPaM & rCursor,bool bExpand)590 static void lcl_CursorSelect(SwPaM& rCursor, bool bExpand)
591 {
592 if(bExpand)
593 {
594 if(!rCursor.HasMark())
595 rCursor.SetMark();
596 }
597 else if(rCursor.HasMark())
598 rCursor.DeleteMark();
599 }
600
lcl_GetTableSeparators(uno::Any & rRet,SwTable const * pTable,SwTableBox const * pBox,bool bRow)601 static void lcl_GetTableSeparators(uno::Any& rRet, SwTable const * pTable, SwTableBox const * pBox, bool bRow)
602 {
603 SwTabCols aCols;
604 aCols.SetLeftMin ( 0 );
605 aCols.SetLeft ( 0 );
606 aCols.SetRight ( UNO_TABLE_COLUMN_SUM );
607 aCols.SetRightMax( UNO_TABLE_COLUMN_SUM );
608
609 pTable->GetTabCols( aCols, pBox, false, bRow );
610
611 const size_t nSepCount = aCols.Count();
612 uno::Sequence< text::TableColumnSeparator> aColSeq(nSepCount);
613 text::TableColumnSeparator* pArray = aColSeq.getArray();
614 bool bError = false;
615 for(size_t i = 0; i < nSepCount; ++i)
616 {
617 pArray[i].Position = static_cast< sal_Int16 >(aCols[i]);
618 pArray[i].IsVisible = !aCols.IsHidden(i);
619 if(!bRow && !pArray[i].IsVisible)
620 {
621 bError = true;
622 break;
623 }
624 }
625 if(!bError)
626 rRet <<= aColSeq;
627
628 }
629
lcl_SetTableSeparators(const uno::Any & rVal,SwTable * pTable,SwTableBox const * pBox,bool bRow,SwDoc * pDoc)630 static void lcl_SetTableSeparators(const uno::Any& rVal, SwTable* pTable, SwTableBox const * pBox, bool bRow, SwDoc* pDoc)
631 {
632 SwTabCols aOldCols;
633
634 aOldCols.SetLeftMin ( 0 );
635 aOldCols.SetLeft ( 0 );
636 aOldCols.SetRight ( UNO_TABLE_COLUMN_SUM );
637 aOldCols.SetRightMax( UNO_TABLE_COLUMN_SUM );
638
639 pTable->GetTabCols( aOldCols, pBox, false, bRow );
640 const size_t nOldCount = aOldCols.Count();
641 // there is no use in setting tab cols if there is only one column
642 if( !nOldCount )
643 return;
644
645 auto pSepSeq =
646 o3tl::tryAccess<uno::Sequence<text::TableColumnSeparator>>(rVal);
647 if(!pSepSeq || static_cast<size_t>(pSepSeq->getLength()) != nOldCount)
648 return;
649 SwTabCols aCols(aOldCols);
650 const text::TableColumnSeparator* pArray = pSepSeq->getConstArray();
651 tools::Long nLastValue = 0;
652 //sal_Int32 nTableWidth = aCols.GetRight() - aCols.GetLeft();
653 for(size_t i = 0; i < nOldCount; ++i)
654 {
655 aCols[i] = pArray[i].Position;
656 if(bool(pArray[i].IsVisible) == aCols.IsHidden(i) ||
657 (!bRow && aCols.IsHidden(i)) ||
658 aCols[i] < nLastValue ||
659 UNO_TABLE_COLUMN_SUM < aCols[i] )
660 return; // probably this should assert()
661 nLastValue = aCols[i];
662 }
663 pDoc->SetTabCols(*pTable, aCols, aOldCols, pBox, bRow );
664 }
665
666 /* non UNO function call to set string in SwXCell */
sw_setString(SwXCell & rCell,const OUString & rText,bool bKeepNumberFormat=false)667 void sw_setString( SwXCell &rCell, const OUString &rText,
668 bool bKeepNumberFormat = false )
669 {
670 if(rCell.IsValid())
671 {
672 SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat();
673 pBoxFormat->LockModify();
674 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA );
675 pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE );
676 if (!bKeepNumberFormat)
677 pBoxFormat->SetFormatAttr( SwTableBoxNumFormat(/*default Text*/) );
678 pBoxFormat->UnlockModify();
679 }
680 rCell.SwXText::setString(rText);
681 }
682
683
684 /* non UNO function call to set value in SwXCell */
sw_setValue(SwXCell & rCell,double nVal)685 void sw_setValue( SwXCell &rCell, double nVal )
686 {
687 if(!rCell.IsValid())
688 return;
689 // first this text (maybe) needs to be deleted
690 SwNodeOffset nNdPos = rCell.m_pBox->IsValidNumTextNd();
691 if(NODE_OFFSET_MAX != nNdPos)
692 sw_setString( rCell, OUString(), true ); // true == keep number format
693 SwDoc* pDoc = rCell.GetDoc();
694 UnoActionContext aAction(pDoc);
695 SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat();
696 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aSet(pDoc->GetAttrPool());
697
698 //!! do we need to set a new number format? Yes, if
699 // - there is no current number format
700 // - the current number format is not a number format according to the number formatter, but rather a text format
701 const SwTableBoxNumFormat* pNumFormat = pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT);
702 if(!pNumFormat
703 || pDoc->GetNumberFormatter()->IsTextFormat(pNumFormat->GetValue()))
704 {
705 aSet.Put(SwTableBoxNumFormat(0));
706 }
707
708 SwTableBoxValue aVal(nVal);
709 aSet.Put(aVal);
710 pDoc->SetTableBoxFormulaAttrs( *rCell.m_pBox, aSet );
711 // update table
712 pDoc->getIDocumentFieldsAccess().UpdateTableFields(SwTable::FindTable(rCell.GetFrameFormat()));
713 }
714
715
SwXCell(SwFrameFormat * pTableFormat,SwTableBox * pBx,size_t const nPos)716 SwXCell::SwXCell(SwFrameFormat* pTableFormat, SwTableBox* pBx, size_t const nPos) :
717 SwXText(pTableFormat->GetDoc(), CursorType::TableText),
718 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)),
719 m_pBox(pBx),
720 m_pStartNode(nullptr),
721 m_pTableFormat(pTableFormat),
722 m_nFndPos(nPos)
723 {
724 StartListening(pTableFormat->GetNotifier());
725 }
726
SwXCell(SwFrameFormat * pTableFormat,const SwStartNode & rStartNode)727 SwXCell::SwXCell(SwFrameFormat* pTableFormat, const SwStartNode& rStartNode) :
728 SwXText(pTableFormat->GetDoc(), CursorType::TableText),
729 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)),
730 m_pBox(nullptr),
731 m_pStartNode(&rStartNode),
732 m_pTableFormat(pTableFormat),
733 m_nFndPos(NOTFOUND)
734 {
735 StartListening(pTableFormat->GetNotifier());
736 }
737
~SwXCell()738 SwXCell::~SwXCell()
739 {
740 SolarMutexGuard aGuard;
741 EndListeningAll();
742 }
743
getTypes()744 uno::Sequence< uno::Type > SAL_CALL SwXCell::getTypes( )
745 {
746 return comphelper::concatSequences(
747 SwXCellBaseClass::getTypes(),
748 SwXText::getTypes()
749 );
750 }
751
getImplementationId()752 uno::Sequence< sal_Int8 > SAL_CALL SwXCell::getImplementationId( )
753 {
754 return css::uno::Sequence<sal_Int8>();
755 }
756
acquire()757 void SAL_CALL SwXCell::acquire( ) noexcept
758 {
759 SwXCellBaseClass::acquire();
760 }
761
release()762 void SAL_CALL SwXCell::release( ) noexcept
763 {
764 SolarMutexGuard aGuard;
765
766 SwXCellBaseClass::release();
767 }
768
queryInterface(const uno::Type & aType)769 uno::Any SAL_CALL SwXCell::queryInterface( const uno::Type& aType )
770 {
771 uno::Any aRet = SwXText::queryInterface(aType);
772 if(aRet.getValueType() == cppu::UnoType<void>::get())
773 aRet = SwXCellBaseClass::queryInterface(aType);
774 return aRet;
775 }
776
GetStartNode() const777 const SwStartNode *SwXCell::GetStartNode() const
778 {
779 const SwStartNode* pSttNd = nullptr;
780
781 if( m_pStartNode || IsValid() )
782 pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
783
784 return pSttNd;
785 }
786
IsValid() const787 bool SwXCell::IsValid() const
788 {
789 // FIXME: this is now a const method, to make SwXText::IsValid invisible
790 // but the const_cast here are still ridiculous. TODO: find a better way.
791 SwFrameFormat* pTableFormat = m_pBox ? GetFrameFormat() : nullptr;
792 if(!pTableFormat)
793 {
794 const_cast<SwXCell*>(this)->m_pBox = nullptr;
795 }
796 else
797 {
798 SwTable* pTable = SwTable::FindTable( pTableFormat );
799 SwTableBox const*const pFoundBox =
800 const_cast<SwXCell*>(this)->FindBox(pTable, m_pBox);
801 if (!pFoundBox)
802 {
803 const_cast<SwXCell*>(this)->m_pBox = nullptr;
804 }
805 }
806 return nullptr != m_pBox;
807 }
808
getFormula()809 OUString SwXCell::getFormula()
810 {
811 SolarMutexGuard aGuard;
812 if(!IsValid())
813 return OUString();
814 SwTableBoxFormula aFormula( m_pBox->GetFrameFormat()->GetTableBoxFormula() );
815 SwTable* pTable = SwTable::FindTable( GetFrameFormat() );
816 aFormula.PtrToBoxNm( pTable );
817 return aFormula.GetFormula();
818 }
819
820 ///@see sw_setValue (TODO: seems to be copy and paste programming here)
setFormula(const OUString & rFormula)821 void SwXCell::setFormula(const OUString& rFormula)
822 {
823 SolarMutexGuard aGuard;
824 if(!IsValid())
825 return;
826 // first this text (maybe) needs to be deleted
827 SwNodeOffset nNdPos = m_pBox->IsValidNumTextNd();
828 if(SwNodeOffset(USHRT_MAX) == nNdPos)
829 sw_setString( *this, OUString(), true );
830 OUString sFormula(comphelper::string::stripStart(rFormula, ' '));
831 if( !sFormula.isEmpty() && '=' == sFormula[0] )
832 sFormula = sFormula.copy( 1 );
833 SwTableBoxFormula aFormula( sFormula );
834 SwDoc* pMyDoc = GetDoc();
835 UnoActionContext aAction(pMyDoc);
836 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_FORMULA> aSet(pMyDoc->GetAttrPool());
837 SwFrameFormat* pBoxFormat = m_pBox->GetFrameFormat();
838 const SwTableBoxNumFormat* pNumFormat =
839 pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT);
840 if(!pNumFormat
841 || pMyDoc->GetNumberFormatter()->IsTextFormat(pNumFormat->GetValue()))
842 {
843 aSet.Put(SwTableBoxNumFormat(0));
844 }
845 aSet.Put(aFormula);
846 GetDoc()->SetTableBoxFormulaAttrs( *m_pBox, aSet );
847 // update table
848 pMyDoc->getIDocumentFieldsAccess().UpdateTableFields(SwTable::FindTable(GetFrameFormat()));
849 }
850
getValue()851 double SwXCell::getValue()
852 {
853 SolarMutexGuard aGuard;
854 // #i112652# a table cell may contain NaN as a value, do not filter that
855 if(IsValid() && !getString().isEmpty())
856 return m_pBox->GetFrameFormat()->GetTableBoxValue().GetValue();
857 return std::numeric_limits<double>::quiet_NaN();
858 }
859
setValue(double rValue)860 void SwXCell::setValue(double rValue)
861 {
862 SolarMutexGuard aGuard;
863 sw_setValue( *this, rValue );
864 }
865
getType()866 table::CellContentType SwXCell::getType()
867 {
868 SolarMutexGuard aGuard;
869
870 table::CellContentType nRes = table::CellContentType_EMPTY;
871 sal_uInt32 nNdPos = m_pBox->IsFormulaOrValueBox();
872 switch (nNdPos)
873 {
874 case 0 : nRes = table::CellContentType_TEXT; break;
875 case USHRT_MAX : nRes = table::CellContentType_EMPTY; break;
876 case RES_BOXATR_VALUE : nRes = table::CellContentType_VALUE; break;
877 case RES_BOXATR_FORMULA : nRes = table::CellContentType_FORMULA; break;
878 default :
879 OSL_FAIL( "unexpected case" );
880 }
881 return nRes;
882 }
883
setString(const OUString & aString)884 void SwXCell::setString(const OUString& aString)
885 {
886 SolarMutexGuard aGuard;
887 sw_setString( *this, aString );
888 }
889
getError()890 sal_Int32 SwXCell::getError()
891 {
892 SolarMutexGuard aGuard;
893 OUString sContent = getString();
894 return sal_Int32(sContent == SwViewShell::GetShellRes()->aCalc_Error);
895 }
896
createXTextCursor()897 rtl::Reference< SwXTextCursor > SwXCell::createXTextCursor()
898 {
899 if(!m_pStartNode && !IsValid())
900 throw uno::RuntimeException();
901 const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
902 SwPosition aPos(*pSttNd);
903 rtl::Reference<SwXTextCursor> const pXCursor =
904 new SwXTextCursor(*GetDoc(), this, CursorType::TableText, aPos);
905 auto& rUnoCursor(pXCursor->GetCursor());
906 rUnoCursor.Move(fnMoveForward, GoInNode);
907 return pXCursor;
908 }
909
createXTextCursorByRange(const uno::Reference<text::XTextRange> & xTextPosition)910 rtl::Reference<SwXTextCursor> SwXCell::createXTextCursorByRange(const uno::Reference< text::XTextRange > & xTextPosition)
911 {
912 SwUnoInternalPaM aPam(*GetDoc());
913 if((!m_pStartNode && !IsValid()) || !::sw::XTextRangeToSwPaM(aPam, xTextPosition))
914 throw uno::RuntimeException();
915 const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
916 // skip sections
917 SwStartNode* p1 = aPam.GetPointNode().StartOfSectionNode();
918 while(p1->IsSectionNode())
919 p1 = p1->StartOfSectionNode();
920 if( p1 != pSttNd )
921 return nullptr;
922 return new SwXTextCursor(*GetDoc(), this, CursorType::TableText,
923 *aPam.GetPoint(), aPam.GetMark());
924 }
925
getPropertySetInfo()926 uno::Reference< beans::XPropertySetInfo > SwXCell::getPropertySetInfo()
927 {
928 static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo();
929 return xRef;
930 }
931
setPropertyValue(const OUString & rPropertyName,const uno::Any & aValue)932 void SwXCell::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
933 {
934 SolarMutexGuard aGuard;
935 if(!IsValid())
936 return;
937 // Hack to support hidden property to transfer textDirection
938 if(rPropertyName == "FRMDirection")
939 {
940 SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, RES_FRAMEDIR);
941 aItem.PutValue(aValue, 0);
942 m_pBox->GetFrameFormat()->SetFormatAttr(aItem);
943 }
944 else if(rPropertyName == "TableRedlineParams")
945 {
946 // Get the table row properties
947 uno::Sequence<beans::PropertyValue> tableCellProperties = aValue.get< uno::Sequence< beans::PropertyValue > >();
948 comphelper::SequenceAsHashMap aPropMap(tableCellProperties);
949 OUString sRedlineType;
950 if(!(aPropMap.getValue(u"RedlineType"_ustr) >>= sRedlineType))
951 throw beans::UnknownPropertyException(u"No redline type property: "_ustr, getXWeak());
952
953 // Create a 'Table Cell Redline' object
954 SwUnoCursorHelper::makeTableCellRedline(*m_pBox, sRedlineType, tableCellProperties);
955
956
957 }
958 else if (rPropertyName == "VerticalMerge")
959 {
960 //Hack to allow clearing of numbering from the paragraphs in the merged cells.
961 SwNodeIndex aIdx(*GetStartNode(), 1);
962 const SwNode* pEndNd = aIdx.GetNode().EndOfSectionNode();
963 while (&aIdx.GetNode() != pEndNd)
964 {
965 SwTextNode* pNd = aIdx.GetNode().GetTextNode();
966 if (pNd)
967 pNd->SetCountedInList(false);
968 ++aIdx;
969 }
970 }
971 else
972 {
973 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
974 if ( !pEntry )
975 {
976 // not a table property: ignore it, if it is a paragraph/character property
977 const SfxItemPropertySet& rParaPropSet = *aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH);
978 pEntry = rParaPropSet.getPropertyMap().getByName(rPropertyName);
979
980 if ( pEntry )
981 return;
982 }
983
984 if(!pEntry)
985 throw beans::UnknownPropertyException(rPropertyName, getXWeak());
986 if(pEntry->nWID != FN_UNO_CELL_ROW_SPAN)
987 {
988 SwFrameFormat* pBoxFormat = m_pBox->ClaimFrameFormat();
989 SwAttrSet aSet(pBoxFormat->GetAttrSet());
990 m_pPropSet->setPropertyValue(rPropertyName, aValue, aSet);
991 pBoxFormat->GetDoc()->SetAttr(aSet, *pBoxFormat);
992 }
993 else if(aValue.isExtractableTo(cppu::UnoType<sal_Int32>::get()))
994 m_pBox->setRowSpan(aValue.get<sal_Int32>());
995 }
996 }
997
getPropertyValue(const OUString & rPropertyName)998 uno::Any SwXCell::getPropertyValue(const OUString& rPropertyName)
999 {
1000 SolarMutexGuard aGuard;
1001 if(!IsValid())
1002 return uno::Any();
1003 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
1004 if(!pEntry)
1005 throw beans::UnknownPropertyException(rPropertyName, getXWeak());
1006 switch(pEntry->nWID)
1007 {
1008 case FN_UNO_CELL_ROW_SPAN:
1009 return uno::Any(m_pBox->getRowSpan());
1010 case FN_UNO_TEXT_SECTION:
1011 {
1012 SwFrameFormat* pTableFormat = GetFrameFormat();
1013 SwTable* pTable = SwTable::FindTable(pTableFormat);
1014 SwTableNode* pTableNode = pTable->GetTableNode();
1015 SwSectionNode* pSectionNode = pTableNode->FindSectionNode();
1016 if(!pSectionNode)
1017 return uno::Any();
1018 SwSection& rSect = pSectionNode->GetSection();
1019 rtl::Reference< SwXTextSection > xSect = SwXTextSections::GetObject(*rSect.GetFormat());
1020 return uno::Any(uno::Reference< text::XTextSection >(xSect));
1021 }
1022 break;
1023 case FN_UNO_CELL_NAME:
1024 return uno::Any(m_pBox->GetName());
1025 case FN_UNO_REDLINE_NODE_START:
1026 case FN_UNO_REDLINE_NODE_END:
1027 {
1028 //redline can only be returned if it's a living object
1029 return SwXText::getPropertyValue(rPropertyName);
1030 }
1031 break;
1032 case FN_UNO_PARENT_TEXT:
1033 {
1034 if (!m_xParentText.is())
1035 {
1036 const SwStartNode* pSttNd = m_pBox->GetSttNd();
1037 if (!pSttNd)
1038 return uno::Any();
1039
1040 const SwTableNode* pTableNode = pSttNd->FindTableNode();
1041 if (!pTableNode)
1042 return uno::Any();
1043
1044 SwPosition aPos(*pTableNode);
1045 SwDoc& rDoc = aPos.GetDoc();
1046 m_xParentText = sw::CreateParentXText(rDoc, aPos);
1047 }
1048
1049 return uno::Any(m_xParentText);
1050 }
1051 break;
1052 default:
1053 {
1054 const SwAttrSet& rSet = m_pBox->GetFrameFormat()->GetAttrSet();
1055 uno::Any aResult;
1056 m_pPropSet->getPropertyValue(rPropertyName, rSet, aResult);
1057 return aResult;
1058 }
1059 }
1060 }
1061
addPropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)1062 void SwXCell::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1063 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1064
removePropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)1065 void SwXCell::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1066 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1067
addVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)1068 void SwXCell::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1069 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1070
removeVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)1071 void SwXCell::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1072 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1073
createEnumeration()1074 uno::Reference<container::XEnumeration> SwXCell::createEnumeration()
1075 {
1076 SolarMutexGuard aGuard;
1077 if(!IsValid())
1078 return uno::Reference<container::XEnumeration>();
1079 const SwStartNode* pSttNd = m_pBox->GetSttNd();
1080 SwPosition aPos(*pSttNd);
1081 auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos));
1082 pUnoCursor->Move(fnMoveForward, GoInNode);
1083 // remember table and start node for later travelling
1084 // (used in export of tables in tables)
1085 return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::TableText, m_pBox);
1086 }
1087
getElementType()1088 uno::Type SAL_CALL SwXCell::getElementType()
1089 {
1090 return cppu::UnoType<text::XTextRange>::get();
1091 }
1092
hasElements()1093 sal_Bool SwXCell::hasElements()
1094 {
1095 return true;
1096 }
1097
Notify(const SfxHint & rHint)1098 void SwXCell::Notify(const SfxHint& rHint)
1099 {
1100 if(rHint.GetId() == SfxHintId::Dying)
1101 {
1102 m_pTableFormat = nullptr;
1103 }
1104 else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableBox, SwXCell>*>(&rHint))
1105 {
1106 if(!pFindHint->m_pResult && pFindHint->m_pCore == GetTableBox())
1107 pFindHint->m_pResult = this;
1108 }
1109 }
1110
CreateXCell(SwFrameFormat * pTableFormat,SwTableBox * pBox,SwTable * pTable)1111 rtl::Reference<SwXCell> SwXCell::CreateXCell(SwFrameFormat* pTableFormat, SwTableBox* pBox, SwTable *pTable )
1112 {
1113 if(!pTableFormat || !pBox)
1114 return nullptr;
1115 if(!pTable)
1116 pTable = SwTable::FindTable(pTableFormat);
1117 SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find(pBox);
1118 if(it == pTable->GetTabSortBoxes().end())
1119 return nullptr;
1120 size_t const nPos = it - pTable->GetTabSortBoxes().begin();
1121 FindUnoInstanceHint<SwTableBox, SwXCell> aHint{pBox};
1122 pTableFormat->GetNotifier().Broadcast(aHint);
1123 return aHint.m_pResult ? aHint.m_pResult.get() : new SwXCell(pTableFormat, pBox, nPos);
1124 }
1125
1126 /** search if a box exists in a table
1127 *
1128 * @param pTable the table to search in
1129 * @param pBox2 box model to find
1130 * @return the box if existent in pTable, 0 (!!!) if not found
1131 */
FindBox(SwTable * pTable,SwTableBox * pBox2)1132 SwTableBox* SwXCell::FindBox(SwTable* pTable, SwTableBox* pBox2)
1133 {
1134 // check if nFndPos happens to point to the right table box
1135 if( m_nFndPos < pTable->GetTabSortBoxes().size() &&
1136 pBox2 == pTable->GetTabSortBoxes()[ m_nFndPos ] )
1137 return pBox2;
1138
1139 // if not, seek the entry (and return, if successful)
1140 SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find( pBox2 );
1141 if( it != pTable->GetTabSortBoxes().end() )
1142 {
1143 m_nFndPos = it - pTable->GetTabSortBoxes().begin();
1144 return pBox2;
1145 }
1146
1147 // box not found: reset nFndPos pointer
1148 m_nFndPos = NOTFOUND;
1149 return nullptr;
1150 }
1151
GetForcedNumericalValue() const1152 double SwXCell::GetForcedNumericalValue() const
1153 {
1154 if(table::CellContentType_TEXT != const_cast<SwXCell*>(this)->getType())
1155 return getValue();
1156 // now we'll try to get a useful numerical value
1157 // from the text in the cell...
1158 sal_uInt32 nFIndex;
1159 SvNumberFormatter* pNumFormatter(const_cast<SvNumberFormatter*>(GetDoc()->GetNumberFormatter()));
1160 // look for SwTableBoxNumFormat value in parents as well
1161 auto pBoxFormat(GetTableBox()->GetFrameFormat());
1162 const SwTableBoxNumFormat* pNumFormat = pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT);
1163
1164 if (pNumFormat)
1165 {
1166 // please note that the language of the numberformat
1167 // is implicitly coded into the below value as well
1168 nFIndex = pNumFormat->GetValue();
1169
1170 // since the current value indicates a text format but the call
1171 // to 'IsNumberFormat' below won't work for text formats
1172 // we need to get rid of the part that indicates the text format.
1173 // According to ER this can be done like this:
1174 nFIndex -= (nFIndex % SV_COUNTRY_LANGUAGE_OFFSET);
1175 }
1176 else
1177 {
1178 // system language is probably not the best possible choice
1179 // but since we have to guess anyway (because the language of at
1180 // the text is NOT the one used for the number format!)
1181 // it is at least conform to what is used in
1182 // SwTableShell::Execute when
1183 // SID_ATTR_NUMBERFORMAT_VALUE is set...
1184 LanguageType eLang = LANGUAGE_SYSTEM;
1185 nFIndex = pNumFormatter->GetStandardIndex( eLang );
1186 }
1187 double fTmp;
1188 if (!const_cast<SwDoc*>(GetDoc())->IsNumberFormat(const_cast<SwXCell*>(this)->getString(), nFIndex, fTmp))
1189 return std::numeric_limits<double>::quiet_NaN();
1190 return fTmp;
1191 }
1192
GetAny() const1193 uno::Any SwXCell::GetAny() const
1194 {
1195 if(!m_pBox)
1196 throw uno::RuntimeException();
1197 // check if table box value item is set
1198 auto pBoxFormat(m_pBox->GetFrameFormat());
1199 const bool bIsNum = pBoxFormat->GetItemState(RES_BOXATR_VALUE, false) == SfxItemState::SET;
1200 return bIsNum ? uno::Any(getValue()) : uno::Any(const_cast<SwXCell*>(this)->getString());
1201 }
1202
getImplementationName()1203 OUString SwXCell::getImplementationName()
1204 { return u"SwXCell"_ustr; }
1205
supportsService(const OUString & rServiceName)1206 sal_Bool SwXCell::supportsService(const OUString& rServiceName)
1207 { return cppu::supportsService(this, rServiceName); }
1208
getSupportedServiceNames()1209 uno::Sequence< OUString > SwXCell::getSupportedServiceNames()
1210 { return {u"com.sun.star.text.CellProperties"_ustr}; }
1211
getImplementationName()1212 OUString SwXTextTableRow::getImplementationName()
1213 { return u"SwXTextTableRow"_ustr; }
1214
supportsService(const OUString & rServiceName)1215 sal_Bool SwXTextTableRow::supportsService(const OUString& rServiceName)
1216 { return cppu::supportsService(this, rServiceName); }
1217
getSupportedServiceNames()1218 uno::Sequence< OUString > SwXTextTableRow::getSupportedServiceNames()
1219 { return {u"com.sun.star.text.TextTableRow"_ustr}; }
1220
1221
SwXTextTableRow(SwFrameFormat * pFormat,SwTableLine * pLn)1222 SwXTextTableRow::SwXTextTableRow(SwFrameFormat* pFormat, SwTableLine* pLn) :
1223 m_pFormat(pFormat),
1224 m_pLine(pLn),
1225 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_ROW))
1226 {
1227 StartListening(m_pFormat->GetNotifier());
1228 }
1229
~SwXTextTableRow()1230 SwXTextTableRow::~SwXTextTableRow()
1231 {
1232 SolarMutexGuard aGuard;
1233 EndListeningAll();
1234 }
1235
getPropertySetInfo()1236 uno::Reference< beans::XPropertySetInfo > SwXTextTableRow::getPropertySetInfo()
1237 {
1238 static uno::Reference<beans::XPropertySetInfo> xRef = m_pPropSet->getPropertySetInfo();
1239 return xRef;
1240 }
1241
setPropertyValue(const OUString & rPropertyName,const uno::Any & aValue)1242 void SwXTextTableRow::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
1243 {
1244 SolarMutexGuard aGuard;
1245 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
1246 SwTable* pTable = SwTable::FindTable( pFormat );
1247 SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, m_pLine);
1248 if(!pLn)
1249 return;
1250
1251 // Check for a specific property
1252 if ( rPropertyName == "TableRedlineParams" )
1253 {
1254 // Get the table row properties
1255 uno::Sequence< beans::PropertyValue > tableRowProperties = aValue.get< uno::Sequence< beans::PropertyValue > >();
1256 comphelper::SequenceAsHashMap aPropMap( tableRowProperties );
1257 OUString sRedlineType;
1258 if( !(aPropMap.getValue(u"RedlineType"_ustr) >>= sRedlineType) )
1259 {
1260 throw beans::UnknownPropertyException(u"No redline type property: "_ustr, getXWeak() );
1261 }
1262
1263 // Create a 'Table Row Redline' object
1264 SwUnoCursorHelper::makeTableRowRedline( *pLn, sRedlineType, tableRowProperties);
1265
1266 }
1267 else
1268 {
1269 const SfxItemPropertyMapEntry* pEntry =
1270 m_pPropSet->getPropertyMap().getByName(rPropertyName);
1271 SwDoc* pDoc = pFormat->GetDoc();
1272 if (!pEntry)
1273 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
1274 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
1275 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() );
1276
1277 switch(pEntry->nWID)
1278 {
1279 case FN_UNO_ROW_HEIGHT:
1280 case FN_UNO_ROW_AUTO_HEIGHT:
1281 {
1282 SwFormatFrameSize aFrameSize(pLn->GetFrameFormat()->GetFrameSize());
1283 if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID)
1284 {
1285 bool bSet = *o3tl::doAccess<bool>(aValue);
1286 aFrameSize.SetHeightSizeType(bSet ? SwFrameSize::Variable : SwFrameSize::Fixed);
1287 }
1288 else
1289 {
1290 sal_Int32 nHeight = 0;
1291 aValue >>= nHeight;
1292 Size aSz(aFrameSize.GetSize());
1293 aSz.setHeight( o3tl::toTwips(nHeight, o3tl::Length::mm100) );
1294 aFrameSize.SetSize(aSz);
1295 }
1296 pDoc->SetAttr(aFrameSize, *pLn->ClaimFrameFormat());
1297 }
1298 break;
1299
1300 case FN_UNO_TABLE_COLUMN_SEPARATORS:
1301 {
1302 UnoActionContext aContext(pDoc);
1303 SwTable* pTable2 = SwTable::FindTable( pFormat );
1304 lcl_SetTableSeparators(aValue, pTable2, m_pLine->GetTabBoxes()[0], true, pDoc);
1305 }
1306 break;
1307
1308 default:
1309 {
1310 SwFrameFormat* pLnFormat = pLn->ClaimFrameFormat();
1311 SwAttrSet aSet(pLnFormat->GetAttrSet());
1312 SfxItemPropertySet::setPropertyValue(*pEntry, aValue, aSet);
1313 pDoc->SetAttr(aSet, *pLnFormat);
1314 }
1315 }
1316 }
1317 }
1318
getPropertyValue(const OUString & rPropertyName)1319 uno::Any SwXTextTableRow::getPropertyValue(const OUString& rPropertyName)
1320 {
1321 SolarMutexGuard aGuard;
1322 uno::Any aRet;
1323 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
1324 SwTable* pTable = SwTable::FindTable( pFormat );
1325 SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, m_pLine);
1326 if(pLn)
1327 {
1328 const SfxItemPropertyMapEntry* pEntry =
1329 m_pPropSet->getPropertyMap().getByName(rPropertyName);
1330 if (!pEntry)
1331 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
1332
1333 switch(pEntry->nWID)
1334 {
1335 case FN_UNO_ROW_HEIGHT:
1336 case FN_UNO_ROW_AUTO_HEIGHT:
1337 {
1338 const SwFormatFrameSize& rSize = pLn->GetFrameFormat()->GetFrameSize();
1339 if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID)
1340 {
1341 aRet <<= SwFrameSize::Variable == rSize.GetHeightSizeType();
1342 }
1343 else
1344 aRet <<= static_cast<sal_Int32>(convertTwipToMm100(rSize.GetSize().Height()));
1345 }
1346 break;
1347
1348 case FN_UNO_TABLE_COLUMN_SEPARATORS:
1349 {
1350 lcl_GetTableSeparators(aRet, pTable, m_pLine->GetTabBoxes()[0], true);
1351 }
1352 break;
1353
1354 default:
1355 {
1356 const SwAttrSet& rSet = pLn->GetFrameFormat()->GetAttrSet();
1357 SfxItemPropertySet::getPropertyValue(*pEntry, rSet, aRet);
1358 }
1359 }
1360 }
1361 return aRet;
1362 }
1363
addPropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)1364 void SwXTextTableRow::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1365 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1366
removePropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)1367 void SwXTextTableRow::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1368 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1369
addVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)1370 void SwXTextTableRow::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1371 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1372
removeVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)1373 void SwXTextTableRow::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1374 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1375
Notify(const SfxHint & rHint)1376 void SwXTextTableRow::Notify(const SfxHint& rHint)
1377 {
1378 if(rHint.GetId() == SfxHintId::Dying)
1379 {
1380 m_pFormat = nullptr;
1381 } else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableLine, SwXTextTableRow>*>(&rHint))
1382 {
1383 if(!pFindHint->m_pCore && pFindHint->m_pCore == m_pLine)
1384 pFindHint->m_pResult = this;
1385 }
1386 }
1387
FindLine(SwTable * pTable,SwTableLine const * pLine)1388 SwTableLine* SwXTextTableRow::FindLine(SwTable* pTable, SwTableLine const * pLine)
1389 {
1390 for(const auto& pCurrentLine : pTable->GetTabLines())
1391 if(pCurrentLine == pLine)
1392 return pCurrentLine;
1393 return nullptr;
1394 }
1395
1396 // SwXTextTableCursor
1397
getImplementationName()1398 OUString SwXTextTableCursor::getImplementationName()
1399 { return u"SwXTextTableCursor"_ustr; }
1400
supportsService(const OUString & rServiceName)1401 sal_Bool SwXTextTableCursor::supportsService(const OUString& rServiceName)
1402 { return cppu::supportsService(this, rServiceName); }
1403
release()1404 void SwXTextTableCursor::release() noexcept
1405 {
1406 SolarMutexGuard aGuard;
1407 SwXTextTableCursor_Base::release();
1408 }
1409
GetPaM() const1410 const SwPaM* SwXTextTableCursor::GetPaM() const { return &GetCursor(); }
GetPaM()1411 SwPaM* SwXTextTableCursor::GetPaM() { return &GetCursor(); }
GetDoc() const1412 const SwDoc* SwXTextTableCursor::GetDoc() const { return GetFrameFormat()->GetDoc(); }
GetDoc()1413 SwDoc* SwXTextTableCursor::GetDoc() { return GetFrameFormat()->GetDoc(); }
GetCursor() const1414 const SwUnoCursor& SwXTextTableCursor::GetCursor() const { return *m_pUnoCursor; }
GetCursor()1415 SwUnoCursor& SwXTextTableCursor::GetCursor() { return *m_pUnoCursor; }
1416
getSupportedServiceNames()1417 uno::Sequence<OUString> SwXTextTableCursor::getSupportedServiceNames()
1418 { return {u"com.sun.star.text.TextTableCursor"_ustr}; }
1419
SwXTextTableCursor(SwFrameFormat * pFrameFormat,SwTableBox const * pBox)1420 SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat* pFrameFormat, SwTableBox const* pBox)
1421 : m_pFrameFormat(pFrameFormat)
1422 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
1423 {
1424 StartListening(m_pFrameFormat->GetNotifier());
1425 SwDoc* pDoc = m_pFrameFormat->GetDoc();
1426 const SwStartNode* pSttNd = pBox->GetSttNd();
1427 SwPosition aPos(*pSttNd);
1428 m_pUnoCursor = pDoc->CreateUnoCursor(aPos, true);
1429 m_pUnoCursor->Move( fnMoveForward, GoInNode );
1430 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor);
1431 rTableCursor.MakeBoxSels();
1432 }
1433
SwXTextTableCursor(SwFrameFormat & rTableFormat,const SwTableCursor * pTableSelection)1434 SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat& rTableFormat, const SwTableCursor* pTableSelection)
1435 : m_pFrameFormat(&rTableFormat)
1436 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
1437 {
1438 StartListening(m_pFrameFormat->GetNotifier());
1439 m_pUnoCursor = pTableSelection->GetDoc().CreateUnoCursor(*pTableSelection->GetPoint(), true);
1440 if(pTableSelection->HasMark())
1441 {
1442 m_pUnoCursor->SetMark();
1443 *m_pUnoCursor->GetMark() = *pTableSelection->GetMark();
1444 }
1445 const SwSelBoxes& rBoxes = pTableSelection->GetSelectedBoxes();
1446 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor);
1447 for(auto pBox : rBoxes)
1448 rTableCursor.InsertBox(*pBox);
1449 rTableCursor.MakeBoxSels();
1450 }
1451
getRangeName()1452 OUString SwXTextTableCursor::getRangeName()
1453 {
1454 SolarMutexGuard aGuard;
1455 SwUnoCursor& rUnoCursor = GetCursor();
1456 SwUnoTableCursor* pTableCursor = dynamic_cast<SwUnoTableCursor*>(&rUnoCursor);
1457 //!! see also SwChartDataSequence::getSourceRangeRepresentation
1458 if(!pTableCursor)
1459 return OUString();
1460 pTableCursor->MakeBoxSels();
1461 const SwStartNode* pNode = pTableCursor->GetPoint()->GetNode().FindTableBoxStartNode();
1462 const SwTable* pTable = SwTable::FindTable(GetFrameFormat());
1463 const SwTableBox* pEndBox = pTable->GetTableBox(pNode->GetIndex());
1464 if(pTableCursor->HasMark())
1465 {
1466 pNode = pTableCursor->GetMark()->GetNode().FindTableBoxStartNode();
1467 const SwTableBox* pStartBox = pTable->GetTableBox(pNode->GetIndex());
1468 if(pEndBox != pStartBox)
1469 {
1470 // need to switch start and end?
1471 if(*pTableCursor->GetPoint() < *pTableCursor->GetMark())
1472 std::swap(pStartBox, pEndBox);
1473 return pStartBox->GetName() + ":" + pEndBox->GetName();
1474 }
1475 }
1476 return pEndBox->GetName();
1477 }
1478
gotoCellByName(const OUString & sCellName,sal_Bool bExpand)1479 sal_Bool SwXTextTableCursor::gotoCellByName(const OUString& sCellName, sal_Bool bExpand)
1480 {
1481 SolarMutexGuard aGuard;
1482 SwUnoCursor& rUnoCursor = GetCursor();
1483 auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1484 lcl_CursorSelect(rTableCursor, bExpand);
1485 return rTableCursor.GotoTableBox(sCellName);
1486 }
1487
goLeft(sal_Int16 Count,sal_Bool bExpand)1488 sal_Bool SwXTextTableCursor::goLeft(sal_Int16 Count, sal_Bool bExpand)
1489 {
1490 SolarMutexGuard aGuard;
1491 SwUnoCursor& rUnoCursor = GetCursor();
1492 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1493 lcl_CursorSelect(rTableCursor, bExpand);
1494 return rTableCursor.Left(Count);
1495 }
1496
goRight(sal_Int16 Count,sal_Bool bExpand)1497 sal_Bool SwXTextTableCursor::goRight(sal_Int16 Count, sal_Bool bExpand)
1498 {
1499 SolarMutexGuard aGuard;
1500 SwUnoCursor& rUnoCursor = GetCursor();
1501 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1502 lcl_CursorSelect(rTableCursor, bExpand);
1503 return rTableCursor.Right(Count);
1504 }
1505
goUp(sal_Int16 Count,sal_Bool bExpand)1506 sal_Bool SwXTextTableCursor::goUp(sal_Int16 Count, sal_Bool bExpand)
1507 {
1508 SolarMutexGuard aGuard;
1509 SwUnoCursor& rUnoCursor = GetCursor();
1510 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1511 lcl_CursorSelect(rTableCursor, bExpand);
1512 return rTableCursor.UpDown(true, Count, nullptr, 0,
1513 *rUnoCursor.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout());
1514 }
1515
goDown(sal_Int16 Count,sal_Bool bExpand)1516 sal_Bool SwXTextTableCursor::goDown(sal_Int16 Count, sal_Bool bExpand)
1517 {
1518 SolarMutexGuard aGuard;
1519 SwUnoCursor& rUnoCursor = GetCursor();
1520 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1521 lcl_CursorSelect(rTableCursor, bExpand);
1522 return rTableCursor.UpDown(false, Count, nullptr, 0,
1523 *rUnoCursor.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout());
1524 }
1525
gotoStart(sal_Bool bExpand)1526 void SwXTextTableCursor::gotoStart(sal_Bool bExpand)
1527 {
1528 SolarMutexGuard aGuard;
1529 SwUnoCursor& rUnoCursor = GetCursor();
1530 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1531 lcl_CursorSelect(rTableCursor, bExpand);
1532 rTableCursor.MoveTable(GotoCurrTable, fnTableStart);
1533 }
1534
gotoEnd(sal_Bool bExpand)1535 void SwXTextTableCursor::gotoEnd(sal_Bool bExpand)
1536 {
1537 SolarMutexGuard aGuard;
1538 SwUnoCursor& rUnoCursor = GetCursor();
1539 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1540 lcl_CursorSelect(rTableCursor, bExpand);
1541 rTableCursor.MoveTable(GotoCurrTable, fnTableEnd);
1542 }
1543
mergeRange()1544 sal_Bool SwXTextTableCursor::mergeRange()
1545 {
1546 SolarMutexGuard aGuard;
1547 SwUnoCursor& rUnoCursor = GetCursor();
1548
1549 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1550 {
1551 // HACK: remove pending actions for selecting old style tables
1552 UnoActionRemoveContext aRemoveContext(rTableCursor);
1553 }
1554 rTableCursor.MakeBoxSels();
1555 bool bResult;
1556 {
1557 UnoActionContext aContext(&rUnoCursor.GetDoc());
1558 bResult = TableMergeErr::Ok == rTableCursor.GetDoc().MergeTable(rTableCursor);
1559 }
1560 if(bResult)
1561 {
1562 size_t nCount = rTableCursor.GetSelectedBoxesCount();
1563 while (nCount--)
1564 rTableCursor.DeleteBox(nCount);
1565 }
1566 rTableCursor.MakeBoxSels();
1567 return bResult;
1568 }
1569
splitRange(sal_Int16 Count,sal_Bool Horizontal)1570 sal_Bool SwXTextTableCursor::splitRange(sal_Int16 Count, sal_Bool Horizontal)
1571 {
1572 SolarMutexGuard aGuard;
1573 if (Count <= 0)
1574 throw uno::RuntimeException(u"Illegal first argument: needs to be > 0"_ustr, getXWeak());
1575 SwUnoCursor& rUnoCursor = GetCursor();
1576 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1577 {
1578 // HACK: remove pending actions for selecting old style tables
1579 UnoActionRemoveContext aRemoveContext(rTableCursor);
1580 }
1581 rTableCursor.MakeBoxSels();
1582 bool bResult;
1583 {
1584 UnoActionContext aContext(&rUnoCursor.GetDoc());
1585 bResult = rTableCursor.GetDoc().SplitTable(rTableCursor.GetSelectedBoxes(), !Horizontal, Count);
1586 }
1587 rTableCursor.MakeBoxSels();
1588 return bResult;
1589 }
1590
getPropertySetInfo()1591 uno::Reference< beans::XPropertySetInfo > SwXTextTableCursor::getPropertySetInfo()
1592 {
1593 static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo();
1594 return xRef;
1595 }
1596
setPropertyValue(const OUString & rPropertyName,const uno::Any & aValue)1597 void SwXTextTableCursor::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
1598 {
1599 SolarMutexGuard aGuard;
1600 SwUnoCursor& rUnoCursor = GetCursor();
1601 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
1602 if(!pEntry)
1603 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak());
1604 if(pEntry->nFlags & beans::PropertyAttribute::READONLY)
1605 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak());
1606 {
1607 auto pSttNode = rUnoCursor.GetPointNode().StartOfSectionNode();
1608 const SwTableNode* pTableNode = pSttNode->FindTableNode();
1609 lcl_FormatTable(pTableNode->GetTable().GetFrameFormat());
1610 }
1611 auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1612 rTableCursor.MakeBoxSels();
1613 SwDoc& rDoc = rUnoCursor.GetDoc();
1614 switch(pEntry->nWID)
1615 {
1616 case FN_UNO_TABLE_CELL_BACKGROUND:
1617 {
1618 std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
1619 SwDoc::GetBoxAttr(rUnoCursor, aBrush);
1620 aBrush->PutValue(aValue, pEntry->nMemberId);
1621 rDoc.SetBoxAttr(rUnoCursor, *aBrush);
1622
1623 }
1624 break;
1625 case RES_BOXATR_FORMAT:
1626 {
1627 SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT);
1628 aNumberFormat.PutValue(aValue, 0);
1629 rDoc.SetBoxAttr(rUnoCursor, aNumberFormat);
1630 }
1631 break;
1632 case FN_UNO_PARA_STYLE:
1633 SwUnoCursorHelper::SetTextFormatColl(aValue, rUnoCursor);
1634 break;
1635 default:
1636 {
1637 SfxItemSet aItemSet(rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID);
1638 SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(),
1639 aItemSet);
1640
1641 if (!SwUnoCursorHelper::SetCursorPropertyValue(
1642 *pEntry, aValue, rTableCursor.GetSelRing(), aItemSet))
1643 {
1644 SfxItemPropertySet::setPropertyValue(*pEntry, aValue, aItemSet);
1645 }
1646 SwUnoCursorHelper::SetCursorAttr(rTableCursor.GetSelRing(),
1647 aItemSet, SetAttrMode::DEFAULT, true);
1648 }
1649 }
1650 }
1651
getPropertyValue(const OUString & rPropertyName)1652 uno::Any SwXTextTableCursor::getPropertyValue(const OUString& rPropertyName)
1653 {
1654 SolarMutexGuard aGuard;
1655 SwUnoCursor& rUnoCursor = GetCursor();
1656 {
1657 auto pSttNode = rUnoCursor.GetPointNode().StartOfSectionNode();
1658 const SwTableNode* pTableNode = pSttNode->FindTableNode();
1659 lcl_FormatTable(pTableNode->GetTable().GetFrameFormat());
1660 }
1661 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1662 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
1663 if(!pEntry)
1664 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak());
1665 rTableCursor.MakeBoxSels();
1666 uno::Any aResult;
1667 switch(pEntry->nWID)
1668 {
1669 case FN_UNO_TABLE_CELL_BACKGROUND:
1670 {
1671 std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
1672 if (SwDoc::GetBoxAttr(rUnoCursor, aBrush))
1673 aBrush->QueryValue(aResult, pEntry->nMemberId);
1674 }
1675 break;
1676 case RES_BOXATR_FORMAT:
1677 // TODO: GetAttr for table selections in a Doc is missing
1678 throw uno::RuntimeException("Unknown property: " + rPropertyName, getXWeak());
1679 break;
1680 case FN_UNO_PARA_STYLE:
1681 {
1682 auto pFormat(SwUnoCursorHelper::GetCurTextFormatColl(rUnoCursor, false));
1683 if(pFormat)
1684 aResult <<= pFormat->GetName();
1685 }
1686 break;
1687 default:
1688 {
1689 SfxItemSetFixed
1690 <RES_CHRATR_BEGIN, RES_FRMATR_END-1,
1691 RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER>
1692 aSet(rTableCursor.GetDoc().GetAttrPool());
1693 SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(), aSet);
1694 SfxItemPropertySet::getPropertyValue(*pEntry, aSet, aResult);
1695 }
1696 }
1697 return aResult;
1698 }
1699
addPropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)1700 void SwXTextTableCursor::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1701 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1702
removePropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)1703 void SwXTextTableCursor::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1704 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1705
addVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)1706 void SwXTextTableCursor::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1707 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1708
removeVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)1709 void SwXTextTableCursor::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1710 { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };
1711
Notify(const SfxHint & rHint)1712 void SwXTextTableCursor::Notify( const SfxHint& rHint )
1713 {
1714 if(rHint.GetId() == SfxHintId::Dying)
1715 m_pFrameFormat = nullptr;
1716 }
1717
1718
1719 // SwXTextTable ===========================================================
1720
1721 namespace {
1722
1723 class SwTableProperties_Impl
1724 {
1725 SwUnoCursorHelper::SwAnyMapHelper m_aAnyMap;
1726
1727 public:
1728 SwTableProperties_Impl();
1729
1730 void SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& aVal);
1731 bool GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny);
1732 void AddItemToSet(SfxItemSet& rSet, std::function<std::unique_ptr<SfxPoolItem>()> aItemFactory,
1733 sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips = false);
1734 void ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc);
1735 };
1736
1737 }
1738
SwTableProperties_Impl()1739 SwTableProperties_Impl::SwTableProperties_Impl()
1740 { }
1741
SetProperty(sal_uInt16 nWhichId,sal_uInt16 nMemberId,const uno::Any & rVal)1742 void SwTableProperties_Impl::SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rVal)
1743 {
1744 m_aAnyMap.SetValue(nWhichId, nMemberId, rVal);
1745 }
1746
GetProperty(sal_uInt16 nWhichId,sal_uInt16 nMemberId,const uno::Any * & rpAny)1747 bool SwTableProperties_Impl::GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny )
1748 {
1749 return m_aAnyMap.FillValue(nWhichId, nMemberId, rpAny);
1750 }
1751
AddItemToSet(SfxItemSet & rSet,std::function<std::unique_ptr<SfxPoolItem> ()> aItemFactory,sal_uInt16 nWhich,std::initializer_list<sal_uInt16> vMember,bool bAddTwips)1752 void SwTableProperties_Impl::AddItemToSet(SfxItemSet& rSet,
1753 std::function<std::unique_ptr<SfxPoolItem>()> aItemFactory,
1754 sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips)
1755 {
1756 std::vector< std::pair<sal_uInt16, const uno::Any* > > vMemberAndAny;
1757 for(sal_uInt16 nMember : vMember)
1758 {
1759 const uno::Any* pAny = nullptr;
1760 GetProperty(nWhich, nMember, pAny);
1761 if(pAny)
1762 vMemberAndAny.emplace_back(nMember, pAny);
1763 }
1764 if(!vMemberAndAny.empty())
1765 {
1766 std::unique_ptr<SfxPoolItem> aItem(aItemFactory());
1767 for(const auto& aMemberAndAny : vMemberAndAny)
1768 aItem->PutValue(*aMemberAndAny.second, aMemberAndAny.first | (bAddTwips ? CONVERT_TWIPS : 0) );
1769 rSet.Put(std::move(aItem));
1770 }
1771 }
ApplyTableAttr(const SwTable & rTable,SwDoc & rDoc)1772 void SwTableProperties_Impl::ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc)
1773 {
1774 SfxItemSetFixed<
1775 RES_FRM_SIZE, RES_BREAK,
1776 RES_HORI_ORIENT, RES_HORI_ORIENT,
1777 RES_BACKGROUND, RES_BACKGROUND,
1778 RES_SHADOW, RES_SHADOW,
1779 RES_KEEP, RES_KEEP,
1780 RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT>
1781 aSet(rDoc.GetAttrPool());
1782 const uno::Any* pRepHead;
1783 const SwFrameFormat &rFrameFormat = *rTable.GetFrameFormat();
1784 if(GetProperty(FN_TABLE_HEADLINE_REPEAT, 0xff, pRepHead ))
1785 {
1786 bool bVal(pRepHead->get<bool>());
1787 const_cast<SwTable&>(rTable).SetRowsToRepeat( bVal ? 1 : 0 ); // TODO: MULTIHEADER
1788 }
1789
1790 AddItemToSet(aSet, [&rFrameFormat]() { return rFrameFormat.makeBackgroundBrushItem(); }, RES_BACKGROUND, {
1791 MID_BACK_COLOR,
1792 MID_GRAPHIC_TRANSPARENT,
1793 MID_GRAPHIC_POSITION,
1794 MID_GRAPHIC,
1795 MID_GRAPHIC_FILTER });
1796
1797 bool bPutBreak = true;
1798 const uno::Any* pPage;
1799 if(GetProperty(FN_UNO_PAGE_STYLE, 0, pPage) || GetProperty(RES_PAGEDESC, 0xff, pPage))
1800 {
1801 OUString sPageStyle = pPage->get<OUString>();
1802 if(!sPageStyle.isEmpty())
1803 {
1804 SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc);
1805 const SwPageDesc* pDesc = SwPageDesc::GetByName(rDoc, sPageStyle);
1806 if(pDesc)
1807 {
1808 SwFormatPageDesc aDesc(pDesc);
1809 const uno::Any* pPgNo;
1810 if(GetProperty(RES_PAGEDESC, MID_PAGEDESC_PAGENUMOFFSET, pPgNo))
1811 {
1812 aDesc.SetNumOffset(pPgNo->get<sal_Int16>());
1813 }
1814 aSet.Put(aDesc);
1815 bPutBreak = false;
1816 }
1817
1818 }
1819 }
1820
1821 if(bPutBreak)
1822 AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetBreak().Clone()); }, RES_BREAK, {0});
1823 AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetShadow().Clone()); }, RES_SHADOW, {0}, true);
1824 AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetKeep().Clone()); }, RES_KEEP, {0});
1825 AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetHoriOrient().Clone()); }, RES_HORI_ORIENT, {MID_HORIORIENT_ORIENT}, true);
1826
1827 const uno::Any* pSzRel(nullptr);
1828 GetProperty(FN_TABLE_IS_RELATIVE_WIDTH, 0xff, pSzRel);
1829 const uno::Any* pRelWidth(nullptr);
1830 GetProperty(FN_TABLE_RELATIVE_WIDTH, 0xff, pRelWidth);
1831 const uno::Any* pWidth(nullptr);
1832 GetProperty(FN_TABLE_WIDTH, 0xff, pWidth);
1833
1834 bool bPutSize = pWidth != nullptr;
1835 SwFormatFrameSize aSz(SwFrameSize::Variable);
1836 if(pWidth)
1837 {
1838 aSz.PutValue(*pWidth, MID_FRMSIZE_WIDTH);
1839 bPutSize = true;
1840 }
1841 if(pSzRel && pSzRel->get<bool>() && pRelWidth)
1842 {
1843 aSz.PutValue(*pRelWidth, MID_FRMSIZE_REL_WIDTH|CONVERT_TWIPS);
1844 bPutSize = true;
1845 }
1846 if(bPutSize)
1847 {
1848 if(!aSz.GetWidth())
1849 aSz.SetWidth(MINLAY);
1850 aSet.Put(aSz);
1851 }
1852 AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetLRSpace().Clone()); }, RES_LR_SPACE, {
1853 MID_L_MARGIN|CONVERT_TWIPS,
1854 MID_R_MARGIN|CONVERT_TWIPS });
1855 AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetULSpace().Clone()); }, RES_UL_SPACE, {
1856 MID_UP_MARGIN|CONVERT_TWIPS,
1857 MID_LO_MARGIN|CONVERT_TWIPS });
1858 const::uno::Any* pSplit(nullptr);
1859 if(GetProperty(RES_LAYOUT_SPLIT, 0, pSplit))
1860 {
1861 SwFormatLayoutSplit aSp(pSplit->get<bool>());
1862 aSet.Put(aSp);
1863 }
1864 if(aSet.Count())
1865 {
1866 rDoc.SetAttr(aSet, *rTable.GetFrameFormat());
1867 }
1868 }
1869
1870 class SwXTextTable::Impl
1871 : public SvtListener
1872 {
1873 private:
1874 SwFrameFormat* m_pFrameFormat;
1875
1876 public:
1877 unotools::WeakReference<SwXTextTable> m_wThis;
1878 std::mutex m_Mutex; // just for OInterfaceContainerHelper4
1879 ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners;
1880 ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> m_ChartListeners;
1881
1882 const SfxItemPropertySet * m_pPropSet;
1883
1884 css::uno::WeakReference<css::table::XTableRows> m_xRows;
1885 css::uno::WeakReference<css::table::XTableColumns> m_xColumns;
1886
1887 bool m_bFirstRowAsLabel;
1888 bool m_bFirstColumnAsLabel;
1889
1890 // Descriptor-interface
1891 std::unique_ptr<SwTableProperties_Impl> m_pTableProps;
1892 OUString m_sTableName;
1893 unsigned short m_nRows;
1894 unsigned short m_nColumns;
1895
Impl(SwFrameFormat * const pFrameFormat)1896 explicit Impl(SwFrameFormat* const pFrameFormat)
1897 : m_pFrameFormat(pFrameFormat)
1898 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE))
1899 , m_bFirstRowAsLabel(false)
1900 , m_bFirstColumnAsLabel(false)
1901 , m_pTableProps(pFrameFormat ? nullptr : new SwTableProperties_Impl)
1902 , m_nRows(pFrameFormat ? 0 : 2)
1903 , m_nColumns(pFrameFormat ? 0 : 2)
1904 {
1905 if(m_pFrameFormat)
1906 StartListening(m_pFrameFormat->GetNotifier());
1907 }
1908
GetFrameFormat()1909 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
SetFrameFormat(SwFrameFormat & rFrameFormat)1910 void SetFrameFormat(SwFrameFormat& rFrameFormat)
1911 {
1912 EndListeningAll();
1913 m_pFrameFormat = &rFrameFormat;
1914 StartListening(m_pFrameFormat->GetNotifier());
1915 }
1916
IsDescriptor() const1917 bool IsDescriptor() const { return m_pTableProps != nullptr; }
1918
1919 // note: lock mutex before calling this to avoid concurrent update
ThrowIfComplex(SwXTextTable & rThis)1920 static std::pair<sal_uInt16, sal_uInt16> ThrowIfComplex(SwXTextTable &rThis)
1921 {
1922 sal_uInt16 const nRowCount(rThis.m_pImpl->GetRowCount());
1923 sal_uInt16 const nColCount(rThis.m_pImpl->GetColumnCount());
1924 if (!nRowCount || !nColCount)
1925 {
1926 throw uno::RuntimeException(u"Table too complex"_ustr, rThis.getXWeak());
1927 }
1928 return std::make_pair(nRowCount, nColCount);
1929 }
1930
1931 sal_uInt16 GetRowCount();
1932 sal_uInt16 GetColumnCount();
1933
1934 virtual void Notify(const SfxHint&) override;
1935
1936 };
1937
SwXTextTable()1938 SwXTextTable::SwXTextTable()
1939 : m_pImpl(new Impl(nullptr))
1940 {
1941 }
1942
SwXTextTable(SwFrameFormat & rFrameFormat)1943 SwXTextTable::SwXTextTable(SwFrameFormat& rFrameFormat)
1944 : m_pImpl(new Impl(&rFrameFormat))
1945 {
1946 }
1947
~SwXTextTable()1948 SwXTextTable::~SwXTextTable()
1949 {
1950 }
1951
CreateXTextTable(SwFrameFormat * const pFrameFormat)1952 rtl::Reference<SwXTextTable> SwXTextTable::CreateXTextTable(SwFrameFormat* const pFrameFormat)
1953 {
1954 rtl::Reference<SwXTextTable> xTable;
1955 if (pFrameFormat)
1956 xTable = dynamic_cast<SwXTextTable*>(pFrameFormat->GetXObject().get().get()); // cached?
1957 if (xTable.is())
1958 return xTable;
1959 if (pFrameFormat)
1960 {
1961 xTable = new SwXTextTable(*pFrameFormat);
1962 pFrameFormat->SetXObject(xTable->getXWeak());
1963 }
1964 else
1965 xTable = new SwXTextTable();
1966
1967 // need a permanent Reference to initialize m_wThis
1968 xTable->m_pImpl->m_wThis = xTable.get();
1969 return xTable;
1970 }
1971
GetFrameFormat()1972 SwFrameFormat* SwXTextTable::GetFrameFormat()
1973 {
1974 return m_pImpl->GetFrameFormat();
1975 }
1976
initialize(sal_Int32 nR,sal_Int32 nC)1977 void SwXTextTable::initialize(sal_Int32 nR, sal_Int32 nC)
1978 {
1979 if (!m_pImpl->IsDescriptor() || nR <= 0 || nC <= 0 || nR >= SAL_MAX_UINT16 || nC >= SAL_MAX_UINT16)
1980 throw uno::RuntimeException();
1981 m_pImpl->m_nRows = o3tl::narrowing<sal_uInt16>(nR);
1982 m_pImpl->m_nColumns = o3tl::narrowing<sal_uInt16>(nC);
1983 }
1984
getRows()1985 uno::Reference<table::XTableRows> SAL_CALL SwXTextTable::getRows()
1986 {
1987 SolarMutexGuard aGuard;
1988 uno::Reference<table::XTableRows> xResult(m_pImpl->m_xRows);
1989 if(xResult.is())
1990 return xResult;
1991 if(SwFrameFormat* pFormat = GetFrameFormat())
1992 m_pImpl->m_xRows = xResult = new SwXTableRows(*pFormat);
1993 if(!xResult.is())
1994 throw uno::RuntimeException();
1995 return xResult;
1996 }
1997
getColumns()1998 uno::Reference<table::XTableColumns> SAL_CALL SwXTextTable::getColumns()
1999 {
2000 SolarMutexGuard aGuard;
2001 uno::Reference<table::XTableColumns> xResult(m_pImpl->m_xColumns);
2002 if(xResult.is())
2003 return xResult;
2004 if(SwFrameFormat* pFormat = GetFrameFormat())
2005 m_pImpl->m_xColumns = xResult = new SwXTableColumns(*pFormat);
2006 if(!xResult.is())
2007 throw uno::RuntimeException();
2008 return xResult;
2009 }
2010
getCellByName(const OUString & sCellName)2011 uno::Reference<table::XCell> SwXTextTable::getCellByName(const OUString& sCellName)
2012 {
2013 SolarMutexGuard aGuard;
2014 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
2015 SwTable* pTable = SwTable::FindTable(pFormat);
2016 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
2017 if(!pBox)
2018 return nullptr;
2019 return SwXCell::CreateXCell(pFormat, pBox);
2020 }
2021
getCellNames()2022 uno::Sequence<OUString> SwXTextTable::getCellNames()
2023 {
2024 SolarMutexGuard aGuard;
2025 SwFrameFormat* pFormat(GetFrameFormat());
2026 if(!pFormat)
2027 return {};
2028 SwTable* pTable = SwTable::FindTable(pFormat);
2029 // exists at the table and at all boxes
2030 SwTableLines& rTableLines = pTable->GetTabLines();
2031 std::vector<OUString> aAllNames;
2032 lcl_InspectLines(rTableLines, aAllNames);
2033 return comphelper::containerToSequence(aAllNames);
2034 }
2035
createCursorByCellName(const OUString & sCellName)2036 uno::Reference<text::XTextTableCursor> SwXTextTable::createCursorByCellName(const OUString& sCellName)
2037 {
2038 SolarMutexGuard aGuard;
2039 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
2040 SwTable* pTable = SwTable::FindTable(pFormat);
2041 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
2042 if(!pBox || pBox->getRowSpan() == 0)
2043 throw uno::RuntimeException();
2044 return new SwXTextTableCursor(pFormat, pBox);
2045 }
2046
2047 void SAL_CALL
attach(const uno::Reference<text::XTextRange> & xTextRange)2048 SwXTextTable::attach(const uno::Reference<text::XTextRange> & xTextRange)
2049 {
2050 SolarMutexGuard aGuard;
2051
2052 // attach() must only be called once
2053 if (!m_pImpl->IsDescriptor()) /* already attached ? */
2054 throw uno::RuntimeException(u"SwXTextTable: already attached to range."_ustr, getXWeak());
2055
2056 SwXTextRange* pRange(dynamic_cast<SwXTextRange*>(xTextRange.get()));
2057 OTextCursorHelper* pCursor(dynamic_cast<OTextCursorHelper*>(xTextRange.get()));
2058 SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr;
2059 if (!pDoc || !m_pImpl->m_nRows || !m_pImpl->m_nColumns)
2060 throw lang::IllegalArgumentException();
2061 SwUnoInternalPaM aPam(*pDoc);
2062 // this now needs to return TRUE
2063 ::sw::XTextRangeToSwPaM(aPam, xTextRange);
2064 {
2065 UnoActionContext aCont(pDoc);
2066
2067 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
2068 const SwTable* pTable(nullptr);
2069 if( 0 != aPam.Start()->GetContentIndex() )
2070 {
2071 pDoc->getIDocumentContentOperations().SplitNode(*aPam.Start(), false);
2072 }
2073 //TODO: if it is the last paragraph than add another one!
2074 if(aPam.HasMark())
2075 {
2076 pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam);
2077 aPam.DeleteMark();
2078 }
2079
2080 OUString tableName;
2081 if (const::uno::Any* pName;
2082 m_pImpl->m_pTableProps->GetProperty(FN_UNO_TABLE_NAME, 0, pName))
2083 {
2084 tableName = pName->get<OUString>();
2085 }
2086 else if (!m_pImpl->m_sTableName.isEmpty())
2087 {
2088 sal_uInt16 nIndex = 1;
2089 tableName = m_pImpl->m_sTableName;
2090 while (pDoc->FindTableFormatByName(tableName, true) && nIndex < USHRT_MAX)
2091 tableName = m_pImpl->m_sTableName + OUString::number(nIndex++);
2092 }
2093
2094 pTable = pDoc->InsertTable(SwInsertTableOptions( SwInsertTableFlags::Headline | SwInsertTableFlags::DefaultBorder | SwInsertTableFlags::SplitLayout, 0 ),
2095 *aPam.GetPoint(),
2096 m_pImpl->m_nRows,
2097 m_pImpl->m_nColumns,
2098 text::HoriOrientation::FULL,
2099 nullptr, nullptr, false, true,
2100 tableName);
2101 if(pTable)
2102 {
2103 // here, the properties of the descriptor need to be analyzed
2104 m_pImpl->m_pTableProps->ApplyTableAttr(*pTable, *pDoc);
2105 SwFrameFormat* pTableFormat(pTable->GetFrameFormat());
2106 lcl_FormatTable(pTableFormat);
2107
2108 m_pImpl->SetFrameFormat(*pTableFormat);
2109
2110 m_pImpl->m_pTableProps.reset();
2111 }
2112 pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
2113 }
2114 }
2115
getAnchor()2116 uno::Reference<text::XTextRange> SwXTextTable::getAnchor()
2117 {
2118 SolarMutexGuard aGuard;
2119 SwTableFormat *const pFormat = static_cast<SwTableFormat*>(
2120 lcl_EnsureCoreConnected(GetFrameFormat(), this));
2121 return new SwXTextRange(*pFormat);
2122 }
2123
dispose()2124 void SwXTextTable::dispose()
2125 {
2126 SolarMutexGuard aGuard;
2127 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
2128 SwTable* pTable = SwTable::FindTable(pFormat);
2129 SwSelBoxes aSelBoxes;
2130 for(auto& rBox : pTable->GetTabSortBoxes() )
2131 aSelBoxes.insert(rBox);
2132 pFormat->GetDoc()->DeleteRowCol(aSelBoxes, SwDoc::RowColMode::DeleteProtected);
2133 }
2134
addEventListener(const uno::Reference<lang::XEventListener> & xListener)2135 void SAL_CALL SwXTextTable::addEventListener(
2136 const uno::Reference<lang::XEventListener> & xListener)
2137 {
2138 // no need to lock here as m_pImpl is const and container threadsafe
2139 std::unique_lock aGuard(m_pImpl->m_Mutex);
2140 m_pImpl->m_EventListeners.addInterface(aGuard, xListener);
2141 }
2142
removeEventListener(const uno::Reference<lang::XEventListener> & xListener)2143 void SAL_CALL SwXTextTable::removeEventListener(
2144 const uno::Reference< lang::XEventListener > & xListener)
2145 {
2146 // no need to lock here as m_pImpl is const and container threadsafe
2147 std::unique_lock aGuard(m_pImpl->m_Mutex);
2148 m_pImpl->m_EventListeners.removeInterface(aGuard, xListener);
2149 }
2150
getCellByPosition(sal_Int32 nColumn,sal_Int32 nRow)2151 uno::Reference<table::XCell> SwXTextTable::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow)
2152 {
2153 SolarMutexGuard aGuard;
2154 SwFrameFormat* pFormat(GetFrameFormat());
2155 // sheet is unimportant
2156 if(nColumn >= 0 && nRow >= 0 && pFormat)
2157 {
2158 auto pXCell = lcl_CreateXCell(pFormat, nColumn, nRow);
2159 if(pXCell)
2160 return pXCell;
2161 }
2162 throw lang::IndexOutOfBoundsException();
2163 }
2164
2165 namespace {
2166
GetRangeByName(SwFrameFormat * pFormat,SwTable const * pTable,const OUString & rTLName,const OUString & rBRName,SwRangeDescriptor const & rDesc)2167 rtl::Reference<SwXCellRange> GetRangeByName(
2168 SwFrameFormat* pFormat, SwTable const * pTable,
2169 const OUString& rTLName, const OUString& rBRName,
2170 SwRangeDescriptor const & rDesc)
2171 {
2172 const SwTableBox* pTLBox = pTable->GetTableBox(rTLName);
2173 if(!pTLBox)
2174 return nullptr;
2175 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2176 SwPosition aPos(*pSttNd);
2177 // set cursor to the upper-left cell of the range
2178 auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true));
2179 pUnoCursor->Move(fnMoveForward, GoInNode);
2180 pUnoCursor->SetRemainInSection(false);
2181 const SwTableBox* pBRBox(pTable->GetTableBox(rBRName));
2182 if(!pBRBox)
2183 return nullptr;
2184 pUnoCursor->SetMark();
2185 pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
2186 pUnoCursor->Move( fnMoveForward, GoInNode );
2187 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2188 // HACK: remove pending actions for selecting old style tables
2189 UnoActionRemoveContext aRemoveContext(rCursor);
2190 rCursor.MakeBoxSels();
2191 // pUnoCursor will be provided and will not be deleted
2192 return SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, rDesc);
2193 }
2194
2195 } // namespace
2196
getCellRangeByPosition(sal_Int32 nLeft,sal_Int32 nTop,sal_Int32 nRight,sal_Int32 nBottom)2197 uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByPosition(sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom)
2198 {
2199 SolarMutexGuard aGuard;
2200 SwFrameFormat* pFormat(GetFrameFormat());
2201 if(pFormat &&
2202 nLeft <= nRight && nTop <= nBottom &&
2203 nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 )
2204 {
2205 SwTable* pTable = SwTable::FindTable(pFormat);
2206 if(!pTable->IsTableComplex())
2207 {
2208 SwRangeDescriptor aDesc;
2209 aDesc.nTop = nTop;
2210 aDesc.nBottom = nBottom;
2211 aDesc.nLeft = nLeft;
2212 aDesc.nRight = nRight;
2213 const OUString sTLName = sw_GetCellName(aDesc.nLeft, aDesc.nTop);
2214 const OUString sBRName = sw_GetCellName(aDesc.nRight, aDesc.nBottom);
2215 // please note that according to the 'if' statement at the begin
2216 // sTLName:sBRName already denotes the normalized range string
2217 return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc);
2218 }
2219 }
2220 throw lang::IndexOutOfBoundsException();
2221 }
2222
getCellRangeByName(const OUString & sRange)2223 uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByName(const OUString& sRange)
2224 {
2225 SolarMutexGuard aGuard;
2226 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
2227 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), this);
2228 sal_Int32 nPos = 0;
2229 const OUString sTLName(sRange.getToken(0, ':', nPos));
2230 const OUString sBRName(sRange.getToken(0, ':', nPos));
2231 if(sTLName.isEmpty() || sBRName.isEmpty())
2232 throw uno::RuntimeException();
2233 SwRangeDescriptor aDesc;
2234 aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1;
2235 SwXTextTable::GetCellPosition(sTLName, aDesc.nLeft, aDesc.nTop );
2236 SwXTextTable::GetCellPosition(sBRName, aDesc.nRight, aDesc.nBottom );
2237
2238 // we should normalize the range now (e.g. A5:C1 will become A1:C5)
2239 // since (depending on what is done later) it will be troublesome
2240 // elsewhere when the cursor in the implementation does not
2241 // point to the top-left and bottom-right cells
2242 aDesc.Normalize();
2243 return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc);
2244 }
2245
getDataArray()2246 uno::Sequence< uno::Sequence< uno::Any > > SAL_CALL SwXTextTable::getDataArray()
2247 {
2248 SolarMutexGuard aGuard;
2249 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2250 uno::Reference<sheet::XCellRangeData> const xAllRange(
2251 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2252 uno::UNO_QUERY_THROW);
2253 return xAllRange->getDataArray();
2254 }
2255
setDataArray(const uno::Sequence<uno::Sequence<uno::Any>> & rArray)2256 void SAL_CALL SwXTextTable::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray)
2257 {
2258 SolarMutexGuard aGuard;
2259 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2260 uno::Reference<sheet::XCellRangeData> const xAllRange(
2261 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2262 uno::UNO_QUERY_THROW);
2263 return xAllRange->setDataArray(rArray);
2264 }
2265
getData()2266 uno::Sequence< uno::Sequence< double > > SwXTextTable::getData()
2267 {
2268 SolarMutexGuard aGuard;
2269 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2270 uno::Reference<chart::XChartDataArray> const xAllRange(
2271 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2272 uno::UNO_QUERY_THROW);
2273 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2274 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2275 return xAllRange->getData();
2276 }
2277
setData(const uno::Sequence<uno::Sequence<double>> & rData)2278 void SwXTextTable::setData(const uno::Sequence< uno::Sequence< double > >& rData)
2279 {
2280 SolarMutexGuard aGuard;
2281 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2282 uno::Reference<chart::XChartDataArray> const xAllRange(
2283 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2284 uno::UNO_QUERY_THROW);
2285 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2286 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2287 xAllRange->setData(rData);
2288 // this is rather inconsistent: setData on XTextTable sends events, but e.g. CellRanges do not
2289 std::unique_lock aGuard2(m_pImpl->m_Mutex);
2290 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
2291 }
2292
getRowDescriptions()2293 uno::Sequence<OUString> SwXTextTable::getRowDescriptions()
2294 {
2295 SolarMutexGuard aGuard;
2296 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2297 uno::Reference<chart::XChartDataArray> const xAllRange(
2298 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2299 uno::UNO_QUERY_THROW);
2300 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2301 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2302 return xAllRange->getRowDescriptions();
2303 }
2304
setRowDescriptions(const uno::Sequence<OUString> & rRowDesc)2305 void SwXTextTable::setRowDescriptions(const uno::Sequence<OUString>& rRowDesc)
2306 {
2307 SolarMutexGuard aGuard;
2308 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2309 uno::Reference<chart::XChartDataArray> const xAllRange(
2310 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2311 uno::UNO_QUERY_THROW);
2312 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2313 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2314 xAllRange->setRowDescriptions(rRowDesc);
2315 }
2316
getColumnDescriptions()2317 uno::Sequence<OUString> SwXTextTable::getColumnDescriptions()
2318 {
2319 SolarMutexGuard aGuard;
2320 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2321 uno::Reference<chart::XChartDataArray> const xAllRange(
2322 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2323 uno::UNO_QUERY_THROW);
2324 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2325 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2326 return xAllRange->getColumnDescriptions();
2327 }
2328
setColumnDescriptions(const uno::Sequence<OUString> & rColumnDesc)2329 void SwXTextTable::setColumnDescriptions(const uno::Sequence<OUString>& rColumnDesc)
2330 {
2331 SolarMutexGuard aGuard;
2332 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2333 uno::Reference<chart::XChartDataArray> const xAllRange(
2334 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2335 uno::UNO_QUERY_THROW);
2336 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2337 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2338 return xAllRange->setColumnDescriptions(rColumnDesc);
2339 }
2340
addChartDataChangeEventListener(const uno::Reference<chart::XChartDataChangeEventListener> & xListener)2341 void SAL_CALL SwXTextTable::addChartDataChangeEventListener(
2342 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
2343 {
2344 // no need to lock here as m_pImpl is const and container threadsafe
2345 std::unique_lock aGuard(m_pImpl->m_Mutex);
2346 m_pImpl->m_ChartListeners.addInterface(aGuard, xListener);
2347 }
2348
removeChartDataChangeEventListener(const uno::Reference<chart::XChartDataChangeEventListener> & xListener)2349 void SAL_CALL SwXTextTable::removeChartDataChangeEventListener(
2350 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
2351 {
2352 // no need to lock here as m_pImpl is const and container threadsafe
2353 std::unique_lock aGuard(m_pImpl->m_Mutex);
2354 m_pImpl->m_ChartListeners.removeInterface(aGuard, xListener);
2355 }
2356
isNotANumber(double nNumber)2357 sal_Bool SwXTextTable::isNotANumber(double nNumber)
2358 {
2359 // We use DBL_MIN because starcalc does (which uses it because chart
2360 // wants it that way!)
2361 return ( nNumber == DBL_MIN );
2362 }
2363
getNotANumber()2364 double SwXTextTable::getNotANumber()
2365 {
2366 // We use DBL_MIN because starcalc does (which uses it because chart
2367 // wants it that way!)
2368 return DBL_MIN;
2369 }
2370
createSortDescriptor()2371 uno::Sequence< beans::PropertyValue > SwXTextTable::createSortDescriptor()
2372 {
2373 SolarMutexGuard aGuard;
2374
2375 return SwUnoCursorHelper::CreateSortDescriptor(true);
2376 }
2377
sort(const uno::Sequence<beans::PropertyValue> & rDescriptor)2378 void SwXTextTable::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
2379 {
2380 SolarMutexGuard aGuard;
2381 SwSortOptions aSortOpt;
2382 SwFrameFormat* pFormat = GetFrameFormat();
2383 if(!(pFormat &&
2384 SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt)))
2385 return;
2386
2387 SwTable* pTable = SwTable::FindTable( pFormat );
2388 SwSelBoxes aBoxes;
2389 const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes();
2390 for (size_t n = 0; n < rTBoxes.size(); ++n)
2391 {
2392 SwTableBox* pBox = rTBoxes[ n ];
2393 aBoxes.insert( pBox );
2394 }
2395 UnoActionContext aContext( pFormat->GetDoc() );
2396 pFormat->GetDoc()->SortTable(aBoxes, aSortOpt);
2397 }
2398
autoFormat(const OUString & sAutoFormatName)2399 void SwXTextTable::autoFormat(const OUString& sAutoFormatName)
2400 {
2401 SolarMutexGuard aGuard;
2402 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
2403 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), this);
2404 SwTableAutoFormatTable aAutoFormatTable;
2405 aAutoFormatTable.Load();
2406 for (size_t i = aAutoFormatTable.size(); i;)
2407 if( sAutoFormatName == aAutoFormatTable[ --i ].GetName() )
2408 {
2409 SwSelBoxes aBoxes;
2410 const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes();
2411 for (size_t n = 0; n < rTBoxes.size(); ++n)
2412 {
2413 SwTableBox* pBox = rTBoxes[ n ];
2414 aBoxes.insert( pBox );
2415 }
2416 UnoActionContext aContext( pFormat->GetDoc() );
2417 pFormat->GetDoc()->SetTableAutoFormat( aBoxes, aAutoFormatTable[i] );
2418 break;
2419 }
2420 }
2421
getPropertySetInfo()2422 uno::Reference< beans::XPropertySetInfo > SwXTextTable::getPropertySetInfo()
2423 {
2424 static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo();
2425 return xRef;
2426 }
2427
setPropertyValue(const OUString & rPropertyName,const uno::Any & aValue)2428 void SwXTextTable::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
2429 {
2430 SolarMutexGuard aGuard;
2431 SwFrameFormat* pFormat = GetFrameFormat();
2432 if(!aValue.hasValue())
2433 throw lang::IllegalArgumentException();
2434 const SfxItemPropertyMapEntry* pEntry =
2435 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
2436 if( !pEntry )
2437 throw lang::IllegalArgumentException();
2438 if(pFormat)
2439 {
2440 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
2441 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() );
2442
2443 if(0xBF == pEntry->nMemberId)
2444 {
2445 lcl_SetSpecialProperty(pFormat, pEntry, aValue);
2446 }
2447 else
2448 {
2449 switch(pEntry->nWID)
2450 {
2451 case FN_UNO_TABLE_NAME :
2452 {
2453 OUString sName;
2454 aValue >>= sName;
2455 setName( sName );
2456 }
2457 break;
2458
2459 case FN_UNO_RANGE_ROW_LABEL:
2460 {
2461 bool bTmp = *o3tl::doAccess<bool>(aValue);
2462 if (m_pImpl->m_bFirstRowAsLabel != bTmp)
2463 {
2464 std::unique_lock aGuard2(m_pImpl->m_Mutex);
2465 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
2466 m_pImpl->m_bFirstRowAsLabel = bTmp;
2467 }
2468 }
2469 break;
2470
2471 case FN_UNO_RANGE_COL_LABEL:
2472 {
2473 bool bTmp = *o3tl::doAccess<bool>(aValue);
2474 if (m_pImpl->m_bFirstColumnAsLabel != bTmp)
2475 {
2476 std::unique_lock aGuard2(m_pImpl->m_Mutex);
2477 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
2478 m_pImpl->m_bFirstColumnAsLabel = bTmp;
2479 }
2480 }
2481 break;
2482
2483 case FN_UNO_TABLE_BORDER:
2484 case FN_UNO_TABLE_BORDER2:
2485 {
2486 table::TableBorder oldBorder;
2487 table::TableBorder2 aBorder;
2488 SvxBorderLine aTopLine;
2489 SvxBorderLine aBottomLine;
2490 SvxBorderLine aLeftLine;
2491 SvxBorderLine aRightLine;
2492 SvxBorderLine aHoriLine;
2493 SvxBorderLine aVertLine;
2494 if (aValue >>= oldBorder)
2495 {
2496 aBorder.IsTopLineValid = oldBorder.IsTopLineValid;
2497 aBorder.IsBottomLineValid = oldBorder.IsBottomLineValid;
2498 aBorder.IsLeftLineValid = oldBorder.IsLeftLineValid;
2499 aBorder.IsRightLineValid = oldBorder.IsRightLineValid;
2500 aBorder.IsHorizontalLineValid = oldBorder.IsHorizontalLineValid;
2501 aBorder.IsVerticalLineValid = oldBorder.IsVerticalLineValid;
2502 aBorder.Distance = oldBorder.Distance;
2503 aBorder.IsDistanceValid = oldBorder.IsDistanceValid;
2504 lcl_LineToSvxLine(
2505 oldBorder.TopLine, aTopLine);
2506 lcl_LineToSvxLine(
2507 oldBorder.BottomLine, aBottomLine);
2508 lcl_LineToSvxLine(
2509 oldBorder.LeftLine, aLeftLine);
2510 lcl_LineToSvxLine(
2511 oldBorder.RightLine, aRightLine);
2512 lcl_LineToSvxLine(
2513 oldBorder.HorizontalLine, aHoriLine);
2514 lcl_LineToSvxLine(
2515 oldBorder.VerticalLine, aVertLine);
2516 }
2517 else if (aValue >>= aBorder)
2518 {
2519 SvxBoxItem::LineToSvxLine(
2520 aBorder.TopLine, aTopLine, true);
2521 SvxBoxItem::LineToSvxLine(
2522 aBorder.BottomLine, aBottomLine, true);
2523 SvxBoxItem::LineToSvxLine(
2524 aBorder.LeftLine, aLeftLine, true);
2525 SvxBoxItem::LineToSvxLine(
2526 aBorder.RightLine, aRightLine, true);
2527 SvxBoxItem::LineToSvxLine(
2528 aBorder.HorizontalLine, aHoriLine, true);
2529 SvxBoxItem::LineToSvxLine(
2530 aBorder.VerticalLine, aVertLine, true);
2531 }
2532 else
2533 {
2534 break; // something else
2535 }
2536 SwDoc* pDoc = pFormat->GetDoc();
2537 if(!lcl_FormatTable(pFormat))
2538 break;
2539 SwTable* pTable = SwTable::FindTable( pFormat );
2540 SwTableLines &rLines = pTable->GetTabLines();
2541
2542 const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true);
2543 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2544 SwPosition aPos(*pSttNd);
2545 // set cursor to top left cell
2546 auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true));
2547 pUnoCursor->Move( fnMoveForward, GoInNode );
2548 pUnoCursor->SetRemainInSection( false );
2549
2550 const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false);
2551 pUnoCursor->SetMark();
2552 pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
2553 pUnoCursor->Move( fnMoveForward, GoInNode );
2554 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2555 // HACK: remove pending actions for selecting old style tables
2556 UnoActionRemoveContext aRemoveContext(rCursor);
2557 rCursor.MakeBoxSels();
2558
2559 SfxItemSetFixed<RES_BOX, RES_BOX,
2560 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
2561 aSet(pDoc->GetAttrPool());
2562
2563 SvxBoxItem aBox( RES_BOX );
2564 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
2565
2566 aBox.SetLine(aTopLine.isEmpty() ? nullptr : &aTopLine, SvxBoxItemLine::TOP);
2567 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, aBorder.IsTopLineValid);
2568
2569 aBox.SetLine(aBottomLine.isEmpty() ? nullptr : &aBottomLine, SvxBoxItemLine::BOTTOM);
2570 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::BOTTOM, aBorder.IsBottomLineValid);
2571
2572 aBox.SetLine(aLeftLine.isEmpty() ? nullptr : &aLeftLine, SvxBoxItemLine::LEFT);
2573 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, aBorder.IsLeftLineValid);
2574
2575 aBox.SetLine(aRightLine.isEmpty() ? nullptr : &aRightLine, SvxBoxItemLine::RIGHT);
2576 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::RIGHT, aBorder.IsRightLineValid);
2577
2578 aBoxInfo.SetLine(aHoriLine.isEmpty() ? nullptr : &aHoriLine, SvxBoxInfoItemLine::HORI);
2579 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI, aBorder.IsHorizontalLineValid);
2580
2581 aBoxInfo.SetLine(aVertLine.isEmpty() ? nullptr : &aVertLine, SvxBoxInfoItemLine::VERT);
2582 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT, aBorder.IsVerticalLineValid);
2583
2584 aBox.SetAllDistances(o3tl::toTwips(aBorder.Distance, o3tl::Length::mm100));
2585 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE, aBorder.IsDistanceValid);
2586
2587 aSet.Put(aBox);
2588 aSet.Put(aBoxInfo);
2589
2590 pDoc->SetTabBorders(rCursor, aSet);
2591 }
2592 break;
2593
2594 case FN_UNO_TABLE_BORDER_DISTANCES:
2595 {
2596 table::TableBorderDistances aTableBorderDistances;
2597 if( !(aValue >>= aTableBorderDistances) ||
2598 (!aTableBorderDistances.IsLeftDistanceValid &&
2599 !aTableBorderDistances.IsRightDistanceValid &&
2600 !aTableBorderDistances.IsTopDistanceValid &&
2601 !aTableBorderDistances.IsBottomDistanceValid ))
2602 break;
2603
2604 const sal_uInt16 nLeftDistance = o3tl::toTwips(aTableBorderDistances.LeftDistance, o3tl::Length::mm100);
2605 const sal_uInt16 nRightDistance = o3tl::toTwips(aTableBorderDistances.RightDistance, o3tl::Length::mm100);
2606 const sal_uInt16 nTopDistance = o3tl::toTwips(aTableBorderDistances.TopDistance, o3tl::Length::mm100);
2607 const sal_uInt16 nBottomDistance = o3tl::toTwips(aTableBorderDistances.BottomDistance, o3tl::Length::mm100);
2608 SwDoc* pDoc = pFormat->GetDoc();
2609 SwTable* pTable = SwTable::FindTable( pFormat );
2610 SwTableLines &rLines = pTable->GetTabLines();
2611 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr);
2612 for(size_t i = 0; i < rLines.size(); ++i)
2613 {
2614 SwTableLine* pLine = rLines[i];
2615 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2616 for(size_t k = 0; k < rBoxes.size(); ++k)
2617 {
2618 SwTableBox* pBox = rBoxes[k];
2619 const SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
2620 const SvxBoxItem& rBox = pBoxFormat->GetBox();
2621 if(
2622 (aTableBorderDistances.IsLeftDistanceValid && nLeftDistance != rBox.GetDistance( SvxBoxItemLine::LEFT )) ||
2623 (aTableBorderDistances.IsRightDistanceValid && nRightDistance != rBox.GetDistance( SvxBoxItemLine::RIGHT )) ||
2624 (aTableBorderDistances.IsTopDistanceValid && nTopDistance != rBox.GetDistance( SvxBoxItemLine::TOP )) ||
2625 (aTableBorderDistances.IsBottomDistanceValid && nBottomDistance != rBox.GetDistance( SvxBoxItemLine::BOTTOM )))
2626 {
2627 SvxBoxItem aSetBox( rBox );
2628 SwFrameFormat* pSetBoxFormat = pBox->ClaimFrameFormat();
2629 if( aTableBorderDistances.IsLeftDistanceValid )
2630 aSetBox.SetDistance( nLeftDistance, SvxBoxItemLine::LEFT );
2631 if( aTableBorderDistances.IsRightDistanceValid )
2632 aSetBox.SetDistance( nRightDistance, SvxBoxItemLine::RIGHT );
2633 if( aTableBorderDistances.IsTopDistanceValid )
2634 aSetBox.SetDistance( nTopDistance, SvxBoxItemLine::TOP );
2635 if( aTableBorderDistances.IsBottomDistanceValid )
2636 aSetBox.SetDistance( nBottomDistance, SvxBoxItemLine::BOTTOM );
2637 pDoc->SetAttr( aSetBox, *pSetBoxFormat );
2638 }
2639 }
2640 }
2641 pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr);
2642 }
2643 break;
2644
2645 case FN_UNO_TABLE_COLUMN_SEPARATORS:
2646 {
2647 UnoActionContext aContext(pFormat->GetDoc());
2648 SwTable* pTable = SwTable::FindTable( pFormat );
2649 lcl_SetTableSeparators(aValue, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false, pFormat->GetDoc());
2650 }
2651 break;
2652
2653 case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:/*_readonly_*/ break;
2654
2655 case FN_UNO_TABLE_TEMPLATE_NAME:
2656 {
2657 SwTable* pTable = SwTable::FindTable(pFormat);
2658 OUString sName;
2659 if (!(aValue >>= sName))
2660 break;
2661 SwStyleNameMapper::FillUIName(sName, sName, SwGetPoolIdFromName::TabStyle);
2662 pTable->SetTableStyleName(sName);
2663 SwDoc* pDoc = pFormat->GetDoc();
2664 if (SwFEShell* pFEShell = pDoc->GetDocShell()->GetFEShell())
2665 pFEShell->UpdateTableStyleFormatting(pTable->GetTableNode());
2666 }
2667 break;
2668
2669 default:
2670 {
2671 SwAttrSet aSet(pFormat->GetAttrSet());
2672 SfxItemPropertySet::setPropertyValue(*pEntry, aValue, aSet);
2673 pFormat->GetDoc()->SetAttr(aSet, *pFormat);
2674 }
2675 }
2676 }
2677 }
2678 else if (m_pImpl->IsDescriptor())
2679 {
2680 m_pImpl->m_pTableProps->SetProperty(pEntry->nWID, pEntry->nMemberId, aValue);
2681 }
2682 else
2683 throw uno::RuntimeException();
2684 }
2685
getPropertyValue(const OUString & rPropertyName)2686 uno::Any SwXTextTable::getPropertyValue(const OUString& rPropertyName)
2687 {
2688 SolarMutexGuard aGuard;
2689 uno::Any aRet;
2690 SwFrameFormat* pFormat = GetFrameFormat();
2691 const SfxItemPropertyMapEntry* pEntry =
2692 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
2693
2694 if (!pEntry)
2695 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
2696
2697 if(pFormat)
2698 {
2699 if(0xBF == pEntry->nMemberId)
2700 {
2701 aRet = lcl_GetSpecialProperty(pFormat, pEntry );
2702 }
2703 else
2704 {
2705 switch(pEntry->nWID)
2706 {
2707 case FN_UNO_TABLE_NAME:
2708 {
2709 aRet <<= getName();
2710 }
2711 break;
2712
2713 case FN_UNO_ANCHOR_TYPES:
2714 case FN_UNO_TEXT_WRAP:
2715 case FN_UNO_ANCHOR_TYPE:
2716 (void)::sw::GetDefaultTextContentValue(
2717 aRet, u"", pEntry->nWID);
2718 break;
2719
2720 case FN_UNO_RANGE_ROW_LABEL:
2721 {
2722 aRet <<= m_pImpl->m_bFirstRowAsLabel;
2723 }
2724 break;
2725
2726 case FN_UNO_RANGE_COL_LABEL:
2727 aRet <<= m_pImpl->m_bFirstColumnAsLabel;
2728 break;
2729
2730 case FN_UNO_TABLE_BORDER:
2731 case FN_UNO_TABLE_BORDER2:
2732 {
2733 SwDoc* pDoc = pFormat->GetDoc();
2734 // tables without layout (invisible header/footer?)
2735 if(!lcl_FormatTable(pFormat))
2736 break;
2737 SwTable* pTable = SwTable::FindTable( pFormat );
2738 SwTableLines &rLines = pTable->GetTabLines();
2739
2740 const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true);
2741 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2742 SwPosition aPos(*pSttNd);
2743 // set cursor to top left cell
2744 auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true));
2745 pUnoCursor->Move( fnMoveForward, GoInNode );
2746 pUnoCursor->SetRemainInSection( false );
2747
2748 const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false);
2749 pUnoCursor->SetMark();
2750 const SwStartNode* pLastNd = pBRBox->GetSttNd();
2751 pUnoCursor->GetPoint()->Assign( *pLastNd );
2752
2753 pUnoCursor->Move( fnMoveForward, GoInNode );
2754 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2755 // HACK: remove pending actions for selecting old style tables
2756 UnoActionRemoveContext aRemoveContext(rCursor);
2757 rCursor.MakeBoxSels();
2758
2759 SfxItemSetFixed<RES_BOX, RES_BOX,
2760 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
2761 aSet(pDoc->GetAttrPool());
2762 aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER ));
2763 SwDoc::GetTabBorders(rCursor, aSet);
2764 const SvxBoxInfoItem& rBoxInfoItem = aSet.Get(SID_ATTR_BORDER_INNER);
2765 const SvxBoxItem& rBox = aSet.Get(RES_BOX);
2766
2767 if (FN_UNO_TABLE_BORDER == pEntry->nWID)
2768 {
2769 table::TableBorder aTableBorder;
2770 aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true);
2771 aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
2772 aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true);
2773 aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
2774 aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true);
2775 aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
2776 aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true);
2777 aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
2778 aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true);
2779 aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
2780 aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true);
2781 aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
2782 aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance());
2783 aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
2784 aRet <<= aTableBorder;
2785 }
2786 else
2787 {
2788 table::TableBorder2 aTableBorder;
2789 aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true);
2790 aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
2791 aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true);
2792 aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
2793 aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true);
2794 aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
2795 aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true);
2796 aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
2797 aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true);
2798 aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
2799 aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true);
2800 aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
2801 aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance());
2802 aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
2803 aRet <<= aTableBorder;
2804 }
2805 }
2806 break;
2807
2808 case FN_UNO_TABLE_BORDER_DISTANCES :
2809 {
2810 table::TableBorderDistances aTableBorderDistances( 0, true, 0, true, 0, true, 0, true ) ;
2811 SwTable* pTable = SwTable::FindTable( pFormat );
2812 const SwTableLines &rLines = pTable->GetTabLines();
2813 bool bFirst = true;
2814 sal_uInt16 nLeftDistance = 0;
2815 sal_uInt16 nRightDistance = 0;
2816 sal_uInt16 nTopDistance = 0;
2817 sal_uInt16 nBottomDistance = 0;
2818
2819 for(size_t i = 0; i < rLines.size(); ++i)
2820 {
2821 const SwTableLine* pLine = rLines[i];
2822 const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2823 for(size_t k = 0; k < rBoxes.size(); ++k)
2824 {
2825 const SwTableBox* pBox = rBoxes[k];
2826 SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
2827 const SvxBoxItem& rBox = pBoxFormat->GetBox();
2828 if( bFirst )
2829 {
2830 nLeftDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT ));
2831 nRightDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT ));
2832 nTopDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP ));
2833 nBottomDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM ));
2834 bFirst = false;
2835 }
2836 else
2837 {
2838 if( aTableBorderDistances.IsLeftDistanceValid &&
2839 nLeftDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT )))
2840 aTableBorderDistances.IsLeftDistanceValid = false;
2841 if( aTableBorderDistances.IsRightDistanceValid &&
2842 nRightDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT )))
2843 aTableBorderDistances.IsRightDistanceValid = false;
2844 if( aTableBorderDistances.IsTopDistanceValid &&
2845 nTopDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP )))
2846 aTableBorderDistances.IsTopDistanceValid = false;
2847 if( aTableBorderDistances.IsBottomDistanceValid &&
2848 nBottomDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM )))
2849 aTableBorderDistances.IsBottomDistanceValid = false;
2850 }
2851
2852 }
2853 if( !aTableBorderDistances.IsLeftDistanceValid &&
2854 !aTableBorderDistances.IsRightDistanceValid &&
2855 !aTableBorderDistances.IsTopDistanceValid &&
2856 !aTableBorderDistances.IsBottomDistanceValid )
2857 break;
2858 }
2859 if( aTableBorderDistances.IsLeftDistanceValid)
2860 aTableBorderDistances.LeftDistance = nLeftDistance;
2861 if( aTableBorderDistances.IsRightDistanceValid)
2862 aTableBorderDistances.RightDistance = nRightDistance;
2863 if( aTableBorderDistances.IsTopDistanceValid)
2864 aTableBorderDistances.TopDistance = nTopDistance;
2865 if( aTableBorderDistances.IsBottomDistanceValid)
2866 aTableBorderDistances.BottomDistance = nBottomDistance;
2867
2868 aRet <<= aTableBorderDistances;
2869 }
2870 break;
2871
2872 case FN_UNO_TABLE_COLUMN_SEPARATORS:
2873 {
2874 SwTable* pTable = SwTable::FindTable( pFormat );
2875 lcl_GetTableSeparators(aRet, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false);
2876 }
2877 break;
2878
2879 case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:
2880 aRet <<= sal_Int16(UNO_TABLE_COLUMN_SUM);
2881 break;
2882
2883 case RES_ANCHOR:
2884 // AnchorType is readonly and might be void (no return value)
2885 break;
2886
2887 case FN_UNO_TEXT_SECTION:
2888 {
2889 SwTable* pTable = SwTable::FindTable( pFormat );
2890 SwTableNode* pTableNode = pTable->GetTableNode();
2891 SwSectionNode* pSectionNode = pTableNode->FindSectionNode();
2892 if(pSectionNode)
2893 {
2894 SwSection& rSect = pSectionNode->GetSection();
2895 rtl::Reference< SwXTextSection > xSect =
2896 SwXTextSections::GetObject( *rSect.GetFormat() );
2897 aRet <<= uno::Reference< text::XTextSection >(xSect);
2898 }
2899 }
2900 break;
2901
2902 case FN_UNO_TABLE_TEMPLATE_NAME:
2903 {
2904 SwTable* pTable = SwTable::FindTable(pFormat);
2905 OUString sName;
2906 SwStyleNameMapper::FillProgName(pTable->GetTableStyleName(), sName, SwGetPoolIdFromName::TabStyle);
2907 aRet <<= sName;
2908 }
2909 break;
2910
2911 default:
2912 {
2913 const SwAttrSet& rSet = pFormat->GetAttrSet();
2914 SfxItemPropertySet::getPropertyValue(*pEntry, rSet, aRet);
2915 }
2916 }
2917 }
2918 }
2919 else if (m_pImpl->IsDescriptor())
2920 {
2921 const uno::Any* pAny = nullptr;
2922 if (!m_pImpl->m_pTableProps->GetProperty(pEntry->nWID, pEntry->nMemberId, pAny))
2923 throw lang::IllegalArgumentException();
2924 else if(pAny)
2925 aRet = *pAny;
2926 }
2927 else
2928 throw uno::RuntimeException();
2929 return aRet;
2930 }
2931
addPropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)2932 void SwXTextTable::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
2933 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
2934
removePropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)2935 void SwXTextTable::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
2936 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
2937
addVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)2938 void SwXTextTable::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
2939 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
2940
removeVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)2941 void SwXTextTable::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
2942 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
2943
getName()2944 OUString SwXTextTable::getName()
2945 {
2946 SolarMutexGuard aGuard;
2947 SwFrameFormat* pFormat = GetFrameFormat();
2948 if (!pFormat && !m_pImpl->IsDescriptor())
2949 throw uno::RuntimeException();
2950 if(pFormat)
2951 {
2952 return pFormat->GetName();
2953 }
2954 return m_pImpl->m_sTableName;
2955 }
2956
setName(const OUString & rName)2957 void SwXTextTable::setName(const OUString& rName)
2958 {
2959 SolarMutexGuard aGuard;
2960 SwFrameFormat* pFormat = GetFrameFormat();
2961 if ((!pFormat && !m_pImpl->IsDescriptor()) ||
2962 rName.isEmpty() ||
2963 rName.indexOf('.')>=0 ||
2964 rName.indexOf(' ')>=0 )
2965 throw uno::RuntimeException();
2966
2967 if(pFormat)
2968 {
2969 const OUString aOldName( pFormat->GetName() );
2970 const sw::TableFrameFormats* pFrameFormats = pFormat->GetDoc()->GetTableFrameFormats();
2971 for (size_t i = pFrameFormats->size(); i;)
2972 {
2973 const SwTableFormat* pTmpFormat = (*pFrameFormats)[--i];
2974 if( !pTmpFormat->IsDefault() &&
2975 pTmpFormat->GetName() == rName &&
2976 pFormat->GetDoc()->IsUsed( *pTmpFormat ))
2977 {
2978 throw uno::RuntimeException();
2979 }
2980 }
2981
2982 pFormat->SetFormatName( rName );
2983
2984 SwStartNode *pStNd;
2985 SwNodeIndex aIdx( *pFormat->GetDoc()->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
2986 while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
2987 {
2988 ++aIdx;
2989 SwNode *const pNd = & aIdx.GetNode();
2990 if ( pNd->IsOLENode() &&
2991 aOldName == static_cast<const SwOLENode*>(pNd)->GetChartTableName() )
2992 {
2993 static_cast<SwOLENode*>(pNd)->SetChartTableName( rName );
2994
2995 SwTable* pTable = SwTable::FindTable( pFormat );
2996 //TL_CHART2: chart needs to be notified about name changes
2997 pFormat->GetDoc()->UpdateCharts( pTable->GetFrameFormat()->GetName() );
2998 }
2999 aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
3000 }
3001 pFormat->GetDoc()->getIDocumentState().SetModified();
3002 }
3003 else
3004 m_pImpl->m_sTableName = rName;
3005 }
3006
GetRowCount()3007 sal_uInt16 SwXTextTable::Impl::GetRowCount()
3008 {
3009 sal_uInt16 nRet = 0;
3010 SwFrameFormat* pFormat = GetFrameFormat();
3011 if(pFormat)
3012 {
3013 SwTable* pTable = SwTable::FindTable( pFormat );
3014 if(!pTable->IsTableComplex())
3015 {
3016 nRet = pTable->GetTabLines().size();
3017 }
3018 }
3019 return nRet;
3020 }
3021
GetColumnCount()3022 sal_uInt16 SwXTextTable::Impl::GetColumnCount()
3023 {
3024 SwFrameFormat* pFormat = GetFrameFormat();
3025 sal_uInt16 nRet = 0;
3026 if(pFormat)
3027 {
3028 SwTable* pTable = SwTable::FindTable( pFormat );
3029 if(!pTable->IsTableComplex())
3030 {
3031 SwTableLines& rLines = pTable->GetTabLines();
3032 SwTableLine* pLine = rLines.front();
3033 nRet = pLine->GetTabBoxes().size();
3034 }
3035 }
3036 return nRet;
3037 }
3038
Notify(const SfxHint & rHint)3039 void SwXTextTable::Impl::Notify(const SfxHint& rHint)
3040 {
3041 if(rHint.GetId() == SfxHintId::Dying)
3042 {
3043 m_pFrameFormat = nullptr;
3044 EndListeningAll();
3045 }
3046 std::unique_lock aGuard(m_Mutex);
3047 if (m_EventListeners.getLength(aGuard) == 0 && m_ChartListeners.getLength(aGuard) == 0)
3048 return;
3049 uno::Reference<uno::XInterface> const xThis(m_wThis);
3050 // fdo#72695: if UNO object is already dead, don't revive it with event
3051 if (!xThis)
3052 return;
3053 if(!m_pFrameFormat)
3054 {
3055 lang::EventObject const ev(xThis);
3056 m_EventListeners.disposeAndClear(aGuard, ev);
3057 m_ChartListeners.disposeAndClear(aGuard, ev);
3058 }
3059 else
3060 {
3061 lcl_SendChartEvent(aGuard, xThis, m_ChartListeners);
3062 }
3063 }
3064
getImplementationName()3065 OUString SAL_CALL SwXTextTable::getImplementationName()
3066 { return u"SwXTextTable"_ustr; }
3067
supportsService(const OUString & rServiceName)3068 sal_Bool SwXTextTable::supportsService(const OUString& rServiceName)
3069 { return cppu::supportsService(this, rServiceName); }
3070
getSupportedServiceNames()3071 uno::Sequence<OUString> SwXTextTable::getSupportedServiceNames()
3072 {
3073 return {
3074 u"com.sun.star.document.LinkTarget"_ustr,
3075 u"com.sun.star.text.TextTable"_ustr,
3076 u"com.sun.star.text.TextContent"_ustr,
3077 u"com.sun.star.text.TextSortable"_ustr };
3078 }
3079
3080
3081 class SwXCellRange::Impl
3082 : public SvtListener
3083 {
3084 private:
3085 SwFrameFormat* m_pFrameFormat;
3086
3087 public:
3088 uno::WeakReference<uno::XInterface> m_wThis;
3089 std::mutex m_Mutex; // just for OInterfaceContainerHelper4
3090 ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> m_ChartListeners;
3091
3092 sw::UnoCursorPointer m_pTableCursor;
3093
3094 SwRangeDescriptor m_RangeDescriptor;
3095 const SfxItemPropertySet* m_pPropSet;
3096
3097 bool m_bFirstRowAsLabel;
3098 bool m_bFirstColumnAsLabel;
3099
Impl(sw::UnoCursorPointer const & pCursor,SwFrameFormat & rFrameFormat,SwRangeDescriptor const & rDesc)3100 Impl(sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat, SwRangeDescriptor const& rDesc)
3101 : m_pFrameFormat(&rFrameFormat)
3102 , m_pTableCursor(pCursor)
3103 , m_RangeDescriptor(rDesc)
3104 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_RANGE))
3105 , m_bFirstRowAsLabel(false)
3106 , m_bFirstColumnAsLabel(false)
3107 {
3108 StartListening(rFrameFormat.GetNotifier());
3109 m_RangeDescriptor.Normalize();
3110 }
3111
GetFrameFormat()3112 SwFrameFormat* GetFrameFormat()
3113 {
3114 return m_pFrameFormat;
3115 }
3116
3117 std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32> GetLabelCoordinates(bool bRow);
3118
3119 uno::Sequence<OUString> GetLabelDescriptions(SwXCellRange & rThis, bool bRow);
3120
3121 void SetLabelDescriptions(SwXCellRange & rThis,
3122 const css::uno::Sequence<OUString>& rDesc, bool bRow);
3123
3124 sal_Int32 GetRowCount() const;
3125 sal_Int32 GetColumnCount() const;
3126
3127 virtual void Notify(const SfxHint& ) override;
3128
3129 };
3130
getImplementationName()3131 OUString SwXCellRange::getImplementationName()
3132 { return u"SwXCellRange"_ustr; }
3133
supportsService(const OUString & rServiceName)3134 sal_Bool SwXCellRange::supportsService(const OUString& rServiceName)
3135 { return cppu::supportsService(this, rServiceName); }
3136
getSupportedServiceNames()3137 uno::Sequence<OUString> SwXCellRange::getSupportedServiceNames()
3138 {
3139 return {
3140 u"com.sun.star.text.CellRange"_ustr,
3141 u"com.sun.star.style.CharacterProperties"_ustr,
3142 u"com.sun.star.style.CharacterPropertiesAsian"_ustr,
3143 u"com.sun.star.style.CharacterPropertiesComplex"_ustr,
3144 u"com.sun.star.style.ParagraphProperties"_ustr,
3145 u"com.sun.star.style.ParagraphPropertiesAsian"_ustr,
3146 u"com.sun.star.style.ParagraphPropertiesComplex"_ustr };
3147 }
3148
SwXCellRange(sw::UnoCursorPointer const & pCursor,SwFrameFormat & rFrameFormat,SwRangeDescriptor const & rDesc)3149 SwXCellRange::SwXCellRange(sw::UnoCursorPointer const& pCursor,
3150 SwFrameFormat& rFrameFormat, SwRangeDescriptor const & rDesc)
3151 : m_pImpl(new Impl(pCursor, rFrameFormat, rDesc))
3152 {
3153 }
3154
~SwXCellRange()3155 SwXCellRange::~SwXCellRange()
3156 {
3157 }
3158
CreateXCellRange(sw::UnoCursorPointer const & pCursor,SwFrameFormat & rFrameFormat,SwRangeDescriptor const & rDesc)3159 rtl::Reference<SwXCellRange> SwXCellRange::CreateXCellRange(
3160 sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat,
3161 SwRangeDescriptor const & rDesc)
3162 {
3163 rtl::Reference<SwXCellRange> pCellRange(new SwXCellRange(pCursor, rFrameFormat, rDesc));
3164 // need a permanent Reference to initialize m_wThis
3165 pCellRange->m_pImpl->m_wThis = uno::Reference<table::XCellRange>(pCellRange);
3166 return pCellRange;
3167 }
3168
SetLabels(bool bFirstRowAsLabel,bool bFirstColumnAsLabel)3169 void SwXCellRange::SetLabels(bool bFirstRowAsLabel, bool bFirstColumnAsLabel)
3170 {
3171 m_pImpl->m_bFirstRowAsLabel = bFirstRowAsLabel;
3172 m_pImpl->m_bFirstColumnAsLabel = bFirstColumnAsLabel;
3173 }
3174
GetCells()3175 std::vector< uno::Reference< table::XCell > > SwXCellRange::GetCells()
3176 {
3177 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3178 const sal_Int32 nRowCount(m_pImpl->GetRowCount());
3179 const sal_Int32 nColCount(m_pImpl->GetColumnCount());
3180 std::vector< uno::Reference< table::XCell > > vResult;
3181 vResult.reserve(static_cast<size_t>(nRowCount)*static_cast<size_t>(nColCount));
3182 for(sal_Int32 nRow = 0; nRow < nRowCount; ++nRow)
3183 for(sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
3184 vResult.emplace_back(lcl_CreateXCell(pFormat, m_pImpl->m_RangeDescriptor.nLeft + nCol, m_pImpl->m_RangeDescriptor.nTop + nRow));
3185 return vResult;
3186 }
3187
3188 uno::Reference<table::XCell> SAL_CALL
getCellByPosition(sal_Int32 nColumn,sal_Int32 nRow)3189 SwXCellRange::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow)
3190 {
3191 SolarMutexGuard aGuard;
3192 uno::Reference< table::XCell > aRet;
3193 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3194 if(pFormat)
3195 {
3196 if(nColumn >= 0 && nRow >= 0 &&
3197 m_pImpl->GetColumnCount() > nColumn && m_pImpl->GetRowCount() > nRow )
3198 {
3199 rtl::Reference<SwXCell> pXCell = lcl_CreateXCell(pFormat,
3200 m_pImpl->m_RangeDescriptor.nLeft + nColumn,
3201 m_pImpl->m_RangeDescriptor.nTop + nRow);
3202 if(pXCell)
3203 aRet = pXCell;
3204 }
3205 }
3206 if(!aRet.is())
3207 throw lang::IndexOutOfBoundsException();
3208 return aRet;
3209 }
3210
3211 uno::Reference<table::XCellRange> SAL_CALL
getCellRangeByPosition(sal_Int32 nLeft,sal_Int32 nTop,sal_Int32 nRight,sal_Int32 nBottom)3212 SwXCellRange::getCellRangeByPosition(
3213 sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom)
3214 {
3215 SolarMutexGuard aGuard;
3216 rtl::Reference< SwXCellRange > aRet;
3217 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3218 if (pFormat && m_pImpl->GetColumnCount() > nRight
3219 && m_pImpl->GetRowCount() > nBottom &&
3220 nLeft <= nRight && nTop <= nBottom
3221 && nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 )
3222 {
3223 SwTable* pTable = SwTable::FindTable( pFormat );
3224 if(!pTable->IsTableComplex())
3225 {
3226 SwRangeDescriptor aNewDesc;
3227 aNewDesc.nTop = nTop + m_pImpl->m_RangeDescriptor.nTop;
3228 aNewDesc.nBottom = nBottom + m_pImpl->m_RangeDescriptor.nTop;
3229 aNewDesc.nLeft = nLeft + m_pImpl->m_RangeDescriptor.nLeft;
3230 aNewDesc.nRight = nRight + m_pImpl->m_RangeDescriptor.nLeft;
3231 aNewDesc.Normalize();
3232 const OUString sTLName = sw_GetCellName(aNewDesc.nLeft, aNewDesc.nTop);
3233 const OUString sBRName = sw_GetCellName(aNewDesc.nRight, aNewDesc.nBottom);
3234 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
3235 if(pTLBox)
3236 {
3237 const SwStartNode* pSttNd = pTLBox->GetSttNd();
3238 SwPosition aPos(*pSttNd);
3239 // set cursor in the upper-left cell of the range
3240 auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true));
3241 pUnoCursor->Move( fnMoveForward, GoInNode );
3242 pUnoCursor->SetRemainInSection( false );
3243 const SwTableBox* pBRBox = pTable->GetTableBox( sBRName );
3244 if(pBRBox)
3245 {
3246 pUnoCursor->SetMark();
3247 pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
3248 pUnoCursor->Move( fnMoveForward, GoInNode );
3249 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
3250 // HACK: remove pending actions for selecting old style tables
3251 UnoActionRemoveContext aRemoveContext(rCursor);
3252 rCursor.MakeBoxSels();
3253 // pUnoCursor will be provided and will not be deleted
3254 aRet = SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, aNewDesc).get();
3255 }
3256 }
3257 }
3258 }
3259 if(!aRet.is())
3260 throw lang::IndexOutOfBoundsException();
3261 return aRet;
3262 }
3263
3264 uno::Reference<table::XCellRange> SAL_CALL
getCellRangeByName(const OUString & rRange)3265 SwXCellRange::getCellRangeByName(const OUString& rRange)
3266 {
3267 SolarMutexGuard aGuard;
3268 sal_Int32 nPos = 0;
3269 const OUString sTLName(rRange.getToken(0, ':', nPos));
3270 const OUString sBRName(rRange.getToken(0, ':', nPos));
3271 if(sTLName.isEmpty() || sBRName.isEmpty())
3272 throw uno::RuntimeException();
3273 SwRangeDescriptor aDesc;
3274 aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1;
3275 SwXTextTable::GetCellPosition( sTLName, aDesc.nLeft, aDesc.nTop );
3276 SwXTextTable::GetCellPosition( sBRName, aDesc.nRight, aDesc.nBottom );
3277 aDesc.Normalize();
3278 return getCellRangeByPosition(
3279 aDesc.nLeft - m_pImpl->m_RangeDescriptor.nLeft,
3280 aDesc.nTop - m_pImpl->m_RangeDescriptor.nTop,
3281 aDesc.nRight - m_pImpl->m_RangeDescriptor.nLeft,
3282 aDesc.nBottom - m_pImpl->m_RangeDescriptor.nTop);
3283 }
3284
getPropertySetInfo()3285 uno::Reference< beans::XPropertySetInfo > SwXCellRange::getPropertySetInfo()
3286 {
3287 static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo();
3288 return xRef;
3289 }
3290
3291 void SAL_CALL
setPropertyValue(const OUString & rPropertyName,const uno::Any & aValue)3292 SwXCellRange::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
3293 {
3294 SolarMutexGuard aGuard;
3295 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3296 if(!pFormat)
3297 return;
3298
3299 const SfxItemPropertyMapEntry *const pEntry =
3300 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
3301 if(!pEntry)
3302 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
3303
3304 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
3305 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() );
3306
3307 SwDoc& rDoc = m_pImpl->m_pTableCursor->GetDoc();
3308 SwUnoTableCursor& rCursor(dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor));
3309 {
3310 // HACK: remove pending actions for selecting old style tables
3311 UnoActionRemoveContext aRemoveContext(rCursor);
3312 }
3313 rCursor.MakeBoxSels();
3314 switch(pEntry->nWID )
3315 {
3316 case FN_UNO_TABLE_CELL_BACKGROUND:
3317 {
3318 std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
3319 SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush);
3320 aBrush->PutValue(aValue, pEntry->nMemberId);
3321 rDoc.SetBoxAttr(*m_pImpl->m_pTableCursor, *aBrush);
3322
3323 }
3324 break;
3325 case RES_BOX :
3326 {
3327 SfxItemSetFixed<RES_BOX, RES_BOX,
3328 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
3329 aSet(rDoc.GetAttrPool());
3330 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
3331 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::ALL, false);
3332 SvxBoxInfoItemValidFlags nValid = SvxBoxInfoItemValidFlags::NONE;
3333 switch(pEntry->nMemberId & ~CONVERT_TWIPS)
3334 {
3335 case LEFT_BORDER : nValid = SvxBoxInfoItemValidFlags::LEFT; break;
3336 case RIGHT_BORDER: nValid = SvxBoxInfoItemValidFlags::RIGHT; break;
3337 case TOP_BORDER : nValid = SvxBoxInfoItemValidFlags::TOP; break;
3338 case BOTTOM_BORDER: nValid = SvxBoxInfoItemValidFlags::BOTTOM; break;
3339 case LEFT_BORDER_DISTANCE :
3340 case RIGHT_BORDER_DISTANCE:
3341 case TOP_BORDER_DISTANCE :
3342 case BOTTOM_BORDER_DISTANCE:
3343 nValid = SvxBoxInfoItemValidFlags::DISTANCE;
3344 break;
3345 }
3346 aBoxInfo.SetValid(nValid);
3347
3348 aSet.Put(aBoxInfo);
3349 SwDoc::GetTabBorders(rCursor, aSet);
3350
3351 aSet.Put(aBoxInfo);
3352 SvxBoxItem aBoxItem(aSet.Get(RES_BOX));
3353 static_cast<SfxPoolItem&>(aBoxItem).PutValue(aValue, pEntry->nMemberId);
3354 aSet.Put(aBoxItem);
3355 rDoc.SetTabBorders(*m_pImpl->m_pTableCursor, aSet);
3356 }
3357 break;
3358 case RES_BOXATR_FORMAT:
3359 {
3360 SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT);
3361 static_cast<SfxPoolItem&>(aNumberFormat).PutValue(aValue, 0);
3362 rDoc.SetBoxAttr(rCursor, aNumberFormat);
3363 }
3364 break;
3365 case FN_UNO_RANGE_ROW_LABEL:
3366 {
3367 bool bTmp = *o3tl::doAccess<bool>(aValue);
3368 if (m_pImpl->m_bFirstRowAsLabel != bTmp)
3369 {
3370 std::unique_lock aGuard2(m_pImpl->m_Mutex);
3371 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
3372 m_pImpl->m_bFirstRowAsLabel = bTmp;
3373 }
3374 }
3375 break;
3376 case FN_UNO_RANGE_COL_LABEL:
3377 {
3378 bool bTmp = *o3tl::doAccess<bool>(aValue);
3379 if (m_pImpl->m_bFirstColumnAsLabel != bTmp)
3380 {
3381 std::unique_lock aGuard2(m_pImpl->m_Mutex);
3382 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
3383 m_pImpl->m_bFirstColumnAsLabel = bTmp;
3384 }
3385 }
3386 break;
3387 case RES_VERT_ORIENT:
3388 {
3389 sal_Int16 nAlign = -1;
3390 aValue >>= nAlign;
3391 if( nAlign >= text::VertOrientation::NONE && nAlign <= text::VertOrientation::BOTTOM)
3392 rDoc.SetBoxAlign( rCursor, nAlign );
3393 }
3394 break;
3395 default:
3396 {
3397 SfxItemSet aItemSet( rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID );
3398 SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(),
3399 aItemSet);
3400
3401 if (!SwUnoCursorHelper::SetCursorPropertyValue(
3402 *pEntry, aValue, rCursor.GetSelRing(), aItemSet))
3403 {
3404 SfxItemPropertySet::setPropertyValue(*pEntry, aValue, aItemSet);
3405 }
3406 SwUnoCursorHelper::SetCursorAttr(rCursor.GetSelRing(),
3407 aItemSet, SetAttrMode::DEFAULT, true);
3408 }
3409 }
3410 }
3411
getPropertyValue(const OUString & rPropertyName)3412 uno::Any SAL_CALL SwXCellRange::getPropertyValue(const OUString& rPropertyName)
3413 {
3414 SolarMutexGuard aGuard;
3415 uno::Any aRet;
3416 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3417 if(pFormat)
3418 {
3419 const SfxItemPropertyMapEntry *const pEntry =
3420 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
3421 if(!pEntry)
3422 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
3423
3424 switch(pEntry->nWID )
3425 {
3426 case FN_UNO_TABLE_CELL_BACKGROUND:
3427 {
3428 std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
3429 if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush))
3430 aBrush->QueryValue(aRet, pEntry->nMemberId);
3431
3432 }
3433 break;
3434 case RES_BOX :
3435 {
3436 SwDoc& rDoc = m_pImpl->m_pTableCursor->GetDoc();
3437 SfxItemSetFixed<RES_BOX, RES_BOX,
3438 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
3439 aSet(rDoc.GetAttrPool());
3440 aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER ));
3441 SwDoc::GetTabBorders(*m_pImpl->m_pTableCursor, aSet);
3442 const SvxBoxItem& rBoxItem = aSet.Get(RES_BOX);
3443 rBoxItem.QueryValue(aRet, pEntry->nMemberId);
3444 }
3445 break;
3446 case RES_BOXATR_FORMAT:
3447 OSL_FAIL("not implemented");
3448 break;
3449 case FN_UNO_PARA_STYLE:
3450 {
3451 SwFormatColl *const pTmpFormat =
3452 SwUnoCursorHelper::GetCurTextFormatColl(*m_pImpl->m_pTableCursor, false);
3453 OUString sRet;
3454 if (pTmpFormat)
3455 sRet = pTmpFormat->GetName();
3456 aRet <<= sRet;
3457 }
3458 break;
3459 case FN_UNO_RANGE_ROW_LABEL:
3460 aRet <<= m_pImpl->m_bFirstRowAsLabel;
3461 break;
3462 case FN_UNO_RANGE_COL_LABEL:
3463 aRet <<= m_pImpl->m_bFirstColumnAsLabel;
3464 break;
3465 case RES_VERT_ORIENT:
3466 {
3467 std::unique_ptr<SfxPoolItem> aVertOrient(
3468 std::make_unique<SwFormatVertOrient>(RES_VERT_ORIENT));
3469 if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aVertOrient))
3470 {
3471 aVertOrient->QueryValue( aRet, pEntry->nMemberId );
3472 }
3473 }
3474 break;
3475 default:
3476 {
3477 SfxItemSetFixed<
3478 RES_CHRATR_BEGIN, RES_FRMATR_END - 1,
3479 RES_UNKNOWNATR_CONTAINER,
3480 RES_UNKNOWNATR_CONTAINER>
3481 aSet(m_pImpl->m_pTableCursor->GetDoc().GetAttrPool());
3482 // first look at the attributes of the cursor
3483 SwUnoTableCursor& rCursor =
3484 dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor);
3485 SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(), aSet);
3486 SfxItemPropertySet::getPropertyValue(*pEntry, aSet, aRet);
3487 }
3488 }
3489
3490 }
3491 return aRet;
3492 }
3493
addPropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)3494 void SwXCellRange::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
3495 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
3496
removePropertyChangeListener(const OUString &,const uno::Reference<beans::XPropertyChangeListener> &)3497 void SwXCellRange::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
3498 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
3499
addVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)3500 void SwXCellRange::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
3501 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
3502
removeVetoableChangeListener(const OUString &,const uno::Reference<beans::XVetoableChangeListener> &)3503 void SwXCellRange::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
3504 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
3505
3506 ///@see SwXCellRange::getData
getDataArray()3507 uno::Sequence<uno::Sequence<uno::Any>> SAL_CALL SwXCellRange::getDataArray()
3508 {
3509 SolarMutexGuard aGuard;
3510 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3511 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3512 if(!nRowCount || !nColCount)
3513 throw uno::RuntimeException(u"Table too complex"_ustr, getXWeak());
3514 lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), this);
3515 uno::Sequence< uno::Sequence< uno::Any > > aRowSeq(nRowCount);
3516 auto vCells(GetCells());
3517 auto pCurrentCell(vCells.begin());
3518 for(auto& rRow : asNonConstRange(aRowSeq))
3519 {
3520 rRow = uno::Sequence< uno::Any >(nColCount);
3521 for(auto& rCellAny : asNonConstRange(rRow))
3522 {
3523 auto pCell(static_cast<SwXCell*>(pCurrentCell->get()));
3524 if(!pCell)
3525 throw uno::RuntimeException(u"Table too complex"_ustr, getXWeak());
3526 rCellAny = pCell->GetAny();
3527 ++pCurrentCell;
3528 }
3529 }
3530 return aRowSeq;
3531 }
3532
3533 ///@see SwXCellRange::setData
setDataArray(const uno::Sequence<uno::Sequence<uno::Any>> & rArray)3534 void SAL_CALL SwXCellRange::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray)
3535 {
3536 SolarMutexGuard aGuard;
3537 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3538 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3539 if(!nRowCount || !nColCount)
3540 throw uno::RuntimeException(u"Table too complex"_ustr, getXWeak());
3541 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3542 if(!pFormat)
3543 return;
3544 if(rArray.getLength() != nRowCount)
3545 throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rArray.getLength()), getXWeak());
3546 auto vCells(GetCells());
3547 auto pCurrentCell(vCells.begin());
3548 for(const auto& rColSeq : rArray)
3549 {
3550 if(rColSeq.getLength() != nColCount)
3551 throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rColSeq.getLength()), getXWeak());
3552 for(const auto& aValue : rColSeq)
3553 {
3554 auto pCell(static_cast<SwXCell*>(pCurrentCell->get()));
3555 if(!pCell || !pCell->GetTableBox())
3556 throw uno::RuntimeException(u"Box for cell missing"_ustr, getXWeak());
3557 if(aValue.isExtractableTo(cppu::UnoType<OUString>::get()))
3558 sw_setString(*pCell, aValue.get<OUString>());
3559 else if(aValue.isExtractableTo(cppu::UnoType<double>::get()))
3560 sw_setValue(*pCell, aValue.get<double>());
3561 else
3562 sw_setString(*pCell, OUString(), true);
3563 ++pCurrentCell;
3564 }
3565 }
3566 }
3567
3568 uno::Sequence<uno::Sequence<double>> SAL_CALL
getData()3569 SwXCellRange::getData()
3570 {
3571 SolarMutexGuard aGuard;
3572 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3573 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3574 if(!nRowCount || !nColCount)
3575 throw uno::RuntimeException(u"Table too complex"_ustr, getXWeak());
3576 if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel)
3577 {
3578 uno::Reference<chart::XChartDataArray> const xDataRange(
3579 getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0,
3580 (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0,
3581 nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW);
3582 return xDataRange->getData();
3583 }
3584 uno::Sequence< uno::Sequence< double > > vRows(nRowCount);
3585 auto vCells(GetCells());
3586 auto pCurrentCell(vCells.begin());
3587 for(auto& rRow : asNonConstRange(vRows))
3588 {
3589 rRow = uno::Sequence<double>(nColCount);
3590 for(auto& rValue : asNonConstRange(rRow))
3591 {
3592 if(!(*pCurrentCell))
3593 throw uno::RuntimeException(u"Table too complex"_ustr, getXWeak());
3594 rValue = (*pCurrentCell)->getValue();
3595 ++pCurrentCell;
3596 }
3597 }
3598 return vRows;
3599 }
3600
3601 void SAL_CALL
setData(const uno::Sequence<uno::Sequence<double>> & rData)3602 SwXCellRange::setData(const uno::Sequence< uno::Sequence<double> >& rData)
3603 {
3604 SolarMutexGuard aGuard;
3605 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3606 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3607 if(!nRowCount || !nColCount)
3608 throw uno::RuntimeException(u"Table too complex"_ustr, getXWeak());
3609 if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel)
3610 {
3611 uno::Reference<chart::XChartDataArray> const xDataRange(
3612 getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0,
3613 (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0,
3614 nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW);
3615 return xDataRange->setData(rData);
3616 }
3617 lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), this);
3618 if(rData.getLength() != nRowCount)
3619 throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rData.getLength()), getXWeak());
3620 auto vCells(GetCells());
3621 auto pCurrentCell(vCells.begin());
3622 for(const auto& rRow : rData)
3623 {
3624 if(rRow.getLength() != nColCount)
3625 throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rRow.getLength()), getXWeak());
3626 for(const auto& rValue : rRow)
3627 {
3628 uno::Reference<table::XCell>(*pCurrentCell, uno::UNO_SET_THROW)->setValue(rValue);
3629 ++pCurrentCell;
3630 }
3631 }
3632 }
3633
3634 std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32>
GetLabelCoordinates(bool bRow)3635 SwXCellRange::Impl::GetLabelCoordinates(bool bRow)
3636 {
3637 sal_uInt32 nLeft, nTop, nRight, nBottom;
3638 nLeft = nTop = nRight = nBottom = 0;
3639 if(bRow)
3640 {
3641 nTop = m_bFirstRowAsLabel ? 1 : 0;
3642 nBottom = GetRowCount() - 1;
3643 }
3644 else
3645 {
3646 nLeft = m_bFirstColumnAsLabel ? 1 : 0;
3647 nRight = GetColumnCount() - 1;
3648 }
3649 return std::make_tuple(nLeft, nTop, nRight, nBottom);
3650 }
3651
3652 uno::Sequence<OUString>
GetLabelDescriptions(SwXCellRange & rThis,bool bRow)3653 SwXCellRange::Impl::GetLabelDescriptions(SwXCellRange & rThis, bool bRow)
3654 {
3655 SolarMutexGuard aGuard;
3656 sal_uInt32 nLeft, nTop, nRight, nBottom;
3657 std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow);
3658 if(!nRight && !nBottom)
3659 throw uno::RuntimeException(u"Table too complex"_ustr, rThis.getXWeak());
3660 lcl_EnsureCoreConnected(GetFrameFormat(), &rThis);
3661 if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel))
3662 return {}; // without labels we have no descriptions
3663 auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom));
3664 auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells());
3665 uno::Sequence<OUString> vResult(vCells.size());
3666 std::transform(vCells.begin(), vCells.end(), vResult.getArray(),
3667 [](uno::Reference<table::XCell> xCell) -> OUString { return uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->getString(); });
3668 return vResult;
3669 }
3670
getRowDescriptions()3671 uno::Sequence<OUString> SAL_CALL SwXCellRange::getRowDescriptions()
3672 {
3673 return m_pImpl->GetLabelDescriptions(*this, true);
3674 }
3675
getColumnDescriptions()3676 uno::Sequence<OUString> SAL_CALL SwXCellRange::getColumnDescriptions()
3677 {
3678 return m_pImpl->GetLabelDescriptions(*this, false);
3679 }
3680
SetLabelDescriptions(SwXCellRange & rThis,const uno::Sequence<OUString> & rDesc,bool bRow)3681 void SwXCellRange::Impl::SetLabelDescriptions(SwXCellRange & rThis,
3682 const uno::Sequence<OUString>& rDesc, bool bRow)
3683 {
3684 SolarMutexGuard aGuard;
3685 lcl_EnsureCoreConnected(GetFrameFormat(), &rThis);
3686 if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel))
3687 return; // if there are no labels we cannot set descriptions
3688 sal_uInt32 nLeft, nTop, nRight, nBottom;
3689 std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow);
3690 if(!nRight && !nBottom)
3691 throw uno::RuntimeException(u"Table too complex"_ustr, rThis.getXWeak());
3692 auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom));
3693 if (!xLabelRange.is())
3694 throw uno::RuntimeException(u"Missing Cell Range"_ustr, rThis.getXWeak());
3695 auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells());
3696 if (sal::static_int_cast<sal_uInt32>(rDesc.getLength()) != vCells.size())
3697 throw uno::RuntimeException(u"Too few or too many descriptions"_ustr, rThis.getXWeak());
3698 auto pDescIterator(rDesc.begin());
3699 for(auto& xCell : vCells)
3700 uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->setString(*pDescIterator++);
3701 }
3702
setRowDescriptions(const uno::Sequence<OUString> & rRowDesc)3703 void SAL_CALL SwXCellRange::setRowDescriptions(
3704 const uno::Sequence<OUString>& rRowDesc)
3705 {
3706 m_pImpl->SetLabelDescriptions(*this, rRowDesc, true);
3707 }
3708
setColumnDescriptions(const uno::Sequence<OUString> & rColumnDesc)3709 void SAL_CALL SwXCellRange::setColumnDescriptions(
3710 const uno::Sequence<OUString>& rColumnDesc)
3711 {
3712 m_pImpl->SetLabelDescriptions(*this, rColumnDesc, false);
3713 }
3714
addChartDataChangeEventListener(const uno::Reference<chart::XChartDataChangeEventListener> & xListener)3715 void SAL_CALL SwXCellRange::addChartDataChangeEventListener(
3716 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
3717 {
3718 // no need to lock here as m_pImpl is const and container threadsafe
3719 std::unique_lock aGuard(m_pImpl->m_Mutex);
3720 m_pImpl->m_ChartListeners.addInterface(aGuard, xListener);
3721 }
3722
removeChartDataChangeEventListener(const uno::Reference<chart::XChartDataChangeEventListener> & xListener)3723 void SAL_CALL SwXCellRange::removeChartDataChangeEventListener(
3724 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
3725 {
3726 // no need to lock here as m_pImpl is const and container threadsafe
3727 std::unique_lock aGuard(m_pImpl->m_Mutex);
3728 m_pImpl->m_ChartListeners.removeInterface(aGuard, xListener);
3729 }
3730
isNotANumber(double)3731 sal_Bool SwXCellRange::isNotANumber(double /*fNumber*/)
3732 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
3733
getNotANumber()3734 double SwXCellRange::getNotANumber()
3735 { throw uno::RuntimeException(u"Not implemented"_ustr, getXWeak()); }
3736
createSortDescriptor()3737 uno::Sequence< beans::PropertyValue > SwXCellRange::createSortDescriptor()
3738 {
3739 SolarMutexGuard aGuard;
3740 return SwUnoCursorHelper::CreateSortDescriptor(true);
3741 }
3742
sort(const uno::Sequence<beans::PropertyValue> & rDescriptor)3743 void SAL_CALL SwXCellRange::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
3744 {
3745 SolarMutexGuard aGuard;
3746 SwSortOptions aSortOpt;
3747 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3748 if(pFormat && SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt))
3749 {
3750 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor);
3751 rTableCursor.MakeBoxSels();
3752 UnoActionContext aContext(pFormat->GetDoc());
3753 pFormat->GetDoc()->SortTable(rTableCursor.GetSelectedBoxes(), aSortOpt);
3754 }
3755 }
3756
GetColumnCount() const3757 sal_Int32 SwXCellRange::Impl::GetColumnCount() const
3758 {
3759 return m_RangeDescriptor.nRight - m_RangeDescriptor.nLeft + 1;
3760 }
3761
GetRowCount() const3762 sal_Int32 SwXCellRange::Impl::GetRowCount() const
3763 {
3764 return m_RangeDescriptor.nBottom - m_RangeDescriptor.nTop + 1;
3765 }
3766
GetTableCursor() const3767 const SwUnoCursor* SwXCellRange::GetTableCursor() const
3768 {
3769 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3770 return pFormat ? &(*m_pImpl->m_pTableCursor) : nullptr;
3771 }
3772
Notify(const SfxHint & rHint)3773 void SwXCellRange::Impl::Notify( const SfxHint& rHint )
3774 {
3775 uno::Reference<uno::XInterface> const xThis(m_wThis);
3776 if(rHint.GetId() == SfxHintId::Dying)
3777 {
3778 m_pFrameFormat = nullptr;
3779 m_pTableCursor.reset(nullptr);
3780 }
3781 if (xThis.is())
3782 { // fdo#72695: if UNO object is already dead, don't revive it with event
3783 if(m_pFrameFormat)
3784 {
3785 std::unique_lock aGuard(m_Mutex);
3786 lcl_SendChartEvent(aGuard, xThis, m_ChartListeners);
3787 }
3788 else
3789 {
3790 std::unique_lock aGuard(m_Mutex);
3791 m_ChartListeners.disposeAndClear(aGuard, lang::EventObject(xThis));
3792 }
3793 }
3794 }
3795
3796 class SwXTableRows::Impl : public SvtListener
3797 {
3798 private:
3799 SwFrameFormat* m_pFrameFormat;
3800
3801 public:
Impl(SwFrameFormat & rFrameFormat)3802 explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat)
3803 {
3804 StartListening(rFrameFormat.GetNotifier());
3805 }
GetFrameFormat()3806 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
3807 virtual void Notify(const SfxHint&) override;
3808 };
3809
3810 // SwXTableRows
3811
getImplementationName()3812 OUString SwXTableRows::getImplementationName()
3813 { return u"SwXTableRows"_ustr; }
3814
supportsService(const OUString & rServiceName)3815 sal_Bool SwXTableRows::supportsService(const OUString& rServiceName)
3816 { return cppu::supportsService(this, rServiceName); }
3817
getSupportedServiceNames()3818 uno::Sequence< OUString > SwXTableRows::getSupportedServiceNames()
3819 { return { u"com.sun.star.text.TableRows"_ustr }; }
3820
3821
SwXTableRows(SwFrameFormat & rFrameFormat)3822 SwXTableRows::SwXTableRows(SwFrameFormat& rFrameFormat) :
3823 m_pImpl(new SwXTableRows::Impl(rFrameFormat))
3824 { }
3825
~SwXTableRows()3826 SwXTableRows::~SwXTableRows()
3827 { }
3828
GetFrameFormat()3829 SwFrameFormat* SwXTableRows::GetFrameFormat()
3830 {
3831 return m_pImpl->GetFrameFormat();
3832 }
3833
getCount()3834 sal_Int32 SwXTableRows::getCount()
3835 {
3836 SolarMutexGuard aGuard;
3837 SwFrameFormat* pFrameFormat = GetFrameFormat();
3838 if(!pFrameFormat)
3839 throw uno::RuntimeException();
3840 SwTable* pTable = SwTable::FindTable(pFrameFormat);
3841 return pTable->GetTabLines().size();
3842 }
3843
3844 ///@see SwXCell::CreateXCell (TODO: seems to be copy and paste programming here)
getByIndex(sal_Int32 nIndex)3845 uno::Any SwXTableRows::getByIndex(sal_Int32 nIndex)
3846 {
3847 SolarMutexGuard aGuard;
3848 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
3849 if(nIndex < 0)
3850 throw lang::IndexOutOfBoundsException();
3851 SwTable* pTable = SwTable::FindTable( pFrameFormat );
3852 if(o3tl::make_unsigned(nIndex) >= pTable->GetTabLines().size())
3853 throw lang::IndexOutOfBoundsException();
3854 SwTableLine* pLine = pTable->GetTabLines()[nIndex];
3855 FindUnoInstanceHint<SwTableLine,SwXTextTableRow> aHint{pLine};
3856 pFrameFormat->GetNotifier().Broadcast(aHint);
3857 if(!aHint.m_pResult)
3858 aHint.m_pResult = new SwXTextTableRow(pFrameFormat, pLine);
3859 uno::Reference<beans::XPropertySet> xRet = static_cast<beans::XPropertySet*>(aHint.m_pResult.get());
3860 return uno::Any(xRet);
3861 }
3862
getElementType()3863 uno::Type SAL_CALL SwXTableRows::getElementType()
3864 {
3865 return cppu::UnoType<beans::XPropertySet>::get();
3866 }
3867
hasElements()3868 sal_Bool SwXTableRows::hasElements()
3869 {
3870 SolarMutexGuard aGuard;
3871 SwFrameFormat* pFrameFormat = GetFrameFormat();
3872 if(!pFrameFormat)
3873 throw uno::RuntimeException();
3874 // a table always has rows
3875 return true;
3876 }
3877
insertByIndex(sal_Int32 nIndex,sal_Int32 nCount)3878 void SwXTableRows::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount)
3879 {
3880 SolarMutexGuard aGuard;
3881 if (nCount == 0)
3882 return;
3883 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
3884 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this);
3885 const size_t nRowCount = pTable->GetTabLines().size();
3886 if (nCount <= 0 || 0 > nIndex || o3tl::make_unsigned(nIndex) > nRowCount)
3887 throw uno::RuntimeException(u"Illegal arguments"_ustr, getXWeak());
3888 const OUString sTLName = sw_GetCellName(0, nIndex);
3889 const SwTableBox* pTLBox = pTable->GetTableBox(sTLName);
3890 bool bAppend = false;
3891 if(!pTLBox)
3892 {
3893 bAppend = true;
3894 // to append at the end the cursor must be in the last line
3895 SwTableLines& rLines = pTable->GetTabLines();
3896 SwTableLine* pLine = rLines.back();
3897 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
3898 pTLBox = rBoxes.front();
3899 }
3900 if(!pTLBox)
3901 throw uno::RuntimeException(u"Illegal arguments"_ustr, getXWeak());
3902 const SwStartNode* pSttNd = pTLBox->GetSttNd();
3903 SwPosition aPos(*pSttNd);
3904 // set cursor to the upper-left cell of the range
3905 UnoActionContext aAction(pFrameFormat->GetDoc());
3906 std::shared_ptr<SwUnoTableCursor> const pUnoCursor(
3907 std::dynamic_pointer_cast<SwUnoTableCursor>(
3908 pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)));
3909 pUnoCursor->Move( fnMoveForward, GoInNode );
3910 {
3911 // remove actions - TODO: why?
3912 UnoActionRemoveContext aRemoveContext(&pUnoCursor->GetDoc());
3913 }
3914 pFrameFormat->GetDoc()->InsertRow(*pUnoCursor, o3tl::narrowing<sal_uInt16>(nCount), bAppend);
3915 }
3916
removeByIndex(sal_Int32 nIndex,sal_Int32 nCount)3917 void SwXTableRows::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount)
3918 {
3919 SolarMutexGuard aGuard;
3920 if (nCount == 0)
3921 return;
3922 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
3923 if(nIndex < 0 || nCount <=0 )
3924 throw uno::RuntimeException();
3925 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this);
3926 OUString sTLName = sw_GetCellName(0, nIndex);
3927 const SwTableBox* pTLBox = pTable->GetTableBox(sTLName);
3928 if(!pTLBox)
3929 throw uno::RuntimeException(u"Illegal arguments"_ustr, getXWeak());
3930 const SwStartNode* pSttNd = pTLBox->GetSttNd();
3931 SwPosition aPos(*pSttNd);
3932 // set cursor to the upper-left cell of the range
3933 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
3934 pUnoCursor->Move(fnMoveForward, GoInNode);
3935 pUnoCursor->SetRemainInSection( false );
3936 const OUString sBLName = sw_GetCellName(0, nIndex + nCount - 1);
3937 const SwTableBox* pBLBox = pTable->GetTableBox( sBLName );
3938 if(!pBLBox)
3939 throw uno::RuntimeException(u"Illegal arguments"_ustr, getXWeak());
3940 pUnoCursor->SetMark();
3941 pUnoCursor->GetPoint()->Assign( *pBLBox->GetSttNd() );
3942 pUnoCursor->Move(fnMoveForward, GoInNode);
3943 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
3944 {
3945 // HACK: remove pending actions for selecting old style tables
3946 UnoActionRemoveContext aRemoveContext(rCursor);
3947 }
3948 rCursor.MakeBoxSels();
3949 { // these braces are important
3950 UnoActionContext aAction(pFrameFormat->GetDoc());
3951 pFrameFormat->GetDoc()->DeleteRow(*pUnoCursor);
3952 pUnoCursor.reset();
3953 }
3954 {
3955 // invalidate all actions - TODO: why?
3956 UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc());
3957 }
3958 }
3959
Notify(const SfxHint & rHint)3960 void SwXTableRows::Impl::Notify( const SfxHint& rHint)
3961 {
3962 if(rHint.GetId() == SfxHintId::Dying)
3963 m_pFrameFormat = nullptr;
3964 }
3965
3966 // SwXTableColumns
3967
3968 class SwXTableColumns::Impl : public SvtListener
3969 {
3970 SwFrameFormat* m_pFrameFormat;
3971 public:
Impl(SwFrameFormat & rFrameFormat)3972 explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat)
3973 {
3974 StartListening(rFrameFormat.GetNotifier());
3975 }
GetFrameFormat()3976 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
3977 virtual void Notify(const SfxHint&) override;
3978 };
3979
getImplementationName()3980 OUString SwXTableColumns::getImplementationName()
3981 { return u"SwXTableColumns"_ustr; }
3982
supportsService(const OUString & rServiceName)3983 sal_Bool SwXTableColumns::supportsService(const OUString& rServiceName)
3984 { return cppu::supportsService(this, rServiceName); }
3985
getSupportedServiceNames()3986 uno::Sequence< OUString > SwXTableColumns::getSupportedServiceNames()
3987 { return { u"com.sun.star.text.TableColumns"_ustr}; }
3988
3989
SwXTableColumns(SwFrameFormat & rFrameFormat)3990 SwXTableColumns::SwXTableColumns(SwFrameFormat& rFrameFormat) :
3991 m_pImpl(new SwXTableColumns::Impl(rFrameFormat))
3992 { }
3993
~SwXTableColumns()3994 SwXTableColumns::~SwXTableColumns()
3995 { }
3996
GetFrameFormat() const3997 SwFrameFormat* SwXTableColumns::GetFrameFormat() const
3998 {
3999 return m_pImpl->GetFrameFormat();
4000 }
4001
getCount()4002 sal_Int32 SwXTableColumns::getCount()
4003 {
4004 SolarMutexGuard aGuard;
4005 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
4006 SwTable* pTable = SwTable::FindTable( pFrameFormat );
4007 // if(!pTable->IsTableComplex())
4008 // throw uno::RuntimeException("Table too complex", getXWeak());
4009 SwTableLines& rLines = pTable->GetTabLines();
4010 SwTableLine* pLine = rLines.front();
4011 return pLine->GetTabBoxes().size();
4012 }
4013
getByIndex(sal_Int32 nIndex)4014 uno::Any SwXTableColumns::getByIndex(sal_Int32 nIndex)
4015 {
4016 SolarMutexGuard aGuard;
4017 if(nIndex < 0 || getCount() <= nIndex)
4018 throw lang::IndexOutOfBoundsException();
4019 return uno::Any(uno::Reference<uno::XInterface>()); // i#21699 not supported
4020 }
4021
getElementType()4022 uno::Type SAL_CALL SwXTableColumns::getElementType()
4023 {
4024 return cppu::UnoType<uno::XInterface>::get();
4025 }
4026
hasElements()4027 sal_Bool SwXTableColumns::hasElements()
4028 {
4029 SolarMutexGuard aGuard;
4030 lcl_EnsureCoreConnected(GetFrameFormat(), this);
4031 return true;
4032 }
4033
4034 ///@see SwXTableRows::insertByIndex (TODO: seems to be copy and paste programming here)
insertByIndex(sal_Int32 nIndex,sal_Int32 nCount)4035 void SwXTableColumns::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount)
4036 {
4037 SolarMutexGuard aGuard;
4038 if (nCount == 0)
4039 return;
4040 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
4041 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this);
4042 SwTableLines& rLines = pTable->GetTabLines();
4043 SwTableLine* pLine = rLines.front();
4044 const size_t nColCount = pLine->GetTabBoxes().size();
4045 if (nCount <= 0 || 0 > nIndex || o3tl::make_unsigned(nIndex) > nColCount)
4046 throw uno::RuntimeException(u"Illegal arguments"_ustr, getXWeak());
4047 const OUString sTLName = sw_GetCellName(nIndex, 0);
4048 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
4049 bool bAppend = false;
4050 if(!pTLBox)
4051 {
4052 bAppend = true;
4053 // to append at the end the cursor must be in the last line
4054 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
4055 pTLBox = rBoxes.back();
4056 }
4057 if(!pTLBox)
4058 throw uno::RuntimeException(u"Illegal arguments"_ustr, getXWeak());
4059 const SwStartNode* pSttNd = pTLBox->GetSttNd();
4060 SwPosition aPos(*pSttNd);
4061 UnoActionContext aAction(pFrameFormat->GetDoc());
4062 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
4063 pUnoCursor->Move(fnMoveForward, GoInNode);
4064
4065 {
4066 // remove actions - TODO: why?
4067 UnoActionRemoveContext aRemoveContext(&pUnoCursor->GetDoc());
4068 }
4069
4070 pFrameFormat->GetDoc()->InsertCol(*pUnoCursor, o3tl::narrowing<sal_uInt16>(nCount), bAppend);
4071 }
4072
4073 ///@see SwXTableRows::removeByIndex (TODO: seems to be copy and paste programming here)
removeByIndex(sal_Int32 nIndex,sal_Int32 nCount)4074 void SwXTableColumns::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount)
4075 {
4076 SolarMutexGuard aGuard;
4077 if (nCount == 0)
4078 return;
4079 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
4080 if(nIndex < 0 || nCount <=0 )
4081 throw uno::RuntimeException();
4082 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this);
4083 const OUString sTLName = sw_GetCellName(nIndex, 0);
4084 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
4085 if(!pTLBox)
4086 throw uno::RuntimeException(u"Cell not found"_ustr, getXWeak());
4087 const SwStartNode* pSttNd = pTLBox->GetSttNd();
4088 SwPosition aPos(*pSttNd);
4089 // set cursor to the upper-left cell of the range
4090 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
4091 pUnoCursor->Move(fnMoveForward, GoInNode);
4092 pUnoCursor->SetRemainInSection(false);
4093 const OUString sTRName = sw_GetCellName(nIndex + nCount - 1, 0);
4094 const SwTableBox* pTRBox = pTable->GetTableBox(sTRName);
4095 if(!pTRBox)
4096 throw uno::RuntimeException(u"Cell not found"_ustr, getXWeak());
4097 pUnoCursor->SetMark();
4098 pUnoCursor->GetPoint()->Assign( *pTRBox->GetSttNd() );
4099 pUnoCursor->Move(fnMoveForward, GoInNode);
4100 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
4101 {
4102 // HACK: remove pending actions for selecting old style tables
4103 UnoActionRemoveContext aRemoveContext(rCursor);
4104 }
4105 rCursor.MakeBoxSels();
4106 { // these braces are important
4107 UnoActionContext aAction(pFrameFormat->GetDoc());
4108 pFrameFormat->GetDoc()->DeleteCol(*pUnoCursor);
4109 pUnoCursor.reset();
4110 }
4111 {
4112 // invalidate all actions - TODO: why?
4113 UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc());
4114 }
4115 }
4116
Notify(const SfxHint & rHint)4117 void SwXTableColumns::Impl::Notify(const SfxHint& rHint)
4118 {
4119 if(rHint.GetId() == SfxHintId::Dying)
4120 m_pFrameFormat = nullptr;
4121 }
4122
4123 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4124