Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / unocore / unotbl.cxx
blob66e43fb1828edde437826d87d4311269ab86eda5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tuple>
21 #include <utility>
22 #include <memory>
23 #include <vector>
24 #include <algorithm>
25 #include <limits>
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 <section.hxx>
40 #include <unocrsr.hxx>
41 #include <hints.hxx>
42 #include <swtblfmt.hxx>
43 #include <doc.hxx>
44 #include <IDocumentUndoRedo.hxx>
45 #include <IDocumentContentOperations.hxx>
46 #include <IDocumentFieldsAccess.hxx>
47 #include <IDocumentRedlineAccess.hxx>
48 #include <IDocumentState.hxx>
49 #include <IDocumentLayoutAccess.hxx>
50 #include <shellres.hxx>
51 #include <docary.hxx>
52 #include <ndole.hxx>
53 #include <ndtxt.hxx>
54 #include <frame.hxx>
55 #include <vcl/svapp.hxx>
56 #include <fmtfsize.hxx>
57 #include <tblafmt.hxx>
58 #include <tabcol.hxx>
59 #include <cellatr.hxx>
60 #include <fmtpdsc.hxx>
61 #include <pagedesc.hxx>
62 #include <viewsh.hxx>
63 #include <rootfrm.hxx>
64 #include <tabfrm.hxx>
65 #include <redline.hxx>
66 #include <unoport.hxx>
67 #include <unocrsrhelper.hxx>
68 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
69 #include <com/sun/star/text/WrapTextMode.hpp>
70 #include <com/sun/star/text/TextContentAnchorType.hpp>
71 #include <com/sun/star/text/TableColumnSeparator.hpp>
72 #include <com/sun/star/text/VertOrientation.hpp>
73 #include <com/sun/star/text/XTextSection.hpp>
74 #include <com/sun/star/table/TableBorder.hpp>
75 #include <com/sun/star/table/TableBorder2.hpp>
76 #include <com/sun/star/table/BorderLine2.hpp>
77 #include <com/sun/star/table/TableBorderDistances.hpp>
78 #include <com/sun/star/beans/PropertyAttribute.hpp>
79 #include <com/sun/star/chart/XChartDataChangeEventListener.hpp>
80 #include <com/sun/star/chart/ChartDataChangeEvent.hpp>
81 #include <com/sun/star/table/CellContentType.hpp>
82 #include <unotextrange.hxx>
83 #include <unotextcursor.hxx>
84 #include <unoparagraph.hxx>
85 #include <svl/numformat.hxx>
86 #include <svl/zforlist.hxx>
87 #include <editeng/formatbreakitem.hxx>
88 #include <editeng/shaditem.hxx>
89 #include <editeng/lrspitem.hxx>
90 #include <editeng/ulspitem.hxx>
91 #include <fmtornt.hxx>
92 #include <editeng/keepitem.hxx>
93 #include <fmtlsplt.hxx>
94 #include <swundo.hxx>
95 #include <SwStyleNameMapper.hxx>
96 #include <frmatr.hxx>
97 #include <sortopt.hxx>
98 #include <sal/log.hxx>
99 #include <editeng/frmdiritem.hxx>
100 #include <comphelper/servicehelper.hxx>
101 #include <comphelper/string.hxx>
102 #include <cppuhelper/supportsservice.hxx>
103 #include <comphelper/sequence.hxx>
104 #include <comphelper/sequenceashashmap.hxx>
105 #include <swtable.hxx>
106 #include <docsh.hxx>
107 #include <fesh.hxx>
108 #include <itabenum.hxx>
109 #include <frameformats.hxx>
110 #include <o3tl/string_view.hxx>
112 using namespace ::com::sun::star;
113 using ::editeng::SvxBorderLine;
115 namespace
117 template<typename Tcoretype, typename Tunotype>
118 struct FindUnoInstanceHint final : SfxHint
120 FindUnoInstanceHint(Tcoretype* pCore) : m_pCore(pCore), m_pResult(nullptr) {};
121 const Tcoretype* const m_pCore;
122 mutable rtl::Reference<Tunotype> m_pResult;
124 SwFrameFormat* lcl_EnsureCoreConnected(SwFrameFormat* pFormat, cppu::OWeakObject* pObject)
126 if(!pFormat)
127 throw uno::RuntimeException("Lost connection to core objects", pObject);
128 return pFormat;
130 SwTable* lcl_EnsureTableNotComplex(SwTable* pTable, cppu::OWeakObject* pObject)
132 if(pTable->IsTableComplex())
133 throw uno::RuntimeException("Table too complex", pObject);
134 return pTable;
137 chart::ChartDataChangeEvent createChartEvent(uno::Reference<uno::XInterface> const& xSource)
139 //TODO: find appropriate settings of the Event
140 chart::ChartDataChangeEvent event;
141 event.Source = xSource;
142 event.Type = chart::ChartDataChangeType_ALL;
143 event.StartColumn = 0;
144 event.EndColumn = 1;
145 event.StartRow = 0;
146 event.EndRow = 1;
147 return event;
150 void lcl_SendChartEvent(std::unique_lock<std::mutex>& rGuard,
151 uno::Reference<uno::XInterface> const& xSource,
152 ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> & rListeners)
154 if (rListeners.getLength(rGuard))
155 rListeners.notifyEach(rGuard,
156 &chart::XChartDataChangeEventListener::chartDataChanged,
157 createChartEvent(xSource));
161 #define UNO_TABLE_COLUMN_SUM 10000
164 static bool lcl_LineToSvxLine(const table::BorderLine& rLine, SvxBorderLine& rSvxLine)
166 rSvxLine.SetColor(Color(ColorTransparency, rLine.Color));
168 rSvxLine.GuessLinesWidths( SvxBorderLineStyle::NONE,
169 o3tl::toTwips(rLine.OuterLineWidth, o3tl::Length::mm100),
170 o3tl::toTwips(rLine.InnerLineWidth, o3tl::Length::mm100),
171 o3tl::toTwips(rLine.LineDistance, o3tl::Length::mm100) );
173 return rLine.InnerLineWidth > 0 || rLine.OuterLineWidth > 0;
176 /// @throws lang::IllegalArgumentException
177 /// @throws uno::RuntimeException
178 static void lcl_SetSpecialProperty(SwFrameFormat* pFormat,
179 const SfxItemPropertyMapEntry* pEntry,
180 const uno::Any& aValue)
182 // special treatment for "non-items"
183 switch(pEntry->nWID)
185 case FN_TABLE_HEADLINE_REPEAT:
186 case FN_TABLE_HEADLINE_COUNT:
188 SwTable* pTable = SwTable::FindTable( pFormat );
189 UnoActionContext aAction(pFormat->GetDoc());
190 if( pEntry->nWID == FN_TABLE_HEADLINE_REPEAT)
192 pFormat->GetDoc()->SetRowsToRepeat( *pTable, aValue.get<bool>() ? 1 : 0 );
194 else
196 sal_Int32 nRepeat = 0;
197 aValue >>= nRepeat;
198 if( nRepeat >= 0 && nRepeat < SAL_MAX_UINT16 )
199 pFormat->GetDoc()->SetRowsToRepeat( *pTable, o3tl::narrowing<sal_uInt16>(nRepeat) );
202 break;
204 case FN_TABLE_IS_RELATIVE_WIDTH:
205 case FN_TABLE_WIDTH:
206 case FN_TABLE_RELATIVE_WIDTH:
208 SwFormatFrameSize aSz( pFormat->GetFrameSize() );
209 if(FN_TABLE_WIDTH == pEntry->nWID)
211 sal_Int32 nWidth = 0;
212 aValue >>= nWidth;
213 aSz.SetWidthPercent(0);
214 aSz.SetWidth ( o3tl::toTwips(nWidth, o3tl::Length::mm100) );
216 else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID)
218 sal_Int16 nSet = 0;
219 aValue >>= nSet;
220 if(nSet && nSet <=100)
221 aSz.SetWidthPercent( static_cast<sal_uInt8>(nSet) );
223 else if(FN_TABLE_IS_RELATIVE_WIDTH == pEntry->nWID)
225 if(!aValue.get<bool>())
226 aSz.SetWidthPercent(0);
227 else
229 lang::IllegalArgumentException aExcept;
230 aExcept.Message = "relative width cannot be switched on with this property";
231 throw aExcept;
234 pFormat->GetDoc()->SetAttr(aSz, *pFormat);
236 break;
238 case RES_PAGEDESC:
240 OUString sPageStyle;
241 aValue >>= sPageStyle;
242 const SwPageDesc* pDesc = nullptr;
243 if (!sPageStyle.isEmpty())
245 SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc);
246 pDesc = SwPageDesc::GetByName(*pFormat->GetDoc(), sPageStyle);
248 SwFormatPageDesc aDesc( pDesc );
249 pFormat->GetDoc()->SetAttr(aDesc, *pFormat);
251 break;
253 default:
254 throw lang::IllegalArgumentException();
258 static uno::Any lcl_GetSpecialProperty(SwFrameFormat* pFormat, const SfxItemPropertyMapEntry* pEntry )
260 switch(pEntry->nWID)
262 case FN_TABLE_HEADLINE_REPEAT:
263 case FN_TABLE_HEADLINE_COUNT:
265 SwTable* pTable = SwTable::FindTable( pFormat );
266 const sal_uInt16 nRepeat = pTable->GetRowsToRepeat();
267 if(pEntry->nWID == FN_TABLE_HEADLINE_REPEAT)
268 return uno::Any(nRepeat > 0);
269 return uno::Any(sal_Int32(nRepeat));
272 case FN_TABLE_WIDTH:
273 case FN_TABLE_IS_RELATIVE_WIDTH:
274 case FN_TABLE_RELATIVE_WIDTH:
276 uno::Any aRet;
277 const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
278 if(FN_TABLE_WIDTH == pEntry->nWID)
279 rSz.QueryValue(aRet, MID_FRMSIZE_WIDTH|CONVERT_TWIPS);
280 else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID)
281 rSz.QueryValue(aRet, MID_FRMSIZE_REL_WIDTH);
282 else
283 aRet <<= (0 != rSz.GetWidthPercent());
284 return aRet;
287 case RES_PAGEDESC:
289 const SfxItemSet& rSet = pFormat->GetAttrSet();
290 if(const SwFormatPageDesc* pItem = rSet.GetItemIfSet(RES_PAGEDESC, false))
292 const SwPageDesc* pDsc = pItem->GetPageDesc();
293 if(pDsc)
294 return uno::Any(SwStyleNameMapper::GetProgName(pDsc->GetName(), SwGetPoolIdFromName::PageDesc ));
296 return uno::Any(OUString());
299 case RES_ANCHOR:
300 return uno::Any(text::TextContentAnchorType_AT_PARAGRAPH);
302 case FN_UNO_ANCHOR_TYPES:
304 uno::Sequence<text::TextContentAnchorType> aTypes{text::TextContentAnchorType_AT_PARAGRAPH};
305 return uno::Any(aTypes);
308 case FN_UNO_WRAP :
309 return uno::Any(text::WrapTextMode_NONE);
311 case FN_PARAM_LINK_DISPLAY_NAME :
312 return uno::Any(pFormat->GetName());
314 case FN_UNO_REDLINE_NODE_START:
315 case FN_UNO_REDLINE_NODE_END:
317 SwTable* pTable = SwTable::FindTable( pFormat );
318 SwNode* pTableNode = pTable->GetTableNode();
319 if(FN_UNO_REDLINE_NODE_END == pEntry->nWID)
320 pTableNode = pTableNode->EndOfSectionNode();
321 for(const SwRangeRedline* pRedline : pFormat->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable())
323 const SwNode& rRedPointNode = pRedline->GetPointNode();
324 const SwNode& rRedMarkNode = pRedline->GetMarkNode();
325 if(rRedPointNode == *pTableNode || rRedMarkNode == *pTableNode)
327 const SwNode& rStartOfRedline = SwNodeIndex(rRedPointNode) <= SwNodeIndex(rRedMarkNode) ?
328 rRedPointNode : rRedMarkNode;
329 bool bIsStart = &rStartOfRedline == pTableNode;
330 return uno::Any(SwXRedlinePortion::CreateRedlineProperties(*pRedline, bIsStart));
335 return uno::Any();
338 /** get position of a cell with a given name
340 * If everything was OK, the indices for column and row are changed (both >= 0).
341 * In case of errors, at least one of them is < 0.
343 * Also since the implementations of tables does not really have columns using
344 * this function is appropriate only for tables that are not complex (i.e.
345 * where IsTableComplex() returns false).
347 * @param rCellName e.g. A1..Z1, a1..z1, AA1..AZ1, Aa1..Az1, BA1..BZ1, Ba1..Bz1, ...
348 * @param [IN,OUT] o_rColumn (0-based)
349 * @param [IN,OUT] o_rRow (0-based)
351 //TODO: potential for throwing proper exceptions instead of having every caller to check for errors
352 void SwXTextTable::GetCellPosition(std::u16string_view aCellName, sal_Int32& o_rColumn, sal_Int32& o_rRow)
354 o_rColumn = o_rRow = -1; // default return values indicating failure
355 const sal_Int32 nLen = aCellName.size();
356 if(!nLen)
358 SAL_WARN("sw.uno", "failed to get column or row index");
359 return;
361 sal_Int32 nRowPos = 0;
362 while (nRowPos<nLen)
364 if (aCellName[nRowPos]>='0' && aCellName[nRowPos]<='9')
366 break;
368 ++nRowPos;
370 if (nRowPos<=0 || nRowPos>=nLen)
371 return;
373 sal_Int32 nColIdx = 0;
374 for (sal_Int32 i = 0; i < nRowPos; ++i)
376 nColIdx *= 52;
377 if (i < nRowPos - 1)
378 ++nColIdx;
379 const sal_Unicode cChar = aCellName[i];
380 if ('A' <= cChar && cChar <= 'Z')
381 nColIdx += cChar - 'A';
382 else if ('a' <= cChar && cChar <= 'z')
383 nColIdx += 26 + cChar - 'a';
384 else
386 nColIdx = -1; // sth failed
387 break;
391 o_rColumn = nColIdx;
392 o_rRow = o3tl::toInt32(aCellName.substr(nRowPos)) - 1; // - 1 because indices ought to be 0 based
395 /** compare position of two cells (check rows first)
397 * @note this function probably also make sense only
398 * for cell names of non-complex tables
400 * @param rCellName1 e.g. "A1" (non-empty string with valid cell name)
401 * @param rCellName2 e.g. "A1" (non-empty string with valid cell name)
402 * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2
404 int sw_CompareCellsByRowFirst( std::u16string_view aCellName1, std::u16string_view aCellName2 )
406 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
407 SwXTextTable::GetCellPosition( aCellName1, nCol1, nRow1 );
408 SwXTextTable::GetCellPosition( aCellName2, nCol2, nRow2 );
410 if (nRow1 < nRow2 || (nRow1 == nRow2 && nCol1 < nCol2))
411 return -1;
412 else if (nCol1 == nCol2 && nRow1 == nRow2)
413 return 0;
414 else
415 return +1;
418 /** compare position of two cells (check columns first)
420 * @note this function probably also make sense only
421 * for cell names of non-complex tables
423 * @param rCellName1 e.g. "A1" (non-empty string with valid cell name)
424 * @param rCellName2 e.g. "A1" (non-empty string with valid cell name)
425 * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2
427 int sw_CompareCellsByColFirst( std::u16string_view aCellName1, std::u16string_view aCellName2 )
429 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
430 SwXTextTable::GetCellPosition( aCellName1, nCol1, nRow1 );
431 SwXTextTable::GetCellPosition( aCellName2, nCol2, nRow2 );
433 if (nCol1 < nCol2 || (nCol1 == nCol2 && nRow1 < nRow2))
434 return -1;
435 else if (nRow1 == nRow2 && nCol1 == nCol2)
436 return 0;
437 else
438 return +1;
441 /** compare position of two cell ranges
443 * @note this function probably also make sense only
444 * for cell names of non-complex tables
446 * @param rRange1StartCell e.g. "A1" (non-empty string with valid cell name)
447 * @param rRange1EndCell e.g. "A1" (non-empty string with valid cell name)
448 * @param rRange2StartCell e.g. "A1" (non-empty string with valid cell name)
449 * @param rRange2EndCell e.g. "A1" (non-empty string with valid cell name)
450 * @param bCmpColsFirst if <true> position in columns will be compared first before rows
452 * @return -1 if cell_range_1 < cell_range_2; 0 if both cell ranges are equal; +1 if cell_range_1 > cell_range_2
454 int sw_CompareCellRanges(
455 std::u16string_view aRange1StartCell, std::u16string_view aRange1EndCell,
456 std::u16string_view aRange2StartCell, std::u16string_view aRange2EndCell,
457 bool bCmpColsFirst )
459 int (*pCompareCells)( std::u16string_view, std::u16string_view ) =
460 bCmpColsFirst ? &sw_CompareCellsByColFirst : &sw_CompareCellsByRowFirst;
462 int nCmpResStartCells = pCompareCells( aRange1StartCell, aRange2StartCell );
463 if ((-1 == nCmpResStartCells ) ||
464 ( 0 == nCmpResStartCells &&
465 -1 == pCompareCells( aRange1EndCell, aRange2EndCell ) ))
466 return -1;
467 else if (0 == nCmpResStartCells &&
468 0 == pCompareCells( aRange1EndCell, aRange2EndCell ))
469 return 0;
470 else
471 return +1;
474 /** get cell name at a specified coordinate
476 * @param nColumn column index (0-based)
477 * @param nRow row index (0-based)
478 * @return the cell name
480 OUString sw_GetCellName( sal_Int32 nColumn, sal_Int32 nRow )
482 if (nColumn < 0 || nRow < 0)
483 return OUString();
484 OUString sCellName;
485 sw_GetTableBoxColStr( static_cast< sal_uInt16 >(nColumn), sCellName );
486 return sCellName + OUString::number( nRow + 1 );
489 /** Find the top left or bottom right corner box in given table.
490 Consider nested lines when finding the box.
492 @param rTableLines the table
493 @param i_bTopLeft if true, find top left box, otherwise find bottom
494 right box
496 static const SwTableBox* lcl_FindCornerTableBox(const SwTableLines& rTableLines, const bool i_bTopLeft)
498 const SwTableLines* pLines(&rTableLines);
499 while(true)
501 assert(!pLines->empty());
502 if(pLines->empty())
503 return nullptr;
504 const SwTableLine* pLine(i_bTopLeft ? pLines->front() : pLines->back());
505 assert(pLine);
506 const SwTableBoxes& rBoxes(pLine->GetTabBoxes());
507 assert(rBoxes.size() != 0);
508 const SwTableBox* pBox = i_bTopLeft ? rBoxes.front() : rBoxes.back();
509 assert(pBox);
510 if (pBox->GetSttNd())
511 return pBox;
512 pLines = &pBox->GetTabLines();
516 /** cleanup order in a range
518 * Sorts the input to a uniform format. I.e. for the four possible representation
519 * A1:C5, C5:A1, A5:C1, C1:A5
520 * the result will be always A1:C5.
522 * @param [IN,OUT] rCell1 cell name (will be modified to upper-left corner), e.g. "A1" (non-empty string with valid cell name)
523 * @param [IN,OUT] rCell2 cell name (will be modified to lower-right corner), e.g. "A1" (non-empty string with valid cell name)
525 void sw_NormalizeRange(OUString &rCell1, OUString &rCell2)
527 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
528 SwXTextTable::GetCellPosition( rCell1, nCol1, nRow1 );
529 SwXTextTable::GetCellPosition( rCell2, nCol2, nRow2 );
530 if (nCol2 < nCol1 || nRow2 < nRow1)
532 rCell1 = sw_GetCellName( std::min(nCol1, nCol2), std::min(nRow1, nRow2) );
533 rCell2 = sw_GetCellName( std::max(nCol1, nCol2), std::max(nRow1, nRow2) );
537 void SwRangeDescriptor::Normalize()
539 if (nTop > nBottom)
540 std::swap(nBottom, nTop);
541 if (nLeft > nRight)
542 std::swap(nLeft, nRight);
545 static rtl::Reference<SwXCell> lcl_CreateXCell(SwFrameFormat* pFormat, sal_Int32 nColumn, sal_Int32 nRow)
547 const OUString sCellName = sw_GetCellName(nColumn, nRow);
548 SwTable* pTable = SwTable::FindTable(pFormat);
549 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
550 if(!pBox)
551 return nullptr;
552 return SwXCell::CreateXCell(pFormat, pBox, pTable);
555 static void lcl_InspectLines(SwTableLines& rLines, std::vector<OUString>& rAllNames)
557 for(auto pLine : rLines)
559 for(auto pBox : pLine->GetTabBoxes())
561 if(!pBox->GetName().isEmpty() && pBox->getRowSpan() > 0)
562 rAllNames.push_back(pBox->GetName());
563 SwTableLines& rBoxLines = pBox->GetTabLines();
564 if(!rBoxLines.empty())
565 lcl_InspectLines(rBoxLines, rAllNames);
570 static bool lcl_FormatTable(SwFrameFormat const * pTableFormat)
572 bool bHasFrames = false;
573 SwIterator<SwFrame,SwFormat> aIter( *pTableFormat );
574 for(SwFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
576 vcl::RenderContext* pRenderContext = pFrame->getRootFrame()->GetCurrShell()->GetOut();
577 // mba: no TYPEINFO for SwTabFrame
578 if(!pFrame->IsTabFrame())
579 continue;
580 DisableCallbackAction a(*pFrame->getRootFrame());
581 SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pFrame);
582 if(pTabFrame->isFrameAreaDefinitionValid())
583 pTabFrame->InvalidatePos();
584 pTabFrame->SetONECalcLowers();
585 pTabFrame->Calc(pRenderContext);
586 bHasFrames = true;
588 return bHasFrames;
591 static void lcl_CursorSelect(SwPaM& rCursor, bool bExpand)
593 if(bExpand)
595 if(!rCursor.HasMark())
596 rCursor.SetMark();
598 else if(rCursor.HasMark())
599 rCursor.DeleteMark();
602 static void lcl_GetTableSeparators(uno::Any& rRet, SwTable const * pTable, SwTableBox const * pBox, bool bRow)
604 SwTabCols aCols;
605 aCols.SetLeftMin ( 0 );
606 aCols.SetLeft ( 0 );
607 aCols.SetRight ( UNO_TABLE_COLUMN_SUM );
608 aCols.SetRightMax( UNO_TABLE_COLUMN_SUM );
610 pTable->GetTabCols( aCols, pBox, false, bRow );
612 const size_t nSepCount = aCols.Count();
613 uno::Sequence< text::TableColumnSeparator> aColSeq(nSepCount);
614 text::TableColumnSeparator* pArray = aColSeq.getArray();
615 bool bError = false;
616 for(size_t i = 0; i < nSepCount; ++i)
618 pArray[i].Position = static_cast< sal_Int16 >(aCols[i]);
619 pArray[i].IsVisible = !aCols.IsHidden(i);
620 if(!bRow && !pArray[i].IsVisible)
622 bError = true;
623 break;
626 if(!bError)
627 rRet <<= aColSeq;
631 static void lcl_SetTableSeparators(const uno::Any& rVal, SwTable* pTable, SwTableBox const * pBox, bool bRow, SwDoc* pDoc)
633 SwTabCols aOldCols;
635 aOldCols.SetLeftMin ( 0 );
636 aOldCols.SetLeft ( 0 );
637 aOldCols.SetRight ( UNO_TABLE_COLUMN_SUM );
638 aOldCols.SetRightMax( UNO_TABLE_COLUMN_SUM );
640 pTable->GetTabCols( aOldCols, pBox, false, bRow );
641 const size_t nOldCount = aOldCols.Count();
642 // there is no use in setting tab cols if there is only one column
643 if( !nOldCount )
644 return;
646 auto pSepSeq =
647 o3tl::tryAccess<uno::Sequence<text::TableColumnSeparator>>(rVal);
648 if(!pSepSeq || static_cast<size_t>(pSepSeq->getLength()) != nOldCount)
649 return;
650 SwTabCols aCols(aOldCols);
651 const text::TableColumnSeparator* pArray = pSepSeq->getConstArray();
652 tools::Long nLastValue = 0;
653 //sal_Int32 nTableWidth = aCols.GetRight() - aCols.GetLeft();
654 for(size_t i = 0; i < nOldCount; ++i)
656 aCols[i] = pArray[i].Position;
657 if(bool(pArray[i].IsVisible) == aCols.IsHidden(i) ||
658 (!bRow && aCols.IsHidden(i)) ||
659 aCols[i] < nLastValue ||
660 UNO_TABLE_COLUMN_SUM < aCols[i] )
661 return; // probably this should assert()
662 nLastValue = aCols[i];
664 pDoc->SetTabCols(*pTable, aCols, aOldCols, pBox, bRow );
667 /* non UNO function call to set string in SwXCell */
668 void sw_setString( SwXCell &rCell, const OUString &rText,
669 bool bKeepNumberFormat = false )
671 if(rCell.IsValid())
673 SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat();
674 pBoxFormat->LockModify();
675 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA );
676 pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE );
677 if (!bKeepNumberFormat)
678 pBoxFormat->SetFormatAttr( SwTableBoxNumFormat(/*default Text*/) );
679 pBoxFormat->UnlockModify();
681 rCell.SwXText::setString(rText);
685 /* non UNO function call to set value in SwXCell */
686 void sw_setValue( SwXCell &rCell, double nVal )
688 if(!rCell.IsValid())
689 return;
690 // first this text (maybe) needs to be deleted
691 SwNodeOffset nNdPos = rCell.m_pBox->IsValidNumTextNd();
692 if(NODE_OFFSET_MAX != nNdPos)
693 sw_setString( rCell, OUString(), true ); // true == keep number format
694 SwDoc* pDoc = rCell.GetDoc();
695 UnoActionContext aAction(pDoc);
696 SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat();
697 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aSet(pDoc->GetAttrPool());
699 //!! do we need to set a new number format? Yes, if
700 // - there is no current number format
701 // - the current number format is not a number format according to the number formatter, but rather a text format
702 const SwTableBoxNumFormat* pNumFormat = pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT);
703 if(!pNumFormat
704 || pDoc->GetNumberFormatter()->IsTextFormat(pNumFormat->GetValue()))
706 aSet.Put(SwTableBoxNumFormat(0));
709 SwTableBoxValue aVal(nVal);
710 aSet.Put(aVal);
711 pDoc->SetTableBoxFormulaAttrs( *rCell.m_pBox, aSet );
712 // update table
713 pDoc->getIDocumentFieldsAccess().UpdateTableFields(SwTable::FindTable(rCell.GetFrameFormat()));
717 SwXCell::SwXCell(SwFrameFormat* pTableFormat, SwTableBox* pBx, size_t const nPos) :
718 SwXText(pTableFormat->GetDoc(), CursorType::TableText),
719 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)),
720 m_pBox(pBx),
721 m_pStartNode(nullptr),
722 m_pTableFormat(pTableFormat),
723 m_nFndPos(nPos)
725 StartListening(pTableFormat->GetNotifier());
728 SwXCell::SwXCell(SwFrameFormat* pTableFormat, const SwStartNode& rStartNode) :
729 SwXText(pTableFormat->GetDoc(), CursorType::TableText),
730 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)),
731 m_pBox(nullptr),
732 m_pStartNode(&rStartNode),
733 m_pTableFormat(pTableFormat),
734 m_nFndPos(NOTFOUND)
736 StartListening(pTableFormat->GetNotifier());
739 SwXCell::~SwXCell()
741 SolarMutexGuard aGuard;
742 EndListeningAll();
745 uno::Sequence< uno::Type > SAL_CALL SwXCell::getTypes( )
747 return comphelper::concatSequences(
748 SwXCellBaseClass::getTypes(),
749 SwXText::getTypes()
753 uno::Sequence< sal_Int8 > SAL_CALL SwXCell::getImplementationId( )
755 return css::uno::Sequence<sal_Int8>();
758 void SAL_CALL SwXCell::acquire( ) noexcept
760 SwXCellBaseClass::acquire();
763 void SAL_CALL SwXCell::release( ) noexcept
765 SolarMutexGuard aGuard;
767 SwXCellBaseClass::release();
770 uno::Any SAL_CALL SwXCell::queryInterface( const uno::Type& aType )
772 uno::Any aRet = SwXText::queryInterface(aType);
773 if(aRet.getValueType() == cppu::UnoType<void>::get())
774 aRet = SwXCellBaseClass::queryInterface(aType);
775 return aRet;
778 const SwStartNode *SwXCell::GetStartNode() const
780 const SwStartNode* pSttNd = nullptr;
782 if( m_pStartNode || IsValid() )
783 pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
785 return pSttNd;
788 bool SwXCell::IsValid() const
790 // FIXME: this is now a const method, to make SwXText::IsValid invisible
791 // but the const_cast here are still ridiculous. TODO: find a better way.
792 SwFrameFormat* pTableFormat = m_pBox ? GetFrameFormat() : nullptr;
793 if(!pTableFormat)
795 const_cast<SwXCell*>(this)->m_pBox = nullptr;
797 else
799 SwTable* pTable = SwTable::FindTable( pTableFormat );
800 SwTableBox const*const pFoundBox =
801 const_cast<SwXCell*>(this)->FindBox(pTable, m_pBox);
802 if (!pFoundBox)
804 const_cast<SwXCell*>(this)->m_pBox = nullptr;
807 return nullptr != m_pBox;
810 OUString SwXCell::getFormula()
812 SolarMutexGuard aGuard;
813 if(!IsValid())
814 return OUString();
815 SwTableBoxFormula aFormula( m_pBox->GetFrameFormat()->GetTableBoxFormula() );
816 SwTable* pTable = SwTable::FindTable( GetFrameFormat() );
817 aFormula.PtrToBoxNm( pTable );
818 return aFormula.GetFormula();
821 ///@see sw_setValue (TODO: seems to be copy and paste programming here)
822 void SwXCell::setFormula(const OUString& rFormula)
824 SolarMutexGuard aGuard;
825 if(!IsValid())
826 return;
827 // first this text (maybe) needs to be deleted
828 SwNodeOffset nNdPos = m_pBox->IsValidNumTextNd();
829 if(SwNodeOffset(USHRT_MAX) == nNdPos)
830 sw_setString( *this, OUString(), true );
831 OUString sFormula(comphelper::string::stripStart(rFormula, ' '));
832 if( !sFormula.isEmpty() && '=' == sFormula[0] )
833 sFormula = sFormula.copy( 1 );
834 SwTableBoxFormula aFormula( sFormula );
835 SwDoc* pMyDoc = GetDoc();
836 UnoActionContext aAction(pMyDoc);
837 SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_FORMULA> aSet(pMyDoc->GetAttrPool());
838 SwFrameFormat* pBoxFormat = m_pBox->GetFrameFormat();
839 const SwTableBoxNumFormat* pNumFormat =
840 pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT);
841 if(!pNumFormat
842 || pMyDoc->GetNumberFormatter()->IsTextFormat(pNumFormat->GetValue()))
844 aSet.Put(SwTableBoxNumFormat(0));
846 aSet.Put(aFormula);
847 GetDoc()->SetTableBoxFormulaAttrs( *m_pBox, aSet );
848 // update table
849 pMyDoc->getIDocumentFieldsAccess().UpdateTableFields(SwTable::FindTable(GetFrameFormat()));
852 double SwXCell::getValue()
854 SolarMutexGuard aGuard;
855 // #i112652# a table cell may contain NaN as a value, do not filter that
856 if(IsValid() && !getString().isEmpty())
857 return m_pBox->GetFrameFormat()->GetTableBoxValue().GetValue();
858 return std::numeric_limits<double>::quiet_NaN();
861 void SwXCell::setValue(double rValue)
863 SolarMutexGuard aGuard;
864 sw_setValue( *this, rValue );
867 table::CellContentType SwXCell::getType()
869 SolarMutexGuard aGuard;
871 table::CellContentType nRes = table::CellContentType_EMPTY;
872 sal_uInt32 nNdPos = m_pBox->IsFormulaOrValueBox();
873 switch (nNdPos)
875 case 0 : nRes = table::CellContentType_TEXT; break;
876 case USHRT_MAX : nRes = table::CellContentType_EMPTY; break;
877 case RES_BOXATR_VALUE : nRes = table::CellContentType_VALUE; break;
878 case RES_BOXATR_FORMULA : nRes = table::CellContentType_FORMULA; break;
879 default :
880 OSL_FAIL( "unexpected case" );
882 return nRes;
885 void SwXCell::setString(const OUString& aString)
887 SolarMutexGuard aGuard;
888 sw_setString( *this, aString );
891 sal_Int32 SwXCell::getError()
893 SolarMutexGuard aGuard;
894 OUString sContent = getString();
895 return sal_Int32(sContent == SwViewShell::GetShellRes()->aCalc_Error);
898 rtl::Reference< SwXTextCursor > SwXCell::createXTextCursor()
900 if(!m_pStartNode && !IsValid())
901 throw uno::RuntimeException();
902 const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
903 SwPosition aPos(*pSttNd);
904 rtl::Reference<SwXTextCursor> const pXCursor =
905 new SwXTextCursor(*GetDoc(), this, CursorType::TableText, aPos);
906 auto& rUnoCursor(pXCursor->GetCursor());
907 rUnoCursor.Move(fnMoveForward, GoInNode);
908 return pXCursor;
911 rtl::Reference<SwXTextCursor> SwXCell::createXTextCursorByRange(const uno::Reference< text::XTextRange > & xTextPosition)
913 SwUnoInternalPaM aPam(*GetDoc());
914 if((!m_pStartNode && !IsValid()) || !::sw::XTextRangeToSwPaM(aPam, xTextPosition))
915 throw uno::RuntimeException();
916 const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
917 // skip sections
918 SwStartNode* p1 = aPam.GetPointNode().StartOfSectionNode();
919 while(p1->IsSectionNode())
920 p1 = p1->StartOfSectionNode();
921 if( p1 != pSttNd )
922 return nullptr;
923 return new SwXTextCursor(*GetDoc(), this, CursorType::TableText,
924 *aPam.GetPoint(), aPam.GetMark());
927 uno::Reference< beans::XPropertySetInfo > SwXCell::getPropertySetInfo()
929 static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo();
930 return xRef;
933 void SwXCell::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
935 SolarMutexGuard aGuard;
936 if(!IsValid())
937 return;
938 // Hack to support hidden property to transfer textDirection
939 if(rPropertyName == "FRMDirection")
941 SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, RES_FRAMEDIR);
942 aItem.PutValue(aValue, 0);
943 m_pBox->GetFrameFormat()->SetFormatAttr(aItem);
945 else if(rPropertyName == "TableRedlineParams")
947 // Get the table row properties
948 uno::Sequence<beans::PropertyValue> tableCellProperties = aValue.get< uno::Sequence< beans::PropertyValue > >();
949 comphelper::SequenceAsHashMap aPropMap(tableCellProperties);
950 OUString sRedlineType;
951 if(!(aPropMap.getValue("RedlineType") >>= sRedlineType))
952 throw beans::UnknownPropertyException("No redline type property: ", static_cast<cppu::OWeakObject*>(this));
954 // Create a 'Table Cell Redline' object
955 SwUnoCursorHelper::makeTableCellRedline(*m_pBox, sRedlineType, tableCellProperties);
959 else if (rPropertyName == "VerticalMerge")
961 //Hack to allow clearing of numbering from the paragraphs in the merged cells.
962 SwNodeIndex aIdx(*GetStartNode(), 1);
963 const SwNode* pEndNd = aIdx.GetNode().EndOfSectionNode();
964 while (&aIdx.GetNode() != pEndNd)
966 SwTextNode* pNd = aIdx.GetNode().GetTextNode();
967 if (pNd)
968 pNd->SetCountedInList(false);
969 ++aIdx;
972 else
974 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
975 if ( !pEntry )
977 // not a table property: ignore it, if it is a paragraph/character property
978 const SfxItemPropertySet& rParaPropSet = *aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH);
979 pEntry = rParaPropSet.getPropertyMap().getByName(rPropertyName);
981 if ( pEntry )
982 return;
985 if(!pEntry)
986 throw beans::UnknownPropertyException(rPropertyName, static_cast<cppu::OWeakObject*>(this));
987 if(pEntry->nWID != FN_UNO_CELL_ROW_SPAN)
989 SwFrameFormat* pBoxFormat = m_pBox->ClaimFrameFormat();
990 SwAttrSet aSet(pBoxFormat->GetAttrSet());
991 m_pPropSet->setPropertyValue(rPropertyName, aValue, aSet);
992 pBoxFormat->GetDoc()->SetAttr(aSet, *pBoxFormat);
994 else if(aValue.isExtractableTo(cppu::UnoType<sal_Int32>::get()))
995 m_pBox->setRowSpan(aValue.get<sal_Int32>());
999 uno::Any SwXCell::getPropertyValue(const OUString& rPropertyName)
1001 SolarMutexGuard aGuard;
1002 if(!IsValid())
1003 return uno::Any();
1004 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
1005 if(!pEntry)
1006 throw beans::UnknownPropertyException(rPropertyName, static_cast<cppu::OWeakObject*>(this));
1007 switch(pEntry->nWID)
1009 case FN_UNO_CELL_ROW_SPAN:
1010 return uno::Any(m_pBox->getRowSpan());
1011 case FN_UNO_TEXT_SECTION:
1013 SwFrameFormat* pTableFormat = GetFrameFormat();
1014 SwTable* pTable = SwTable::FindTable(pTableFormat);
1015 SwTableNode* pTableNode = pTable->GetTableNode();
1016 SwSectionNode* pSectionNode = pTableNode->FindSectionNode();
1017 if(!pSectionNode)
1018 return uno::Any();
1019 SwSection& rSect = pSectionNode->GetSection();
1020 return uno::Any(SwXTextSections::GetObject(*rSect.GetFormat()));
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:
1028 //redline can only be returned if it's a living object
1029 return SwXText::getPropertyValue(rPropertyName);
1031 break;
1032 case FN_UNO_PARENT_TEXT:
1034 if (!m_xParentText.is())
1036 const SwStartNode* pSttNd = m_pBox->GetSttNd();
1037 if (!pSttNd)
1038 return uno::Any();
1040 const SwTableNode* pTableNode = pSttNd->FindTableNode();
1041 if (!pTableNode)
1042 return uno::Any();
1044 SwPosition aPos(*pTableNode);
1045 SwDoc& rDoc = aPos.GetDoc();
1046 m_xParentText = sw::CreateParentXText(rDoc, aPos);
1049 return uno::Any(m_xParentText);
1051 break;
1052 default:
1054 const SwAttrSet& rSet = m_pBox->GetFrameFormat()->GetAttrSet();
1055 uno::Any aResult;
1056 m_pPropSet->getPropertyValue(rPropertyName, rSet, aResult);
1057 return aResult;
1062 void SwXCell::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1063 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1065 void SwXCell::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1066 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1068 void SwXCell::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1069 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1071 void SwXCell::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1072 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1074 uno::Reference<container::XEnumeration> SwXCell::createEnumeration()
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);
1088 uno::Type SAL_CALL SwXCell::getElementType()
1090 return cppu::UnoType<text::XTextRange>::get();
1093 sal_Bool SwXCell::hasElements()
1095 return true;
1098 void SwXCell::Notify(const SfxHint& rHint)
1100 if(rHint.GetId() == SfxHintId::Dying)
1102 m_pTableFormat = nullptr;
1104 else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableBox, SwXCell>*>(&rHint))
1106 if(!pFindHint->m_pResult && pFindHint->m_pCore == GetTableBox())
1107 pFindHint->m_pResult = this;
1111 rtl::Reference<SwXCell> SwXCell::CreateXCell(SwFrameFormat* pTableFormat, SwTableBox* pBox, SwTable *pTable )
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);
1126 /** search if a box exists in a table
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
1132 SwTableBox* SwXCell::FindBox(SwTable* pTable, SwTableBox* pBox2)
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;
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() )
1143 m_nFndPos = it - pTable->GetTabSortBoxes().begin();
1144 return pBox2;
1147 // box not found: reset nFndPos pointer
1148 m_nFndPos = NOTFOUND;
1149 return nullptr;
1152 double SwXCell::GetForcedNumericalValue() const
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);
1164 if (pNumFormat)
1166 // please note that the language of the numberformat
1167 // is implicitly coded into the below value as well
1168 nFIndex = pNumFormat->GetValue();
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);
1176 else
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 );
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;
1193 uno::Any SwXCell::GetAny() const
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());
1203 OUString SwXCell::getImplementationName()
1204 { return "SwXCell"; }
1206 sal_Bool SwXCell::supportsService(const OUString& rServiceName)
1207 { return cppu::supportsService(this, rServiceName); }
1209 uno::Sequence< OUString > SwXCell::getSupportedServiceNames()
1210 { return {"com.sun.star.text.CellProperties"}; }
1212 OUString SwXTextTableRow::getImplementationName()
1213 { return "SwXTextTableRow"; }
1215 sal_Bool SwXTextTableRow::supportsService(const OUString& rServiceName)
1216 { return cppu::supportsService(this, rServiceName); }
1218 uno::Sequence< OUString > SwXTextTableRow::getSupportedServiceNames()
1219 { return {"com.sun.star.text.TextTableRow"}; }
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))
1227 StartListening(m_pFormat->GetNotifier());
1230 SwXTextTableRow::~SwXTextTableRow()
1232 SolarMutexGuard aGuard;
1233 EndListeningAll();
1236 uno::Reference< beans::XPropertySetInfo > SwXTextTableRow::getPropertySetInfo()
1238 static uno::Reference<beans::XPropertySetInfo> xRef = m_pPropSet->getPropertySetInfo();
1239 return xRef;
1242 void SwXTextTableRow::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
1244 SolarMutexGuard aGuard;
1245 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
1246 SwTable* pTable = SwTable::FindTable( pFormat );
1247 SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, m_pLine);
1248 if(!pLn)
1249 return;
1251 // Check for a specific property
1252 if ( rPropertyName == "TableRedlineParams" )
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("RedlineType") >>= sRedlineType) )
1260 throw beans::UnknownPropertyException("No redline type property: ", static_cast < cppu::OWeakObject * > ( this ) );
1263 // Create a 'Table Row Redline' object
1264 SwUnoCursorHelper::makeTableRowRedline( *pLn, sRedlineType, tableRowProperties);
1267 else
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, static_cast < cppu::OWeakObject * > ( this ) );
1274 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
1275 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
1277 switch(pEntry->nWID)
1279 case FN_UNO_ROW_HEIGHT:
1280 case FN_UNO_ROW_AUTO_HEIGHT:
1282 SwFormatFrameSize aFrameSize(pLn->GetFrameFormat()->GetFrameSize());
1283 if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID)
1285 bool bSet = *o3tl::doAccess<bool>(aValue);
1286 aFrameSize.SetHeightSizeType(bSet ? SwFrameSize::Variable : SwFrameSize::Fixed);
1288 else
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);
1296 pDoc->SetAttr(aFrameSize, *pLn->ClaimFrameFormat());
1298 break;
1300 case FN_UNO_TABLE_COLUMN_SEPARATORS:
1302 UnoActionContext aContext(pDoc);
1303 SwTable* pTable2 = SwTable::FindTable( pFormat );
1304 lcl_SetTableSeparators(aValue, pTable2, m_pLine->GetTabBoxes()[0], true, pDoc);
1306 break;
1308 default:
1310 SwFrameFormat* pLnFormat = pLn->ClaimFrameFormat();
1311 SwAttrSet aSet(pLnFormat->GetAttrSet());
1312 m_pPropSet->setPropertyValue(*pEntry, aValue, aSet);
1313 pDoc->SetAttr(aSet, *pLnFormat);
1319 uno::Any SwXTextTableRow::getPropertyValue(const OUString& rPropertyName)
1321 SolarMutexGuard aGuard;
1322 uno::Any aRet;
1323 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
1324 SwTable* pTable = SwTable::FindTable( pFormat );
1325 SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, m_pLine);
1326 if(pLn)
1328 const SfxItemPropertyMapEntry* pEntry =
1329 m_pPropSet->getPropertyMap().getByName(rPropertyName);
1330 if (!pEntry)
1331 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
1333 switch(pEntry->nWID)
1335 case FN_UNO_ROW_HEIGHT:
1336 case FN_UNO_ROW_AUTO_HEIGHT:
1338 const SwFormatFrameSize& rSize = pLn->GetFrameFormat()->GetFrameSize();
1339 if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID)
1341 aRet <<= SwFrameSize::Variable == rSize.GetHeightSizeType();
1343 else
1344 aRet <<= static_cast<sal_Int32>(convertTwipToMm100(rSize.GetSize().Height()));
1346 break;
1348 case FN_UNO_TABLE_COLUMN_SEPARATORS:
1350 lcl_GetTableSeparators(aRet, pTable, m_pLine->GetTabBoxes()[0], true);
1352 break;
1354 default:
1356 const SwAttrSet& rSet = pLn->GetFrameFormat()->GetAttrSet();
1357 m_pPropSet->getPropertyValue(*pEntry, rSet, aRet);
1361 return aRet;
1364 void SwXTextTableRow::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1365 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1367 void SwXTextTableRow::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1368 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1370 void SwXTextTableRow::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1371 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1373 void SwXTextTableRow::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1374 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1376 void SwXTextTableRow::Notify(const SfxHint& rHint)
1378 if(rHint.GetId() == SfxHintId::Dying)
1380 m_pFormat = nullptr;
1381 } else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableLine, SwXTextTableRow>*>(&rHint))
1383 if(!pFindHint->m_pCore && pFindHint->m_pCore == m_pLine)
1384 pFindHint->m_pResult = this;
1388 SwTableLine* SwXTextTableRow::FindLine(SwTable* pTable, SwTableLine const * pLine)
1390 for(const auto& pCurrentLine : pTable->GetTabLines())
1391 if(pCurrentLine == pLine)
1392 return pCurrentLine;
1393 return nullptr;
1396 // SwXTextTableCursor
1398 OUString SwXTextTableCursor::getImplementationName()
1399 { return "SwXTextTableCursor"; }
1401 sal_Bool SwXTextTableCursor::supportsService(const OUString& rServiceName)
1402 { return cppu::supportsService(this, rServiceName); }
1404 void SwXTextTableCursor::release() noexcept
1406 SolarMutexGuard aGuard;
1407 SwXTextTableCursor_Base::release();
1410 const SwPaM* SwXTextTableCursor::GetPaM() const { return &GetCursor(); }
1411 SwPaM* SwXTextTableCursor::GetPaM() { return &GetCursor(); }
1412 const SwDoc* SwXTextTableCursor::GetDoc() const { return GetFrameFormat()->GetDoc(); }
1413 SwDoc* SwXTextTableCursor::GetDoc() { return GetFrameFormat()->GetDoc(); }
1414 const SwUnoCursor& SwXTextTableCursor::GetCursor() const { return *m_pUnoCursor; }
1415 SwUnoCursor& SwXTextTableCursor::GetCursor() { return *m_pUnoCursor; }
1417 uno::Sequence<OUString> SwXTextTableCursor::getSupportedServiceNames()
1418 { return {"com.sun.star.text.TextTableCursor"}; }
1420 SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat* pFrameFormat, SwTableBox const* pBox)
1421 : m_pFrameFormat(pFrameFormat)
1422 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
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();
1434 SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat& rTableFormat, const SwTableCursor* pTableSelection)
1435 : m_pFrameFormat(&rTableFormat)
1436 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
1438 StartListening(m_pFrameFormat->GetNotifier());
1439 m_pUnoCursor = pTableSelection->GetDoc().CreateUnoCursor(*pTableSelection->GetPoint(), true);
1440 if(pTableSelection->HasMark())
1442 m_pUnoCursor->SetMark();
1443 *m_pUnoCursor->GetMark() = *pTableSelection->GetMark();
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();
1452 OUString SwXTextTableCursor::getRangeName()
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())
1466 pNode = pTableCursor->GetMark()->GetNode().FindTableBoxStartNode();
1467 const SwTableBox* pStartBox = pTable->GetTableBox(pNode->GetIndex());
1468 if(pEndBox != pStartBox)
1470 // need to switch start and end?
1471 if(*pTableCursor->GetPoint() < *pTableCursor->GetMark())
1472 std::swap(pStartBox, pEndBox);
1473 return pStartBox->GetName() + ":" + pEndBox->GetName();
1476 return pEndBox->GetName();
1479 sal_Bool SwXTextTableCursor::gotoCellByName(const OUString& sCellName, sal_Bool bExpand)
1481 SolarMutexGuard aGuard;
1482 SwUnoCursor& rUnoCursor = GetCursor();
1483 auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1484 lcl_CursorSelect(rTableCursor, bExpand);
1485 return rTableCursor.GotoTableBox(sCellName);
1488 sal_Bool SwXTextTableCursor::goLeft(sal_Int16 Count, sal_Bool bExpand)
1490 SolarMutexGuard aGuard;
1491 SwUnoCursor& rUnoCursor = GetCursor();
1492 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1493 lcl_CursorSelect(rTableCursor, bExpand);
1494 return rTableCursor.Left(Count);
1497 sal_Bool SwXTextTableCursor::goRight(sal_Int16 Count, sal_Bool bExpand)
1499 SolarMutexGuard aGuard;
1500 SwUnoCursor& rUnoCursor = GetCursor();
1501 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1502 lcl_CursorSelect(rTableCursor, bExpand);
1503 return rTableCursor.Right(Count);
1506 sal_Bool SwXTextTableCursor::goUp(sal_Int16 Count, sal_Bool bExpand)
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());
1516 sal_Bool SwXTextTableCursor::goDown(sal_Int16 Count, sal_Bool bExpand)
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());
1526 void SwXTextTableCursor::gotoStart(sal_Bool bExpand)
1528 SolarMutexGuard aGuard;
1529 SwUnoCursor& rUnoCursor = GetCursor();
1530 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1531 lcl_CursorSelect(rTableCursor, bExpand);
1532 rTableCursor.MoveTable(GotoCurrTable, fnTableStart);
1535 void SwXTextTableCursor::gotoEnd(sal_Bool bExpand)
1537 SolarMutexGuard aGuard;
1538 SwUnoCursor& rUnoCursor = GetCursor();
1539 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1540 lcl_CursorSelect(rTableCursor, bExpand);
1541 rTableCursor.MoveTable(GotoCurrTable, fnTableEnd);
1544 sal_Bool SwXTextTableCursor::mergeRange()
1546 SolarMutexGuard aGuard;
1547 SwUnoCursor& rUnoCursor = GetCursor();
1549 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1551 // HACK: remove pending actions for selecting old style tables
1552 UnoActionRemoveContext aRemoveContext(rTableCursor);
1554 rTableCursor.MakeBoxSels();
1555 bool bResult;
1557 UnoActionContext aContext(&rUnoCursor.GetDoc());
1558 bResult = TableMergeErr::Ok == rTableCursor.GetDoc().MergeTable(rTableCursor);
1560 if(bResult)
1562 size_t nCount = rTableCursor.GetSelectedBoxesCount();
1563 while (nCount--)
1564 rTableCursor.DeleteBox(nCount);
1566 rTableCursor.MakeBoxSels();
1567 return bResult;
1570 sal_Bool SwXTextTableCursor::splitRange(sal_Int16 Count, sal_Bool Horizontal)
1572 SolarMutexGuard aGuard;
1573 if (Count <= 0)
1574 throw uno::RuntimeException("Illegal first argument: needs to be > 0", static_cast<cppu::OWeakObject*>(this));
1575 SwUnoCursor& rUnoCursor = GetCursor();
1576 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1578 // HACK: remove pending actions for selecting old style tables
1579 UnoActionRemoveContext aRemoveContext(rTableCursor);
1581 rTableCursor.MakeBoxSels();
1582 bool bResult;
1584 UnoActionContext aContext(&rUnoCursor.GetDoc());
1585 bResult = rTableCursor.GetDoc().SplitTable(rTableCursor.GetSelectedBoxes(), !Horizontal, Count);
1587 rTableCursor.MakeBoxSels();
1588 return bResult;
1591 uno::Reference< beans::XPropertySetInfo > SwXTextTableCursor::getPropertySetInfo()
1593 static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo();
1594 return xRef;
1597 void SwXTextTableCursor::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
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, static_cast<cppu::OWeakObject*>(this));
1604 if(pEntry->nFlags & beans::PropertyAttribute::READONLY)
1605 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast<cppu::OWeakObject*>(this));
1607 auto pSttNode = rUnoCursor.GetPointNode().StartOfSectionNode();
1608 const SwTableNode* pTableNode = pSttNode->FindTableNode();
1609 lcl_FormatTable(pTableNode->GetTable().GetFrameFormat());
1611 auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1612 rTableCursor.MakeBoxSels();
1613 SwDoc& rDoc = rUnoCursor.GetDoc();
1614 switch(pEntry->nWID)
1616 case FN_UNO_TABLE_CELL_BACKGROUND:
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);
1624 break;
1625 case RES_BOXATR_FORMAT:
1627 SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT);
1628 aNumberFormat.PutValue(aValue, 0);
1629 rDoc.SetBoxAttr(rUnoCursor, aNumberFormat);
1631 break;
1632 case FN_UNO_PARA_STYLE:
1633 SwUnoCursorHelper::SetTextFormatColl(aValue, rUnoCursor);
1634 break;
1635 default:
1637 SfxItemSet aItemSet(rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID);
1638 SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(),
1639 aItemSet);
1641 if (!SwUnoCursorHelper::SetCursorPropertyValue(
1642 *pEntry, aValue, rTableCursor.GetSelRing(), aItemSet))
1644 m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet);
1646 SwUnoCursorHelper::SetCursorAttr(rTableCursor.GetSelRing(),
1647 aItemSet, SetAttrMode::DEFAULT, true);
1652 uno::Any SwXTextTableCursor::getPropertyValue(const OUString& rPropertyName)
1654 SolarMutexGuard aGuard;
1655 SwUnoCursor& rUnoCursor = GetCursor();
1657 auto pSttNode = rUnoCursor.GetPointNode().StartOfSectionNode();
1658 const SwTableNode* pTableNode = pSttNode->FindTableNode();
1659 lcl_FormatTable(pTableNode->GetTable().GetFrameFormat());
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, static_cast<cppu::OWeakObject*>(this));
1665 rTableCursor.MakeBoxSels();
1666 uno::Any aResult;
1667 switch(pEntry->nWID)
1669 case FN_UNO_TABLE_CELL_BACKGROUND:
1671 std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
1672 if (SwDoc::GetBoxAttr(rUnoCursor, aBrush))
1673 aBrush->QueryValue(aResult, pEntry->nMemberId);
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, static_cast<cppu::OWeakObject*>(this));
1679 break;
1680 case FN_UNO_PARA_STYLE:
1682 auto pFormat(SwUnoCursorHelper::GetCurTextFormatColl(rUnoCursor, false));
1683 if(pFormat)
1684 aResult <<= pFormat->GetName();
1686 break;
1687 default:
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 m_pPropSet->getPropertyValue(*pEntry, aSet, aResult);
1697 return aResult;
1700 void SwXTextTableCursor::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1701 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1703 void SwXTextTableCursor::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1704 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1706 void SwXTextTableCursor::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1707 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1709 void SwXTextTableCursor::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1710 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1712 void SwXTextTableCursor::Notify( const SfxHint& rHint )
1714 if(rHint.GetId() == SfxHintId::Dying)
1715 m_pFrameFormat = nullptr;
1719 // SwXTextTable ===========================================================
1721 namespace {
1723 class SwTableProperties_Impl
1725 SwUnoCursorHelper::SwAnyMapHelper m_aAnyMap;
1727 public:
1728 SwTableProperties_Impl();
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);
1739 SwTableProperties_Impl::SwTableProperties_Impl()
1742 void SwTableProperties_Impl::SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rVal)
1744 m_aAnyMap.SetValue(nWhichId, nMemberId, rVal);
1747 bool SwTableProperties_Impl::GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny )
1749 return m_aAnyMap.FillValue(nWhichId, nMemberId, rpAny);
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)
1756 std::vector< std::pair<sal_uInt16, const uno::Any* > > vMemberAndAny;
1757 for(sal_uInt16 nMember : vMember)
1759 const uno::Any* pAny = nullptr;
1760 GetProperty(nWhich, nMember, pAny);
1761 if(pAny)
1762 vMemberAndAny.emplace_back(nMember, pAny);
1764 if(!vMemberAndAny.empty())
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));
1772 void SwTableProperties_Impl::ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc)
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 ))
1786 bool bVal(pRepHead->get<bool>());
1787 const_cast<SwTable&>(rTable).SetRowsToRepeat( bVal ? 1 : 0 ); // TODO: MULTIHEADER
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 });
1797 bool bPutBreak = true;
1798 const uno::Any* pPage;
1799 if(GetProperty(FN_UNO_PAGE_STYLE, 0, pPage) || GetProperty(RES_PAGEDESC, 0xff, pPage))
1801 OUString sPageStyle = pPage->get<OUString>();
1802 if(!sPageStyle.isEmpty())
1804 SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc);
1805 const SwPageDesc* pDesc = SwPageDesc::GetByName(rDoc, sPageStyle);
1806 if(pDesc)
1808 SwFormatPageDesc aDesc(pDesc);
1809 const uno::Any* pPgNo;
1810 if(GetProperty(RES_PAGEDESC, MID_PAGEDESC_PAGENUMOFFSET, pPgNo))
1812 aDesc.SetNumOffset(pPgNo->get<sal_Int16>());
1814 aSet.Put(aDesc);
1815 bPutBreak = false;
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);
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);
1834 bool bPutSize = pWidth != nullptr;
1835 SwFormatFrameSize aSz(SwFrameSize::Variable);
1836 if(pWidth)
1838 aSz.PutValue(*pWidth, MID_FRMSIZE_WIDTH);
1839 bPutSize = true;
1841 if(pSzRel && pSzRel->get<bool>() && pRelWidth)
1843 aSz.PutValue(*pRelWidth, MID_FRMSIZE_REL_WIDTH|CONVERT_TWIPS);
1844 bPutSize = true;
1846 if(bPutSize)
1848 if(!aSz.GetWidth())
1849 aSz.SetWidth(MINLAY);
1850 aSet.Put(aSz);
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))
1861 SwFormatLayoutSplit aSp(pSplit->get<bool>());
1862 aSet.Put(aSp);
1864 if(aSet.Count())
1866 rDoc.SetAttr(aSet, *rTable.GetFrameFormat());
1870 class SwXTextTable::Impl
1871 : public SvtListener
1873 private:
1874 SwFrameFormat* m_pFrameFormat;
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;
1882 const SfxItemPropertySet * m_pPropSet;
1884 css::uno::WeakReference<css::table::XTableRows> m_xRows;
1885 css::uno::WeakReference<css::table::XTableColumns> m_xColumns;
1887 bool m_bFirstRowAsLabel;
1888 bool m_bFirstColumnAsLabel;
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;
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)
1905 if(m_pFrameFormat)
1906 StartListening(m_pFrameFormat->GetNotifier());
1909 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
1910 void SetFrameFormat(SwFrameFormat& rFrameFormat)
1912 EndListeningAll();
1913 m_pFrameFormat = &rFrameFormat;
1914 StartListening(m_pFrameFormat->GetNotifier());
1917 bool IsDescriptor() const { return m_pTableProps != nullptr; }
1919 // note: lock mutex before calling this to avoid concurrent update
1920 static std::pair<sal_uInt16, sal_uInt16> ThrowIfComplex(SwXTextTable &rThis)
1922 sal_uInt16 const nRowCount(rThis.m_pImpl->GetRowCount());
1923 sal_uInt16 const nColCount(rThis.m_pImpl->GetColumnCount());
1924 if (!nRowCount || !nColCount)
1926 throw uno::RuntimeException("Table too complex",
1927 static_cast<cppu::OWeakObject*>(&rThis));
1929 return std::make_pair(nRowCount, nColCount);
1932 sal_uInt16 GetRowCount();
1933 sal_uInt16 GetColumnCount();
1935 virtual void Notify(const SfxHint&) override;
1939 SwXTextTable::SwXTextTable()
1940 : m_pImpl(new Impl(nullptr))
1944 SwXTextTable::SwXTextTable(SwFrameFormat& rFrameFormat)
1945 : m_pImpl(new Impl(&rFrameFormat))
1949 SwXTextTable::~SwXTextTable()
1953 rtl::Reference<SwXTextTable> SwXTextTable::CreateXTextTable(SwFrameFormat* const pFrameFormat)
1955 rtl::Reference<SwXTextTable> xTable;
1956 if(pFrameFormat)
1957 xTable = dynamic_cast<SwXTextTable*>(pFrameFormat->GetXObject().get().get()); // cached?
1958 if(xTable.is())
1959 return xTable;
1960 xTable = pFrameFormat ? new SwXTextTable(*pFrameFormat) : new SwXTextTable();
1961 if(pFrameFormat)
1962 pFrameFormat->SetXObject(static_cast<cppu::OWeakObject*>(xTable.get()));
1963 // need a permanent Reference to initialize m_wThis
1964 xTable->m_pImpl->m_wThis = xTable.get();
1965 return xTable;
1968 SwFrameFormat* SwXTextTable::GetFrameFormat()
1970 return m_pImpl->GetFrameFormat();
1973 void SwXTextTable::initialize(sal_Int32 nR, sal_Int32 nC)
1975 if (!m_pImpl->IsDescriptor() || nR <= 0 || nC <= 0 || nR >= SAL_MAX_UINT16 || nC >= SAL_MAX_UINT16)
1976 throw uno::RuntimeException();
1977 m_pImpl->m_nRows = o3tl::narrowing<sal_uInt16>(nR);
1978 m_pImpl->m_nColumns = o3tl::narrowing<sal_uInt16>(nC);
1981 uno::Reference<table::XTableRows> SAL_CALL SwXTextTable::getRows()
1983 SolarMutexGuard aGuard;
1984 uno::Reference<table::XTableRows> xResult(m_pImpl->m_xRows);
1985 if(xResult.is())
1986 return xResult;
1987 if(SwFrameFormat* pFormat = GetFrameFormat())
1988 m_pImpl->m_xRows = xResult = new SwXTableRows(*pFormat);
1989 if(!xResult.is())
1990 throw uno::RuntimeException();
1991 return xResult;
1994 uno::Reference<table::XTableColumns> SAL_CALL SwXTextTable::getColumns()
1996 SolarMutexGuard aGuard;
1997 uno::Reference<table::XTableColumns> xResult(m_pImpl->m_xColumns);
1998 if(xResult.is())
1999 return xResult;
2000 if(SwFrameFormat* pFormat = GetFrameFormat())
2001 m_pImpl->m_xColumns = xResult = new SwXTableColumns(*pFormat);
2002 if(!xResult.is())
2003 throw uno::RuntimeException();
2004 return xResult;
2007 uno::Reference<table::XCell> SwXTextTable::getCellByName(const OUString& sCellName)
2009 SolarMutexGuard aGuard;
2010 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2011 SwTable* pTable = SwTable::FindTable(pFormat);
2012 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
2013 if(!pBox)
2014 return nullptr;
2015 return SwXCell::CreateXCell(pFormat, pBox);
2018 uno::Sequence<OUString> SwXTextTable::getCellNames()
2020 SolarMutexGuard aGuard;
2021 SwFrameFormat* pFormat(GetFrameFormat());
2022 if(!pFormat)
2023 return {};
2024 SwTable* pTable = SwTable::FindTable(pFormat);
2025 // exists at the table and at all boxes
2026 SwTableLines& rTableLines = pTable->GetTabLines();
2027 std::vector<OUString> aAllNames;
2028 lcl_InspectLines(rTableLines, aAllNames);
2029 return comphelper::containerToSequence(aAllNames);
2032 uno::Reference<text::XTextTableCursor> SwXTextTable::createCursorByCellName(const OUString& sCellName)
2034 SolarMutexGuard aGuard;
2035 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2036 SwTable* pTable = SwTable::FindTable(pFormat);
2037 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
2038 if(!pBox || pBox->getRowSpan() == 0)
2039 throw uno::RuntimeException();
2040 return new SwXTextTableCursor(pFormat, pBox);
2043 void SAL_CALL
2044 SwXTextTable::attach(const uno::Reference<text::XTextRange> & xTextRange)
2046 SolarMutexGuard aGuard;
2048 // attach() must only be called once
2049 if (!m_pImpl->IsDescriptor()) /* already attached ? */
2050 throw uno::RuntimeException("SwXTextTable: already attached to range.", static_cast<cppu::OWeakObject*>(this));
2052 SwXTextRange* pRange(dynamic_cast<SwXTextRange*>(xTextRange.get()));
2053 OTextCursorHelper* pCursor(dynamic_cast<OTextCursorHelper*>(xTextRange.get()));
2054 SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr;
2055 if (!pDoc || !m_pImpl->m_nRows || !m_pImpl->m_nColumns)
2056 throw lang::IllegalArgumentException();
2057 SwUnoInternalPaM aPam(*pDoc);
2058 // this now needs to return TRUE
2059 ::sw::XTextRangeToSwPaM(aPam, xTextRange);
2061 UnoActionContext aCont(pDoc);
2063 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
2064 const SwTable* pTable(nullptr);
2065 if( 0 != aPam.Start()->GetContentIndex() )
2067 pDoc->getIDocumentContentOperations().SplitNode(*aPam.Start(), false);
2069 //TODO: if it is the last paragraph than add another one!
2070 if(aPam.HasMark())
2072 pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam);
2073 aPam.DeleteMark();
2076 OUString tableName;
2077 if (const::uno::Any* pName;
2078 m_pImpl->m_pTableProps->GetProperty(FN_UNO_TABLE_NAME, 0, pName))
2080 tableName = pName->get<OUString>();
2082 else if (!m_pImpl->m_sTableName.isEmpty())
2084 sal_uInt16 nIndex = 1;
2085 tableName = m_pImpl->m_sTableName;
2086 while (pDoc->FindTableFormatByName(tableName, true) && nIndex < USHRT_MAX)
2087 tableName = m_pImpl->m_sTableName + OUString::number(nIndex++);
2090 pTable = pDoc->InsertTable(SwInsertTableOptions( SwInsertTableFlags::Headline | SwInsertTableFlags::DefaultBorder | SwInsertTableFlags::SplitLayout, 0 ),
2091 *aPam.GetPoint(),
2092 m_pImpl->m_nRows,
2093 m_pImpl->m_nColumns,
2094 text::HoriOrientation::FULL,
2095 nullptr, nullptr, false, true,
2096 tableName);
2097 if(pTable)
2099 // here, the properties of the descriptor need to be analyzed
2100 m_pImpl->m_pTableProps->ApplyTableAttr(*pTable, *pDoc);
2101 SwFrameFormat* pTableFormat(pTable->GetFrameFormat());
2102 lcl_FormatTable(pTableFormat);
2104 m_pImpl->SetFrameFormat(*pTableFormat);
2106 m_pImpl->m_pTableProps.reset();
2108 pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
2112 uno::Reference<text::XTextRange> SwXTextTable::getAnchor()
2114 SolarMutexGuard aGuard;
2115 SwTableFormat *const pFormat = static_cast<SwTableFormat*>(
2116 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
2117 return new SwXTextRange(*pFormat);
2120 void SwXTextTable::dispose()
2122 SolarMutexGuard aGuard;
2123 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2124 SwTable* pTable = SwTable::FindTable(pFormat);
2125 SwSelBoxes aSelBoxes;
2126 for(auto& rBox : pTable->GetTabSortBoxes() )
2127 aSelBoxes.insert(rBox);
2128 pFormat->GetDoc()->DeleteRowCol(aSelBoxes, SwDoc::RowColMode::DeleteProtected);
2131 void SAL_CALL SwXTextTable::addEventListener(
2132 const uno::Reference<lang::XEventListener> & xListener)
2134 // no need to lock here as m_pImpl is const and container threadsafe
2135 std::unique_lock aGuard(m_pImpl->m_Mutex);
2136 m_pImpl->m_EventListeners.addInterface(aGuard, xListener);
2139 void SAL_CALL SwXTextTable::removeEventListener(
2140 const uno::Reference< lang::XEventListener > & xListener)
2142 // no need to lock here as m_pImpl is const and container threadsafe
2143 std::unique_lock aGuard(m_pImpl->m_Mutex);
2144 m_pImpl->m_EventListeners.removeInterface(aGuard, xListener);
2147 uno::Reference<table::XCell> SwXTextTable::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow)
2149 SolarMutexGuard aGuard;
2150 SwFrameFormat* pFormat(GetFrameFormat());
2151 // sheet is unimportant
2152 if(nColumn >= 0 && nRow >= 0 && pFormat)
2154 auto pXCell = lcl_CreateXCell(pFormat, nColumn, nRow);
2155 if(pXCell)
2156 return pXCell;
2158 throw lang::IndexOutOfBoundsException();
2161 namespace {
2163 uno::Reference<table::XCellRange> GetRangeByName(
2164 SwFrameFormat* pFormat, SwTable const * pTable,
2165 const OUString& rTLName, const OUString& rBRName,
2166 SwRangeDescriptor const & rDesc)
2168 const SwTableBox* pTLBox = pTable->GetTableBox(rTLName);
2169 if(!pTLBox)
2170 return nullptr;
2171 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2172 SwPosition aPos(*pSttNd);
2173 // set cursor to the upper-left cell of the range
2174 auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true));
2175 pUnoCursor->Move(fnMoveForward, GoInNode);
2176 pUnoCursor->SetRemainInSection(false);
2177 const SwTableBox* pBRBox(pTable->GetTableBox(rBRName));
2178 if(!pBRBox)
2179 return nullptr;
2180 pUnoCursor->SetMark();
2181 pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
2182 pUnoCursor->Move( fnMoveForward, GoInNode );
2183 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2184 // HACK: remove pending actions for selecting old style tables
2185 UnoActionRemoveContext aRemoveContext(rCursor);
2186 rCursor.MakeBoxSels();
2187 // pUnoCursor will be provided and will not be deleted
2188 return SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, rDesc);
2191 } // namespace
2193 uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByPosition(sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom)
2195 SolarMutexGuard aGuard;
2196 SwFrameFormat* pFormat(GetFrameFormat());
2197 if(pFormat &&
2198 nLeft <= nRight && nTop <= nBottom &&
2199 nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 )
2201 SwTable* pTable = SwTable::FindTable(pFormat);
2202 if(!pTable->IsTableComplex())
2204 SwRangeDescriptor aDesc;
2205 aDesc.nTop = nTop;
2206 aDesc.nBottom = nBottom;
2207 aDesc.nLeft = nLeft;
2208 aDesc.nRight = nRight;
2209 const OUString sTLName = sw_GetCellName(aDesc.nLeft, aDesc.nTop);
2210 const OUString sBRName = sw_GetCellName(aDesc.nRight, aDesc.nBottom);
2211 // please note that according to the 'if' statement at the begin
2212 // sTLName:sBRName already denotes the normalized range string
2213 return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc);
2216 throw lang::IndexOutOfBoundsException();
2219 uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByName(const OUString& sRange)
2221 SolarMutexGuard aGuard;
2222 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2223 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), static_cast<cppu::OWeakObject*>(this));
2224 sal_Int32 nPos = 0;
2225 const OUString sTLName(sRange.getToken(0, ':', nPos));
2226 const OUString sBRName(sRange.getToken(0, ':', nPos));
2227 if(sTLName.isEmpty() || sBRName.isEmpty())
2228 throw uno::RuntimeException();
2229 SwRangeDescriptor aDesc;
2230 aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1;
2231 SwXTextTable::GetCellPosition(sTLName, aDesc.nLeft, aDesc.nTop );
2232 SwXTextTable::GetCellPosition(sBRName, aDesc.nRight, aDesc.nBottom );
2234 // we should normalize the range now (e.g. A5:C1 will become A1:C5)
2235 // since (depending on what is done later) it will be troublesome
2236 // elsewhere when the cursor in the implementation does not
2237 // point to the top-left and bottom-right cells
2238 aDesc.Normalize();
2239 return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc);
2242 uno::Sequence< uno::Sequence< uno::Any > > SAL_CALL SwXTextTable::getDataArray()
2244 SolarMutexGuard aGuard;
2245 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2246 uno::Reference<sheet::XCellRangeData> const xAllRange(
2247 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2248 uno::UNO_QUERY_THROW);
2249 return xAllRange->getDataArray();
2252 void SAL_CALL SwXTextTable::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray)
2254 SolarMutexGuard aGuard;
2255 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2256 uno::Reference<sheet::XCellRangeData> const xAllRange(
2257 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2258 uno::UNO_QUERY_THROW);
2259 return xAllRange->setDataArray(rArray);
2262 uno::Sequence< uno::Sequence< double > > SwXTextTable::getData()
2264 SolarMutexGuard aGuard;
2265 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2266 uno::Reference<chart::XChartDataArray> const xAllRange(
2267 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2268 uno::UNO_QUERY_THROW);
2269 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2270 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2271 return xAllRange->getData();
2274 void SwXTextTable::setData(const uno::Sequence< uno::Sequence< double > >& rData)
2276 SolarMutexGuard aGuard;
2277 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2278 uno::Reference<chart::XChartDataArray> const xAllRange(
2279 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2280 uno::UNO_QUERY_THROW);
2281 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2282 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2283 xAllRange->setData(rData);
2284 // this is rather inconsistent: setData on XTextTable sends events, but e.g. CellRanges do not
2285 std::unique_lock aGuard2(m_pImpl->m_Mutex);
2286 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
2289 uno::Sequence<OUString> SwXTextTable::getRowDescriptions()
2291 SolarMutexGuard aGuard;
2292 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2293 uno::Reference<chart::XChartDataArray> const xAllRange(
2294 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2295 uno::UNO_QUERY_THROW);
2296 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2297 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2298 return xAllRange->getRowDescriptions();
2301 void SwXTextTable::setRowDescriptions(const uno::Sequence<OUString>& rRowDesc)
2303 SolarMutexGuard aGuard;
2304 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2305 uno::Reference<chart::XChartDataArray> const xAllRange(
2306 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2307 uno::UNO_QUERY_THROW);
2308 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2309 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2310 xAllRange->setRowDescriptions(rRowDesc);
2313 uno::Sequence<OUString> SwXTextTable::getColumnDescriptions()
2315 SolarMutexGuard aGuard;
2316 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2317 uno::Reference<chart::XChartDataArray> const xAllRange(
2318 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2319 uno::UNO_QUERY_THROW);
2320 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2321 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2322 return xAllRange->getColumnDescriptions();
2325 void SwXTextTable::setColumnDescriptions(const uno::Sequence<OUString>& rColumnDesc)
2327 SolarMutexGuard aGuard;
2328 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2329 uno::Reference<chart::XChartDataArray> const xAllRange(
2330 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2331 uno::UNO_QUERY_THROW);
2332 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2333 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2334 return xAllRange->setColumnDescriptions(rColumnDesc);
2337 void SAL_CALL SwXTextTable::addChartDataChangeEventListener(
2338 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
2340 // no need to lock here as m_pImpl is const and container threadsafe
2341 std::unique_lock aGuard(m_pImpl->m_Mutex);
2342 m_pImpl->m_ChartListeners.addInterface(aGuard, xListener);
2345 void SAL_CALL SwXTextTable::removeChartDataChangeEventListener(
2346 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
2348 // no need to lock here as m_pImpl is const and container threadsafe
2349 std::unique_lock aGuard(m_pImpl->m_Mutex);
2350 m_pImpl->m_ChartListeners.removeInterface(aGuard, xListener);
2353 sal_Bool SwXTextTable::isNotANumber(double nNumber)
2355 // We use DBL_MIN because starcalc does (which uses it because chart
2356 // wants it that way!)
2357 return ( nNumber == DBL_MIN );
2360 double SwXTextTable::getNotANumber()
2362 // We use DBL_MIN because starcalc does (which uses it because chart
2363 // wants it that way!)
2364 return DBL_MIN;
2367 uno::Sequence< beans::PropertyValue > SwXTextTable::createSortDescriptor()
2369 SolarMutexGuard aGuard;
2371 return SwUnoCursorHelper::CreateSortDescriptor(true);
2374 void SwXTextTable::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
2376 SolarMutexGuard aGuard;
2377 SwSortOptions aSortOpt;
2378 SwFrameFormat* pFormat = GetFrameFormat();
2379 if(!(pFormat &&
2380 SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt)))
2381 return;
2383 SwTable* pTable = SwTable::FindTable( pFormat );
2384 SwSelBoxes aBoxes;
2385 const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes();
2386 for (size_t n = 0; n < rTBoxes.size(); ++n)
2388 SwTableBox* pBox = rTBoxes[ n ];
2389 aBoxes.insert( pBox );
2391 UnoActionContext aContext( pFormat->GetDoc() );
2392 pFormat->GetDoc()->SortTable(aBoxes, aSortOpt);
2395 void SwXTextTable::autoFormat(const OUString& sAutoFormatName)
2397 SolarMutexGuard aGuard;
2398 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2399 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), static_cast<cppu::OWeakObject*>(this));
2400 SwTableAutoFormatTable aAutoFormatTable;
2401 aAutoFormatTable.Load();
2402 for (size_t i = aAutoFormatTable.size(); i;)
2403 if( sAutoFormatName == aAutoFormatTable[ --i ].GetName() )
2405 SwSelBoxes aBoxes;
2406 const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes();
2407 for (size_t n = 0; n < rTBoxes.size(); ++n)
2409 SwTableBox* pBox = rTBoxes[ n ];
2410 aBoxes.insert( pBox );
2412 UnoActionContext aContext( pFormat->GetDoc() );
2413 pFormat->GetDoc()->SetTableAutoFormat( aBoxes, aAutoFormatTable[i] );
2414 break;
2418 uno::Reference< beans::XPropertySetInfo > SwXTextTable::getPropertySetInfo()
2420 static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo();
2421 return xRef;
2424 void SwXTextTable::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
2426 SolarMutexGuard aGuard;
2427 SwFrameFormat* pFormat = GetFrameFormat();
2428 if(!aValue.hasValue())
2429 throw lang::IllegalArgumentException();
2430 const SfxItemPropertyMapEntry* pEntry =
2431 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
2432 if( !pEntry )
2433 throw lang::IllegalArgumentException();
2434 if(pFormat)
2436 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
2437 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
2439 if(0xBF == pEntry->nMemberId)
2441 lcl_SetSpecialProperty(pFormat, pEntry, aValue);
2443 else
2445 switch(pEntry->nWID)
2447 case FN_UNO_TABLE_NAME :
2449 OUString sName;
2450 aValue >>= sName;
2451 setName( sName );
2453 break;
2455 case FN_UNO_RANGE_ROW_LABEL:
2457 bool bTmp = *o3tl::doAccess<bool>(aValue);
2458 if (m_pImpl->m_bFirstRowAsLabel != bTmp)
2460 std::unique_lock aGuard2(m_pImpl->m_Mutex);
2461 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
2462 m_pImpl->m_bFirstRowAsLabel = bTmp;
2465 break;
2467 case FN_UNO_RANGE_COL_LABEL:
2469 bool bTmp = *o3tl::doAccess<bool>(aValue);
2470 if (m_pImpl->m_bFirstColumnAsLabel != bTmp)
2472 std::unique_lock aGuard2(m_pImpl->m_Mutex);
2473 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
2474 m_pImpl->m_bFirstColumnAsLabel = bTmp;
2477 break;
2479 case FN_UNO_TABLE_BORDER:
2480 case FN_UNO_TABLE_BORDER2:
2482 table::TableBorder oldBorder;
2483 table::TableBorder2 aBorder;
2484 SvxBorderLine aTopLine;
2485 SvxBorderLine aBottomLine;
2486 SvxBorderLine aLeftLine;
2487 SvxBorderLine aRightLine;
2488 SvxBorderLine aHoriLine;
2489 SvxBorderLine aVertLine;
2490 if (aValue >>= oldBorder)
2492 aBorder.IsTopLineValid = oldBorder.IsTopLineValid;
2493 aBorder.IsBottomLineValid = oldBorder.IsBottomLineValid;
2494 aBorder.IsLeftLineValid = oldBorder.IsLeftLineValid;
2495 aBorder.IsRightLineValid = oldBorder.IsRightLineValid;
2496 aBorder.IsHorizontalLineValid = oldBorder.IsHorizontalLineValid;
2497 aBorder.IsVerticalLineValid = oldBorder.IsVerticalLineValid;
2498 aBorder.Distance = oldBorder.Distance;
2499 aBorder.IsDistanceValid = oldBorder.IsDistanceValid;
2500 lcl_LineToSvxLine(
2501 oldBorder.TopLine, aTopLine);
2502 lcl_LineToSvxLine(
2503 oldBorder.BottomLine, aBottomLine);
2504 lcl_LineToSvxLine(
2505 oldBorder.LeftLine, aLeftLine);
2506 lcl_LineToSvxLine(
2507 oldBorder.RightLine, aRightLine);
2508 lcl_LineToSvxLine(
2509 oldBorder.HorizontalLine, aHoriLine);
2510 lcl_LineToSvxLine(
2511 oldBorder.VerticalLine, aVertLine);
2513 else if (aValue >>= aBorder)
2515 SvxBoxItem::LineToSvxLine(
2516 aBorder.TopLine, aTopLine, true);
2517 SvxBoxItem::LineToSvxLine(
2518 aBorder.BottomLine, aBottomLine, true);
2519 SvxBoxItem::LineToSvxLine(
2520 aBorder.LeftLine, aLeftLine, true);
2521 SvxBoxItem::LineToSvxLine(
2522 aBorder.RightLine, aRightLine, true);
2523 SvxBoxItem::LineToSvxLine(
2524 aBorder.HorizontalLine, aHoriLine, true);
2525 SvxBoxItem::LineToSvxLine(
2526 aBorder.VerticalLine, aVertLine, true);
2528 else
2530 break; // something else
2532 SwDoc* pDoc = pFormat->GetDoc();
2533 if(!lcl_FormatTable(pFormat))
2534 break;
2535 SwTable* pTable = SwTable::FindTable( pFormat );
2536 SwTableLines &rLines = pTable->GetTabLines();
2538 const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true);
2539 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2540 SwPosition aPos(*pSttNd);
2541 // set cursor to top left cell
2542 auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true));
2543 pUnoCursor->Move( fnMoveForward, GoInNode );
2544 pUnoCursor->SetRemainInSection( false );
2546 const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false);
2547 pUnoCursor->SetMark();
2548 pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
2549 pUnoCursor->Move( fnMoveForward, GoInNode );
2550 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2551 // HACK: remove pending actions for selecting old style tables
2552 UnoActionRemoveContext aRemoveContext(rCursor);
2553 rCursor.MakeBoxSels();
2555 SfxItemSetFixed<RES_BOX, RES_BOX,
2556 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
2557 aSet(pDoc->GetAttrPool());
2559 SvxBoxItem aBox( RES_BOX );
2560 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
2562 aBox.SetLine(aTopLine.isEmpty() ? nullptr : &aTopLine, SvxBoxItemLine::TOP);
2563 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, aBorder.IsTopLineValid);
2565 aBox.SetLine(aBottomLine.isEmpty() ? nullptr : &aBottomLine, SvxBoxItemLine::BOTTOM);
2566 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::BOTTOM, aBorder.IsBottomLineValid);
2568 aBox.SetLine(aLeftLine.isEmpty() ? nullptr : &aLeftLine, SvxBoxItemLine::LEFT);
2569 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, aBorder.IsLeftLineValid);
2571 aBox.SetLine(aRightLine.isEmpty() ? nullptr : &aRightLine, SvxBoxItemLine::RIGHT);
2572 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::RIGHT, aBorder.IsRightLineValid);
2574 aBoxInfo.SetLine(aHoriLine.isEmpty() ? nullptr : &aHoriLine, SvxBoxInfoItemLine::HORI);
2575 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI, aBorder.IsHorizontalLineValid);
2577 aBoxInfo.SetLine(aVertLine.isEmpty() ? nullptr : &aVertLine, SvxBoxInfoItemLine::VERT);
2578 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT, aBorder.IsVerticalLineValid);
2580 aBox.SetAllDistances(o3tl::toTwips(aBorder.Distance, o3tl::Length::mm100));
2581 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE, aBorder.IsDistanceValid);
2583 aSet.Put(aBox);
2584 aSet.Put(aBoxInfo);
2586 pDoc->SetTabBorders(rCursor, aSet);
2588 break;
2590 case FN_UNO_TABLE_BORDER_DISTANCES:
2592 table::TableBorderDistances aTableBorderDistances;
2593 if( !(aValue >>= aTableBorderDistances) ||
2594 (!aTableBorderDistances.IsLeftDistanceValid &&
2595 !aTableBorderDistances.IsRightDistanceValid &&
2596 !aTableBorderDistances.IsTopDistanceValid &&
2597 !aTableBorderDistances.IsBottomDistanceValid ))
2598 break;
2600 const sal_uInt16 nLeftDistance = o3tl::toTwips(aTableBorderDistances.LeftDistance, o3tl::Length::mm100);
2601 const sal_uInt16 nRightDistance = o3tl::toTwips(aTableBorderDistances.RightDistance, o3tl::Length::mm100);
2602 const sal_uInt16 nTopDistance = o3tl::toTwips(aTableBorderDistances.TopDistance, o3tl::Length::mm100);
2603 const sal_uInt16 nBottomDistance = o3tl::toTwips(aTableBorderDistances.BottomDistance, o3tl::Length::mm100);
2604 SwDoc* pDoc = pFormat->GetDoc();
2605 SwTable* pTable = SwTable::FindTable( pFormat );
2606 SwTableLines &rLines = pTable->GetTabLines();
2607 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr);
2608 for(size_t i = 0; i < rLines.size(); ++i)
2610 SwTableLine* pLine = rLines[i];
2611 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2612 for(size_t k = 0; k < rBoxes.size(); ++k)
2614 SwTableBox* pBox = rBoxes[k];
2615 const SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
2616 const SvxBoxItem& rBox = pBoxFormat->GetBox();
2618 (aTableBorderDistances.IsLeftDistanceValid && nLeftDistance != rBox.GetDistance( SvxBoxItemLine::LEFT )) ||
2619 (aTableBorderDistances.IsRightDistanceValid && nRightDistance != rBox.GetDistance( SvxBoxItemLine::RIGHT )) ||
2620 (aTableBorderDistances.IsTopDistanceValid && nTopDistance != rBox.GetDistance( SvxBoxItemLine::TOP )) ||
2621 (aTableBorderDistances.IsBottomDistanceValid && nBottomDistance != rBox.GetDistance( SvxBoxItemLine::BOTTOM )))
2623 SvxBoxItem aSetBox( rBox );
2624 SwFrameFormat* pSetBoxFormat = pBox->ClaimFrameFormat();
2625 if( aTableBorderDistances.IsLeftDistanceValid )
2626 aSetBox.SetDistance( nLeftDistance, SvxBoxItemLine::LEFT );
2627 if( aTableBorderDistances.IsRightDistanceValid )
2628 aSetBox.SetDistance( nRightDistance, SvxBoxItemLine::RIGHT );
2629 if( aTableBorderDistances.IsTopDistanceValid )
2630 aSetBox.SetDistance( nTopDistance, SvxBoxItemLine::TOP );
2631 if( aTableBorderDistances.IsBottomDistanceValid )
2632 aSetBox.SetDistance( nBottomDistance, SvxBoxItemLine::BOTTOM );
2633 pDoc->SetAttr( aSetBox, *pSetBoxFormat );
2637 pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr);
2639 break;
2641 case FN_UNO_TABLE_COLUMN_SEPARATORS:
2643 UnoActionContext aContext(pFormat->GetDoc());
2644 SwTable* pTable = SwTable::FindTable( pFormat );
2645 lcl_SetTableSeparators(aValue, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false, pFormat->GetDoc());
2647 break;
2649 case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:/*_readonly_*/ break;
2651 case FN_UNO_TABLE_TEMPLATE_NAME:
2653 SwTable* pTable = SwTable::FindTable(pFormat);
2654 OUString sName;
2655 if (!(aValue >>= sName))
2656 break;
2657 SwStyleNameMapper::FillUIName(sName, sName, SwGetPoolIdFromName::TabStyle);
2658 pTable->SetTableStyleName(sName);
2659 SwDoc* pDoc = pFormat->GetDoc();
2660 if (SwFEShell* pFEShell = pDoc->GetDocShell()->GetFEShell())
2661 pFEShell->UpdateTableStyleFormatting(pTable->GetTableNode());
2663 break;
2665 default:
2667 SwAttrSet aSet(pFormat->GetAttrSet());
2668 m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aSet);
2669 pFormat->GetDoc()->SetAttr(aSet, *pFormat);
2674 else if (m_pImpl->IsDescriptor())
2676 m_pImpl->m_pTableProps->SetProperty(pEntry->nWID, pEntry->nMemberId, aValue);
2678 else
2679 throw uno::RuntimeException();
2682 uno::Any SwXTextTable::getPropertyValue(const OUString& rPropertyName)
2684 SolarMutexGuard aGuard;
2685 uno::Any aRet;
2686 SwFrameFormat* pFormat = GetFrameFormat();
2687 const SfxItemPropertyMapEntry* pEntry =
2688 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
2690 if (!pEntry)
2691 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
2693 if(pFormat)
2695 if(0xBF == pEntry->nMemberId)
2697 aRet = lcl_GetSpecialProperty(pFormat, pEntry );
2699 else
2701 switch(pEntry->nWID)
2703 case FN_UNO_TABLE_NAME:
2705 aRet <<= getName();
2707 break;
2709 case FN_UNO_ANCHOR_TYPES:
2710 case FN_UNO_TEXT_WRAP:
2711 case FN_UNO_ANCHOR_TYPE:
2712 ::sw::GetDefaultTextContentValue(
2713 aRet, u"", pEntry->nWID);
2714 break;
2716 case FN_UNO_RANGE_ROW_LABEL:
2718 aRet <<= m_pImpl->m_bFirstRowAsLabel;
2720 break;
2722 case FN_UNO_RANGE_COL_LABEL:
2723 aRet <<= m_pImpl->m_bFirstColumnAsLabel;
2724 break;
2726 case FN_UNO_TABLE_BORDER:
2727 case FN_UNO_TABLE_BORDER2:
2729 SwDoc* pDoc = pFormat->GetDoc();
2730 // tables without layout (invisible header/footer?)
2731 if(!lcl_FormatTable(pFormat))
2732 break;
2733 SwTable* pTable = SwTable::FindTable( pFormat );
2734 SwTableLines &rLines = pTable->GetTabLines();
2736 const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true);
2737 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2738 SwPosition aPos(*pSttNd);
2739 // set cursor to top left cell
2740 auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true));
2741 pUnoCursor->Move( fnMoveForward, GoInNode );
2742 pUnoCursor->SetRemainInSection( false );
2744 const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false);
2745 pUnoCursor->SetMark();
2746 const SwStartNode* pLastNd = pBRBox->GetSttNd();
2747 pUnoCursor->GetPoint()->Assign( *pLastNd );
2749 pUnoCursor->Move( fnMoveForward, GoInNode );
2750 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2751 // HACK: remove pending actions for selecting old style tables
2752 UnoActionRemoveContext aRemoveContext(rCursor);
2753 rCursor.MakeBoxSels();
2755 SfxItemSetFixed<RES_BOX, RES_BOX,
2756 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
2757 aSet(pDoc->GetAttrPool());
2758 aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER ));
2759 SwDoc::GetTabBorders(rCursor, aSet);
2760 const SvxBoxInfoItem& rBoxInfoItem = aSet.Get(SID_ATTR_BORDER_INNER);
2761 const SvxBoxItem& rBox = aSet.Get(RES_BOX);
2763 if (FN_UNO_TABLE_BORDER == pEntry->nWID)
2765 table::TableBorder aTableBorder;
2766 aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true);
2767 aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
2768 aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true);
2769 aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
2770 aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true);
2771 aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
2772 aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true);
2773 aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
2774 aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true);
2775 aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
2776 aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true);
2777 aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
2778 aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance());
2779 aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
2780 aRet <<= aTableBorder;
2782 else
2784 table::TableBorder2 aTableBorder;
2785 aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true);
2786 aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
2787 aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true);
2788 aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
2789 aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true);
2790 aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
2791 aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true);
2792 aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
2793 aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true);
2794 aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
2795 aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true);
2796 aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
2797 aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance());
2798 aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
2799 aRet <<= aTableBorder;
2802 break;
2804 case FN_UNO_TABLE_BORDER_DISTANCES :
2806 table::TableBorderDistances aTableBorderDistances( 0, true, 0, true, 0, true, 0, true ) ;
2807 SwTable* pTable = SwTable::FindTable( pFormat );
2808 const SwTableLines &rLines = pTable->GetTabLines();
2809 bool bFirst = true;
2810 sal_uInt16 nLeftDistance = 0;
2811 sal_uInt16 nRightDistance = 0;
2812 sal_uInt16 nTopDistance = 0;
2813 sal_uInt16 nBottomDistance = 0;
2815 for(size_t i = 0; i < rLines.size(); ++i)
2817 const SwTableLine* pLine = rLines[i];
2818 const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2819 for(size_t k = 0; k < rBoxes.size(); ++k)
2821 const SwTableBox* pBox = rBoxes[k];
2822 SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
2823 const SvxBoxItem& rBox = pBoxFormat->GetBox();
2824 if( bFirst )
2826 nLeftDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT ));
2827 nRightDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT ));
2828 nTopDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP ));
2829 nBottomDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM ));
2830 bFirst = false;
2832 else
2834 if( aTableBorderDistances.IsLeftDistanceValid &&
2835 nLeftDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT )))
2836 aTableBorderDistances.IsLeftDistanceValid = false;
2837 if( aTableBorderDistances.IsRightDistanceValid &&
2838 nRightDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT )))
2839 aTableBorderDistances.IsRightDistanceValid = false;
2840 if( aTableBorderDistances.IsTopDistanceValid &&
2841 nTopDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP )))
2842 aTableBorderDistances.IsTopDistanceValid = false;
2843 if( aTableBorderDistances.IsBottomDistanceValid &&
2844 nBottomDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM )))
2845 aTableBorderDistances.IsBottomDistanceValid = false;
2849 if( !aTableBorderDistances.IsLeftDistanceValid &&
2850 !aTableBorderDistances.IsRightDistanceValid &&
2851 !aTableBorderDistances.IsTopDistanceValid &&
2852 !aTableBorderDistances.IsBottomDistanceValid )
2853 break;
2855 if( aTableBorderDistances.IsLeftDistanceValid)
2856 aTableBorderDistances.LeftDistance = nLeftDistance;
2857 if( aTableBorderDistances.IsRightDistanceValid)
2858 aTableBorderDistances.RightDistance = nRightDistance;
2859 if( aTableBorderDistances.IsTopDistanceValid)
2860 aTableBorderDistances.TopDistance = nTopDistance;
2861 if( aTableBorderDistances.IsBottomDistanceValid)
2862 aTableBorderDistances.BottomDistance = nBottomDistance;
2864 aRet <<= aTableBorderDistances;
2866 break;
2868 case FN_UNO_TABLE_COLUMN_SEPARATORS:
2870 SwTable* pTable = SwTable::FindTable( pFormat );
2871 lcl_GetTableSeparators(aRet, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false);
2873 break;
2875 case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:
2876 aRet <<= sal_Int16(UNO_TABLE_COLUMN_SUM);
2877 break;
2879 case RES_ANCHOR:
2880 // AnchorType is readonly and might be void (no return value)
2881 break;
2883 case FN_UNO_TEXT_SECTION:
2885 SwTable* pTable = SwTable::FindTable( pFormat );
2886 SwTableNode* pTableNode = pTable->GetTableNode();
2887 SwSectionNode* pSectionNode = pTableNode->FindSectionNode();
2888 if(pSectionNode)
2890 SwSection& rSect = pSectionNode->GetSection();
2891 uno::Reference< text::XTextSection > xSect =
2892 SwXTextSections::GetObject( *rSect.GetFormat() );
2893 aRet <<= xSect;
2896 break;
2898 case FN_UNO_TABLE_TEMPLATE_NAME:
2900 SwTable* pTable = SwTable::FindTable(pFormat);
2901 OUString sName;
2902 SwStyleNameMapper::FillProgName(pTable->GetTableStyleName(), sName, SwGetPoolIdFromName::TabStyle);
2903 aRet <<= sName;
2905 break;
2907 default:
2909 const SwAttrSet& rSet = pFormat->GetAttrSet();
2910 m_pImpl->m_pPropSet->getPropertyValue(*pEntry, rSet, aRet);
2915 else if (m_pImpl->IsDescriptor())
2917 const uno::Any* pAny = nullptr;
2918 if (!m_pImpl->m_pTableProps->GetProperty(pEntry->nWID, pEntry->nMemberId, pAny))
2919 throw lang::IllegalArgumentException();
2920 else if(pAny)
2921 aRet = *pAny;
2923 else
2924 throw uno::RuntimeException();
2925 return aRet;
2928 void SwXTextTable::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
2929 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
2931 void SwXTextTable::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
2932 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
2934 void SwXTextTable::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
2935 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
2937 void SwXTextTable::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
2938 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
2940 OUString SwXTextTable::getName()
2942 SolarMutexGuard aGuard;
2943 SwFrameFormat* pFormat = GetFrameFormat();
2944 if (!pFormat && !m_pImpl->IsDescriptor())
2945 throw uno::RuntimeException();
2946 if(pFormat)
2948 return pFormat->GetName();
2950 return m_pImpl->m_sTableName;
2953 void SwXTextTable::setName(const OUString& rName)
2955 SolarMutexGuard aGuard;
2956 SwFrameFormat* pFormat = GetFrameFormat();
2957 if ((!pFormat && !m_pImpl->IsDescriptor()) ||
2958 rName.isEmpty() ||
2959 rName.indexOf('.')>=0 ||
2960 rName.indexOf(' ')>=0 )
2961 throw uno::RuntimeException();
2963 if(pFormat)
2965 const OUString aOldName( pFormat->GetName() );
2966 const sw::TableFrameFormats* pFrameFormats = pFormat->GetDoc()->GetTableFrameFormats();
2967 for (size_t i = pFrameFormats->size(); i;)
2969 const SwTableFormat* pTmpFormat = (*pFrameFormats)[--i];
2970 if( !pTmpFormat->IsDefault() &&
2971 pTmpFormat->GetName() == rName &&
2972 pFormat->GetDoc()->IsUsed( *pTmpFormat ))
2974 throw uno::RuntimeException();
2978 pFormat->SetFormatName( rName );
2980 SwStartNode *pStNd;
2981 SwNodeIndex aIdx( *pFormat->GetDoc()->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
2982 while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
2984 ++aIdx;
2985 SwNode *const pNd = & aIdx.GetNode();
2986 if ( pNd->IsOLENode() &&
2987 aOldName == static_cast<const SwOLENode*>(pNd)->GetChartTableName() )
2989 static_cast<SwOLENode*>(pNd)->SetChartTableName( rName );
2991 SwTable* pTable = SwTable::FindTable( pFormat );
2992 //TL_CHART2: chart needs to be notified about name changes
2993 pFormat->GetDoc()->UpdateCharts( pTable->GetFrameFormat()->GetName() );
2995 aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
2997 pFormat->GetDoc()->getIDocumentState().SetModified();
2999 else
3000 m_pImpl->m_sTableName = rName;
3003 sal_uInt16 SwXTextTable::Impl::GetRowCount()
3005 sal_uInt16 nRet = 0;
3006 SwFrameFormat* pFormat = GetFrameFormat();
3007 if(pFormat)
3009 SwTable* pTable = SwTable::FindTable( pFormat );
3010 if(!pTable->IsTableComplex())
3012 nRet = pTable->GetTabLines().size();
3015 return nRet;
3018 sal_uInt16 SwXTextTable::Impl::GetColumnCount()
3020 SwFrameFormat* pFormat = GetFrameFormat();
3021 sal_uInt16 nRet = 0;
3022 if(pFormat)
3024 SwTable* pTable = SwTable::FindTable( pFormat );
3025 if(!pTable->IsTableComplex())
3027 SwTableLines& rLines = pTable->GetTabLines();
3028 SwTableLine* pLine = rLines.front();
3029 nRet = pLine->GetTabBoxes().size();
3032 return nRet;
3035 void SwXTextTable::Impl::Notify(const SfxHint& rHint)
3037 if(rHint.GetId() == SfxHintId::Dying)
3039 m_pFrameFormat = nullptr;
3040 EndListeningAll();
3042 std::unique_lock aGuard(m_Mutex);
3043 if (m_EventListeners.getLength(aGuard) == 0 && m_ChartListeners.getLength(aGuard) == 0)
3044 return;
3045 uno::Reference<uno::XInterface> const xThis(m_wThis);
3046 // fdo#72695: if UNO object is already dead, don't revive it with event
3047 if (!xThis)
3048 return;
3049 if(!m_pFrameFormat)
3051 lang::EventObject const ev(xThis);
3052 m_EventListeners.disposeAndClear(aGuard, ev);
3053 m_ChartListeners.disposeAndClear(aGuard, ev);
3055 else
3057 lcl_SendChartEvent(aGuard, xThis, m_ChartListeners);
3061 OUString SAL_CALL SwXTextTable::getImplementationName()
3062 { return "SwXTextTable"; }
3064 sal_Bool SwXTextTable::supportsService(const OUString& rServiceName)
3065 { return cppu::supportsService(this, rServiceName); }
3067 uno::Sequence<OUString> SwXTextTable::getSupportedServiceNames()
3069 return {
3070 "com.sun.star.document.LinkTarget",
3071 "com.sun.star.text.TextTable",
3072 "com.sun.star.text.TextContent",
3073 "com.sun.star.text.TextSortable" };
3077 class SwXCellRange::Impl
3078 : public SvtListener
3080 private:
3081 SwFrameFormat* m_pFrameFormat;
3083 public:
3084 uno::WeakReference<uno::XInterface> m_wThis;
3085 std::mutex m_Mutex; // just for OInterfaceContainerHelper4
3086 ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> m_ChartListeners;
3088 sw::UnoCursorPointer m_pTableCursor;
3090 SwRangeDescriptor m_RangeDescriptor;
3091 const SfxItemPropertySet* m_pPropSet;
3093 bool m_bFirstRowAsLabel;
3094 bool m_bFirstColumnAsLabel;
3096 Impl(sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat, SwRangeDescriptor const& rDesc)
3097 : m_pFrameFormat(&rFrameFormat)
3098 , m_pTableCursor(pCursor)
3099 , m_RangeDescriptor(rDesc)
3100 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_RANGE))
3101 , m_bFirstRowAsLabel(false)
3102 , m_bFirstColumnAsLabel(false)
3104 StartListening(rFrameFormat.GetNotifier());
3105 m_RangeDescriptor.Normalize();
3108 SwFrameFormat* GetFrameFormat()
3110 return m_pFrameFormat;
3113 std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32> GetLabelCoordinates(bool bRow);
3115 uno::Sequence<OUString> GetLabelDescriptions(SwXCellRange & rThis, bool bRow);
3117 void SetLabelDescriptions(SwXCellRange & rThis,
3118 const css::uno::Sequence<OUString>& rDesc, bool bRow);
3120 sal_Int32 GetRowCount() const;
3121 sal_Int32 GetColumnCount() const;
3123 virtual void Notify(const SfxHint& ) override;
3127 OUString SwXCellRange::getImplementationName()
3128 { return "SwXCellRange"; }
3130 sal_Bool SwXCellRange::supportsService(const OUString& rServiceName)
3131 { return cppu::supportsService(this, rServiceName); }
3133 uno::Sequence<OUString> SwXCellRange::getSupportedServiceNames()
3135 return {
3136 "com.sun.star.text.CellRange",
3137 "com.sun.star.style.CharacterProperties",
3138 "com.sun.star.style.CharacterPropertiesAsian",
3139 "com.sun.star.style.CharacterPropertiesComplex",
3140 "com.sun.star.style.ParagraphProperties",
3141 "com.sun.star.style.ParagraphPropertiesAsian",
3142 "com.sun.star.style.ParagraphPropertiesComplex" };
3145 SwXCellRange::SwXCellRange(sw::UnoCursorPointer const& pCursor,
3146 SwFrameFormat& rFrameFormat, SwRangeDescriptor const & rDesc)
3147 : m_pImpl(new Impl(pCursor, rFrameFormat, rDesc))
3151 SwXCellRange::~SwXCellRange()
3155 rtl::Reference<SwXCellRange> SwXCellRange::CreateXCellRange(
3156 sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat,
3157 SwRangeDescriptor const & rDesc)
3159 rtl::Reference<SwXCellRange> pCellRange(new SwXCellRange(pCursor, rFrameFormat, rDesc));
3160 // need a permanent Reference to initialize m_wThis
3161 pCellRange->m_pImpl->m_wThis = uno::Reference<table::XCellRange>(pCellRange);
3162 return pCellRange;
3165 void SwXCellRange::SetLabels(bool bFirstRowAsLabel, bool bFirstColumnAsLabel)
3167 m_pImpl->m_bFirstRowAsLabel = bFirstRowAsLabel;
3168 m_pImpl->m_bFirstColumnAsLabel = bFirstColumnAsLabel;
3171 std::vector< uno::Reference< table::XCell > > SwXCellRange::GetCells()
3173 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3174 const sal_Int32 nRowCount(m_pImpl->GetRowCount());
3175 const sal_Int32 nColCount(m_pImpl->GetColumnCount());
3176 std::vector< uno::Reference< table::XCell > > vResult;
3177 vResult.reserve(static_cast<size_t>(nRowCount)*static_cast<size_t>(nColCount));
3178 for(sal_Int32 nRow = 0; nRow < nRowCount; ++nRow)
3179 for(sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
3180 vResult.emplace_back(lcl_CreateXCell(pFormat, m_pImpl->m_RangeDescriptor.nLeft + nCol, m_pImpl->m_RangeDescriptor.nTop + nRow));
3181 return vResult;
3184 uno::Reference<table::XCell> SAL_CALL
3185 SwXCellRange::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow)
3187 SolarMutexGuard aGuard;
3188 uno::Reference< table::XCell > aRet;
3189 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3190 if(pFormat)
3192 if(nColumn >= 0 && nRow >= 0 &&
3193 m_pImpl->GetColumnCount() > nColumn && m_pImpl->GetRowCount() > nRow )
3195 rtl::Reference<SwXCell> pXCell = lcl_CreateXCell(pFormat,
3196 m_pImpl->m_RangeDescriptor.nLeft + nColumn,
3197 m_pImpl->m_RangeDescriptor.nTop + nRow);
3198 if(pXCell)
3199 aRet = pXCell;
3202 if(!aRet.is())
3203 throw lang::IndexOutOfBoundsException();
3204 return aRet;
3207 uno::Reference<table::XCellRange> SAL_CALL
3208 SwXCellRange::getCellRangeByPosition(
3209 sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom)
3211 SolarMutexGuard aGuard;
3212 uno::Reference< table::XCellRange > aRet;
3213 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3214 if (pFormat && m_pImpl->GetColumnCount() > nRight
3215 && m_pImpl->GetRowCount() > nBottom &&
3216 nLeft <= nRight && nTop <= nBottom
3217 && nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 )
3219 SwTable* pTable = SwTable::FindTable( pFormat );
3220 if(!pTable->IsTableComplex())
3222 SwRangeDescriptor aNewDesc;
3223 aNewDesc.nTop = nTop + m_pImpl->m_RangeDescriptor.nTop;
3224 aNewDesc.nBottom = nBottom + m_pImpl->m_RangeDescriptor.nTop;
3225 aNewDesc.nLeft = nLeft + m_pImpl->m_RangeDescriptor.nLeft;
3226 aNewDesc.nRight = nRight + m_pImpl->m_RangeDescriptor.nLeft;
3227 aNewDesc.Normalize();
3228 const OUString sTLName = sw_GetCellName(aNewDesc.nLeft, aNewDesc.nTop);
3229 const OUString sBRName = sw_GetCellName(aNewDesc.nRight, aNewDesc.nBottom);
3230 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
3231 if(pTLBox)
3233 const SwStartNode* pSttNd = pTLBox->GetSttNd();
3234 SwPosition aPos(*pSttNd);
3235 // set cursor in the upper-left cell of the range
3236 auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true));
3237 pUnoCursor->Move( fnMoveForward, GoInNode );
3238 pUnoCursor->SetRemainInSection( false );
3239 const SwTableBox* pBRBox = pTable->GetTableBox( sBRName );
3240 if(pBRBox)
3242 pUnoCursor->SetMark();
3243 pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
3244 pUnoCursor->Move( fnMoveForward, GoInNode );
3245 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
3246 // HACK: remove pending actions for selecting old style tables
3247 UnoActionRemoveContext aRemoveContext(rCursor);
3248 rCursor.MakeBoxSels();
3249 // pUnoCursor will be provided and will not be deleted
3250 aRet = SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, aNewDesc).get();
3255 if(!aRet.is())
3256 throw lang::IndexOutOfBoundsException();
3257 return aRet;
3260 uno::Reference<table::XCellRange> SAL_CALL
3261 SwXCellRange::getCellRangeByName(const OUString& rRange)
3263 SolarMutexGuard aGuard;
3264 sal_Int32 nPos = 0;
3265 const OUString sTLName(rRange.getToken(0, ':', nPos));
3266 const OUString sBRName(rRange.getToken(0, ':', nPos));
3267 if(sTLName.isEmpty() || sBRName.isEmpty())
3268 throw uno::RuntimeException();
3269 SwRangeDescriptor aDesc;
3270 aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1;
3271 SwXTextTable::GetCellPosition( sTLName, aDesc.nLeft, aDesc.nTop );
3272 SwXTextTable::GetCellPosition( sBRName, aDesc.nRight, aDesc.nBottom );
3273 aDesc.Normalize();
3274 return getCellRangeByPosition(
3275 aDesc.nLeft - m_pImpl->m_RangeDescriptor.nLeft,
3276 aDesc.nTop - m_pImpl->m_RangeDescriptor.nTop,
3277 aDesc.nRight - m_pImpl->m_RangeDescriptor.nLeft,
3278 aDesc.nBottom - m_pImpl->m_RangeDescriptor.nTop);
3281 uno::Reference< beans::XPropertySetInfo > SwXCellRange::getPropertySetInfo()
3283 static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo();
3284 return xRef;
3287 void SAL_CALL
3288 SwXCellRange::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
3290 SolarMutexGuard aGuard;
3291 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3292 if(!pFormat)
3293 return;
3295 const SfxItemPropertyMapEntry *const pEntry =
3296 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
3297 if(!pEntry)
3298 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
3300 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
3301 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
3303 SwDoc& rDoc = m_pImpl->m_pTableCursor->GetDoc();
3304 SwUnoTableCursor& rCursor(dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor));
3306 // HACK: remove pending actions for selecting old style tables
3307 UnoActionRemoveContext aRemoveContext(rCursor);
3309 rCursor.MakeBoxSels();
3310 switch(pEntry->nWID )
3312 case FN_UNO_TABLE_CELL_BACKGROUND:
3314 std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
3315 SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush);
3316 aBrush->PutValue(aValue, pEntry->nMemberId);
3317 rDoc.SetBoxAttr(*m_pImpl->m_pTableCursor, *aBrush);
3320 break;
3321 case RES_BOX :
3323 SfxItemSetFixed<RES_BOX, RES_BOX,
3324 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
3325 aSet(rDoc.GetAttrPool());
3326 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
3327 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::ALL, false);
3328 SvxBoxInfoItemValidFlags nValid = SvxBoxInfoItemValidFlags::NONE;
3329 switch(pEntry->nMemberId & ~CONVERT_TWIPS)
3331 case LEFT_BORDER : nValid = SvxBoxInfoItemValidFlags::LEFT; break;
3332 case RIGHT_BORDER: nValid = SvxBoxInfoItemValidFlags::RIGHT; break;
3333 case TOP_BORDER : nValid = SvxBoxInfoItemValidFlags::TOP; break;
3334 case BOTTOM_BORDER: nValid = SvxBoxInfoItemValidFlags::BOTTOM; break;
3335 case LEFT_BORDER_DISTANCE :
3336 case RIGHT_BORDER_DISTANCE:
3337 case TOP_BORDER_DISTANCE :
3338 case BOTTOM_BORDER_DISTANCE:
3339 nValid = SvxBoxInfoItemValidFlags::DISTANCE;
3340 break;
3342 aBoxInfo.SetValid(nValid);
3344 aSet.Put(aBoxInfo);
3345 SwDoc::GetTabBorders(rCursor, aSet);
3347 aSet.Put(aBoxInfo);
3348 SvxBoxItem aBoxItem(aSet.Get(RES_BOX));
3349 static_cast<SfxPoolItem&>(aBoxItem).PutValue(aValue, pEntry->nMemberId);
3350 aSet.Put(aBoxItem);
3351 rDoc.SetTabBorders(*m_pImpl->m_pTableCursor, aSet);
3353 break;
3354 case RES_BOXATR_FORMAT:
3356 SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT);
3357 static_cast<SfxPoolItem&>(aNumberFormat).PutValue(aValue, 0);
3358 rDoc.SetBoxAttr(rCursor, aNumberFormat);
3360 break;
3361 case FN_UNO_RANGE_ROW_LABEL:
3363 bool bTmp = *o3tl::doAccess<bool>(aValue);
3364 if (m_pImpl->m_bFirstRowAsLabel != bTmp)
3366 std::unique_lock aGuard2(m_pImpl->m_Mutex);
3367 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
3368 m_pImpl->m_bFirstRowAsLabel = bTmp;
3371 break;
3372 case FN_UNO_RANGE_COL_LABEL:
3374 bool bTmp = *o3tl::doAccess<bool>(aValue);
3375 if (m_pImpl->m_bFirstColumnAsLabel != bTmp)
3377 std::unique_lock aGuard2(m_pImpl->m_Mutex);
3378 lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
3379 m_pImpl->m_bFirstColumnAsLabel = bTmp;
3382 break;
3383 case RES_VERT_ORIENT:
3385 sal_Int16 nAlign = -1;
3386 aValue >>= nAlign;
3387 if( nAlign >= text::VertOrientation::NONE && nAlign <= text::VertOrientation::BOTTOM)
3388 rDoc.SetBoxAlign( rCursor, nAlign );
3390 break;
3391 default:
3393 SfxItemSet aItemSet( rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID );
3394 SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(),
3395 aItemSet);
3397 if (!SwUnoCursorHelper::SetCursorPropertyValue(
3398 *pEntry, aValue, rCursor.GetSelRing(), aItemSet))
3400 m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet);
3402 SwUnoCursorHelper::SetCursorAttr(rCursor.GetSelRing(),
3403 aItemSet, SetAttrMode::DEFAULT, true);
3408 uno::Any SAL_CALL SwXCellRange::getPropertyValue(const OUString& rPropertyName)
3410 SolarMutexGuard aGuard;
3411 uno::Any aRet;
3412 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3413 if(pFormat)
3415 const SfxItemPropertyMapEntry *const pEntry =
3416 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
3417 if(!pEntry)
3418 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
3420 switch(pEntry->nWID )
3422 case FN_UNO_TABLE_CELL_BACKGROUND:
3424 std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
3425 if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush))
3426 aBrush->QueryValue(aRet, pEntry->nMemberId);
3429 break;
3430 case RES_BOX :
3432 SwDoc& rDoc = m_pImpl->m_pTableCursor->GetDoc();
3433 SfxItemSetFixed<RES_BOX, RES_BOX,
3434 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
3435 aSet(rDoc.GetAttrPool());
3436 aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER ));
3437 SwDoc::GetTabBorders(*m_pImpl->m_pTableCursor, aSet);
3438 const SvxBoxItem& rBoxItem = aSet.Get(RES_BOX);
3439 rBoxItem.QueryValue(aRet, pEntry->nMemberId);
3441 break;
3442 case RES_BOXATR_FORMAT:
3443 OSL_FAIL("not implemented");
3444 break;
3445 case FN_UNO_PARA_STYLE:
3447 SwFormatColl *const pTmpFormat =
3448 SwUnoCursorHelper::GetCurTextFormatColl(*m_pImpl->m_pTableCursor, false);
3449 OUString sRet;
3450 if (pTmpFormat)
3451 sRet = pTmpFormat->GetName();
3452 aRet <<= sRet;
3454 break;
3455 case FN_UNO_RANGE_ROW_LABEL:
3456 aRet <<= m_pImpl->m_bFirstRowAsLabel;
3457 break;
3458 case FN_UNO_RANGE_COL_LABEL:
3459 aRet <<= m_pImpl->m_bFirstColumnAsLabel;
3460 break;
3461 case RES_VERT_ORIENT:
3463 std::unique_ptr<SfxPoolItem> aVertOrient(
3464 std::make_unique<SwFormatVertOrient>(RES_VERT_ORIENT));
3465 if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aVertOrient))
3467 aVertOrient->QueryValue( aRet, pEntry->nMemberId );
3470 break;
3471 default:
3473 SfxItemSetFixed<
3474 RES_CHRATR_BEGIN, RES_FRMATR_END - 1,
3475 RES_UNKNOWNATR_CONTAINER,
3476 RES_UNKNOWNATR_CONTAINER>
3477 aSet(m_pImpl->m_pTableCursor->GetDoc().GetAttrPool());
3478 // first look at the attributes of the cursor
3479 SwUnoTableCursor& rCursor =
3480 dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor);
3481 SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(), aSet);
3482 m_pImpl->m_pPropSet->getPropertyValue(*pEntry, aSet, aRet);
3487 return aRet;
3490 void SwXCellRange::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
3491 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3493 void SwXCellRange::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
3494 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3496 void SwXCellRange::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
3497 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3499 void SwXCellRange::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
3500 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3502 ///@see SwXCellRange::getData
3503 uno::Sequence<uno::Sequence<uno::Any>> SAL_CALL SwXCellRange::getDataArray()
3505 SolarMutexGuard aGuard;
3506 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3507 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3508 if(!nRowCount || !nColCount)
3509 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3510 lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
3511 uno::Sequence< uno::Sequence< uno::Any > > aRowSeq(nRowCount);
3512 auto vCells(GetCells());
3513 auto pCurrentCell(vCells.begin());
3514 for(auto& rRow : asNonConstRange(aRowSeq))
3516 rRow = uno::Sequence< uno::Any >(nColCount);
3517 for(auto& rCellAny : asNonConstRange(rRow))
3519 auto pCell(static_cast<SwXCell*>(pCurrentCell->get()));
3520 if(!pCell)
3521 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3522 rCellAny = pCell->GetAny();
3523 ++pCurrentCell;
3526 return aRowSeq;
3529 ///@see SwXCellRange::setData
3530 void SAL_CALL SwXCellRange::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray)
3532 SolarMutexGuard aGuard;
3533 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3534 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3535 if(!nRowCount || !nColCount)
3536 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3537 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3538 if(!pFormat)
3539 return;
3540 if(rArray.getLength() != nRowCount)
3541 throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rArray.getLength()), static_cast<cppu::OWeakObject*>(this));
3542 auto vCells(GetCells());
3543 auto pCurrentCell(vCells.begin());
3544 for(const auto& rColSeq : rArray)
3546 if(rColSeq.getLength() != nColCount)
3547 throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rColSeq.getLength()), static_cast<cppu::OWeakObject*>(this));
3548 for(const auto& aValue : rColSeq)
3550 auto pCell(static_cast<SwXCell*>(pCurrentCell->get()));
3551 if(!pCell || !pCell->GetTableBox())
3552 throw uno::RuntimeException("Box for cell missing", static_cast<cppu::OWeakObject*>(this));
3553 if(aValue.isExtractableTo(cppu::UnoType<OUString>::get()))
3554 sw_setString(*pCell, aValue.get<OUString>());
3555 else if(aValue.isExtractableTo(cppu::UnoType<double>::get()))
3556 sw_setValue(*pCell, aValue.get<double>());
3557 else
3558 sw_setString(*pCell, OUString(), true);
3559 ++pCurrentCell;
3564 uno::Sequence<uno::Sequence<double>> SAL_CALL
3565 SwXCellRange::getData()
3567 SolarMutexGuard aGuard;
3568 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3569 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3570 if(!nRowCount || !nColCount)
3571 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3572 if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel)
3574 uno::Reference<chart::XChartDataArray> const xDataRange(
3575 getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0,
3576 (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0,
3577 nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW);
3578 return xDataRange->getData();
3580 uno::Sequence< uno::Sequence< double > > vRows(nRowCount);
3581 auto vCells(GetCells());
3582 auto pCurrentCell(vCells.begin());
3583 for(auto& rRow : asNonConstRange(vRows))
3585 rRow = uno::Sequence<double>(nColCount);
3586 for(auto& rValue : asNonConstRange(rRow))
3588 if(!(*pCurrentCell))
3589 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3590 rValue = (*pCurrentCell)->getValue();
3591 ++pCurrentCell;
3594 return vRows;
3597 void SAL_CALL
3598 SwXCellRange::setData(const uno::Sequence< uno::Sequence<double> >& rData)
3600 SolarMutexGuard aGuard;
3601 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3602 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3603 if(!nRowCount || !nColCount)
3604 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3605 if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel)
3607 uno::Reference<chart::XChartDataArray> const xDataRange(
3608 getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0,
3609 (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0,
3610 nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW);
3611 return xDataRange->setData(rData);
3613 lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
3614 if(rData.getLength() != nRowCount)
3615 throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rData.getLength()), static_cast<cppu::OWeakObject*>(this));
3616 auto vCells(GetCells());
3617 auto pCurrentCell(vCells.begin());
3618 for(const auto& rRow : rData)
3620 if(rRow.getLength() != nColCount)
3621 throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rRow.getLength()), static_cast<cppu::OWeakObject*>(this));
3622 for(const auto& rValue : rRow)
3624 uno::Reference<table::XCell>(*pCurrentCell, uno::UNO_SET_THROW)->setValue(rValue);
3625 ++pCurrentCell;
3630 std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32>
3631 SwXCellRange::Impl::GetLabelCoordinates(bool bRow)
3633 sal_uInt32 nLeft, nTop, nRight, nBottom;
3634 nLeft = nTop = nRight = nBottom = 0;
3635 if(bRow)
3637 nTop = m_bFirstRowAsLabel ? 1 : 0;
3638 nBottom = GetRowCount() - 1;
3640 else
3642 nLeft = m_bFirstColumnAsLabel ? 1 : 0;
3643 nRight = GetColumnCount() - 1;
3645 return std::make_tuple(nLeft, nTop, nRight, nBottom);
3648 uno::Sequence<OUString>
3649 SwXCellRange::Impl::GetLabelDescriptions(SwXCellRange & rThis, bool bRow)
3651 SolarMutexGuard aGuard;
3652 sal_uInt32 nLeft, nTop, nRight, nBottom;
3653 std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow);
3654 if(!nRight && !nBottom)
3655 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(&rThis));
3656 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(&rThis));
3657 if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel))
3658 return {}; // without labels we have no descriptions
3659 auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom));
3660 auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells());
3661 uno::Sequence<OUString> vResult(vCells.size());
3662 std::transform(vCells.begin(), vCells.end(), vResult.getArray(),
3663 [](uno::Reference<table::XCell> xCell) -> OUString { return uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->getString(); });
3664 return vResult;
3667 uno::Sequence<OUString> SAL_CALL SwXCellRange::getRowDescriptions()
3669 return m_pImpl->GetLabelDescriptions(*this, true);
3672 uno::Sequence<OUString> SAL_CALL SwXCellRange::getColumnDescriptions()
3674 return m_pImpl->GetLabelDescriptions(*this, false);
3677 void SwXCellRange::Impl::SetLabelDescriptions(SwXCellRange & rThis,
3678 const uno::Sequence<OUString>& rDesc, bool bRow)
3680 SolarMutexGuard aGuard;
3681 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(&rThis));
3682 if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel))
3683 return; // if there are no labels we cannot set descriptions
3684 sal_uInt32 nLeft, nTop, nRight, nBottom;
3685 std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow);
3686 if(!nRight && !nBottom)
3687 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(&rThis));
3688 auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom));
3689 if (!xLabelRange.is())
3690 throw uno::RuntimeException("Missing Cell Range", static_cast<cppu::OWeakObject*>(&rThis));
3691 auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells());
3692 if (sal::static_int_cast<sal_uInt32>(rDesc.getLength()) != vCells.size())
3693 throw uno::RuntimeException("Too few or too many descriptions", static_cast<cppu::OWeakObject*>(&rThis));
3694 auto pDescIterator(rDesc.begin());
3695 for(auto& xCell : vCells)
3696 uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->setString(*pDescIterator++);
3699 void SAL_CALL SwXCellRange::setRowDescriptions(
3700 const uno::Sequence<OUString>& rRowDesc)
3702 m_pImpl->SetLabelDescriptions(*this, rRowDesc, true);
3705 void SAL_CALL SwXCellRange::setColumnDescriptions(
3706 const uno::Sequence<OUString>& rColumnDesc)
3708 m_pImpl->SetLabelDescriptions(*this, rColumnDesc, false);
3711 void SAL_CALL SwXCellRange::addChartDataChangeEventListener(
3712 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
3714 // no need to lock here as m_pImpl is const and container threadsafe
3715 std::unique_lock aGuard(m_pImpl->m_Mutex);
3716 m_pImpl->m_ChartListeners.addInterface(aGuard, xListener);
3719 void SAL_CALL SwXCellRange::removeChartDataChangeEventListener(
3720 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
3722 // no need to lock here as m_pImpl is const and container threadsafe
3723 std::unique_lock aGuard(m_pImpl->m_Mutex);
3724 m_pImpl->m_ChartListeners.removeInterface(aGuard, xListener);
3727 sal_Bool SwXCellRange::isNotANumber(double /*fNumber*/)
3728 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3730 double SwXCellRange::getNotANumber()
3731 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3733 uno::Sequence< beans::PropertyValue > SwXCellRange::createSortDescriptor()
3735 SolarMutexGuard aGuard;
3736 return SwUnoCursorHelper::CreateSortDescriptor(true);
3739 void SAL_CALL SwXCellRange::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
3741 SolarMutexGuard aGuard;
3742 SwSortOptions aSortOpt;
3743 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3744 if(pFormat && SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt))
3746 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor);
3747 rTableCursor.MakeBoxSels();
3748 UnoActionContext aContext(pFormat->GetDoc());
3749 pFormat->GetDoc()->SortTable(rTableCursor.GetSelectedBoxes(), aSortOpt);
3753 sal_Int32 SwXCellRange::Impl::GetColumnCount() const
3755 return m_RangeDescriptor.nRight - m_RangeDescriptor.nLeft + 1;
3758 sal_Int32 SwXCellRange::Impl::GetRowCount() const
3760 return m_RangeDescriptor.nBottom - m_RangeDescriptor.nTop + 1;
3763 const SwUnoCursor* SwXCellRange::GetTableCursor() const
3765 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3766 return pFormat ? &(*m_pImpl->m_pTableCursor) : nullptr;
3769 void SwXCellRange::Impl::Notify( const SfxHint& rHint )
3771 uno::Reference<uno::XInterface> const xThis(m_wThis);
3772 if(rHint.GetId() == SfxHintId::Dying)
3774 m_pFrameFormat = nullptr;
3775 m_pTableCursor.reset(nullptr);
3777 if (xThis.is())
3778 { // fdo#72695: if UNO object is already dead, don't revive it with event
3779 if(m_pFrameFormat)
3781 std::unique_lock aGuard(m_Mutex);
3782 lcl_SendChartEvent(aGuard, xThis, m_ChartListeners);
3784 else
3786 std::unique_lock aGuard(m_Mutex);
3787 m_ChartListeners.disposeAndClear(aGuard, lang::EventObject(xThis));
3792 class SwXTableRows::Impl : public SvtListener
3794 private:
3795 SwFrameFormat* m_pFrameFormat;
3797 public:
3798 explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat)
3800 StartListening(rFrameFormat.GetNotifier());
3802 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
3803 virtual void Notify(const SfxHint&) override;
3806 // SwXTableRows
3808 OUString SwXTableRows::getImplementationName()
3809 { return "SwXTableRows"; }
3811 sal_Bool SwXTableRows::supportsService(const OUString& rServiceName)
3812 { return cppu::supportsService(this, rServiceName); }
3814 uno::Sequence< OUString > SwXTableRows::getSupportedServiceNames()
3815 { return { "com.sun.star.text.TableRows" }; }
3818 SwXTableRows::SwXTableRows(SwFrameFormat& rFrameFormat) :
3819 m_pImpl(new SwXTableRows::Impl(rFrameFormat))
3822 SwXTableRows::~SwXTableRows()
3825 SwFrameFormat* SwXTableRows::GetFrameFormat()
3827 return m_pImpl->GetFrameFormat();
3830 sal_Int32 SwXTableRows::getCount()
3832 SolarMutexGuard aGuard;
3833 SwFrameFormat* pFrameFormat = GetFrameFormat();
3834 if(!pFrameFormat)
3835 throw uno::RuntimeException();
3836 SwTable* pTable = SwTable::FindTable(pFrameFormat);
3837 return pTable->GetTabLines().size();
3840 ///@see SwXCell::CreateXCell (TODO: seems to be copy and paste programming here)
3841 uno::Any SwXTableRows::getByIndex(sal_Int32 nIndex)
3843 SolarMutexGuard aGuard;
3844 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
3845 if(nIndex < 0)
3846 throw lang::IndexOutOfBoundsException();
3847 SwTable* pTable = SwTable::FindTable( pFrameFormat );
3848 if(o3tl::make_unsigned(nIndex) >= pTable->GetTabLines().size())
3849 throw lang::IndexOutOfBoundsException();
3850 SwTableLine* pLine = pTable->GetTabLines()[nIndex];
3851 FindUnoInstanceHint<SwTableLine,SwXTextTableRow> aHint{pLine};
3852 pFrameFormat->GetNotifier().Broadcast(aHint);
3853 if(!aHint.m_pResult)
3854 aHint.m_pResult = new SwXTextTableRow(pFrameFormat, pLine);
3855 uno::Reference<beans::XPropertySet> xRet = static_cast<beans::XPropertySet*>(aHint.m_pResult.get());
3856 return uno::Any(xRet);
3859 uno::Type SAL_CALL SwXTableRows::getElementType()
3861 return cppu::UnoType<beans::XPropertySet>::get();
3864 sal_Bool SwXTableRows::hasElements()
3866 SolarMutexGuard aGuard;
3867 SwFrameFormat* pFrameFormat = GetFrameFormat();
3868 if(!pFrameFormat)
3869 throw uno::RuntimeException();
3870 // a table always has rows
3871 return true;
3874 void SwXTableRows::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount)
3876 SolarMutexGuard aGuard;
3877 if (nCount == 0)
3878 return;
3879 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
3880 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this));
3881 const size_t nRowCount = pTable->GetTabLines().size();
3882 if (nCount <= 0 || 0 > nIndex || o3tl::make_unsigned(nIndex) > nRowCount)
3883 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
3884 const OUString sTLName = sw_GetCellName(0, nIndex);
3885 const SwTableBox* pTLBox = pTable->GetTableBox(sTLName);
3886 bool bAppend = false;
3887 if(!pTLBox)
3889 bAppend = true;
3890 // to append at the end the cursor must be in the last line
3891 SwTableLines& rLines = pTable->GetTabLines();
3892 SwTableLine* pLine = rLines.back();
3893 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
3894 pTLBox = rBoxes.front();
3896 if(!pTLBox)
3897 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
3898 const SwStartNode* pSttNd = pTLBox->GetSttNd();
3899 SwPosition aPos(*pSttNd);
3900 // set cursor to the upper-left cell of the range
3901 UnoActionContext aAction(pFrameFormat->GetDoc());
3902 std::shared_ptr<SwUnoTableCursor> const pUnoCursor(
3903 std::dynamic_pointer_cast<SwUnoTableCursor>(
3904 pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)));
3905 pUnoCursor->Move( fnMoveForward, GoInNode );
3907 // remove actions - TODO: why?
3908 UnoActionRemoveContext aRemoveContext(&pUnoCursor->GetDoc());
3910 pFrameFormat->GetDoc()->InsertRow(*pUnoCursor, o3tl::narrowing<sal_uInt16>(nCount), bAppend);
3913 void SwXTableRows::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount)
3915 SolarMutexGuard aGuard;
3916 if (nCount == 0)
3917 return;
3918 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
3919 if(nIndex < 0 || nCount <=0 )
3920 throw uno::RuntimeException();
3921 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this));
3922 OUString sTLName = sw_GetCellName(0, nIndex);
3923 const SwTableBox* pTLBox = pTable->GetTableBox(sTLName);
3924 if(!pTLBox)
3925 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
3926 const SwStartNode* pSttNd = pTLBox->GetSttNd();
3927 SwPosition aPos(*pSttNd);
3928 // set cursor to the upper-left cell of the range
3929 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
3930 pUnoCursor->Move(fnMoveForward, GoInNode);
3931 pUnoCursor->SetRemainInSection( false );
3932 const OUString sBLName = sw_GetCellName(0, nIndex + nCount - 1);
3933 const SwTableBox* pBLBox = pTable->GetTableBox( sBLName );
3934 if(!pBLBox)
3935 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
3936 pUnoCursor->SetMark();
3937 pUnoCursor->GetPoint()->Assign( *pBLBox->GetSttNd() );
3938 pUnoCursor->Move(fnMoveForward, GoInNode);
3939 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
3941 // HACK: remove pending actions for selecting old style tables
3942 UnoActionRemoveContext aRemoveContext(rCursor);
3944 rCursor.MakeBoxSels();
3945 { // these braces are important
3946 UnoActionContext aAction(pFrameFormat->GetDoc());
3947 pFrameFormat->GetDoc()->DeleteRow(*pUnoCursor);
3948 pUnoCursor.reset();
3951 // invalidate all actions - TODO: why?
3952 UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc());
3956 void SwXTableRows::Impl::Notify( const SfxHint& rHint)
3958 if(rHint.GetId() == SfxHintId::Dying)
3959 m_pFrameFormat = nullptr;
3962 // SwXTableColumns
3964 class SwXTableColumns::Impl : public SvtListener
3966 SwFrameFormat* m_pFrameFormat;
3967 public:
3968 explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat)
3970 StartListening(rFrameFormat.GetNotifier());
3972 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
3973 virtual void Notify(const SfxHint&) override;
3976 OUString SwXTableColumns::getImplementationName()
3977 { return "SwXTableColumns"; }
3979 sal_Bool SwXTableColumns::supportsService(const OUString& rServiceName)
3980 { return cppu::supportsService(this, rServiceName); }
3982 uno::Sequence< OUString > SwXTableColumns::getSupportedServiceNames()
3983 { return { "com.sun.star.text.TableColumns"}; }
3986 SwXTableColumns::SwXTableColumns(SwFrameFormat& rFrameFormat) :
3987 m_pImpl(new SwXTableColumns::Impl(rFrameFormat))
3990 SwXTableColumns::~SwXTableColumns()
3993 SwFrameFormat* SwXTableColumns::GetFrameFormat() const
3995 return m_pImpl->GetFrameFormat();
3998 sal_Int32 SwXTableColumns::getCount()
4000 SolarMutexGuard aGuard;
4001 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
4002 SwTable* pTable = SwTable::FindTable( pFrameFormat );
4003 // if(!pTable->IsTableComplex())
4004 // throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
4005 SwTableLines& rLines = pTable->GetTabLines();
4006 SwTableLine* pLine = rLines.front();
4007 return pLine->GetTabBoxes().size();
4010 uno::Any SwXTableColumns::getByIndex(sal_Int32 nIndex)
4012 SolarMutexGuard aGuard;
4013 if(nIndex < 0 || getCount() <= nIndex)
4014 throw lang::IndexOutOfBoundsException();
4015 return uno::Any(uno::Reference<uno::XInterface>()); // i#21699 not supported
4018 uno::Type SAL_CALL SwXTableColumns::getElementType()
4020 return cppu::UnoType<uno::XInterface>::get();
4023 sal_Bool SwXTableColumns::hasElements()
4025 SolarMutexGuard aGuard;
4026 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
4027 return true;
4030 ///@see SwXTableRows::insertByIndex (TODO: seems to be copy and paste programming here)
4031 void SwXTableColumns::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount)
4033 SolarMutexGuard aGuard;
4034 if (nCount == 0)
4035 return;
4036 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
4037 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this));
4038 SwTableLines& rLines = pTable->GetTabLines();
4039 SwTableLine* pLine = rLines.front();
4040 const size_t nColCount = pLine->GetTabBoxes().size();
4041 if (nCount <= 0 || 0 > nIndex || o3tl::make_unsigned(nIndex) > nColCount)
4042 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
4043 const OUString sTLName = sw_GetCellName(nIndex, 0);
4044 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
4045 bool bAppend = false;
4046 if(!pTLBox)
4048 bAppend = true;
4049 // to append at the end the cursor must be in the last line
4050 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
4051 pTLBox = rBoxes.back();
4053 if(!pTLBox)
4054 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
4055 const SwStartNode* pSttNd = pTLBox->GetSttNd();
4056 SwPosition aPos(*pSttNd);
4057 UnoActionContext aAction(pFrameFormat->GetDoc());
4058 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
4059 pUnoCursor->Move(fnMoveForward, GoInNode);
4062 // remove actions - TODO: why?
4063 UnoActionRemoveContext aRemoveContext(&pUnoCursor->GetDoc());
4066 pFrameFormat->GetDoc()->InsertCol(*pUnoCursor, o3tl::narrowing<sal_uInt16>(nCount), bAppend);
4069 ///@see SwXTableRows::removeByIndex (TODO: seems to be copy and paste programming here)
4070 void SwXTableColumns::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount)
4072 SolarMutexGuard aGuard;
4073 if (nCount == 0)
4074 return;
4075 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
4076 if(nIndex < 0 || nCount <=0 )
4077 throw uno::RuntimeException();
4078 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this));
4079 const OUString sTLName = sw_GetCellName(nIndex, 0);
4080 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
4081 if(!pTLBox)
4082 throw uno::RuntimeException("Cell not found", static_cast<cppu::OWeakObject*>(this));
4083 const SwStartNode* pSttNd = pTLBox->GetSttNd();
4084 SwPosition aPos(*pSttNd);
4085 // set cursor to the upper-left cell of the range
4086 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
4087 pUnoCursor->Move(fnMoveForward, GoInNode);
4088 pUnoCursor->SetRemainInSection(false);
4089 const OUString sTRName = sw_GetCellName(nIndex + nCount - 1, 0);
4090 const SwTableBox* pTRBox = pTable->GetTableBox(sTRName);
4091 if(!pTRBox)
4092 throw uno::RuntimeException("Cell not found", static_cast<cppu::OWeakObject*>(this));
4093 pUnoCursor->SetMark();
4094 pUnoCursor->GetPoint()->Assign( *pTRBox->GetSttNd() );
4095 pUnoCursor->Move(fnMoveForward, GoInNode);
4096 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
4098 // HACK: remove pending actions for selecting old style tables
4099 UnoActionRemoveContext aRemoveContext(rCursor);
4101 rCursor.MakeBoxSels();
4102 { // these braces are important
4103 UnoActionContext aAction(pFrameFormat->GetDoc());
4104 pFrameFormat->GetDoc()->DeleteCol(*pUnoCursor);
4105 pUnoCursor.reset();
4108 // invalidate all actions - TODO: why?
4109 UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc());
4113 void SwXTableColumns::Impl::Notify(const SfxHint& rHint)
4115 if(rHint.GetId() == SfxHintId::Dying)
4116 m_pFrameFormat = nullptr;
4119 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */