loplugin:constvars in sw
[LibreOffice.git] / sw / source / core / unocore / unotbl.cxx
blob57d645baf4954741e7b745af4b746b8d7ebd7772
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 <array>
22 #include <utility>
23 #include <memory>
24 #include <vector>
25 #include <algorithm>
27 #include <o3tl/any.hxx>
28 #include <svx/svxids.hrc>
29 #include <editeng/memberids.h>
30 #include <float.h>
31 #include <swtypes.hxx>
32 #include <cmdid.h>
33 #include <unomid.h>
34 #include <unomap.hxx>
35 #include <unotbl.hxx>
36 #include <unostyle.hxx>
37 #include <section.hxx>
38 #include <unocrsr.hxx>
39 #include <svx/unomid.hxx>
40 #include <hints.hxx>
41 #include <swtblfmt.hxx>
42 #include <doc.hxx>
43 #include <IDocumentUndoRedo.hxx>
44 #include <IDocumentContentOperations.hxx>
45 #include <IDocumentFieldsAccess.hxx>
46 #include <IDocumentState.hxx>
47 #include <IDocumentLayoutAccess.hxx>
48 #include <shellres.hxx>
49 #include <docary.hxx>
50 #include <ndole.hxx>
51 #include <ndtxt.hxx>
52 #include <frame.hxx>
53 #include <vcl/svapp.hxx>
54 #include <fmtfsize.hxx>
55 #include <tblafmt.hxx>
56 #include <tabcol.hxx>
57 #include <cellatr.hxx>
58 #include <fmtpdsc.hxx>
59 #include <pagedesc.hxx>
60 #include <viewsh.hxx>
61 #include <rootfrm.hxx>
62 #include <tabfrm.hxx>
63 #include <redline.hxx>
64 #include <unoport.hxx>
65 #include <unoprnms.hxx>
66 #include <unocrsrhelper.hxx>
67 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
68 #include <com/sun/star/text/WrapTextMode.hpp>
69 #include <com/sun/star/text/TextContentAnchorType.hpp>
70 #include <com/sun/star/text/TableColumnSeparator.hpp>
71 #include <com/sun/star/text/VertOrientation.hpp>
72 #include <com/sun/star/text/XTextSection.hpp>
73 #include <com/sun/star/table/ShadowFormat.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/BorderLineStyle.hpp>
78 #include <com/sun/star/table/TableBorderDistances.hpp>
79 #include <com/sun/star/style/PageStyleLayout.hpp>
80 #include <com/sun/star/style/BreakType.hpp>
81 #include <com/sun/star/style/GraphicLocation.hpp>
82 #include <com/sun/star/beans/PropertyAttribute.hpp>
83 #include <com/sun/star/chart/XChartDataChangeEventListener.hpp>
84 #include <com/sun/star/chart/ChartDataChangeEvent.hpp>
85 #include <com/sun/star/chart2/data/XDataSequence.hpp>
86 #include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
87 #include <com/sun/star/table/CellContentType.hpp>
88 #include <unotextrange.hxx>
89 #include <unotextcursor.hxx>
90 #include <unoparagraph.hxx>
91 #include <svl/zforlist.hxx>
92 #include <editeng/formatbreakitem.hxx>
93 #include <editeng/shaditem.hxx>
94 #include <editeng/lrspitem.hxx>
95 #include <editeng/ulspitem.hxx>
96 #include <fmtornt.hxx>
97 #include <editeng/keepitem.hxx>
98 #include <fmtlsplt.hxx>
99 #include <swundo.hxx>
100 #include <osl/mutex.hxx>
101 #include <SwStyleNameMapper.hxx>
102 #include <frmatr.hxx>
103 #include <unochart.hxx>
104 #include <sortopt.hxx>
105 #include <rtl/math.hxx>
106 #include <sal/log.hxx>
107 #include <editeng/frmdiritem.hxx>
108 #include <comphelper/interfacecontainer2.hxx>
109 #include <comphelper/servicehelper.hxx>
110 #include <comphelper/string.hxx>
111 #include <cppuhelper/supportsservice.hxx>
112 #include <comphelper/sequence.hxx>
113 #include <comphelper/sequenceashashmap.hxx>
114 #include <swtable.hxx>
115 #include <docsh.hxx>
116 #include <fesh.hxx>
117 #include <itabenum.hxx>
119 using namespace ::com::sun::star;
120 using ::editeng::SvxBorderLine;
122 namespace
124 template<typename Tcoretype, typename Tunotype>
125 struct FindUnoInstanceHint final : SfxHint
127 FindUnoInstanceHint(Tcoretype* pCore) : m_pCore(pCore), m_pResult(nullptr) {};
128 const Tcoretype* const m_pCore;
129 mutable Tunotype* m_pResult;
131 SwFrameFormat* lcl_EnsureCoreConnected(SwFrameFormat* pFormat, cppu::OWeakObject* pObject)
133 if(!pFormat)
134 throw uno::RuntimeException("Lost connection to core objects", pObject);
135 return pFormat;
137 SwTable* lcl_EnsureTableNotComplex(SwTable* pTable, cppu::OWeakObject* pObject)
139 if(pTable->IsTableComplex())
140 throw uno::RuntimeException("Table too complex", pObject);
141 return pTable;
144 chart::ChartDataChangeEvent createChartEvent(uno::Reference<uno::XInterface> const& xSource)
146 //TODO: find appropriate settings of the Event
147 chart::ChartDataChangeEvent event;
148 event.Source = xSource;
149 event.Type = chart::ChartDataChangeType_ALL;
150 event.StartColumn = 0;
151 event.EndColumn = 1;
152 event.StartRow = 0;
153 event.EndRow = 1;
154 return event;
157 void lcl_SendChartEvent(
158 uno::Reference<uno::XInterface> const& xSource,
159 ::comphelper::OInterfaceContainerHelper2& rListeners)
161 rListeners.notifyEach(
162 &chart::XChartDataChangeEventListener::chartDataChanged,
163 createChartEvent(xSource));
166 void lcl_SendChartEvent(
167 uno::Reference<uno::XInterface> const& xSource,
168 ::cppu::OMultiTypeInterfaceContainerHelper const& rListeners)
170 auto pContainer(rListeners.getContainer(cppu::UnoType<chart::XChartDataChangeEventListener>::get()));
171 if (pContainer)
172 pContainer->notifyEach(
173 &chart::XChartDataChangeEventListener::chartDataChanged,
174 createChartEvent(xSource));
178 #define UNO_TABLE_COLUMN_SUM 10000
181 static bool lcl_LineToSvxLine(const table::BorderLine& rLine, SvxBorderLine& rSvxLine)
183 rSvxLine.SetColor(Color(rLine.Color));
185 rSvxLine.GuessLinesWidths( SvxBorderLineStyle::NONE,
186 convertMm100ToTwip( rLine.OuterLineWidth ),
187 convertMm100ToTwip( rLine.InnerLineWidth ),
188 convertMm100ToTwip( rLine.LineDistance ) );
190 return rLine.InnerLineWidth > 0 || rLine.OuterLineWidth > 0;
193 /// @throws lang::IllegalArgumentException
194 /// @throws uno::RuntimeException
195 static void lcl_SetSpecialProperty(SwFrameFormat* pFormat,
196 const SfxItemPropertySimpleEntry* pEntry,
197 const uno::Any& aValue)
199 // special treatment for "non-items"
200 switch(pEntry->nWID)
202 case FN_TABLE_HEADLINE_REPEAT:
203 case FN_TABLE_HEADLINE_COUNT:
205 SwTable* pTable = SwTable::FindTable( pFormat );
206 UnoActionContext aAction(pFormat->GetDoc());
207 if( pEntry->nWID == FN_TABLE_HEADLINE_REPEAT)
209 pFormat->GetDoc()->SetRowsToRepeat( *pTable, aValue.get<bool>() ? 1 : 0 );
211 else
213 sal_Int32 nRepeat = 0;
214 aValue >>= nRepeat;
215 if( nRepeat >= 0 && nRepeat < SAL_MAX_UINT16 )
216 pFormat->GetDoc()->SetRowsToRepeat( *pTable, static_cast<sal_uInt16>(nRepeat) );
219 break;
221 case FN_TABLE_IS_RELATIVE_WIDTH:
222 case FN_TABLE_WIDTH:
223 case FN_TABLE_RELATIVE_WIDTH:
225 SwFormatFrameSize aSz( pFormat->GetFrameSize() );
226 if(FN_TABLE_WIDTH == pEntry->nWID)
228 sal_Int32 nWidth = 0;
229 aValue >>= nWidth;
230 aSz.SetWidthPercent(0);
231 aSz.SetWidth ( convertMm100ToTwip ( nWidth ) );
233 else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID)
235 sal_Int16 nSet = 0;
236 aValue >>= nSet;
237 if(nSet && nSet <=100)
238 aSz.SetWidthPercent( static_cast<sal_uInt8>(nSet) );
240 else if(FN_TABLE_IS_RELATIVE_WIDTH == pEntry->nWID)
242 if(!aValue.get<bool>())
243 aSz.SetWidthPercent(0);
244 else
246 lang::IllegalArgumentException aExcept;
247 aExcept.Message = "relative width cannot be switched on with this property";
248 throw aExcept;
251 pFormat->GetDoc()->SetAttr(aSz, *pFormat);
253 break;
255 case RES_PAGEDESC:
257 OUString sPageStyle;
258 aValue >>= sPageStyle;
259 const SwPageDesc* pDesc = nullptr;
260 if (!sPageStyle.isEmpty())
262 SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc);
263 pDesc = SwPageDesc::GetByName(*pFormat->GetDoc(), sPageStyle);
265 SwFormatPageDesc aDesc( pDesc );
266 pFormat->GetDoc()->SetAttr(aDesc, *pFormat);
268 break;
270 default:
271 throw lang::IllegalArgumentException();
275 static uno::Any lcl_GetSpecialProperty(SwFrameFormat* pFormat, const SfxItemPropertySimpleEntry* pEntry )
277 switch(pEntry->nWID)
279 case FN_TABLE_HEADLINE_REPEAT:
280 case FN_TABLE_HEADLINE_COUNT:
282 SwTable* pTable = SwTable::FindTable( pFormat );
283 const sal_uInt16 nRepeat = pTable->GetRowsToRepeat();
284 if(pEntry->nWID == FN_TABLE_HEADLINE_REPEAT)
285 return uno::makeAny<bool>(nRepeat > 0);
286 return uno::makeAny<sal_Int32>(nRepeat);
289 case FN_TABLE_WIDTH:
290 case FN_TABLE_IS_RELATIVE_WIDTH:
291 case FN_TABLE_RELATIVE_WIDTH:
293 uno::Any aRet;
294 const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
295 if(FN_TABLE_WIDTH == pEntry->nWID)
296 rSz.QueryValue(aRet, MID_FRMSIZE_WIDTH|CONVERT_TWIPS);
297 else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID)
298 rSz.QueryValue(aRet, MID_FRMSIZE_REL_WIDTH);
299 else
300 aRet <<= (0 != rSz.GetWidthPercent());
301 return aRet;
304 case RES_PAGEDESC:
306 const SfxItemSet& rSet = pFormat->GetAttrSet();
307 const SfxPoolItem* pItem;
308 if(SfxItemState::SET == rSet.GetItemState(RES_PAGEDESC, false, &pItem))
310 const SwPageDesc* pDsc = static_cast<const SwFormatPageDesc*>(pItem)->GetPageDesc();
311 if(pDsc)
312 return uno::makeAny<OUString>(SwStyleNameMapper::GetProgName(pDsc->GetName(), SwGetPoolIdFromName::PageDesc ));
314 return uno::makeAny(OUString());
317 case RES_ANCHOR:
318 return uno::makeAny(text::TextContentAnchorType_AT_PARAGRAPH);
320 case FN_UNO_ANCHOR_TYPES:
322 uno::Sequence<text::TextContentAnchorType> aTypes{text::TextContentAnchorType_AT_PARAGRAPH};
323 return uno::makeAny(aTypes);
326 case FN_UNO_WRAP :
327 return uno::makeAny(text::WrapTextMode_NONE);
329 case FN_PARAM_LINK_DISPLAY_NAME :
330 return uno::makeAny(pFormat->GetName());
332 case FN_UNO_REDLINE_NODE_START:
333 case FN_UNO_REDLINE_NODE_END:
335 SwTable* pTable = SwTable::FindTable( pFormat );
336 SwNode* pTableNode = pTable->GetTableNode();
337 if(FN_UNO_REDLINE_NODE_END == pEntry->nWID)
338 pTableNode = pTableNode->EndOfSectionNode();
339 for(const SwRangeRedline* pRedline : pFormat->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable())
341 const SwNode& rRedPointNode = pRedline->GetNode();
342 const SwNode& rRedMarkNode = pRedline->GetNode(false);
343 if(&rRedPointNode == pTableNode || &rRedMarkNode == pTableNode)
345 const SwNode& rStartOfRedline = SwNodeIndex(rRedPointNode) <= SwNodeIndex(rRedMarkNode) ?
346 rRedPointNode : rRedMarkNode;
347 bool bIsStart = &rStartOfRedline == pTableNode;
348 return uno::makeAny(SwXRedlinePortion::CreateRedlineProperties(*pRedline, bIsStart));
353 return uno::Any();
356 /** get position of a cell with a given name
358 * If everything was OK, the indices for column and row are changed (both >= 0).
359 * In case of errors, at least one of them is < 0.
361 * Also since the implementations of tables does not really have columns using
362 * this function is appropriate only for tables that are not complex (i.e.
363 * where IsTableComplex() returns false).
365 * @param rCellName e.g. A1..Z1, a1..z1, AA1..AZ1, Aa1..Az1, BA1..BZ1, Ba1..Bz1, ...
366 * @param [IN,OUT] o_rColumn (0-based)
367 * @param [IN,OUT] o_rRow (0-based)
369 //TODO: potential for throwing proper exceptions instead of having every caller to check for errors
370 void SwXTextTable::GetCellPosition(const OUString& rCellName, sal_Int32& o_rColumn, sal_Int32& o_rRow)
372 o_rColumn = o_rRow = -1; // default return values indicating failure
373 const sal_Int32 nLen = rCellName.getLength();
374 if(!nLen)
376 SAL_WARN("sw.uno", "failed to get column or row index");
377 return;
379 sal_Int32 nRowPos = 0;
380 while (nRowPos<nLen)
382 if (rCellName[nRowPos]>='0' && rCellName[nRowPos]<='9')
384 break;
386 ++nRowPos;
388 if (nRowPos>0 && nRowPos<nLen)
390 sal_Int32 nColIdx = 0;
391 for (sal_Int32 i = 0; i < nRowPos; ++i)
393 nColIdx *= 52;
394 if (i < nRowPos - 1)
395 ++nColIdx;
396 const sal_Unicode cChar = rCellName[i];
397 if ('A' <= cChar && cChar <= 'Z')
398 nColIdx += cChar - 'A';
399 else if ('a' <= cChar && cChar <= 'z')
400 nColIdx += 26 + cChar - 'a';
401 else
403 nColIdx = -1; // sth failed
404 break;
408 o_rColumn = nColIdx;
409 o_rRow = rCellName.copy(nRowPos).toInt32() - 1; // - 1 because indices ought to be 0 based
413 /** compare position of two cells (check rows first)
415 * @note this function probably also make sense only
416 * for cell names of non-complex tables
418 * @param rCellName1 e.g. "A1" (non-empty string with valid cell name)
419 * @param rCellName2 e.g. "A1" (non-empty string with valid cell name)
420 * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2
422 int sw_CompareCellsByRowFirst( const OUString &rCellName1, const OUString &rCellName2 )
424 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
425 SwXTextTable::GetCellPosition( rCellName1, nCol1, nRow1 );
426 SwXTextTable::GetCellPosition( rCellName2, nCol2, nRow2 );
428 if (nRow1 < nRow2 || (nRow1 == nRow2 && nCol1 < nCol2))
429 return -1;
430 else if (nCol1 == nCol2 && nRow1 == nRow2)
431 return 0;
432 else
433 return +1;
436 /** compare position of two cells (check columns first)
438 * @note this function probably also make sense only
439 * for cell names of non-complex tables
441 * @param rCellName1 e.g. "A1" (non-empty string with valid cell name)
442 * @param rCellName2 e.g. "A1" (non-empty string with valid cell name)
443 * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2
445 int sw_CompareCellsByColFirst( const OUString &rCellName1, const OUString &rCellName2 )
447 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
448 SwXTextTable::GetCellPosition( rCellName1, nCol1, nRow1 );
449 SwXTextTable::GetCellPosition( rCellName2, nCol2, nRow2 );
451 if (nCol1 < nCol2 || (nCol1 == nCol2 && nRow1 < nRow2))
452 return -1;
453 else if (nRow1 == nRow2 && nCol1 == nCol2)
454 return 0;
455 else
456 return +1;
459 /** compare position of two cell ranges
461 * @note this function probably also make sense only
462 * for cell names of non-complex tables
464 * @param rRange1StartCell e.g. "A1" (non-empty string with valid cell name)
465 * @param rRange1EndCell e.g. "A1" (non-empty string with valid cell name)
466 * @param rRange2StartCell e.g. "A1" (non-empty string with valid cell name)
467 * @param rRange2EndCell e.g. "A1" (non-empty string with valid cell name)
468 * @param bCmpColsFirst if <true> position in columns will be compared first before rows
470 * @return -1 if cell_range_1 < cell_range_2; 0 if both cell ranges are equal; +1 if cell_range_1 > cell_range_2
472 int sw_CompareCellRanges(
473 const OUString &rRange1StartCell, const OUString &rRange1EndCell,
474 const OUString &rRange2StartCell, const OUString &rRange2EndCell,
475 bool bCmpColsFirst )
477 int (*pCompareCells)( const OUString &, const OUString & ) =
478 bCmpColsFirst ? &sw_CompareCellsByColFirst : &sw_CompareCellsByRowFirst;
480 int nCmpResStartCells = pCompareCells( rRange1StartCell, rRange2StartCell );
481 if ((-1 == nCmpResStartCells ) ||
482 ( 0 == nCmpResStartCells &&
483 -1 == pCompareCells( rRange1EndCell, rRange2EndCell ) ))
484 return -1;
485 else if (0 == nCmpResStartCells &&
486 0 == pCompareCells( rRange1EndCell, rRange2EndCell ))
487 return 0;
488 else
489 return +1;
492 /** get cell name at a specified coordinate
494 * @param nColumn column index (0-based)
495 * @param nRow row index (0-based)
496 * @return the cell name
498 OUString sw_GetCellName( sal_Int32 nColumn, sal_Int32 nRow )
500 if (nColumn < 0 || nRow < 0)
501 return OUString();
502 OUString sCellName;
503 sw_GetTableBoxColStr( static_cast< sal_uInt16 >(nColumn), sCellName );
504 return sCellName + OUString::number( nRow + 1 );
507 /** Find the top left or bottom right corner box in given table.
508 Consider nested lines when finding the box.
510 @param rTableLines the table
511 @param i_bTopLeft if true, find top left box, otherwise find bottom
512 right box
514 static const SwTableBox* lcl_FindCornerTableBox(const SwTableLines& rTableLines, const bool i_bTopLeft)
516 const SwTableLines* pLines(&rTableLines);
517 while(true)
519 assert(!pLines->empty());
520 if(pLines->empty())
521 return nullptr;
522 const SwTableLine* pLine(i_bTopLeft ? pLines->front() : pLines->back());
523 assert(pLine);
524 const SwTableBoxes& rBoxes(pLine->GetTabBoxes());
525 assert(rBoxes.size() != 0);
526 const SwTableBox* pBox = i_bTopLeft ? rBoxes.front() : rBoxes.back();
527 assert(pBox);
528 if (pBox->GetSttNd())
529 return pBox;
530 pLines = &pBox->GetTabLines();
534 /** cleanup order in a range
536 * Sorts the input to a uniform format. I.e. for the four possible representation
537 * A1:C5, C5:A1, A5:C1, C1:A5
538 * the result will be always A1:C5.
540 * @param [IN,OUT] rCell1 cell name (will be modified to upper-left corner), e.g. "A1" (non-empty string with valid cell name)
541 * @param [IN,OUT] rCell2 cell name (will be modified to lower-right corner), e.g. "A1" (non-empty string with valid cell name)
543 void sw_NormalizeRange(OUString &rCell1, OUString &rCell2)
545 sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
546 SwXTextTable::GetCellPosition( rCell1, nCol1, nRow1 );
547 SwXTextTable::GetCellPosition( rCell2, nCol2, nRow2 );
548 if (nCol2 < nCol1 || nRow2 < nRow1)
550 rCell1 = sw_GetCellName( std::min(nCol1, nCol2), std::min(nRow1, nRow2) );
551 rCell2 = sw_GetCellName( std::max(nCol1, nCol2), std::max(nRow1, nRow2) );
555 void SwRangeDescriptor::Normalize()
557 if (nTop > nBottom)
558 std::swap(nBottom, nTop);
559 if (nLeft > nRight)
560 std::swap(nLeft, nRight);
563 static SwXCell* lcl_CreateXCell(SwFrameFormat* pFormat, sal_Int32 nColumn, sal_Int32 nRow)
565 const OUString sCellName = sw_GetCellName(nColumn, nRow);
566 SwTable* pTable = SwTable::FindTable(pFormat);
567 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
568 if(!pBox)
569 return nullptr;
570 return SwXCell::CreateXCell(pFormat, pBox, pTable);
573 static void lcl_InspectLines(SwTableLines& rLines, std::vector<OUString>& rAllNames)
575 for(auto pLine : rLines)
577 for(auto pBox : pLine->GetTabBoxes())
579 if(!pBox->GetName().isEmpty() && pBox->getRowSpan() > 0)
580 rAllNames.push_back(pBox->GetName());
581 SwTableLines& rBoxLines = pBox->GetTabLines();
582 if(!rBoxLines.empty())
583 lcl_InspectLines(rBoxLines, rAllNames);
588 static bool lcl_FormatTable(SwFrameFormat const * pTableFormat)
590 bool bHasFrames = false;
591 SwIterator<SwFrame,SwFormat> aIter( *pTableFormat );
592 for(SwFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
594 vcl::RenderContext* pRenderContext = pFrame->getRootFrame()->GetCurrShell()->GetOut();
595 // mba: no TYPEINFO for SwTabFrame
596 if(!pFrame->IsTabFrame())
597 continue;
598 DisableCallbackAction a(*pFrame->getRootFrame());
599 SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pFrame);
600 if(pTabFrame->isFrameAreaDefinitionValid())
601 pTabFrame->InvalidatePos();
602 pTabFrame->SetONECalcLowers();
603 pTabFrame->Calc(pRenderContext);
604 bHasFrames = true;
606 return bHasFrames;
609 static void lcl_CursorSelect(SwPaM& rCursor, bool bExpand)
611 if(bExpand)
613 if(!rCursor.HasMark())
614 rCursor.SetMark();
616 else if(rCursor.HasMark())
617 rCursor.DeleteMark();
620 static void lcl_GetTableSeparators(uno::Any& rRet, SwTable const * pTable, SwTableBox const * pBox, bool bRow)
622 SwTabCols aCols;
623 aCols.SetLeftMin ( 0 );
624 aCols.SetLeft ( 0 );
625 aCols.SetRight ( UNO_TABLE_COLUMN_SUM );
626 aCols.SetRightMax( UNO_TABLE_COLUMN_SUM );
628 pTable->GetTabCols( aCols, pBox, false, bRow );
630 const size_t nSepCount = aCols.Count();
631 uno::Sequence< text::TableColumnSeparator> aColSeq(nSepCount);
632 text::TableColumnSeparator* pArray = aColSeq.getArray();
633 bool bError = false;
634 for(size_t i = 0; i < nSepCount; ++i)
636 pArray[i].Position = static_cast< sal_Int16 >(aCols[i]);
637 pArray[i].IsVisible = !aCols.IsHidden(i);
638 if(!bRow && !pArray[i].IsVisible)
640 bError = true;
641 break;
644 if(!bError)
645 rRet <<= aColSeq;
649 static void lcl_SetTableSeparators(const uno::Any& rVal, SwTable* pTable, SwTableBox const * pBox, bool bRow, SwDoc* pDoc)
651 SwTabCols aOldCols;
653 aOldCols.SetLeftMin ( 0 );
654 aOldCols.SetLeft ( 0 );
655 aOldCols.SetRight ( UNO_TABLE_COLUMN_SUM );
656 aOldCols.SetRightMax( UNO_TABLE_COLUMN_SUM );
658 pTable->GetTabCols( aOldCols, pBox, false, bRow );
659 const size_t nOldCount = aOldCols.Count();
660 // there is no use in setting tab cols if there is only one column
661 if( !nOldCount )
662 return;
664 auto pSepSeq =
665 o3tl::tryAccess<uno::Sequence<text::TableColumnSeparator>>(rVal);
666 if(!pSepSeq || static_cast<size_t>(pSepSeq->getLength()) != nOldCount)
667 return;
668 SwTabCols aCols(aOldCols);
669 const text::TableColumnSeparator* pArray = pSepSeq->getConstArray();
670 long nLastValue = 0;
671 //sal_Int32 nTableWidth = aCols.GetRight() - aCols.GetLeft();
672 for(size_t i = 0; i < nOldCount; ++i)
674 aCols[i] = pArray[i].Position;
675 if(bool(pArray[i].IsVisible) == aCols.IsHidden(i) ||
676 (!bRow && aCols.IsHidden(i)) ||
677 aCols[i] < nLastValue ||
678 UNO_TABLE_COLUMN_SUM < aCols[i] )
679 return; // probably this should assert()
680 nLastValue = aCols[i];
682 pDoc->SetTabCols(*pTable, aCols, aOldCols, pBox, bRow );
685 /* non UNO function call to set string in SwXCell */
686 void sw_setString( SwXCell &rCell, const OUString &rText,
687 bool bKeepNumberFormat = false )
689 if(rCell.IsValid())
691 SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat();
692 pBoxFormat->LockModify();
693 pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA );
694 pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE );
695 if (!bKeepNumberFormat)
696 pBoxFormat->SetFormatAttr( SwTableBoxNumFormat(/*default Text*/) );
697 pBoxFormat->UnlockModify();
699 rCell.SwXText::setString(rText);
703 /* non UNO function call to set value in SwXCell */
704 void sw_setValue( SwXCell &rCell, double nVal )
706 if(!rCell.IsValid())
707 return;
708 // first this text (maybe) needs to be deleted
709 sal_uLong nNdPos = rCell.m_pBox->IsValidNumTextNd();
710 if(ULONG_MAX != nNdPos)
711 sw_setString( rCell, OUString(), true ); // true == keep number format
712 SwDoc* pDoc = rCell.GetDoc();
713 UnoActionContext aAction(pDoc);
714 SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat();
715 SfxItemSet aSet(pDoc->GetAttrPool(), svl::Items<RES_BOXATR_FORMAT, RES_BOXATR_VALUE>{});
716 const SfxPoolItem* pItem;
718 //!! do we need to set a new number format? Yes, if
719 // - there is no current number format
720 // - the current number format is not a number format according to the number formatter, but rather a text format
721 if(SfxItemState::SET != pBoxFormat->GetAttrSet().GetItemState(RES_BOXATR_FORMAT, true, &pItem)
722 || pDoc->GetNumberFormatter()->IsTextFormat(static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue()))
724 aSet.Put(SwTableBoxNumFormat(0));
727 SwTableBoxValue aVal(nVal);
728 aSet.Put(aVal);
729 pDoc->SetTableBoxFormulaAttrs( *rCell.m_pBox, aSet );
730 // update table
731 SwTableFormulaUpdate aTableUpdate( SwTable::FindTable( rCell.GetFrameFormat() ));
732 pDoc->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate );
736 SwXCell::SwXCell(SwFrameFormat* pTableFormat, SwTableBox* pBx, size_t const nPos) :
737 SwXText(pTableFormat->GetDoc(), CursorType::TableText),
738 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)),
739 m_pBox(pBx),
740 m_pStartNode(nullptr),
741 m_pTableFormat(pTableFormat),
742 m_nFndPos(nPos)
744 StartListening(pTableFormat->GetNotifier());
747 SwXCell::SwXCell(SwFrameFormat* pTableFormat, const SwStartNode& rStartNode) :
748 SwXText(pTableFormat->GetDoc(), CursorType::TableText),
749 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)),
750 m_pBox(nullptr),
751 m_pStartNode(&rStartNode),
752 m_pTableFormat(pTableFormat),
753 m_nFndPos(NOTFOUND)
755 StartListening(pTableFormat->GetNotifier());
758 SwXCell::~SwXCell()
760 SolarMutexGuard aGuard;
761 EndListeningAll();
764 namespace
766 class theSwXCellUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXCellUnoTunnelId > {};
769 const uno::Sequence< sal_Int8 > & SwXCell::getUnoTunnelId()
771 return theSwXCellUnoTunnelId::get().getSeq();
774 sal_Int64 SAL_CALL SwXCell::getSomething( const uno::Sequence< sal_Int8 >& rId )
776 if( rId.getLength() == 16
777 && 0 == memcmp( getUnoTunnelId().getConstArray(),
778 rId.getConstArray(), 16 ) )
780 return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) );
782 else
783 return SwXText::getSomething(rId);
786 uno::Sequence< uno::Type > SAL_CALL SwXCell::getTypes( )
788 return comphelper::concatSequences(
789 SwXCellBaseClass::getTypes(),
790 SwXText::getTypes()
794 uno::Sequence< sal_Int8 > SAL_CALL SwXCell::getImplementationId( )
796 return css::uno::Sequence<sal_Int8>();
799 void SAL_CALL SwXCell::acquire( ) throw()
801 SwXCellBaseClass::acquire();
804 void SAL_CALL SwXCell::release( ) throw()
806 SolarMutexGuard aGuard;
808 SwXCellBaseClass::release();
811 uno::Any SAL_CALL SwXCell::queryInterface( const uno::Type& aType )
813 uno::Any aRet = SwXCellBaseClass::queryInterface(aType);
814 if(aRet.getValueType() == cppu::UnoType<void>::get())
815 aRet = SwXText::queryInterface(aType);
816 return aRet;
819 const SwStartNode *SwXCell::GetStartNode() const
821 const SwStartNode* pSttNd = nullptr;
823 if( m_pStartNode || IsValid() )
824 pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
826 return pSttNd;
829 uno::Reference< text::XTextCursor >
830 SwXCell::CreateCursor()
832 return createTextCursor();
835 bool SwXCell::IsValid() const
837 // FIXME: this is now a const method, to make SwXText::IsValid invisible
838 // but the const_cast here are still ridiculous. TODO: find a better way.
839 SwFrameFormat* pTableFormat = m_pBox ? GetFrameFormat() : nullptr;
840 if(!pTableFormat)
842 const_cast<SwXCell*>(this)->m_pBox = nullptr;
844 else
846 SwTable* pTable = SwTable::FindTable( pTableFormat );
847 SwTableBox const*const pFoundBox =
848 const_cast<SwXCell*>(this)->FindBox(pTable, m_pBox);
849 if (!pFoundBox)
851 const_cast<SwXCell*>(this)->m_pBox = nullptr;
854 return nullptr != m_pBox;
857 OUString SwXCell::getFormula()
859 SolarMutexGuard aGuard;
860 if(!IsValid())
861 return OUString();
862 SwTableBoxFormula aFormula( m_pBox->GetFrameFormat()->GetTableBoxFormula() );
863 SwTable* pTable = SwTable::FindTable( GetFrameFormat() );
864 aFormula.PtrToBoxNm( pTable );
865 return aFormula.GetFormula();
868 ///@see sw_setValue (TODO: seems to be copy and paste programming here)
869 void SwXCell::setFormula(const OUString& rFormula)
871 SolarMutexGuard aGuard;
872 if(!IsValid())
873 return;
874 // first this text (maybe) needs to be deleted
875 sal_uInt32 nNdPos = m_pBox->IsValidNumTextNd();
876 if(USHRT_MAX == nNdPos)
877 sw_setString( *this, OUString(), true );
878 OUString sFormula(comphelper::string::stripStart(rFormula, ' '));
879 if( !sFormula.isEmpty() && '=' == sFormula[0] )
880 sFormula = sFormula.copy( 1 );
881 SwTableBoxFormula aFormula( sFormula );
882 SwDoc* pMyDoc = GetDoc();
883 UnoActionContext aAction(pMyDoc);
884 SfxItemSet aSet(pMyDoc->GetAttrPool(), svl::Items<RES_BOXATR_FORMAT, RES_BOXATR_FORMULA>{});
885 const SfxPoolItem* pItem;
886 SwFrameFormat* pBoxFormat = m_pBox->GetFrameFormat();
887 if(SfxItemState::SET != pBoxFormat->GetAttrSet().GetItemState(RES_BOXATR_FORMAT, true, &pItem)
888 || pMyDoc->GetNumberFormatter()->IsTextFormat(static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue()))
890 aSet.Put(SwTableBoxNumFormat(0));
892 aSet.Put(aFormula);
893 GetDoc()->SetTableBoxFormulaAttrs( *m_pBox, aSet );
894 // update table
895 SwTableFormulaUpdate aTableUpdate( SwTable::FindTable( GetFrameFormat() ));
896 pMyDoc->getIDocumentFieldsAccess().UpdateTableFields( &aTableUpdate );
899 double SwXCell::getValue()
901 SolarMutexGuard aGuard;
902 // #i112652# a table cell may contain NaN as a value, do not filter that
903 double fRet;
904 if(IsValid() && !getString().isEmpty())
905 fRet = m_pBox->GetFrameFormat()->GetTableBoxValue().GetValue();
906 else
907 ::rtl::math::setNan( &fRet );
908 return fRet;
911 void SwXCell::setValue(double rValue)
913 SolarMutexGuard aGuard;
914 sw_setValue( *this, rValue );
917 table::CellContentType SwXCell::getType()
919 SolarMutexGuard aGuard;
921 table::CellContentType nRes = table::CellContentType_EMPTY;
922 sal_uInt32 nNdPos = m_pBox->IsFormulaOrValueBox();
923 switch (nNdPos)
925 case 0 : nRes = table::CellContentType_TEXT; break;
926 case USHRT_MAX : nRes = table::CellContentType_EMPTY; break;
927 case RES_BOXATR_VALUE : nRes = table::CellContentType_VALUE; break;
928 case RES_BOXATR_FORMULA : nRes = table::CellContentType_FORMULA; break;
929 default :
930 OSL_FAIL( "unexpected case" );
932 return nRes;
935 void SwXCell::setString(const OUString& aString)
937 SolarMutexGuard aGuard;
938 sw_setString( *this, aString );
941 sal_Int32 SwXCell::getError()
943 SolarMutexGuard aGuard;
944 OUString sContent = getString();
945 return sal_Int32(sContent == SwViewShell::GetShellRes()->aCalc_Error);
948 uno::Reference<text::XTextCursor> SwXCell::createTextCursor()
950 SolarMutexGuard aGuard;
951 if(!m_pStartNode && !IsValid())
952 throw uno::RuntimeException();
953 const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
954 SwPosition aPos(*pSttNd);
955 SwXTextCursor* const pXCursor =
956 new SwXTextCursor(*GetDoc(), this, CursorType::TableText, aPos);
957 auto& rUnoCursor(pXCursor->GetCursor());
958 rUnoCursor.Move(fnMoveForward, GoInNode);
959 return static_cast<text::XWordCursor*>(pXCursor);
962 uno::Reference<text::XTextCursor> SwXCell::createTextCursorByRange(const uno::Reference< text::XTextRange > & xTextPosition)
964 SolarMutexGuard aGuard;
965 SwUnoInternalPaM aPam(*GetDoc());
966 if((!m_pStartNode && !IsValid()) || !::sw::XTextRangeToSwPaM(aPam, xTextPosition))
967 throw uno::RuntimeException();
968 const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
969 // skip sections
970 SwStartNode* p1 = aPam.GetNode().StartOfSectionNode();
971 while(p1->IsSectionNode())
972 p1 = p1->StartOfSectionNode();
973 if( p1 != pSttNd )
974 return nullptr;
975 return static_cast<text::XWordCursor*>(
976 new SwXTextCursor(*GetDoc(), this, CursorType::TableText,
977 *aPam.GetPoint(), aPam.GetMark()));
980 uno::Reference< beans::XPropertySetInfo > SwXCell::getPropertySetInfo()
982 static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo();
983 return xRef;
986 void SwXCell::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
988 SolarMutexGuard aGuard;
989 if(!IsValid())
990 return;
991 // Hack to support hidden property to transfer textDirection
992 if(rPropertyName == "FRMDirection")
994 SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, RES_FRAMEDIR);
995 aItem.PutValue(aValue, 0);
996 m_pBox->GetFrameFormat()->SetFormatAttr(aItem);
998 else if(rPropertyName == "TableRedlineParams")
1000 // Get the table row properties
1001 uno::Sequence<beans::PropertyValue> tableCellProperties = aValue.get< uno::Sequence< beans::PropertyValue > >();
1002 comphelper::SequenceAsHashMap aPropMap(tableCellProperties);
1003 OUString sRedlineType;
1004 if(!(aPropMap.getValue("RedlineType") >>= sRedlineType))
1005 throw beans::UnknownPropertyException("No redline type property: ", static_cast<cppu::OWeakObject*>(this));
1007 // Create a 'Table Cell Redline' object
1008 SwUnoCursorHelper::makeTableCellRedline(*m_pBox, sRedlineType, tableCellProperties);
1012 else
1014 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
1015 if ( !pEntry )
1017 // not a table property: if it is a paragraph/character property, consider applying it to the underlying text.
1018 const SfxItemPropertySet& rParaPropSet = *aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH);
1019 pEntry = rParaPropSet.getPropertyMap().getByName(rPropertyName);
1021 if ( pEntry )
1023 SwNodeIndex aIdx( *GetStartNode(), 1 );
1024 const SwNode* pEndNd = aIdx.GetNode().EndOfSectionNode();
1025 while ( &aIdx.GetNode() != pEndNd )
1027 const SwTextNode* pNd = aIdx.GetNode().GetTextNode();
1028 if ( pNd )
1030 //point and mark selecting the whole paragraph
1031 SwPaM aPaM(*pNd, 0, *pNd, pNd->GetText().getLength());
1032 const bool bHasAttrSet = pNd->HasSwAttrSet();
1033 const SfxItemSet& aSet = pNd->GetSwAttrSet();
1034 // isPARATR: replace DEFAULT_VALUE properties only
1035 // isCHRATR: change the base/auto SwAttr property, but don't remove the DIRECT hints
1036 if ( !bHasAttrSet || SfxItemState::DEFAULT == aSet.GetItemState(pEntry->nWID, /*bSrchInParent=*/false) )
1037 SwUnoCursorHelper::SetPropertyValue(aPaM, rParaPropSet, rPropertyName, aValue, SetAttrMode::DONTREPLACE);
1039 ++aIdx;
1041 return;
1045 if(!pEntry)
1046 throw beans::UnknownPropertyException(rPropertyName, static_cast<cppu::OWeakObject*>(this));
1047 if(pEntry->nWID != FN_UNO_CELL_ROW_SPAN)
1049 SwFrameFormat* pBoxFormat = m_pBox->ClaimFrameFormat();
1050 SwAttrSet aSet(pBoxFormat->GetAttrSet());
1051 m_pPropSet->setPropertyValue(rPropertyName, aValue, aSet);
1052 pBoxFormat->GetDoc()->SetAttr(aSet, *pBoxFormat);
1054 else if(aValue.isExtractableTo(cppu::UnoType<sal_Int32>::get()))
1055 m_pBox->setRowSpan(aValue.get<sal_Int32>());
1059 uno::Any SwXCell::getPropertyValue(const OUString& rPropertyName)
1061 SolarMutexGuard aGuard;
1062 if(!IsValid())
1063 return uno::Any();
1064 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
1065 if(!pEntry)
1066 throw beans::UnknownPropertyException(rPropertyName, static_cast<cppu::OWeakObject*>(this));
1067 switch(pEntry->nWID)
1069 case FN_UNO_CELL_ROW_SPAN:
1070 return uno::makeAny(m_pBox->getRowSpan());
1071 break;
1072 case FN_UNO_TEXT_SECTION:
1074 SwFrameFormat* pTableFormat = GetFrameFormat();
1075 SwTable* pTable = SwTable::FindTable(pTableFormat);
1076 SwTableNode* pTableNode = pTable->GetTableNode();
1077 SwSectionNode* pSectionNode = pTableNode->FindSectionNode();
1078 if(!pSectionNode)
1079 return uno::Any();
1080 SwSection& rSect = pSectionNode->GetSection();
1081 return uno::makeAny(SwXTextSections::GetObject(*rSect.GetFormat()));
1083 break;
1084 case FN_UNO_CELL_NAME:
1085 return uno::makeAny(m_pBox->GetName());
1086 break;
1087 case FN_UNO_REDLINE_NODE_START:
1088 case FN_UNO_REDLINE_NODE_END:
1090 //redline can only be returned if it's a living object
1091 return SwXText::getPropertyValue(rPropertyName);
1093 break;
1094 case FN_UNO_PARENT_TEXT:
1096 if (!m_xParentText.is())
1098 const SwStartNode* pSttNd = m_pBox->GetSttNd();
1099 if (!pSttNd)
1100 return uno::Any();
1102 const SwTableNode* pTableNode = pSttNd->FindTableNode();
1103 if (!pTableNode)
1104 return uno::Any();
1106 SwPosition aPos(*pTableNode);
1107 SwDoc* pDoc = aPos.GetDoc();
1108 if (!pDoc)
1109 return uno::Any();
1111 m_xParentText = sw::CreateParentXText(*pDoc, aPos);
1114 return uno::makeAny(m_xParentText);
1116 break;
1117 default:
1119 const SwAttrSet& rSet = m_pBox->GetFrameFormat()->GetAttrSet();
1120 uno::Any aResult;
1121 m_pPropSet->getPropertyValue(rPropertyName, rSet, aResult);
1122 return aResult;
1127 void SwXCell::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1128 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1130 void SwXCell::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1131 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1133 void SwXCell::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1134 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1136 void SwXCell::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1137 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1139 uno::Reference<container::XEnumeration> SwXCell::createEnumeration()
1141 SolarMutexGuard aGuard;
1142 if(!IsValid())
1143 return uno::Reference<container::XEnumeration>();
1144 const SwStartNode* pSttNd = m_pBox->GetSttNd();
1145 SwPosition aPos(*pSttNd);
1146 auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos));
1147 pUnoCursor->Move(fnMoveForward, GoInNode);
1148 // remember table and start node for later travelling
1149 // (used in export of tables in tables)
1150 SwTable const*const pTable(&pSttNd->FindTableNode()->GetTable());
1151 return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::TableText, pSttNd, pTable);
1154 uno::Type SAL_CALL SwXCell::getElementType()
1156 return cppu::UnoType<text::XTextRange>::get();
1159 sal_Bool SwXCell::hasElements()
1161 return true;
1164 void SwXCell::Notify(const SfxHint& rHint)
1166 if(rHint.GetId() == SfxHintId::Dying)
1168 m_pTableFormat = nullptr;
1170 else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableBox, SwXCell>*>(&rHint))
1172 if(!pFindHint->m_pResult && pFindHint->m_pCore == GetTableBox())
1173 pFindHint->m_pResult = this;
1177 SwXCell* SwXCell::CreateXCell(SwFrameFormat* pTableFormat, SwTableBox* pBox, SwTable *pTable )
1179 if(!pTableFormat || !pBox)
1180 return nullptr;
1181 if(!pTable)
1182 pTable = SwTable::FindTable(pTableFormat);
1183 SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find(pBox);
1184 if(it == pTable->GetTabSortBoxes().end())
1185 return nullptr;
1186 size_t const nPos = it - pTable->GetTabSortBoxes().begin();
1187 FindUnoInstanceHint<SwTableBox, SwXCell> aHint{pBox};
1188 pTableFormat->GetNotifier().Broadcast(aHint);
1189 return aHint.m_pResult ? aHint.m_pResult : new SwXCell(pTableFormat, pBox, nPos);
1192 /** search if a box exists in a table
1194 * @param pTable the table to search in
1195 * @param pBox2 box model to find
1196 * @return the box if existent in pTable, 0 (!!!) if not found
1198 SwTableBox* SwXCell::FindBox(SwTable* pTable, SwTableBox* pBox2)
1200 // check if nFndPos happens to point to the right table box
1201 if( m_nFndPos < pTable->GetTabSortBoxes().size() &&
1202 pBox2 == pTable->GetTabSortBoxes()[ m_nFndPos ] )
1203 return pBox2;
1205 // if not, seek the entry (and return, if successful)
1206 SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find( pBox2 );
1207 if( it != pTable->GetTabSortBoxes().end() )
1209 m_nFndPos = it - pTable->GetTabSortBoxes().begin();
1210 return pBox2;
1213 // box not found: reset nFndPos pointer
1214 m_nFndPos = NOTFOUND;
1215 return nullptr;
1218 double SwXCell::GetForcedNumericalValue() const
1220 if(table::CellContentType_TEXT != const_cast<SwXCell*>(this)->getType())
1221 return getValue();
1222 // now we'll try to get a useful numerical value
1223 // from the text in the cell...
1224 sal_uInt32 nFIndex;
1225 SvNumberFormatter* pNumFormatter(const_cast<SvNumberFormatter*>(GetDoc()->GetNumberFormatter()));
1226 // look for SwTableBoxNumFormat value in parents as well
1227 const SfxPoolItem* pItem;
1228 auto pBoxFormat(GetTableBox()->GetFrameFormat());
1229 SfxItemState eState = pBoxFormat->GetAttrSet().GetItemState(RES_BOXATR_FORMAT, true, &pItem);
1231 if (eState == SfxItemState::SET)
1233 // please note that the language of the numberformat
1234 // is implicitly coded into the below value as well
1235 nFIndex = static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue();
1237 // since the current value indicates a text format but the call
1238 // to 'IsNumberFormat' below won't work for text formats
1239 // we need to get rid of the part that indicates the text format.
1240 // According to ER this can be done like this:
1241 nFIndex -= (nFIndex % SV_COUNTRY_LANGUAGE_OFFSET);
1243 else
1245 // system language is probably not the best possible choice
1246 // but since we have to guess anyway (because the language of at
1247 // the text is NOT the one used for the number format!)
1248 // it is at least conform to what is used in
1249 // SwTableShell::Execute when
1250 // SID_ATTR_NUMBERFORMAT_VALUE is set...
1251 LanguageType eLang = LANGUAGE_SYSTEM;
1252 nFIndex = pNumFormatter->GetStandardIndex( eLang );
1254 double fTmp;
1255 if (!const_cast<SwDoc*>(GetDoc())->IsNumberFormat(const_cast<SwXCell*>(this)->getString(), nFIndex, fTmp))
1256 ::rtl::math::setNan(&fTmp);
1257 return fTmp;
1260 uno::Any SwXCell::GetAny() const
1262 if(!m_pBox)
1263 throw uno::RuntimeException();
1264 // check if table box value item is set
1265 auto pBoxFormat(m_pBox->GetFrameFormat());
1266 const bool bIsNum = pBoxFormat->GetItemState(RES_BOXATR_VALUE, false) == SfxItemState::SET;
1267 return bIsNum ? uno::makeAny(getValue()) : uno::makeAny(const_cast<SwXCell*>(this)->getString());
1270 OUString SwXCell::getImplementationName()
1271 { return "SwXCell"; }
1273 sal_Bool SwXCell::supportsService(const OUString& rServiceName)
1274 { return cppu::supportsService(this, rServiceName); }
1276 uno::Sequence< OUString > SwXCell::getSupportedServiceNames()
1277 { return {"com.sun.star.text.CellProperties"}; }
1279 OUString SwXTextTableRow::getImplementationName()
1280 { return "SwXTextTableRow"; }
1282 sal_Bool SwXTextTableRow::supportsService(const OUString& rServiceName)
1283 { return cppu::supportsService(this, rServiceName); }
1285 uno::Sequence< OUString > SwXTextTableRow::getSupportedServiceNames()
1286 { return {"com.sun.star.text.TextTableRow"}; }
1289 SwXTextTableRow::SwXTextTableRow(SwFrameFormat* pFormat, SwTableLine* pLn) :
1290 m_pFormat(pFormat),
1291 pLine(pLn),
1292 m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_ROW))
1294 StartListening(m_pFormat->GetNotifier());
1297 SwXTextTableRow::~SwXTextTableRow()
1299 SolarMutexGuard aGuard;
1300 EndListeningAll();
1303 uno::Reference< beans::XPropertySetInfo > SwXTextTableRow::getPropertySetInfo()
1305 static uno::Reference<beans::XPropertySetInfo> xRef = m_pPropSet->getPropertySetInfo();
1306 return xRef;
1309 void SwXTextTableRow::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
1311 SolarMutexGuard aGuard;
1312 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
1313 SwTable* pTable = SwTable::FindTable( pFormat );
1314 SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, pLine);
1315 if(pLn)
1317 // Check for a specific property
1318 if ( rPropertyName == "TableRedlineParams" )
1320 // Get the table row properties
1321 uno::Sequence< beans::PropertyValue > tableRowProperties = aValue.get< uno::Sequence< beans::PropertyValue > >();
1322 comphelper::SequenceAsHashMap aPropMap( tableRowProperties );
1323 OUString sRedlineType;
1324 if( !(aPropMap.getValue("RedlineType") >>= sRedlineType) )
1326 throw beans::UnknownPropertyException("No redline type property: ", static_cast < cppu::OWeakObject * > ( this ) );
1329 // Create a 'Table Row Redline' object
1330 SwUnoCursorHelper::makeTableRowRedline( *pLn, sRedlineType, tableRowProperties);
1333 else
1335 const SfxItemPropertySimpleEntry* pEntry =
1336 m_pPropSet->getPropertyMap().getByName(rPropertyName);
1337 SwDoc* pDoc = pFormat->GetDoc();
1338 if (!pEntry)
1339 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
1340 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
1341 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
1343 switch(pEntry->nWID)
1345 case FN_UNO_ROW_HEIGHT:
1346 case FN_UNO_ROW_AUTO_HEIGHT:
1348 SwFormatFrameSize aFrameSize(pLn->GetFrameFormat()->GetFrameSize());
1349 if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID)
1351 bool bSet = *o3tl::doAccess<bool>(aValue);
1352 aFrameSize.SetHeightSizeType(bSet ? ATT_VAR_SIZE : ATT_FIX_SIZE);
1354 else
1356 sal_Int32 nHeight = 0;
1357 aValue >>= nHeight;
1358 Size aSz(aFrameSize.GetSize());
1359 aSz.setHeight( convertMm100ToTwip(nHeight) );
1360 aFrameSize.SetSize(aSz);
1362 pDoc->SetAttr(aFrameSize, *pLn->ClaimFrameFormat());
1364 break;
1366 case FN_UNO_TABLE_COLUMN_SEPARATORS:
1368 UnoActionContext aContext(pDoc);
1369 SwTable* pTable2 = SwTable::FindTable( pFormat );
1370 lcl_SetTableSeparators(aValue, pTable2, pLine->GetTabBoxes()[0], true, pDoc);
1372 break;
1374 default:
1376 SwFrameFormat* pLnFormat = pLn->ClaimFrameFormat();
1377 SwAttrSet aSet(pLnFormat->GetAttrSet());
1378 m_pPropSet->setPropertyValue(*pEntry, aValue, aSet);
1379 pDoc->SetAttr(aSet, *pLnFormat);
1386 uno::Any SwXTextTableRow::getPropertyValue(const OUString& rPropertyName)
1388 SolarMutexGuard aGuard;
1389 uno::Any aRet;
1390 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
1391 SwTable* pTable = SwTable::FindTable( pFormat );
1392 SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, pLine);
1393 if(pLn)
1395 const SfxItemPropertySimpleEntry* pEntry =
1396 m_pPropSet->getPropertyMap().getByName(rPropertyName);
1397 if (!pEntry)
1398 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
1400 switch(pEntry->nWID)
1402 case FN_UNO_ROW_HEIGHT:
1403 case FN_UNO_ROW_AUTO_HEIGHT:
1405 const SwFormatFrameSize& rSize = pLn->GetFrameFormat()->GetFrameSize();
1406 if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID)
1408 aRet <<= ATT_VAR_SIZE == rSize.GetHeightSizeType();
1410 else
1411 aRet <<= static_cast<sal_Int32>(convertTwipToMm100(rSize.GetSize().Height()));
1413 break;
1415 case FN_UNO_TABLE_COLUMN_SEPARATORS:
1417 lcl_GetTableSeparators(aRet, pTable, pLine->GetTabBoxes()[0], true);
1419 break;
1421 default:
1423 const SwAttrSet& rSet = pLn->GetFrameFormat()->GetAttrSet();
1424 m_pPropSet->getPropertyValue(*pEntry, rSet, aRet);
1428 return aRet;
1431 void SwXTextTableRow::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1432 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1434 void SwXTextTableRow::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1435 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1437 void SwXTextTableRow::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1438 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1440 void SwXTextTableRow::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1441 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1443 void SwXTextTableRow::Notify(const SfxHint& rHint)
1445 if(rHint.GetId() == SfxHintId::Dying)
1447 m_pFormat = nullptr;
1448 } else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableLine, SwXTextTableRow>*>(&rHint))
1450 if(!pFindHint->m_pCore && pFindHint->m_pCore == pLine)
1451 pFindHint->m_pResult = this;
1455 SwTableLine* SwXTextTableRow::FindLine(SwTable* pTable, SwTableLine const * pLine)
1457 for(const auto& pCurrentLine : pTable->GetTabLines())
1458 if(pCurrentLine == pLine)
1459 return pCurrentLine;
1460 return nullptr;
1463 // SwXTextTableCursor
1465 OUString SwXTextTableCursor::getImplementationName()
1466 { return "SwXTextTableCursor"; }
1468 sal_Bool SwXTextTableCursor::supportsService(const OUString& rServiceName)
1469 { return cppu::supportsService(this, rServiceName); }
1471 void SwXTextTableCursor::acquire() throw()
1473 SwXTextTableCursor_Base::acquire();
1476 void SwXTextTableCursor::release() throw()
1478 SolarMutexGuard aGuard;
1479 SwXTextTableCursor_Base::release();
1482 css::uno::Any SAL_CALL
1483 SwXTextTableCursor::queryInterface( const css::uno::Type& _rType )
1485 css::uno::Any aReturn = SwXTextTableCursor_Base::queryInterface( _rType );
1486 if ( !aReturn.hasValue() )
1487 aReturn = OTextCursorHelper::queryInterface( _rType );
1488 return aReturn;
1491 const SwPaM* SwXTextTableCursor::GetPaM() const { return &GetCursor(); }
1492 SwPaM* SwXTextTableCursor::GetPaM() { return &GetCursor(); }
1493 const SwDoc* SwXTextTableCursor::GetDoc() const { return GetFrameFormat()->GetDoc(); }
1494 SwDoc* SwXTextTableCursor::GetDoc() { return GetFrameFormat()->GetDoc(); }
1495 const SwUnoCursor& SwXTextTableCursor::GetCursor() const { return *m_pUnoCursor; }
1496 SwUnoCursor& SwXTextTableCursor::GetCursor() { return *m_pUnoCursor; }
1498 uno::Sequence<OUString> SwXTextTableCursor::getSupportedServiceNames()
1499 { return {"com.sun.star.text.TextTableCursor"}; }
1501 SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat* pFrameFormat, SwTableBox const* pBox)
1502 : m_pFrameFormat(pFrameFormat)
1503 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
1505 StartListening(m_pFrameFormat->GetNotifier());
1506 SwDoc* pDoc = m_pFrameFormat->GetDoc();
1507 const SwStartNode* pSttNd = pBox->GetSttNd();
1508 SwPosition aPos(*pSttNd);
1509 m_pUnoCursor = pDoc->CreateUnoCursor(aPos, true);
1510 m_pUnoCursor->Move( fnMoveForward, GoInNode );
1511 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor);
1512 rTableCursor.MakeBoxSels();
1515 SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat& rTableFormat, const SwTableCursor* pTableSelection)
1516 : m_pFrameFormat(&rTableFormat)
1517 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
1519 StartListening(m_pFrameFormat->GetNotifier());
1520 m_pUnoCursor = pTableSelection->GetDoc()->CreateUnoCursor(*pTableSelection->GetPoint(), true);
1521 if(pTableSelection->HasMark())
1523 m_pUnoCursor->SetMark();
1524 *m_pUnoCursor->GetMark() = *pTableSelection->GetMark();
1526 const SwSelBoxes& rBoxes = pTableSelection->GetSelectedBoxes();
1527 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor);
1528 for(auto pBox : rBoxes)
1529 rTableCursor.InsertBox(*pBox);
1530 rTableCursor.MakeBoxSels();
1533 OUString SwXTextTableCursor::getRangeName()
1535 SolarMutexGuard aGuard;
1536 SwUnoCursor& rUnoCursor = GetCursor();
1537 SwUnoTableCursor* pTableCursor = dynamic_cast<SwUnoTableCursor*>(&rUnoCursor);
1538 //!! see also SwChartDataSequence::getSourceRangeRepresentation
1539 if(!pTableCursor)
1540 return OUString();
1541 pTableCursor->MakeBoxSels();
1542 const SwStartNode* pNode = pTableCursor->GetPoint()->nNode.GetNode().FindTableBoxStartNode();
1543 const SwTable* pTable = SwTable::FindTable(GetFrameFormat());
1544 const SwTableBox* pEndBox = pTable->GetTableBox(pNode->GetIndex());
1545 if(pTableCursor->HasMark())
1547 pNode = pTableCursor->GetMark()->nNode.GetNode().FindTableBoxStartNode();
1548 const SwTableBox* pStartBox = pTable->GetTableBox(pNode->GetIndex());
1549 if(pEndBox != pStartBox)
1551 // need to switch start and end?
1552 if(*pTableCursor->GetPoint() < *pTableCursor->GetMark())
1553 std::swap(pStartBox, pEndBox);
1554 return pStartBox->GetName() + ":" + pEndBox->GetName();
1557 return pEndBox->GetName();
1560 sal_Bool SwXTextTableCursor::gotoCellByName(const OUString& sCellName, sal_Bool bExpand)
1562 SolarMutexGuard aGuard;
1563 SwUnoCursor& rUnoCursor = GetCursor();
1564 auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1565 lcl_CursorSelect(rTableCursor, bExpand);
1566 return rTableCursor.GotoTableBox(sCellName);
1569 sal_Bool SwXTextTableCursor::goLeft(sal_Int16 Count, sal_Bool bExpand)
1571 SolarMutexGuard aGuard;
1572 SwUnoCursor& rUnoCursor = GetCursor();
1573 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1574 lcl_CursorSelect(rTableCursor, bExpand);
1575 return rTableCursor.Left(Count);
1578 sal_Bool SwXTextTableCursor::goRight(sal_Int16 Count, sal_Bool bExpand)
1580 SolarMutexGuard aGuard;
1581 SwUnoCursor& rUnoCursor = GetCursor();
1582 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1583 lcl_CursorSelect(rTableCursor, bExpand);
1584 return rTableCursor.Right(Count);
1587 sal_Bool SwXTextTableCursor::goUp(sal_Int16 Count, sal_Bool bExpand)
1589 SolarMutexGuard aGuard;
1590 SwUnoCursor& rUnoCursor = GetCursor();
1591 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1592 lcl_CursorSelect(rTableCursor, bExpand);
1593 return rTableCursor.UpDown(true, Count, nullptr, 0,
1594 *rUnoCursor.GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout());
1597 sal_Bool SwXTextTableCursor::goDown(sal_Int16 Count, sal_Bool bExpand)
1599 SolarMutexGuard aGuard;
1600 SwUnoCursor& rUnoCursor = GetCursor();
1601 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1602 lcl_CursorSelect(rTableCursor, bExpand);
1603 return rTableCursor.UpDown(false, Count, nullptr, 0,
1604 *rUnoCursor.GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout());
1607 void SwXTextTableCursor::gotoStart(sal_Bool bExpand)
1609 SolarMutexGuard aGuard;
1610 SwUnoCursor& rUnoCursor = GetCursor();
1611 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1612 lcl_CursorSelect(rTableCursor, bExpand);
1613 rTableCursor.MoveTable(GotoCurrTable, fnTableStart);
1616 void SwXTextTableCursor::gotoEnd(sal_Bool bExpand)
1618 SolarMutexGuard aGuard;
1619 SwUnoCursor& rUnoCursor = GetCursor();
1620 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1621 lcl_CursorSelect(rTableCursor, bExpand);
1622 rTableCursor.MoveTable(GotoCurrTable, fnTableEnd);
1625 sal_Bool SwXTextTableCursor::mergeRange()
1627 SolarMutexGuard aGuard;
1628 SwUnoCursor& rUnoCursor = GetCursor();
1630 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1632 // HACK: remove pending actions for selecting old style tables
1633 UnoActionRemoveContext aRemoveContext(rTableCursor);
1635 rTableCursor.MakeBoxSels();
1636 bool bResult;
1638 UnoActionContext aContext(rUnoCursor.GetDoc());
1639 bResult = TableMergeErr::Ok == rTableCursor.GetDoc()->MergeTable(rTableCursor);
1641 if(bResult)
1643 size_t nCount = rTableCursor.GetSelectedBoxesCount();
1644 while (nCount--)
1645 rTableCursor.DeleteBox(nCount);
1647 rTableCursor.MakeBoxSels();
1648 return bResult;
1651 sal_Bool SwXTextTableCursor::splitRange(sal_Int16 Count, sal_Bool Horizontal)
1653 SolarMutexGuard aGuard;
1654 if (Count <= 0)
1655 throw uno::RuntimeException("Illegal first argument: needs to be > 0", static_cast<cppu::OWeakObject*>(this));
1656 SwUnoCursor& rUnoCursor = GetCursor();
1657 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1659 // HACK: remove pending actions for selecting old style tables
1660 UnoActionRemoveContext aRemoveContext(rTableCursor);
1662 rTableCursor.MakeBoxSels();
1663 bool bResult;
1665 UnoActionContext aContext(rUnoCursor.GetDoc());
1666 bResult = rTableCursor.GetDoc()->SplitTable(rTableCursor.GetSelectedBoxes(), !Horizontal, Count);
1668 rTableCursor.MakeBoxSels();
1669 return bResult;
1672 uno::Reference< beans::XPropertySetInfo > SwXTextTableCursor::getPropertySetInfo()
1674 static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo();
1675 return xRef;
1678 void SwXTextTableCursor::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
1680 SolarMutexGuard aGuard;
1681 SwUnoCursor& rUnoCursor = GetCursor();
1682 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
1683 if(!pEntry)
1684 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast<cppu::OWeakObject*>(this));
1685 if(pEntry->nFlags & beans::PropertyAttribute::READONLY)
1686 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast<cppu::OWeakObject*>(this));
1688 auto pSttNode = rUnoCursor.GetNode().StartOfSectionNode();
1689 const SwTableNode* pTableNode = pSttNode->FindTableNode();
1690 lcl_FormatTable(pTableNode->GetTable().GetFrameFormat());
1692 auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1693 rTableCursor.MakeBoxSels();
1694 SwDoc* pDoc = rUnoCursor.GetDoc();
1695 switch(pEntry->nWID)
1697 case FN_UNO_TABLE_CELL_BACKGROUND:
1699 std::shared_ptr<SfxPoolItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND));
1700 SwDoc::GetBoxAttr(rUnoCursor, aBrush);
1701 aBrush->PutValue(aValue, pEntry->nMemberId);
1702 pDoc->SetBoxAttr(rUnoCursor, *aBrush);
1705 break;
1706 case RES_BOXATR_FORMAT:
1708 SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT);
1709 aNumberFormat.PutValue(aValue, 0);
1710 pDoc->SetBoxAttr(rUnoCursor, aNumberFormat);
1712 break;
1713 case FN_UNO_PARA_STYLE:
1714 SwUnoCursorHelper::SetTextFormatColl(aValue, rUnoCursor);
1715 break;
1716 default:
1718 SfxItemSet aItemSet(pDoc->GetAttrPool(), {{pEntry->nWID, pEntry->nWID}});
1719 SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(),
1720 aItemSet);
1722 if (!SwUnoCursorHelper::SetCursorPropertyValue(
1723 *pEntry, aValue, rTableCursor.GetSelRing(), aItemSet))
1725 m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet);
1727 SwUnoCursorHelper::SetCursorAttr(rTableCursor.GetSelRing(),
1728 aItemSet, SetAttrMode::DEFAULT, true);
1733 uno::Any SwXTextTableCursor::getPropertyValue(const OUString& rPropertyName)
1735 SolarMutexGuard aGuard;
1736 SwUnoCursor& rUnoCursor = GetCursor();
1738 auto pSttNode = rUnoCursor.GetNode().StartOfSectionNode();
1739 const SwTableNode* pTableNode = pSttNode->FindTableNode();
1740 lcl_FormatTable(pTableNode->GetTable().GetFrameFormat());
1742 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
1743 auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
1744 if(!pEntry)
1745 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast<cppu::OWeakObject*>(this));
1746 rTableCursor.MakeBoxSels();
1747 uno::Any aResult;
1748 switch(pEntry->nWID)
1750 case FN_UNO_TABLE_CELL_BACKGROUND:
1752 std::shared_ptr<SfxPoolItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND));
1753 if (SwDoc::GetBoxAttr(rUnoCursor, aBrush))
1754 aBrush->QueryValue(aResult, pEntry->nMemberId);
1756 break;
1757 case RES_BOXATR_FORMAT:
1758 // TODO: GetAttr for table selections in a Doc is missing
1759 throw uno::RuntimeException("Unknown property: " + rPropertyName, static_cast<cppu::OWeakObject*>(this));
1760 break;
1761 case FN_UNO_PARA_STYLE:
1763 auto pFormat(SwUnoCursorHelper::GetCurTextFormatColl(rUnoCursor, false));
1764 if(pFormat)
1765 aResult <<= pFormat->GetName();
1767 break;
1768 default:
1770 SfxItemSet aSet(rTableCursor.GetDoc()->GetAttrPool(),
1771 svl::Items<RES_CHRATR_BEGIN, RES_FRMATR_END-1,
1772 RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER>{});
1773 SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(), aSet);
1774 m_pPropSet->getPropertyValue(*pEntry, aSet, aResult);
1777 return aResult;
1780 void SwXTextTableCursor::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1781 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1783 void SwXTextTableCursor::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
1784 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1786 void SwXTextTableCursor::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1787 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1789 void SwXTextTableCursor::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
1790 { throw uno::RuntimeException("not implemented", static_cast<cppu::OWeakObject*>(this)); };
1792 void SwXTextTableCursor::Notify( const SfxHint& rHint )
1794 if(rHint.GetId() == SfxHintId::Dying)
1795 m_pFrameFormat = nullptr;
1799 // SwXTextTable ===========================================================
1801 class SwTableProperties_Impl
1803 SwUnoCursorHelper::SwAnyMapHelper aAnyMap;
1804 public:
1805 SwTableProperties_Impl();
1807 void SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& aVal);
1808 bool GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny);
1809 template<typename Tpoolitem>
1810 inline void AddItemToSet(SfxItemSet& rSet, std::function<Tpoolitem()> aItemFactory, sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips = false);
1812 void ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc);
1815 SwTableProperties_Impl::SwTableProperties_Impl()
1818 void SwTableProperties_Impl::SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rVal)
1819 { aAnyMap.SetValue( nWhichId, nMemberId, rVal ); }
1821 bool SwTableProperties_Impl::GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny )
1822 { return aAnyMap.FillValue( nWhichId, nMemberId, rpAny ); }
1824 template<typename Tpoolitem>
1825 void SwTableProperties_Impl::AddItemToSet(SfxItemSet& rSet, std::function<Tpoolitem()> aItemFactory, sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips)
1827 std::vector< std::pair<sal_uInt16, const uno::Any* > > vMemberAndAny;
1828 for(sal_uInt16 nMember : vMember)
1830 const uno::Any* pAny = nullptr;
1831 GetProperty(nWhich, nMember, pAny);
1832 if(pAny)
1833 vMemberAndAny.emplace_back(nMember, pAny);
1835 if(!vMemberAndAny.empty())
1837 Tpoolitem aItem = aItemFactory();
1838 for(const auto& aMemberAndAny : vMemberAndAny)
1839 aItem->PutValue(*aMemberAndAny.second, aMemberAndAny.first | (bAddTwips ? CONVERT_TWIPS : 0) );
1840 rSet.Put(*aItem);
1843 void SwTableProperties_Impl::ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc)
1845 SfxItemSet aSet(
1846 rDoc.GetAttrPool(),
1847 svl::Items<
1848 RES_FRM_SIZE, RES_BREAK,
1849 RES_HORI_ORIENT, RES_HORI_ORIENT,
1850 RES_BACKGROUND, RES_BACKGROUND,
1851 RES_SHADOW, RES_SHADOW,
1852 RES_KEEP, RES_KEEP,
1853 RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT>{});
1854 const uno::Any* pRepHead;
1855 const SwFrameFormat &rFrameFormat = *rTable.GetFrameFormat();
1856 if(GetProperty(FN_TABLE_HEADLINE_REPEAT, 0xff, pRepHead ))
1858 bool bVal(pRepHead->get<bool>());
1859 const_cast<SwTable&>(rTable).SetRowsToRepeat( bVal ? 1 : 0 ); // TODO: MULTIHEADER
1862 AddItemToSet<std::shared_ptr<SvxBrushItem>>(aSet, [&rFrameFormat]() { return rFrameFormat.makeBackgroundBrushItem(); }, RES_BACKGROUND, {
1863 MID_BACK_COLOR,
1864 MID_GRAPHIC_TRANSPARENT,
1865 MID_GRAPHIC_POSITION,
1866 MID_GRAPHIC,
1867 MID_GRAPHIC_FILTER });
1869 bool bPutBreak = true;
1870 const uno::Any* pPage;
1871 if(GetProperty(FN_UNO_PAGE_STYLE, 0, pPage) || GetProperty(RES_PAGEDESC, 0xff, pPage))
1873 OUString sPageStyle = pPage->get<OUString>();
1874 if(!sPageStyle.isEmpty())
1876 SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc);
1877 const SwPageDesc* pDesc = SwPageDesc::GetByName(rDoc, sPageStyle);
1878 if(pDesc)
1880 SwFormatPageDesc aDesc(pDesc);
1881 const uno::Any* pPgNo;
1882 if(GetProperty(RES_PAGEDESC, MID_PAGEDESC_PAGENUMOFFSET, pPgNo))
1884 aDesc.SetNumOffset(pPgNo->get<sal_Int16>());
1886 aSet.Put(aDesc);
1887 bPutBreak = false;
1893 if(bPutBreak)
1894 AddItemToSet<std::shared_ptr<SvxFormatBreakItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxFormatBreakItem>(static_cast<SvxFormatBreakItem*>(rFrameFormat.GetBreak().Clone())); }, RES_BREAK, {0});
1895 AddItemToSet<std::shared_ptr<SvxShadowItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxShadowItem>(static_cast<SvxShadowItem*>(rFrameFormat.GetShadow().Clone())); }, RES_SHADOW, {0}, true);
1896 AddItemToSet<std::shared_ptr<SvxFormatKeepItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxFormatKeepItem>(static_cast<SvxFormatKeepItem*>(rFrameFormat.GetKeep().Clone())); }, RES_KEEP, {0});
1897 AddItemToSet<std::shared_ptr<SwFormatHoriOrient>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SwFormatHoriOrient>(static_cast<SwFormatHoriOrient*>(rFrameFormat.GetHoriOrient().Clone())); }, RES_HORI_ORIENT, {MID_HORIORIENT_ORIENT}, true);
1899 const uno::Any* pSzRel(nullptr);
1900 GetProperty(FN_TABLE_IS_RELATIVE_WIDTH, 0xff, pSzRel);
1901 const uno::Any* pRelWidth(nullptr);
1902 GetProperty(FN_TABLE_RELATIVE_WIDTH, 0xff, pRelWidth);
1903 const uno::Any* pWidth(nullptr);
1904 GetProperty(FN_TABLE_WIDTH, 0xff, pWidth);
1906 bool bPutSize = pWidth != nullptr;
1907 SwFormatFrameSize aSz(ATT_VAR_SIZE);
1908 if(pWidth)
1910 aSz.PutValue(*pWidth, MID_FRMSIZE_WIDTH);
1911 bPutSize = true;
1913 if(pSzRel && pSzRel->get<bool>() && pRelWidth)
1915 aSz.PutValue(*pRelWidth, MID_FRMSIZE_REL_WIDTH|CONVERT_TWIPS);
1916 bPutSize = true;
1918 if(bPutSize)
1920 if(!aSz.GetWidth())
1921 aSz.SetWidth(MINLAY);
1922 aSet.Put(aSz);
1924 AddItemToSet<std::shared_ptr<SvxLRSpaceItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxLRSpaceItem>(static_cast<SvxLRSpaceItem*>(rFrameFormat.GetLRSpace().Clone())); }, RES_LR_SPACE, {
1925 MID_L_MARGIN|CONVERT_TWIPS,
1926 MID_R_MARGIN|CONVERT_TWIPS });
1927 AddItemToSet<std::shared_ptr<SvxULSpaceItem>>(aSet, [&rFrameFormat]() { return std::shared_ptr<SvxULSpaceItem>(static_cast<SvxULSpaceItem*>(rFrameFormat.GetULSpace().Clone())); }, RES_UL_SPACE, {
1928 MID_UP_MARGIN|CONVERT_TWIPS,
1929 MID_LO_MARGIN|CONVERT_TWIPS });
1930 const::uno::Any* pSplit(nullptr);
1931 if(GetProperty(RES_LAYOUT_SPLIT, 0, pSplit))
1933 SwFormatLayoutSplit aSp(pSplit->get<bool>());
1934 aSet.Put(aSp);
1936 if(aSet.Count())
1938 rDoc.SetAttr(aSet, *rTable.GetFrameFormat());
1942 class SwXTextTable::Impl
1943 : public SvtListener
1945 private:
1946 SwFrameFormat* m_pFrameFormat;
1947 ::osl::Mutex m_Mutex; // just for OInterfaceContainerHelper2
1949 public:
1950 uno::WeakReference<uno::XInterface> m_wThis;
1951 ::cppu::OMultiTypeInterfaceContainerHelper m_Listeners;
1953 const SfxItemPropertySet * m_pPropSet;
1955 css::uno::WeakReference<css::table::XTableRows> m_xRows;
1956 css::uno::WeakReference<css::table::XTableColumns> m_xColumns;
1958 bool m_bFirstRowAsLabel;
1959 bool m_bFirstColumnAsLabel;
1961 // Descriptor-interface
1962 std::unique_ptr<SwTableProperties_Impl> m_pTableProps;
1963 OUString m_sTableName;
1964 unsigned short m_nRows;
1965 unsigned short m_nColumns;
1967 explicit Impl(SwFrameFormat* const pFrameFormat)
1968 : m_pFrameFormat(pFrameFormat)
1969 , m_Listeners(m_Mutex)
1970 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE))
1971 , m_bFirstRowAsLabel(false)
1972 , m_bFirstColumnAsLabel(false)
1973 , m_pTableProps(pFrameFormat ? nullptr : new SwTableProperties_Impl)
1974 , m_nRows(pFrameFormat ? 0 : 2)
1975 , m_nColumns(pFrameFormat ? 0 : 2)
1977 if(m_pFrameFormat)
1978 StartListening(m_pFrameFormat->GetNotifier());
1981 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
1982 void SetFrameFormat(SwFrameFormat& rFrameFormat)
1984 EndListeningAll();
1985 m_pFrameFormat = &rFrameFormat;
1986 StartListening(m_pFrameFormat->GetNotifier());
1989 bool IsDescriptor() { return m_pTableProps != nullptr; }
1991 // note: lock mutex before calling this to avoid concurrent update
1992 static std::pair<sal_uInt16, sal_uInt16> ThrowIfComplex(SwXTextTable &rThis)
1994 sal_uInt16 const nRowCount(rThis.m_pImpl->GetRowCount());
1995 sal_uInt16 const nColCount(rThis.m_pImpl->GetColumnCount());
1996 if (!nRowCount || !nColCount)
1998 throw uno::RuntimeException("Table too complex",
1999 static_cast<cppu::OWeakObject*>(&rThis));
2001 return std::make_pair(nRowCount, nColCount);
2004 sal_uInt16 GetRowCount();
2005 sal_uInt16 GetColumnCount();
2007 virtual void Notify(const SfxHint&) override;
2011 namespace
2013 class theSwXTextTableUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextTableUnoTunnelId > {};
2016 const uno::Sequence< sal_Int8 > & SwXTextTable::getUnoTunnelId()
2017 { return theSwXTextTableUnoTunnelId::get().getSeq(); }
2019 sal_Int64 SAL_CALL SwXTextTable::getSomething( const uno::Sequence< sal_Int8 >& rId )
2021 if(rId.getLength() == 16
2022 && 0 == memcmp(getUnoTunnelId().getConstArray(), rId.getConstArray(), 16))
2024 return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
2026 return 0;
2030 SwXTextTable::SwXTextTable()
2031 : m_pImpl(new Impl(nullptr))
2035 SwXTextTable::SwXTextTable(SwFrameFormat& rFrameFormat)
2036 : m_pImpl(new Impl(&rFrameFormat))
2040 SwXTextTable::~SwXTextTable()
2044 uno::Reference<text::XTextTable> SwXTextTable::CreateXTextTable(SwFrameFormat* const pFrameFormat)
2046 uno::Reference<text::XTextTable> xTable;
2047 if(pFrameFormat)
2048 xTable.set(pFrameFormat->GetXObject(), uno::UNO_QUERY); // cached?
2049 if(xTable.is())
2050 return xTable;
2051 SwXTextTable* const pNew( pFrameFormat ? new SwXTextTable(*pFrameFormat) : new SwXTextTable());
2052 xTable.set(pNew);
2053 if(pFrameFormat)
2054 pFrameFormat->SetXObject(xTable);
2055 // need a permanent Reference to initialize m_wThis
2056 pNew->m_pImpl->m_wThis = xTable;
2057 return xTable;
2060 SwFrameFormat* SwXTextTable::GetFrameFormat()
2062 return m_pImpl->GetFrameFormat();
2065 void SwXTextTable::initialize(sal_Int32 nR, sal_Int32 nC)
2067 if (!m_pImpl->IsDescriptor() || nR <= 0 || nC <= 0 || nR >= SAL_MAX_UINT16 || nC >= SAL_MAX_UINT16)
2068 throw uno::RuntimeException();
2069 m_pImpl->m_nRows = static_cast<sal_uInt16>(nR);
2070 m_pImpl->m_nColumns = static_cast<sal_uInt16>(nC);
2073 uno::Reference<table::XTableRows> SAL_CALL SwXTextTable::getRows()
2075 SolarMutexGuard aGuard;
2076 uno::Reference<table::XTableRows> xResult(m_pImpl->m_xRows);
2077 if(xResult.is())
2078 return xResult;
2079 if(SwFrameFormat* pFormat = GetFrameFormat())
2080 m_pImpl->m_xRows = xResult = new SwXTableRows(*pFormat);
2081 if(!xResult.is())
2082 throw uno::RuntimeException();
2083 return xResult;
2086 uno::Reference<table::XTableColumns> SAL_CALL SwXTextTable::getColumns()
2088 SolarMutexGuard aGuard;
2089 uno::Reference<table::XTableColumns> xResult(m_pImpl->m_xColumns);
2090 if(xResult.is())
2091 return xResult;
2092 if(SwFrameFormat* pFormat = GetFrameFormat())
2093 m_pImpl->m_xColumns = xResult = new SwXTableColumns(*pFormat);
2094 if(!xResult.is())
2095 throw uno::RuntimeException();
2096 return xResult;
2099 uno::Reference<table::XCell> SwXTextTable::getCellByName(const OUString& sCellName)
2101 SolarMutexGuard aGuard;
2102 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2103 SwTable* pTable = SwTable::FindTable(pFormat);
2104 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
2105 if(!pBox)
2106 return nullptr;
2107 return SwXCell::CreateXCell(pFormat, pBox);
2110 uno::Sequence<OUString> SwXTextTable::getCellNames()
2112 SolarMutexGuard aGuard;
2113 SwFrameFormat* pFormat(GetFrameFormat());
2114 if(!pFormat)
2115 return {};
2116 SwTable* pTable = SwTable::FindTable(pFormat);
2117 // exists at the table and at all boxes
2118 SwTableLines& rTableLines = pTable->GetTabLines();
2119 std::vector<OUString> aAllNames;
2120 lcl_InspectLines(rTableLines, aAllNames);
2121 return comphelper::containerToSequence(aAllNames);
2124 uno::Reference<text::XTextTableCursor> SwXTextTable::createCursorByCellName(const OUString& sCellName)
2126 SolarMutexGuard aGuard;
2127 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2128 SwTable* pTable = SwTable::FindTable(pFormat);
2129 SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
2130 if(!pBox || pBox->getRowSpan() == 0)
2131 throw uno::RuntimeException();
2132 return new SwXTextTableCursor(pFormat, pBox);
2135 void SAL_CALL
2136 SwXTextTable::attach(const uno::Reference<text::XTextRange> & xTextRange)
2138 SolarMutexGuard aGuard;
2140 // attach() must only be called once
2141 if (!m_pImpl->IsDescriptor()) /* already attached ? */
2142 throw uno::RuntimeException("SwXTextTable: already attached to range.", static_cast<cppu::OWeakObject*>(this));
2144 uno::Reference<XUnoTunnel> xRangeTunnel(xTextRange, uno::UNO_QUERY);
2145 SwXTextRange* pRange(nullptr);
2146 OTextCursorHelper* pCursor(nullptr);
2147 if(xRangeTunnel.is())
2149 pRange = reinterpret_cast<SwXTextRange*>(
2150 sal::static_int_cast<sal_IntPtr>(xRangeTunnel->getSomething(SwXTextRange::getUnoTunnelId())));
2151 pCursor = reinterpret_cast<OTextCursorHelper*>(
2152 sal::static_int_cast<sal_IntPtr>(xRangeTunnel->getSomething(OTextCursorHelper::getUnoTunnelId())));
2154 SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr;
2155 if (!pDoc || !m_pImpl->m_nRows || !m_pImpl->m_nColumns)
2156 throw lang::IllegalArgumentException();
2157 SwUnoInternalPaM aPam(*pDoc);
2158 // this now needs to return TRUE
2159 ::sw::XTextRangeToSwPaM(aPam, xTextRange);
2161 UnoActionContext aCont(pDoc);
2163 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
2164 const SwTable* pTable(nullptr);
2165 if( 0 != aPam.Start()->nContent.GetIndex() )
2167 pDoc->getIDocumentContentOperations().SplitNode(*aPam.Start(), false);
2169 //TODO: if it is the last paragraph than add another one!
2170 if(aPam.HasMark())
2172 pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam);
2173 aPam.DeleteMark();
2175 pTable = pDoc->InsertTable(SwInsertTableOptions( SwInsertTableFlags::Headline | SwInsertTableFlags::DefaultBorder | SwInsertTableFlags::SplitLayout, 0 ),
2176 *aPam.GetPoint(),
2177 m_pImpl->m_nRows,
2178 m_pImpl->m_nColumns,
2179 text::HoriOrientation::FULL);
2180 if(pTable)
2182 // here, the properties of the descriptor need to be analyzed
2183 m_pImpl->m_pTableProps->ApplyTableAttr(*pTable, *pDoc);
2184 SwFrameFormat* pTableFormat(pTable->GetFrameFormat());
2185 lcl_FormatTable(pTableFormat);
2187 m_pImpl->SetFrameFormat(*pTableFormat);
2189 if (!m_pImpl->m_sTableName.isEmpty())
2191 sal_uInt16 nIndex = 1;
2192 OUString sTmpNameIndex(m_pImpl->m_sTableName);
2193 while(pDoc->FindTableFormatByName(sTmpNameIndex, true) && nIndex < USHRT_MAX)
2195 sTmpNameIndex = m_pImpl->m_sTableName + OUString::number(nIndex++);
2197 pDoc->SetTableName( *pTableFormat, sTmpNameIndex);
2200 const::uno::Any* pName;
2201 if (m_pImpl->m_pTableProps->GetProperty(FN_UNO_TABLE_NAME, 0, pName))
2202 setName(pName->get<OUString>());
2203 m_pImpl->m_pTableProps.reset();
2205 pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
2209 uno::Reference<text::XTextRange> SwXTextTable::getAnchor()
2211 SolarMutexGuard aGuard;
2212 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2213 return new SwXTextRange(*pFormat);
2216 void SwXTextTable::dispose()
2218 SolarMutexGuard aGuard;
2219 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2220 SwTable* pTable = SwTable::FindTable(pFormat);
2221 SwSelBoxes aSelBoxes;
2222 for(auto& rBox : pTable->GetTabSortBoxes() )
2223 aSelBoxes.insert(rBox);
2224 pFormat->GetDoc()->DeleteRowCol(aSelBoxes);
2227 void SAL_CALL SwXTextTable::addEventListener(
2228 const uno::Reference<lang::XEventListener> & xListener)
2230 // no need to lock here as m_pImpl is const and container threadsafe
2231 m_pImpl->m_Listeners.addInterface(
2232 cppu::UnoType<lang::XEventListener>::get(), xListener);
2235 void SAL_CALL SwXTextTable::removeEventListener(
2236 const uno::Reference< lang::XEventListener > & xListener)
2238 // no need to lock here as m_pImpl is const and container threadsafe
2239 m_pImpl->m_Listeners.removeInterface(
2240 cppu::UnoType<lang::XEventListener>::get(), xListener);
2243 uno::Reference<table::XCell> SwXTextTable::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow)
2245 SolarMutexGuard aGuard;
2246 SwFrameFormat* pFormat(GetFrameFormat());
2247 // sheet is unimportant
2248 if(nColumn >= 0 && nRow >= 0 && pFormat)
2250 auto pXCell = lcl_CreateXCell(pFormat, nColumn, nRow);
2251 if(pXCell)
2252 return pXCell;
2254 throw lang::IndexOutOfBoundsException();
2257 namespace {
2259 uno::Reference<table::XCellRange> GetRangeByName(
2260 SwFrameFormat* pFormat, SwTable const * pTable,
2261 const OUString& rTLName, const OUString& rBRName,
2262 SwRangeDescriptor const & rDesc)
2264 const SwTableBox* pTLBox = pTable->GetTableBox(rTLName);
2265 if(!pTLBox)
2266 return nullptr;
2267 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2268 SwPosition aPos(*pSttNd);
2269 // set cursor to the upper-left cell of the range
2270 auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true));
2271 pUnoCursor->Move(fnMoveForward, GoInNode);
2272 pUnoCursor->SetRemainInSection(false);
2273 const SwTableBox* pBRBox(pTable->GetTableBox(rBRName));
2274 if(!pBRBox)
2275 return nullptr;
2276 pUnoCursor->SetMark();
2277 pUnoCursor->GetPoint()->nNode = *pBRBox->GetSttNd();
2278 pUnoCursor->Move( fnMoveForward, GoInNode );
2279 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2280 // HACK: remove pending actions for selecting old style tables
2281 UnoActionRemoveContext aRemoveContext(rCursor);
2282 rCursor.MakeBoxSels();
2283 // pUnoCursor will be provided and will not be deleted
2284 return SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, rDesc).get();
2287 } // namespace
2289 uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByPosition(sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom)
2291 SolarMutexGuard aGuard;
2292 SwFrameFormat* pFormat(GetFrameFormat());
2293 if(pFormat &&
2294 nLeft <= nRight && nTop <= nBottom &&
2295 nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 )
2297 SwTable* pTable = SwTable::FindTable(pFormat);
2298 if(!pTable->IsTableComplex())
2300 SwRangeDescriptor aDesc;
2301 aDesc.nTop = nTop;
2302 aDesc.nBottom = nBottom;
2303 aDesc.nLeft = nLeft;
2304 aDesc.nRight = nRight;
2305 const OUString sTLName = sw_GetCellName(aDesc.nLeft, aDesc.nTop);
2306 const OUString sBRName = sw_GetCellName(aDesc.nRight, aDesc.nBottom);
2307 // please note that according to the 'if' statement at the begin
2308 // sTLName:sBRName already denotes the normalized range string
2309 return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc);
2312 throw lang::IndexOutOfBoundsException();
2315 uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByName(const OUString& sRange)
2317 SolarMutexGuard aGuard;
2318 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2319 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), static_cast<cppu::OWeakObject*>(this));
2320 sal_Int32 nPos = 0;
2321 const OUString sTLName(sRange.getToken(0, ':', nPos));
2322 const OUString sBRName(sRange.getToken(0, ':', nPos));
2323 if(sTLName.isEmpty() || sBRName.isEmpty())
2324 throw uno::RuntimeException();
2325 SwRangeDescriptor aDesc;
2326 aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1;
2327 SwXTextTable::GetCellPosition(sTLName, aDesc.nLeft, aDesc.nTop );
2328 SwXTextTable::GetCellPosition(sBRName, aDesc.nRight, aDesc.nBottom );
2330 // we should normalize the range now (e.g. A5:C1 will become A1:C5)
2331 // since (depending on what is done later) it will be troublesome
2332 // elsewhere when the cursor in the implementation does not
2333 // point to the top-left and bottom-right cells
2334 aDesc.Normalize();
2335 return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc);
2338 uno::Sequence< uno::Sequence< uno::Any > > SAL_CALL SwXTextTable::getDataArray()
2340 SolarMutexGuard aGuard;
2341 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2342 uno::Reference<sheet::XCellRangeData> const xAllRange(
2343 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2344 uno::UNO_QUERY_THROW);
2345 return xAllRange->getDataArray();
2348 void SAL_CALL SwXTextTable::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray)
2350 SolarMutexGuard aGuard;
2351 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2352 uno::Reference<sheet::XCellRangeData> const xAllRange(
2353 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2354 uno::UNO_QUERY_THROW);
2355 return xAllRange->setDataArray(rArray);
2358 uno::Sequence< uno::Sequence< double > > SwXTextTable::getData()
2360 SolarMutexGuard aGuard;
2361 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2362 uno::Reference<chart::XChartDataArray> const xAllRange(
2363 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2364 uno::UNO_QUERY_THROW);
2365 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2366 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2367 return xAllRange->getData();
2370 void SwXTextTable::setData(const uno::Sequence< uno::Sequence< double > >& rData)
2372 SolarMutexGuard aGuard;
2373 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2374 uno::Reference<chart::XChartDataArray> const xAllRange(
2375 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2376 uno::UNO_QUERY_THROW);
2377 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2378 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2379 xAllRange->setData(rData);
2380 // this is rather inconsistent: setData on XTextTable sends events, but e.g. CellRanges do not
2381 lcl_SendChartEvent(*this, m_pImpl->m_Listeners);
2384 uno::Sequence<OUString> SwXTextTable::getRowDescriptions()
2386 SolarMutexGuard aGuard;
2387 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2388 uno::Reference<chart::XChartDataArray> const xAllRange(
2389 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2390 uno::UNO_QUERY_THROW);
2391 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2392 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2393 return xAllRange->getRowDescriptions();
2396 void SwXTextTable::setRowDescriptions(const uno::Sequence<OUString>& rRowDesc)
2398 SolarMutexGuard aGuard;
2399 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2400 uno::Reference<chart::XChartDataArray> const xAllRange(
2401 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2402 uno::UNO_QUERY_THROW);
2403 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2404 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2405 xAllRange->setRowDescriptions(rRowDesc);
2408 uno::Sequence<OUString> SwXTextTable::getColumnDescriptions()
2410 SolarMutexGuard aGuard;
2411 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2412 uno::Reference<chart::XChartDataArray> const xAllRange(
2413 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2414 uno::UNO_QUERY_THROW);
2415 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2416 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2417 return xAllRange->getColumnDescriptions();
2420 void SwXTextTable::setColumnDescriptions(const uno::Sequence<OUString>& rColumnDesc)
2422 SolarMutexGuard aGuard;
2423 std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
2424 uno::Reference<chart::XChartDataArray> const xAllRange(
2425 getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
2426 uno::UNO_QUERY_THROW);
2427 static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
2428 m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
2429 return xAllRange->setColumnDescriptions(rColumnDesc);
2432 void SAL_CALL SwXTextTable::addChartDataChangeEventListener(
2433 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
2435 // no need to lock here as m_pImpl is const and container threadsafe
2436 m_pImpl->m_Listeners.addInterface(
2437 cppu::UnoType<chart::XChartDataChangeEventListener>::get(), xListener);
2440 void SAL_CALL SwXTextTable::removeChartDataChangeEventListener(
2441 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
2443 // no need to lock here as m_pImpl is const and container threadsafe
2444 m_pImpl->m_Listeners.removeInterface(
2445 cppu::UnoType<chart::XChartDataChangeEventListener>::get(), xListener);
2448 sal_Bool SwXTextTable::isNotANumber(double nNumber)
2450 // We use DBL_MIN because starcalc does (which uses it because chart
2451 // wants it that way!)
2452 return ( nNumber == DBL_MIN );
2455 double SwXTextTable::getNotANumber()
2457 // We use DBL_MIN because starcalc does (which uses it because chart
2458 // wants it that way!)
2459 return DBL_MIN;
2462 uno::Sequence< beans::PropertyValue > SwXTextTable::createSortDescriptor()
2464 SolarMutexGuard aGuard;
2466 return SwUnoCursorHelper::CreateSortDescriptor(true);
2469 void SwXTextTable::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
2471 SolarMutexGuard aGuard;
2472 SwSortOptions aSortOpt;
2473 SwFrameFormat* pFormat = GetFrameFormat();
2474 if(pFormat &&
2475 SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt))
2477 SwTable* pTable = SwTable::FindTable( pFormat );
2478 SwSelBoxes aBoxes;
2479 const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes();
2480 for (size_t n = 0; n < rTBoxes.size(); ++n)
2482 SwTableBox* pBox = rTBoxes[ n ];
2483 aBoxes.insert( pBox );
2485 UnoActionContext aContext( pFormat->GetDoc() );
2486 pFormat->GetDoc()->SortTable(aBoxes, aSortOpt);
2490 void SwXTextTable::autoFormat(const OUString& sAutoFormatName)
2492 SolarMutexGuard aGuard;
2493 SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
2494 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), static_cast<cppu::OWeakObject*>(this));
2495 SwTableAutoFormatTable aAutoFormatTable;
2496 aAutoFormatTable.Load();
2497 for (size_t i = aAutoFormatTable.size(); i;)
2498 if( sAutoFormatName == aAutoFormatTable[ --i ].GetName() )
2500 SwSelBoxes aBoxes;
2501 const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes();
2502 for (size_t n = 0; n < rTBoxes.size(); ++n)
2504 SwTableBox* pBox = rTBoxes[ n ];
2505 aBoxes.insert( pBox );
2507 UnoActionContext aContext( pFormat->GetDoc() );
2508 pFormat->GetDoc()->SetTableAutoFormat( aBoxes, aAutoFormatTable[i] );
2509 break;
2513 uno::Reference< beans::XPropertySetInfo > SwXTextTable::getPropertySetInfo()
2515 static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo();
2516 return xRef;
2519 void SwXTextTable::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
2521 SolarMutexGuard aGuard;
2522 SwFrameFormat* pFormat = GetFrameFormat();
2523 if(!aValue.hasValue())
2524 throw lang::IllegalArgumentException();
2525 const SfxItemPropertySimpleEntry* pEntry =
2526 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
2527 if( !pEntry )
2528 throw lang::IllegalArgumentException();
2529 if(pFormat)
2531 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
2532 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
2534 if(0xBF == pEntry->nMemberId)
2536 lcl_SetSpecialProperty(pFormat, pEntry, aValue);
2538 else
2540 switch(pEntry->nWID)
2542 case FN_UNO_TABLE_NAME :
2544 OUString sName;
2545 aValue >>= sName;
2546 setName( sName );
2548 break;
2550 case FN_UNO_RANGE_ROW_LABEL:
2552 bool bTmp = *o3tl::doAccess<bool>(aValue);
2553 if (m_pImpl->m_bFirstRowAsLabel != bTmp)
2555 lcl_SendChartEvent(*this, m_pImpl->m_Listeners);
2556 m_pImpl->m_bFirstRowAsLabel = bTmp;
2559 break;
2561 case FN_UNO_RANGE_COL_LABEL:
2563 bool bTmp = *o3tl::doAccess<bool>(aValue);
2564 if (m_pImpl->m_bFirstColumnAsLabel != bTmp)
2566 lcl_SendChartEvent(*this, m_pImpl->m_Listeners);
2567 m_pImpl->m_bFirstColumnAsLabel = bTmp;
2570 break;
2572 case FN_UNO_TABLE_BORDER:
2573 case FN_UNO_TABLE_BORDER2:
2575 table::TableBorder oldBorder;
2576 table::TableBorder2 aBorder;
2577 SvxBorderLine aTopLine;
2578 SvxBorderLine aBottomLine;
2579 SvxBorderLine aLeftLine;
2580 SvxBorderLine aRightLine;
2581 SvxBorderLine aHoriLine;
2582 SvxBorderLine aVertLine;
2583 if (aValue >>= oldBorder)
2585 aBorder.IsTopLineValid = oldBorder.IsTopLineValid;
2586 aBorder.IsBottomLineValid = oldBorder.IsBottomLineValid;
2587 aBorder.IsLeftLineValid = oldBorder.IsLeftLineValid;
2588 aBorder.IsRightLineValid = oldBorder.IsRightLineValid;
2589 aBorder.IsHorizontalLineValid = oldBorder.IsHorizontalLineValid;
2590 aBorder.IsVerticalLineValid = oldBorder.IsVerticalLineValid;
2591 aBorder.Distance = oldBorder.Distance;
2592 aBorder.IsDistanceValid = oldBorder.IsDistanceValid;
2593 lcl_LineToSvxLine(
2594 oldBorder.TopLine, aTopLine);
2595 lcl_LineToSvxLine(
2596 oldBorder.BottomLine, aBottomLine);
2597 lcl_LineToSvxLine(
2598 oldBorder.LeftLine, aLeftLine);
2599 lcl_LineToSvxLine(
2600 oldBorder.RightLine, aRightLine);
2601 lcl_LineToSvxLine(
2602 oldBorder.HorizontalLine, aHoriLine);
2603 lcl_LineToSvxLine(
2604 oldBorder.VerticalLine, aVertLine);
2606 else if (aValue >>= aBorder)
2608 SvxBoxItem::LineToSvxLine(
2609 aBorder.TopLine, aTopLine, true);
2610 SvxBoxItem::LineToSvxLine(
2611 aBorder.BottomLine, aBottomLine, true);
2612 SvxBoxItem::LineToSvxLine(
2613 aBorder.LeftLine, aLeftLine, true);
2614 SvxBoxItem::LineToSvxLine(
2615 aBorder.RightLine, aRightLine, true);
2616 SvxBoxItem::LineToSvxLine(
2617 aBorder.HorizontalLine, aHoriLine, true);
2618 SvxBoxItem::LineToSvxLine(
2619 aBorder.VerticalLine, aVertLine, true);
2621 else
2623 break; // something else
2625 SwDoc* pDoc = pFormat->GetDoc();
2626 if(!lcl_FormatTable(pFormat))
2627 break;
2628 SwTable* pTable = SwTable::FindTable( pFormat );
2629 SwTableLines &rLines = pTable->GetTabLines();
2631 const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true);
2632 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2633 SwPosition aPos(*pSttNd);
2634 // set cursor to top left cell
2635 auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true));
2636 pUnoCursor->Move( fnMoveForward, GoInNode );
2637 pUnoCursor->SetRemainInSection( false );
2639 const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false);
2640 pUnoCursor->SetMark();
2641 pUnoCursor->GetPoint()->nNode = *pBRBox->GetSttNd();
2642 pUnoCursor->Move( fnMoveForward, GoInNode );
2643 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2644 // HACK: remove pending actions for selecting old style tables
2645 UnoActionRemoveContext aRemoveContext(rCursor);
2646 rCursor.MakeBoxSels();
2648 SfxItemSet aSet(pDoc->GetAttrPool(),
2649 svl::Items<RES_BOX, RES_BOX,
2650 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>{});
2652 SvxBoxItem aBox( RES_BOX );
2653 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
2655 aBox.SetLine(aTopLine.isEmpty() ? nullptr : &aTopLine, SvxBoxItemLine::TOP);
2656 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, aBorder.IsTopLineValid);
2658 aBox.SetLine(aBottomLine.isEmpty() ? nullptr : &aBottomLine, SvxBoxItemLine::BOTTOM);
2659 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::BOTTOM, aBorder.IsBottomLineValid);
2661 aBox.SetLine(aLeftLine.isEmpty() ? nullptr : &aLeftLine, SvxBoxItemLine::LEFT);
2662 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, aBorder.IsLeftLineValid);
2664 aBox.SetLine(aRightLine.isEmpty() ? nullptr : &aRightLine, SvxBoxItemLine::RIGHT);
2665 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::RIGHT, aBorder.IsRightLineValid);
2667 aBoxInfo.SetLine(aHoriLine.isEmpty() ? nullptr : &aHoriLine, SvxBoxInfoItemLine::HORI);
2668 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI, aBorder.IsHorizontalLineValid);
2670 aBoxInfo.SetLine(aVertLine.isEmpty() ? nullptr : &aVertLine, SvxBoxInfoItemLine::VERT);
2671 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT, aBorder.IsVerticalLineValid);
2673 aBox.SetAllDistances(static_cast<sal_uInt16>(convertMm100ToTwip(aBorder.Distance)));
2674 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE, aBorder.IsDistanceValid);
2676 aSet.Put(aBox);
2677 aSet.Put(aBoxInfo);
2679 pDoc->SetTabBorders(rCursor, aSet);
2681 break;
2683 case FN_UNO_TABLE_BORDER_DISTANCES:
2685 table::TableBorderDistances aTableBorderDistances;
2686 if( !(aValue >>= aTableBorderDistances) ||
2687 (!aTableBorderDistances.IsLeftDistanceValid &&
2688 !aTableBorderDistances.IsRightDistanceValid &&
2689 !aTableBorderDistances.IsTopDistanceValid &&
2690 !aTableBorderDistances.IsBottomDistanceValid ))
2691 break;
2693 const sal_uInt16 nLeftDistance = convertMm100ToTwip(aTableBorderDistances.LeftDistance);
2694 const sal_uInt16 nRightDistance = convertMm100ToTwip(aTableBorderDistances.RightDistance);
2695 const sal_uInt16 nTopDistance = convertMm100ToTwip(aTableBorderDistances.TopDistance);
2696 const sal_uInt16 nBottomDistance = convertMm100ToTwip(aTableBorderDistances.BottomDistance);
2697 SwDoc* pDoc = pFormat->GetDoc();
2698 SwTable* pTable = SwTable::FindTable( pFormat );
2699 SwTableLines &rLines = pTable->GetTabLines();
2700 pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr);
2701 for(size_t i = 0; i < rLines.size(); ++i)
2703 SwTableLine* pLine = rLines[i];
2704 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2705 for(size_t k = 0; k < rBoxes.size(); ++k)
2707 SwTableBox* pBox = rBoxes[k];
2708 const SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
2709 const SvxBoxItem& rBox = pBoxFormat->GetBox();
2711 (aTableBorderDistances.IsLeftDistanceValid && nLeftDistance != rBox.GetDistance( SvxBoxItemLine::LEFT )) ||
2712 (aTableBorderDistances.IsRightDistanceValid && nRightDistance != rBox.GetDistance( SvxBoxItemLine::RIGHT )) ||
2713 (aTableBorderDistances.IsTopDistanceValid && nTopDistance != rBox.GetDistance( SvxBoxItemLine::TOP )) ||
2714 (aTableBorderDistances.IsBottomDistanceValid && nBottomDistance != rBox.GetDistance( SvxBoxItemLine::BOTTOM )))
2716 SvxBoxItem aSetBox( rBox );
2717 SwFrameFormat* pSetBoxFormat = pBox->ClaimFrameFormat();
2718 if( aTableBorderDistances.IsLeftDistanceValid )
2719 aSetBox.SetDistance( nLeftDistance, SvxBoxItemLine::LEFT );
2720 if( aTableBorderDistances.IsRightDistanceValid )
2721 aSetBox.SetDistance( nRightDistance, SvxBoxItemLine::RIGHT );
2722 if( aTableBorderDistances.IsTopDistanceValid )
2723 aSetBox.SetDistance( nTopDistance, SvxBoxItemLine::TOP );
2724 if( aTableBorderDistances.IsBottomDistanceValid )
2725 aSetBox.SetDistance( nBottomDistance, SvxBoxItemLine::BOTTOM );
2726 pDoc->SetAttr( aSetBox, *pSetBoxFormat );
2730 pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr);
2732 break;
2734 case FN_UNO_TABLE_COLUMN_SEPARATORS:
2736 UnoActionContext aContext(pFormat->GetDoc());
2737 SwTable* pTable = SwTable::FindTable( pFormat );
2738 lcl_SetTableSeparators(aValue, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false, pFormat->GetDoc());
2740 break;
2742 case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:/*_readonly_*/ break;
2744 case FN_UNO_TABLE_TEMPLATE_NAME:
2746 SwTable* pTable = SwTable::FindTable(pFormat);
2747 OUString sName;
2748 if (!(aValue >>= sName))
2749 break;
2750 pTable->SetTableStyleName(sName);
2751 SwDoc* pDoc = pFormat->GetDoc();
2752 pDoc->GetDocShell()->GetFEShell()->UpdateTableStyleFormatting(pTable->GetTableNode());
2754 break;
2756 default:
2758 SwAttrSet aSet(pFormat->GetAttrSet());
2759 m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aSet);
2760 pFormat->GetDoc()->SetAttr(aSet, *pFormat);
2765 else if (m_pImpl->IsDescriptor())
2767 m_pImpl->m_pTableProps->SetProperty(pEntry->nWID, pEntry->nMemberId, aValue);
2769 else
2770 throw uno::RuntimeException();
2773 uno::Any SwXTextTable::getPropertyValue(const OUString& rPropertyName)
2775 SolarMutexGuard aGuard;
2776 uno::Any aRet;
2777 SwFrameFormat* pFormat = GetFrameFormat();
2778 const SfxItemPropertySimpleEntry* pEntry =
2779 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
2781 if (!pEntry)
2782 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
2784 if(pFormat)
2786 if(0xBF == pEntry->nMemberId)
2788 aRet = lcl_GetSpecialProperty(pFormat, pEntry );
2790 else
2792 switch(pEntry->nWID)
2794 case FN_UNO_TABLE_NAME:
2796 aRet <<= getName();
2798 break;
2800 case FN_UNO_ANCHOR_TYPES:
2801 case FN_UNO_TEXT_WRAP:
2802 case FN_UNO_ANCHOR_TYPE:
2803 ::sw::GetDefaultTextContentValue(
2804 aRet, OUString(), pEntry->nWID);
2805 break;
2807 case FN_UNO_RANGE_ROW_LABEL:
2809 aRet <<= m_pImpl->m_bFirstRowAsLabel;
2811 break;
2813 case FN_UNO_RANGE_COL_LABEL:
2814 aRet <<= m_pImpl->m_bFirstColumnAsLabel;
2815 break;
2817 case FN_UNO_TABLE_BORDER:
2818 case FN_UNO_TABLE_BORDER2:
2820 SwDoc* pDoc = pFormat->GetDoc();
2821 // tables without layout (invisible header/footer?)
2822 if(!lcl_FormatTable(pFormat))
2823 break;
2824 SwTable* pTable = SwTable::FindTable( pFormat );
2825 SwTableLines &rLines = pTable->GetTabLines();
2827 const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true);
2828 const SwStartNode* pSttNd = pTLBox->GetSttNd();
2829 SwPosition aPos(*pSttNd);
2830 // set cursor to top left cell
2831 auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true));
2832 pUnoCursor->Move( fnMoveForward, GoInNode );
2833 pUnoCursor->SetRemainInSection( false );
2835 const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false);
2836 pUnoCursor->SetMark();
2837 const SwStartNode* pLastNd = pBRBox->GetSttNd();
2838 pUnoCursor->GetPoint()->nNode = *pLastNd;
2840 pUnoCursor->Move( fnMoveForward, GoInNode );
2841 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
2842 // HACK: remove pending actions for selecting old style tables
2843 UnoActionRemoveContext aRemoveContext(rCursor);
2844 rCursor.MakeBoxSels();
2846 SfxItemSet aSet(pDoc->GetAttrPool(),
2847 svl::Items<RES_BOX, RES_BOX,
2848 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>{});
2849 aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER ));
2850 SwDoc::GetTabBorders(rCursor, aSet);
2851 const SvxBoxInfoItem& rBoxInfoItem = aSet.Get(SID_ATTR_BORDER_INNER);
2852 const SvxBoxItem& rBox = aSet.Get(RES_BOX);
2854 if (FN_UNO_TABLE_BORDER == pEntry->nWID)
2856 table::TableBorder aTableBorder;
2857 aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true);
2858 aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
2859 aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true);
2860 aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
2861 aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true);
2862 aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
2863 aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true);
2864 aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
2865 aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true);
2866 aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
2867 aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true);
2868 aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
2869 aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance());
2870 aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
2871 aRet <<= aTableBorder;
2873 else
2875 table::TableBorder2 aTableBorder;
2876 aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true);
2877 aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
2878 aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true);
2879 aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
2880 aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true);
2881 aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
2882 aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true);
2883 aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
2884 aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true);
2885 aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
2886 aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true);
2887 aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
2888 aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance());
2889 aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
2890 aRet <<= aTableBorder;
2893 break;
2895 case FN_UNO_TABLE_BORDER_DISTANCES :
2897 table::TableBorderDistances aTableBorderDistances( 0, true, 0, true, 0, true, 0, true ) ;
2898 SwTable* pTable = SwTable::FindTable( pFormat );
2899 const SwTableLines &rLines = pTable->GetTabLines();
2900 bool bFirst = true;
2901 sal_uInt16 nLeftDistance = 0;
2902 sal_uInt16 nRightDistance = 0;
2903 sal_uInt16 nTopDistance = 0;
2904 sal_uInt16 nBottomDistance = 0;
2906 for(size_t i = 0; i < rLines.size(); ++i)
2908 const SwTableLine* pLine = rLines[i];
2909 const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2910 for(size_t k = 0; k < rBoxes.size(); ++k)
2912 const SwTableBox* pBox = rBoxes[k];
2913 SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
2914 const SvxBoxItem& rBox = pBoxFormat->GetBox();
2915 if( bFirst )
2917 nLeftDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT ));
2918 nRightDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT ));
2919 nTopDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP ));
2920 nBottomDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM ));
2921 bFirst = false;
2923 else
2925 if( aTableBorderDistances.IsLeftDistanceValid &&
2926 nLeftDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT )))
2927 aTableBorderDistances.IsLeftDistanceValid = false;
2928 if( aTableBorderDistances.IsRightDistanceValid &&
2929 nRightDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT )))
2930 aTableBorderDistances.IsRightDistanceValid = false;
2931 if( aTableBorderDistances.IsTopDistanceValid &&
2932 nTopDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP )))
2933 aTableBorderDistances.IsTopDistanceValid = false;
2934 if( aTableBorderDistances.IsBottomDistanceValid &&
2935 nBottomDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM )))
2936 aTableBorderDistances.IsBottomDistanceValid = false;
2940 if( !aTableBorderDistances.IsLeftDistanceValid &&
2941 !aTableBorderDistances.IsRightDistanceValid &&
2942 !aTableBorderDistances.IsTopDistanceValid &&
2943 !aTableBorderDistances.IsBottomDistanceValid )
2944 break;
2946 if( aTableBorderDistances.IsLeftDistanceValid)
2947 aTableBorderDistances.LeftDistance = nLeftDistance;
2948 if( aTableBorderDistances.IsRightDistanceValid)
2949 aTableBorderDistances.RightDistance = nRightDistance;
2950 if( aTableBorderDistances.IsTopDistanceValid)
2951 aTableBorderDistances.TopDistance = nTopDistance;
2952 if( aTableBorderDistances.IsBottomDistanceValid)
2953 aTableBorderDistances.BottomDistance = nBottomDistance;
2955 aRet <<= aTableBorderDistances;
2957 break;
2959 case FN_UNO_TABLE_COLUMN_SEPARATORS:
2961 SwTable* pTable = SwTable::FindTable( pFormat );
2962 lcl_GetTableSeparators(aRet, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false);
2964 break;
2966 case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:
2967 aRet <<= sal_Int16(UNO_TABLE_COLUMN_SUM);
2968 break;
2970 case RES_ANCHOR:
2971 // AnchorType is readonly and might be void (no return value)
2972 break;
2974 case FN_UNO_TEXT_SECTION:
2976 SwTable* pTable = SwTable::FindTable( pFormat );
2977 SwTableNode* pTableNode = pTable->GetTableNode();
2978 SwSectionNode* pSectionNode = pTableNode->FindSectionNode();
2979 if(pSectionNode)
2981 SwSection& rSect = pSectionNode->GetSection();
2982 uno::Reference< text::XTextSection > xSect =
2983 SwXTextSections::GetObject( *rSect.GetFormat() );
2984 aRet <<= xSect;
2987 break;
2989 case FN_UNO_TABLE_TEMPLATE_NAME:
2991 SwTable* pTable = SwTable::FindTable(pFormat);
2992 aRet <<= pTable->GetTableStyleName();
2994 break;
2996 default:
2998 const SwAttrSet& rSet = pFormat->GetAttrSet();
2999 m_pImpl->m_pPropSet->getPropertyValue(*pEntry, rSet, aRet);
3004 else if (m_pImpl->IsDescriptor())
3006 const uno::Any* pAny = nullptr;
3007 if (!m_pImpl->m_pTableProps->GetProperty(pEntry->nWID, pEntry->nMemberId, pAny))
3008 throw lang::IllegalArgumentException();
3009 else if(pAny)
3010 aRet = *pAny;
3012 else
3013 throw uno::RuntimeException();
3014 return aRet;
3017 void SwXTextTable::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
3018 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3020 void SwXTextTable::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
3021 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3023 void SwXTextTable::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
3024 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3026 void SwXTextTable::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
3027 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3029 OUString SwXTextTable::getName()
3031 SolarMutexGuard aGuard;
3032 SwFrameFormat* pFormat = GetFrameFormat();
3033 if (!pFormat && !m_pImpl->IsDescriptor())
3034 throw uno::RuntimeException();
3035 if(pFormat)
3037 return pFormat->GetName();
3039 return m_pImpl->m_sTableName;
3042 void SwXTextTable::setName(const OUString& rName)
3044 SolarMutexGuard aGuard;
3045 SwFrameFormat* pFormat = GetFrameFormat();
3046 if ((!pFormat && !m_pImpl->IsDescriptor()) ||
3047 rName.isEmpty() ||
3048 rName.indexOf('.')>=0 ||
3049 rName.indexOf(' ')>=0 )
3050 throw uno::RuntimeException();
3052 if(pFormat)
3054 const OUString aOldName( pFormat->GetName() );
3055 const SwFrameFormats* pFrameFormats = pFormat->GetDoc()->GetTableFrameFormats();
3056 for (size_t i = pFrameFormats->size(); i;)
3058 const SwFrameFormat* pTmpFormat = (*pFrameFormats)[--i];
3059 if( !pTmpFormat->IsDefault() &&
3060 pTmpFormat->GetName() == rName &&
3061 pFormat->GetDoc()->IsUsed( *pTmpFormat ))
3063 throw uno::RuntimeException();
3067 pFormat->SetName( rName );
3069 SwStartNode *pStNd;
3070 SwNodeIndex aIdx( *pFormat->GetDoc()->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
3071 while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
3073 ++aIdx;
3074 SwNode *const pNd = & aIdx.GetNode();
3075 if ( pNd->IsOLENode() &&
3076 aOldName == static_cast<const SwOLENode*>(pNd)->GetChartTableName() )
3078 static_cast<SwOLENode*>(pNd)->SetChartTableName( rName );
3080 SwTable* pTable = SwTable::FindTable( pFormat );
3081 //TL_CHART2: chart needs to be notfied about name changes
3082 pFormat->GetDoc()->UpdateCharts( pTable->GetFrameFormat()->GetName() );
3084 aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
3086 pFormat->GetDoc()->getIDocumentState().SetModified();
3088 else
3089 m_pImpl->m_sTableName = rName;
3092 sal_uInt16 SwXTextTable::Impl::GetRowCount()
3094 sal_uInt16 nRet = 0;
3095 SwFrameFormat* pFormat = GetFrameFormat();
3096 if(pFormat)
3098 SwTable* pTable = SwTable::FindTable( pFormat );
3099 if(!pTable->IsTableComplex())
3101 nRet = pTable->GetTabLines().size();
3104 return nRet;
3107 sal_uInt16 SwXTextTable::Impl::GetColumnCount()
3109 SwFrameFormat* pFormat = GetFrameFormat();
3110 sal_uInt16 nRet = 0;
3111 if(pFormat)
3113 SwTable* pTable = SwTable::FindTable( pFormat );
3114 if(!pTable->IsTableComplex())
3116 SwTableLines& rLines = pTable->GetTabLines();
3117 SwTableLine* pLine = rLines.front();
3118 nRet = pLine->GetTabBoxes().size();
3121 return nRet;
3124 void SwXTextTable::Impl::Notify(const SfxHint& rHint)
3126 if(rHint.GetId() == SfxHintId::Dying)
3128 m_pFrameFormat = nullptr;
3129 EndListeningAll();
3131 uno::Reference<uno::XInterface> const xThis(m_wThis);
3132 if (xThis.is())
3133 { // fdo#72695: if UNO object is already dead, don't revive it with event
3134 if(!m_pFrameFormat)
3136 lang::EventObject const ev(xThis);
3137 m_Listeners.disposeAndClear(ev);
3139 else
3141 lcl_SendChartEvent(xThis.get(), m_Listeners);
3146 OUString SAL_CALL SwXTextTable::getImplementationName()
3147 { return "SwXTextTable"; }
3149 sal_Bool SwXTextTable::supportsService(const OUString& rServiceName)
3150 { return cppu::supportsService(this, rServiceName); }
3152 uno::Sequence<OUString> SwXTextTable::getSupportedServiceNames()
3154 return {
3155 "com.sun.star.document.LinkTarget",
3156 "com.sun.star.text.TextTable",
3157 "com.sun.star.text.TextContent",
3158 "com.sun.star.text.TextSortable" };
3162 class SwXCellRange::Impl
3163 : public SvtListener
3165 private:
3166 ::osl::Mutex m_Mutex; // just for OInterfaceContainerHelper2
3167 SwFrameFormat* m_pFrameFormat;
3169 public:
3170 uno::WeakReference<uno::XInterface> m_wThis;
3171 ::comphelper::OInterfaceContainerHelper2 m_ChartListeners;
3173 sw::UnoCursorPointer m_pTableCursor;
3175 SwRangeDescriptor m_RangeDescriptor;
3176 const SfxItemPropertySet* m_pPropSet;
3178 bool m_bFirstRowAsLabel;
3179 bool m_bFirstColumnAsLabel;
3181 Impl(sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat, SwRangeDescriptor const& rDesc)
3182 : m_pFrameFormat(&rFrameFormat)
3183 , m_ChartListeners(m_Mutex)
3184 , m_pTableCursor(pCursor)
3185 , m_RangeDescriptor(rDesc)
3186 , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_RANGE))
3187 , m_bFirstRowAsLabel(false)
3188 , m_bFirstColumnAsLabel(false)
3190 StartListening(rFrameFormat.GetNotifier());
3191 m_RangeDescriptor.Normalize();
3194 SwFrameFormat* GetFrameFormat()
3196 return m_pFrameFormat;
3199 std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32> GetLabelCoordinates(bool bRow);
3201 uno::Sequence<OUString> GetLabelDescriptions(SwXCellRange & rThis, bool bRow);
3203 void SetLabelDescriptions(SwXCellRange & rThis,
3204 const css::uno::Sequence<OUString>& rDesc, bool bRow);
3206 sal_Int32 GetRowCount();
3207 sal_Int32 GetColumnCount();
3209 virtual void Notify(const SfxHint& ) override;
3213 namespace
3215 class theSwXCellRangeUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXCellRangeUnoTunnelId > {};
3218 const uno::Sequence< sal_Int8 > & SwXCellRange::getUnoTunnelId()
3220 return theSwXCellRangeUnoTunnelId::get().getSeq();
3223 sal_Int64 SAL_CALL SwXCellRange::getSomething( const uno::Sequence< sal_Int8 >& rId )
3225 if( rId.getLength() == 16
3226 && 0 == memcmp( getUnoTunnelId().getConstArray(),
3227 rId.getConstArray(), 16 ) )
3229 return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >(this) );
3231 return 0;
3235 OUString SwXCellRange::getImplementationName()
3236 { return "SwXCellRange"; }
3238 sal_Bool SwXCellRange::supportsService(const OUString& rServiceName)
3239 { return cppu::supportsService(this, rServiceName); }
3241 uno::Sequence<OUString> SwXCellRange::getSupportedServiceNames()
3243 return {
3244 "com.sun.star.text.CellRange",
3245 "com.sun.star.style.CharacterProperties",
3246 "com.sun.star.style.CharacterPropertiesAsian",
3247 "com.sun.star.style.CharacterPropertiesComplex",
3248 "com.sun.star.style.ParagraphProperties",
3249 "com.sun.star.style.ParagraphPropertiesAsian",
3250 "com.sun.star.style.ParagraphPropertiesComplex" };
3253 SwXCellRange::SwXCellRange(sw::UnoCursorPointer const& pCursor,
3254 SwFrameFormat& rFrameFormat, SwRangeDescriptor const & rDesc)
3255 : m_pImpl(new Impl(pCursor, rFrameFormat, rDesc))
3259 SwXCellRange::~SwXCellRange()
3263 rtl::Reference<SwXCellRange> SwXCellRange::CreateXCellRange(
3264 sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat,
3265 SwRangeDescriptor const & rDesc)
3267 SwXCellRange *const pCellRange(new SwXCellRange(pCursor, rFrameFormat, rDesc));
3268 uno::Reference<table::XCellRange> xCellRange(pCellRange);
3269 // need a permanent Reference to initialize m_wThis
3270 pCellRange->m_pImpl->m_wThis = xCellRange;
3271 return pCellRange;
3274 void SwXCellRange::SetLabels(bool bFirstRowAsLabel, bool bFirstColumnAsLabel)
3276 m_pImpl->m_bFirstRowAsLabel = bFirstRowAsLabel;
3277 m_pImpl->m_bFirstColumnAsLabel = bFirstColumnAsLabel;
3280 std::vector< uno::Reference< table::XCell > > SwXCellRange::GetCells()
3282 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3283 const sal_Int32 nRowCount(m_pImpl->GetRowCount());
3284 const sal_Int32 nColCount(m_pImpl->GetColumnCount());
3285 std::vector< uno::Reference< table::XCell > > vResult;
3286 vResult.reserve(static_cast<size_t>(nRowCount)*static_cast<size_t>(nColCount));
3287 for(sal_Int32 nRow = 0; nRow < nRowCount; ++nRow)
3288 for(sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
3289 vResult.emplace_back(lcl_CreateXCell(pFormat, m_pImpl->m_RangeDescriptor.nLeft + nCol, m_pImpl->m_RangeDescriptor.nTop + nRow));
3290 return vResult;
3293 uno::Reference<table::XCell> SAL_CALL
3294 SwXCellRange::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow)
3296 SolarMutexGuard aGuard;
3297 uno::Reference< table::XCell > aRet;
3298 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3299 if(pFormat)
3301 if(nColumn >= 0 && nRow >= 0 &&
3302 m_pImpl->GetColumnCount() > nColumn && m_pImpl->GetRowCount() > nRow )
3304 SwXCell* pXCell = lcl_CreateXCell(pFormat,
3305 m_pImpl->m_RangeDescriptor.nLeft + nColumn,
3306 m_pImpl->m_RangeDescriptor.nTop + nRow);
3307 if(pXCell)
3308 aRet = pXCell;
3311 if(!aRet.is())
3312 throw lang::IndexOutOfBoundsException();
3313 return aRet;
3316 uno::Reference<table::XCellRange> SAL_CALL
3317 SwXCellRange::getCellRangeByPosition(
3318 sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom)
3320 SolarMutexGuard aGuard;
3321 uno::Reference< table::XCellRange > aRet;
3322 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3323 if (pFormat && m_pImpl->GetColumnCount() > nRight
3324 && m_pImpl->GetRowCount() > nBottom &&
3325 nLeft <= nRight && nTop <= nBottom
3326 && nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 )
3328 SwTable* pTable = SwTable::FindTable( pFormat );
3329 if(!pTable->IsTableComplex())
3331 SwRangeDescriptor aNewDesc;
3332 aNewDesc.nTop = nTop + m_pImpl->m_RangeDescriptor.nTop;
3333 aNewDesc.nBottom = nBottom + m_pImpl->m_RangeDescriptor.nTop;
3334 aNewDesc.nLeft = nLeft + m_pImpl->m_RangeDescriptor.nLeft;
3335 aNewDesc.nRight = nRight + m_pImpl->m_RangeDescriptor.nLeft;
3336 aNewDesc.Normalize();
3337 const OUString sTLName = sw_GetCellName(aNewDesc.nLeft, aNewDesc.nTop);
3338 const OUString sBRName = sw_GetCellName(aNewDesc.nRight, aNewDesc.nBottom);
3339 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
3340 if(pTLBox)
3342 const SwStartNode* pSttNd = pTLBox->GetSttNd();
3343 SwPosition aPos(*pSttNd);
3344 // set cursor in the upper-left cell of the range
3345 auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true));
3346 pUnoCursor->Move( fnMoveForward, GoInNode );
3347 pUnoCursor->SetRemainInSection( false );
3348 const SwTableBox* pBRBox = pTable->GetTableBox( sBRName );
3349 if(pBRBox)
3351 pUnoCursor->SetMark();
3352 pUnoCursor->GetPoint()->nNode = *pBRBox->GetSttNd();
3353 pUnoCursor->Move( fnMoveForward, GoInNode );
3354 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
3355 // HACK: remove pending actions for selecting old style tables
3356 UnoActionRemoveContext aRemoveContext(rCursor);
3357 rCursor.MakeBoxSels();
3358 // pUnoCursor will be provided and will not be deleted
3359 aRet = SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, aNewDesc).get();
3364 if(!aRet.is())
3365 throw lang::IndexOutOfBoundsException();
3366 return aRet;
3369 uno::Reference<table::XCellRange> SAL_CALL
3370 SwXCellRange::getCellRangeByName(const OUString& rRange)
3372 SolarMutexGuard aGuard;
3373 sal_Int32 nPos = 0;
3374 const OUString sTLName(rRange.getToken(0, ':', nPos));
3375 const OUString sBRName(rRange.getToken(0, ':', nPos));
3376 if(sTLName.isEmpty() || sBRName.isEmpty())
3377 throw uno::RuntimeException();
3378 SwRangeDescriptor aDesc;
3379 aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1;
3380 SwXTextTable::GetCellPosition( sTLName, aDesc.nLeft, aDesc.nTop );
3381 SwXTextTable::GetCellPosition( sBRName, aDesc.nRight, aDesc.nBottom );
3382 aDesc.Normalize();
3383 return getCellRangeByPosition(
3384 aDesc.nLeft - m_pImpl->m_RangeDescriptor.nLeft,
3385 aDesc.nTop - m_pImpl->m_RangeDescriptor.nTop,
3386 aDesc.nRight - m_pImpl->m_RangeDescriptor.nLeft,
3387 aDesc.nBottom - m_pImpl->m_RangeDescriptor.nTop);
3390 uno::Reference< beans::XPropertySetInfo > SwXCellRange::getPropertySetInfo()
3392 static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo();
3393 return xRef;
3396 void SAL_CALL
3397 SwXCellRange::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
3399 SolarMutexGuard aGuard;
3400 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3401 if(pFormat)
3403 const SfxItemPropertySimpleEntry *const pEntry =
3404 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
3405 if(!pEntry)
3406 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
3408 if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
3409 throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
3411 SwDoc *const pDoc = m_pImpl->m_pTableCursor->GetDoc();
3412 SwUnoTableCursor& rCursor(dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor));
3414 // HACK: remove pending actions for selecting old style tables
3415 UnoActionRemoveContext aRemoveContext(rCursor);
3417 rCursor.MakeBoxSels();
3418 switch(pEntry->nWID )
3420 case FN_UNO_TABLE_CELL_BACKGROUND:
3422 std::shared_ptr<SfxPoolItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND));
3423 SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush);
3424 aBrush->PutValue(aValue, pEntry->nMemberId);
3425 pDoc->SetBoxAttr(*m_pImpl->m_pTableCursor, *aBrush);
3428 break;
3429 case RES_BOX :
3431 SfxItemSet aSet(pDoc->GetAttrPool(),
3432 svl::Items<RES_BOX, RES_BOX,
3433 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>{});
3434 SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
3435 aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::ALL, false);
3436 SvxBoxInfoItemValidFlags nValid = SvxBoxInfoItemValidFlags::NONE;
3437 switch(pEntry->nMemberId & ~CONVERT_TWIPS)
3439 case LEFT_BORDER : nValid = SvxBoxInfoItemValidFlags::LEFT; break;
3440 case RIGHT_BORDER: nValid = SvxBoxInfoItemValidFlags::RIGHT; break;
3441 case TOP_BORDER : nValid = SvxBoxInfoItemValidFlags::TOP; break;
3442 case BOTTOM_BORDER: nValid = SvxBoxInfoItemValidFlags::BOTTOM; break;
3443 case LEFT_BORDER_DISTANCE :
3444 case RIGHT_BORDER_DISTANCE:
3445 case TOP_BORDER_DISTANCE :
3446 case BOTTOM_BORDER_DISTANCE:
3447 nValid = SvxBoxInfoItemValidFlags::DISTANCE;
3448 break;
3450 aBoxInfo.SetValid(nValid);
3452 aSet.Put(aBoxInfo);
3453 SwDoc::GetTabBorders(rCursor, aSet);
3455 aSet.Put(aBoxInfo);
3456 SvxBoxItem aBoxItem(aSet.Get(RES_BOX));
3457 static_cast<SfxPoolItem&>(aBoxItem).PutValue(aValue, pEntry->nMemberId);
3458 aSet.Put(aBoxItem);
3459 pDoc->SetTabBorders(*m_pImpl->m_pTableCursor, aSet);
3461 break;
3462 case RES_BOXATR_FORMAT:
3464 SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT);
3465 static_cast<SfxPoolItem&>(aNumberFormat).PutValue(aValue, 0);
3466 pDoc->SetBoxAttr(rCursor, aNumberFormat);
3468 break;
3469 case FN_UNO_RANGE_ROW_LABEL:
3471 bool bTmp = *o3tl::doAccess<bool>(aValue);
3472 if (m_pImpl->m_bFirstRowAsLabel != bTmp)
3474 lcl_SendChartEvent(*this, m_pImpl->m_ChartListeners);
3475 m_pImpl->m_bFirstRowAsLabel = bTmp;
3478 break;
3479 case FN_UNO_RANGE_COL_LABEL:
3481 bool bTmp = *o3tl::doAccess<bool>(aValue);
3482 if (m_pImpl->m_bFirstColumnAsLabel != bTmp)
3484 lcl_SendChartEvent(*this, m_pImpl->m_ChartListeners);
3485 m_pImpl->m_bFirstColumnAsLabel = bTmp;
3488 break;
3489 case RES_VERT_ORIENT:
3491 sal_Int16 nAlign = -1;
3492 aValue >>= nAlign;
3493 if( nAlign >= text::VertOrientation::NONE && nAlign <= text::VertOrientation::BOTTOM)
3494 pDoc->SetBoxAlign( rCursor, nAlign );
3496 break;
3497 default:
3499 SfxItemSet aItemSet( pDoc->GetAttrPool(), {{pEntry->nWID, pEntry->nWID}} );
3500 SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(),
3501 aItemSet);
3503 if (!SwUnoCursorHelper::SetCursorPropertyValue(
3504 *pEntry, aValue, rCursor.GetSelRing(), aItemSet))
3506 m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet);
3508 SwUnoCursorHelper::SetCursorAttr(rCursor.GetSelRing(),
3509 aItemSet, SetAttrMode::DEFAULT, true);
3516 uno::Any SAL_CALL SwXCellRange::getPropertyValue(const OUString& rPropertyName)
3518 SolarMutexGuard aGuard;
3519 uno::Any aRet;
3520 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3521 if(pFormat)
3523 const SfxItemPropertySimpleEntry *const pEntry =
3524 m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
3525 if(!pEntry)
3526 throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, static_cast < cppu::OWeakObject * > ( this ) );
3528 switch(pEntry->nWID )
3530 case FN_UNO_TABLE_CELL_BACKGROUND:
3532 std::shared_ptr<SfxPoolItem> aBrush(std::make_shared<SvxBrushItem>(RES_BACKGROUND));
3533 if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush))
3534 aBrush->QueryValue(aRet, pEntry->nMemberId);
3537 break;
3538 case RES_BOX :
3540 SwDoc *const pDoc = m_pImpl->m_pTableCursor->GetDoc();
3541 SfxItemSet aSet(pDoc->GetAttrPool(),
3542 svl::Items<RES_BOX, RES_BOX,
3543 SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>{});
3544 aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER ));
3545 SwDoc::GetTabBorders(*m_pImpl->m_pTableCursor, aSet);
3546 const SvxBoxItem& rBoxItem = aSet.Get(RES_BOX);
3547 rBoxItem.QueryValue(aRet, pEntry->nMemberId);
3549 break;
3550 case RES_BOXATR_FORMAT:
3551 OSL_FAIL("not implemented");
3552 break;
3553 case FN_UNO_PARA_STYLE:
3555 SwFormatColl *const pTmpFormat =
3556 SwUnoCursorHelper::GetCurTextFormatColl(*m_pImpl->m_pTableCursor, false);
3557 OUString sRet;
3558 if (pTmpFormat)
3559 sRet = pTmpFormat->GetName();
3560 aRet <<= sRet;
3562 break;
3563 case FN_UNO_RANGE_ROW_LABEL:
3564 aRet <<= m_pImpl->m_bFirstRowAsLabel;
3565 break;
3566 case FN_UNO_RANGE_COL_LABEL:
3567 aRet <<= m_pImpl->m_bFirstColumnAsLabel;
3568 break;
3569 case RES_VERT_ORIENT:
3571 std::shared_ptr<SfxPoolItem> aVertOrient;
3572 if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aVertOrient))
3574 aVertOrient->QueryValue( aRet, pEntry->nMemberId );
3577 break;
3578 default:
3580 SfxItemSet aSet(
3581 m_pImpl->m_pTableCursor->GetDoc()->GetAttrPool(),
3582 svl::Items<
3583 RES_CHRATR_BEGIN, RES_FRMATR_END - 1,
3584 RES_UNKNOWNATR_CONTAINER,
3585 RES_UNKNOWNATR_CONTAINER>{});
3586 // first look at the attributes of the cursor
3587 SwUnoTableCursor *const pCursor =
3588 dynamic_cast<SwUnoTableCursor*>(&(*m_pImpl->m_pTableCursor));
3589 SwUnoCursorHelper::GetCursorAttr(pCursor->GetSelRing(), aSet);
3590 m_pImpl->m_pPropSet->getPropertyValue(*pEntry, aSet, aRet);
3595 return aRet;
3598 void SwXCellRange::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
3599 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3601 void SwXCellRange::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
3602 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3604 void SwXCellRange::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
3605 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3607 void SwXCellRange::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
3608 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3610 ///@see SwXCellRange::getData
3611 uno::Sequence<uno::Sequence<uno::Any>> SAL_CALL SwXCellRange::getDataArray()
3613 SolarMutexGuard aGuard;
3614 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3615 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3616 if(!nRowCount || !nColCount)
3617 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3618 lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
3619 uno::Sequence< uno::Sequence< uno::Any > > aRowSeq(nRowCount);
3620 auto vCells(GetCells());
3621 auto pCurrentCell(vCells.begin());
3622 for(auto& rRow : aRowSeq)
3624 rRow = uno::Sequence< uno::Any >(nColCount);
3625 for(auto& rCellAny : rRow)
3627 auto pCell(static_cast<SwXCell*>(pCurrentCell->get()));
3628 if(!pCell)
3629 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3630 rCellAny = pCell->GetAny();
3631 ++pCurrentCell;
3634 return aRowSeq;
3637 ///@see SwXCellRange::setData
3638 void SAL_CALL SwXCellRange::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray)
3640 SolarMutexGuard aGuard;
3641 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3642 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3643 if(!nRowCount || !nColCount)
3644 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3645 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3646 if(!pFormat)
3647 return;
3648 if(rArray.getLength() != nRowCount)
3649 throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rArray.getLength()), static_cast<cppu::OWeakObject*>(this));
3650 auto vCells(GetCells());
3651 auto pCurrentCell(vCells.begin());
3652 for(const auto& rColSeq : rArray)
3654 if(rColSeq.getLength() != nColCount)
3655 throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rColSeq.getLength()), static_cast<cppu::OWeakObject*>(this));
3656 for(const auto& aValue : rColSeq)
3658 auto pCell(static_cast<SwXCell*>(pCurrentCell->get()));
3659 if(!pCell || !pCell->GetTableBox())
3660 throw uno::RuntimeException("Box for cell missing", static_cast<cppu::OWeakObject*>(this));
3661 if(aValue.isExtractableTo(cppu::UnoType<OUString>::get()))
3662 sw_setString(*pCell, aValue.get<OUString>());
3663 else if(aValue.isExtractableTo(cppu::UnoType<double>::get()))
3664 sw_setValue(*pCell, aValue.get<double>());
3665 else
3666 sw_setString(*pCell, OUString(), true);
3667 ++pCurrentCell;
3672 uno::Sequence<uno::Sequence<double>> SAL_CALL
3673 SwXCellRange::getData()
3675 SolarMutexGuard aGuard;
3676 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3677 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3678 if(!nRowCount || !nColCount)
3679 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3680 if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel)
3682 uno::Reference<chart::XChartDataArray> const xDataRange(
3683 getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0,
3684 (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0,
3685 nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW);
3686 return xDataRange->getData();
3688 uno::Sequence< uno::Sequence< double > > vRows(nRowCount);
3689 auto vCells(GetCells());
3690 auto pCurrentCell(vCells.begin());
3691 for(auto& rRow : vRows)
3693 rRow = uno::Sequence<double>(nColCount);
3694 for(auto& rValue : rRow)
3696 if(!(*pCurrentCell))
3697 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3698 rValue = (*pCurrentCell)->getValue();
3699 ++pCurrentCell;
3702 return vRows;
3705 void SAL_CALL
3706 SwXCellRange::setData(const uno::Sequence< uno::Sequence<double> >& rData)
3708 SolarMutexGuard aGuard;
3709 const sal_Int32 nRowCount = m_pImpl->GetRowCount();
3710 const sal_Int32 nColCount = m_pImpl->GetColumnCount();
3711 if(!nRowCount || !nColCount)
3712 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
3713 if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel)
3715 uno::Reference<chart::XChartDataArray> const xDataRange(
3716 getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0,
3717 (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0,
3718 nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW);
3719 return xDataRange->setData(rData);
3721 lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
3722 if(rData.getLength() != nRowCount)
3723 throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rData.getLength()), static_cast<cppu::OWeakObject*>(this));
3724 auto vCells(GetCells());
3725 auto pCurrentCell(vCells.begin());
3726 for(const auto& rRow : rData)
3728 if(rRow.getLength() != nColCount)
3729 throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rRow.getLength()), static_cast<cppu::OWeakObject*>(this));
3730 for(const auto& rValue : rRow)
3732 uno::Reference<table::XCell>(*pCurrentCell, uno::UNO_SET_THROW)->setValue(rValue);
3733 ++pCurrentCell;
3738 std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32>
3739 SwXCellRange::Impl::GetLabelCoordinates(bool bRow)
3741 sal_uInt32 nLeft, nTop, nRight, nBottom;
3742 nLeft = nTop = nRight = nBottom = 0;
3743 if(bRow)
3745 nTop = m_bFirstRowAsLabel ? 1 : 0;
3746 nBottom = GetRowCount() - 1;
3748 else
3750 nLeft = m_bFirstColumnAsLabel ? 1 : 0;
3751 nRight = GetColumnCount() - 1;
3753 return std::make_tuple(nLeft, nTop, nRight, nBottom);
3756 uno::Sequence<OUString>
3757 SwXCellRange::Impl::GetLabelDescriptions(SwXCellRange & rThis, bool bRow)
3759 SolarMutexGuard aGuard;
3760 sal_uInt32 nLeft, nTop, nRight, nBottom;
3761 std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow);
3762 if(!nRight && !nBottom)
3763 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(&rThis));
3764 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(&rThis));
3765 if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel))
3766 return {}; // without labels we have no descriptions
3767 auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom));
3768 auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells());
3769 uno::Sequence<OUString> vResult(vCells.size());
3770 std::transform(vCells.begin(), vCells.end(), vResult.begin(),
3771 [](uno::Reference<table::XCell> xCell) -> OUString { return uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->getString(); });
3772 return vResult;
3775 uno::Sequence<OUString> SAL_CALL SwXCellRange::getRowDescriptions()
3777 return m_pImpl->GetLabelDescriptions(*this, true);
3780 uno::Sequence<OUString> SAL_CALL SwXCellRange::getColumnDescriptions()
3782 return m_pImpl->GetLabelDescriptions(*this, false);
3785 void SwXCellRange::Impl::SetLabelDescriptions(SwXCellRange & rThis,
3786 const uno::Sequence<OUString>& rDesc, bool bRow)
3788 SolarMutexGuard aGuard;
3789 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(&rThis));
3790 if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel))
3791 return; // if there are no labels we cannot set descriptions
3792 sal_uInt32 nLeft, nTop, nRight, nBottom;
3793 std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow);
3794 if(!nRight && !nBottom)
3795 throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(&rThis));
3796 auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom));
3797 if (!xLabelRange.is())
3798 throw uno::RuntimeException("Missing Cell Range", static_cast<cppu::OWeakObject*>(&rThis));
3799 auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells());
3800 if (sal::static_int_cast<sal_uInt32>(rDesc.getLength()) != vCells.size())
3801 throw uno::RuntimeException("Too few or too many descriptions", static_cast<cppu::OWeakObject*>(&rThis));
3802 auto pDescIterator(rDesc.begin());
3803 for(auto& xCell : vCells)
3804 uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->setString(*pDescIterator++);
3807 void SAL_CALL SwXCellRange::setRowDescriptions(
3808 const uno::Sequence<OUString>& rRowDesc)
3810 m_pImpl->SetLabelDescriptions(*this, rRowDesc, true);
3813 void SAL_CALL SwXCellRange::setColumnDescriptions(
3814 const uno::Sequence<OUString>& rColumnDesc)
3816 m_pImpl->SetLabelDescriptions(*this, rColumnDesc, false);
3819 void SAL_CALL SwXCellRange::addChartDataChangeEventListener(
3820 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
3822 // no need to lock here as m_pImpl is const and container threadsafe
3823 m_pImpl->m_ChartListeners.addInterface(xListener);
3826 void SAL_CALL SwXCellRange::removeChartDataChangeEventListener(
3827 const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
3829 // no need to lock here as m_pImpl is const and container threadsafe
3830 m_pImpl->m_ChartListeners.removeInterface(xListener);
3833 sal_Bool SwXCellRange::isNotANumber(double /*fNumber*/)
3834 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3836 double SwXCellRange::getNotANumber()
3837 { throw uno::RuntimeException("Not implemented", static_cast<cppu::OWeakObject*>(this)); }
3839 uno::Sequence< beans::PropertyValue > SwXCellRange::createSortDescriptor()
3841 SolarMutexGuard aGuard;
3842 return SwUnoCursorHelper::CreateSortDescriptor(true);
3845 void SAL_CALL SwXCellRange::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
3847 SolarMutexGuard aGuard;
3848 SwSortOptions aSortOpt;
3849 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3850 if(pFormat && SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt))
3852 SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor);
3853 rTableCursor.MakeBoxSels();
3854 UnoActionContext aContext(pFormat->GetDoc());
3855 pFormat->GetDoc()->SortTable(rTableCursor.GetSelectedBoxes(), aSortOpt);
3859 sal_Int32 SwXCellRange::Impl::GetColumnCount()
3861 return m_RangeDescriptor.nRight - m_RangeDescriptor.nLeft + 1;
3864 sal_Int32 SwXCellRange::Impl::GetRowCount()
3866 return m_RangeDescriptor.nBottom - m_RangeDescriptor.nTop + 1;
3869 const SwUnoCursor* SwXCellRange::GetTableCursor() const
3871 SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
3872 return pFormat ? &(*m_pImpl->m_pTableCursor) : nullptr;
3875 void SwXCellRange::Impl::Notify( const SfxHint& rHint )
3877 uno::Reference<uno::XInterface> const xThis(m_wThis);
3878 if(rHint.GetId() == SfxHintId::Dying)
3880 m_pFrameFormat = nullptr;
3881 m_pTableCursor.reset(nullptr);
3883 if (xThis.is())
3884 { // fdo#72695: if UNO object is already dead, don't revive it with event
3885 if(m_pFrameFormat)
3886 lcl_SendChartEvent(xThis.get(), m_ChartListeners);
3887 else
3888 m_ChartListeners.disposeAndClear(lang::EventObject(xThis));
3892 class SwXTableRows::Impl : public SvtListener
3894 private:
3895 SwFrameFormat* m_pFrameFormat;
3897 public:
3898 explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat)
3900 StartListening(rFrameFormat.GetNotifier());
3902 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
3903 virtual void Notify(const SfxHint&) override;
3906 // SwXTableRows
3908 OUString SwXTableRows::getImplementationName()
3909 { return "SwXTableRows"; }
3911 sal_Bool SwXTableRows::supportsService(const OUString& rServiceName)
3912 { return cppu::supportsService(this, rServiceName); }
3914 uno::Sequence< OUString > SwXTableRows::getSupportedServiceNames()
3915 { return { "com.sun.star.text.TableRows" }; }
3918 SwXTableRows::SwXTableRows(SwFrameFormat& rFrameFormat) :
3919 m_pImpl(new SwXTableRows::Impl(rFrameFormat))
3922 SwXTableRows::~SwXTableRows()
3925 SwFrameFormat* SwXTableRows::GetFrameFormat()
3927 return m_pImpl->GetFrameFormat();
3930 sal_Int32 SwXTableRows::getCount()
3932 SolarMutexGuard aGuard;
3933 SwFrameFormat* pFrameFormat = GetFrameFormat();
3934 if(!pFrameFormat)
3935 throw uno::RuntimeException();
3936 SwTable* pTable = SwTable::FindTable(pFrameFormat);
3937 return pTable->GetTabLines().size();
3940 ///@see SwXCell::CreateXCell (TODO: seems to be copy and paste programming here)
3941 uno::Any SwXTableRows::getByIndex(sal_Int32 nIndex)
3943 SolarMutexGuard aGuard;
3944 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
3945 if(nIndex < 0)
3946 throw lang::IndexOutOfBoundsException();
3947 SwTable* pTable = SwTable::FindTable( pFrameFormat );
3948 if(static_cast<size_t>(nIndex) >= pTable->GetTabLines().size())
3949 throw lang::IndexOutOfBoundsException();
3950 SwTableLine* pLine = pTable->GetTabLines()[nIndex];
3951 FindUnoInstanceHint<SwTableLine,SwXTextTableRow> aHint{pLine};
3952 pFrameFormat->GetNotifier().Broadcast(aHint);
3953 if(!aHint.m_pResult)
3954 aHint.m_pResult = new SwXTextTableRow(pFrameFormat, pLine);
3955 uno::Reference<beans::XPropertySet> xRet = static_cast<beans::XPropertySet*>(aHint.m_pResult);
3956 return uno::makeAny(xRet);
3959 uno::Type SAL_CALL SwXTableRows::getElementType()
3961 return cppu::UnoType<beans::XPropertySet>::get();
3964 sal_Bool SwXTableRows::hasElements()
3966 SolarMutexGuard aGuard;
3967 SwFrameFormat* pFrameFormat = GetFrameFormat();
3968 if(!pFrameFormat)
3969 throw uno::RuntimeException();
3970 // a table always has rows
3971 return true;
3974 void SwXTableRows::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount)
3976 SolarMutexGuard aGuard;
3977 if (nCount == 0)
3978 return;
3979 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
3980 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this));
3981 const size_t nRowCount = pTable->GetTabLines().size();
3982 if (nCount <= 0 || !(0 <= nIndex && static_cast<size_t>(nIndex) <= nRowCount))
3983 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
3984 const OUString sTLName = sw_GetCellName(0, nIndex);
3985 const SwTableBox* pTLBox = pTable->GetTableBox(sTLName);
3986 bool bAppend = false;
3987 if(!pTLBox)
3989 bAppend = true;
3990 // to append at the end the cursor must be in the last line
3991 SwTableLines& rLines = pTable->GetTabLines();
3992 SwTableLine* pLine = rLines.back();
3993 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
3994 pTLBox = rBoxes.front();
3996 if(!pTLBox)
3997 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
3998 const SwStartNode* pSttNd = pTLBox->GetSttNd();
3999 SwPosition aPos(*pSttNd);
4000 // set cursor to the upper-left cell of the range
4001 UnoActionContext aAction(pFrameFormat->GetDoc());
4002 std::shared_ptr<SwUnoTableCursor> const pUnoCursor(
4003 std::dynamic_pointer_cast<SwUnoTableCursor>(
4004 pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)));
4005 pUnoCursor->Move( fnMoveForward, GoInNode );
4007 // remove actions - TODO: why?
4008 UnoActionRemoveContext aRemoveContext(pUnoCursor->GetDoc());
4010 pFrameFormat->GetDoc()->InsertRow(*pUnoCursor, static_cast<sal_uInt16>(nCount), bAppend);
4013 void SwXTableRows::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount)
4015 SolarMutexGuard aGuard;
4016 if (nCount == 0)
4017 return;
4018 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
4019 if(nIndex < 0 || nCount <=0 )
4020 throw uno::RuntimeException();
4021 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this));
4022 OUString sTLName = sw_GetCellName(0, nIndex);
4023 const SwTableBox* pTLBox = pTable->GetTableBox(sTLName);
4024 if(!pTLBox)
4025 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
4026 const SwStartNode* pSttNd = pTLBox->GetSttNd();
4027 SwPosition aPos(*pSttNd);
4028 // set cursor to the upper-left cell of the range
4029 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
4030 pUnoCursor->Move(fnMoveForward, GoInNode);
4031 pUnoCursor->SetRemainInSection( false );
4032 const OUString sBLName = sw_GetCellName(0, nIndex + nCount - 1);
4033 const SwTableBox* pBLBox = pTable->GetTableBox( sBLName );
4034 if(!pBLBox)
4035 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
4036 pUnoCursor->SetMark();
4037 pUnoCursor->GetPoint()->nNode = *pBLBox->GetSttNd();
4038 pUnoCursor->Move(fnMoveForward, GoInNode);
4039 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
4041 // HACK: remove pending actions for selecting old style tables
4042 UnoActionRemoveContext aRemoveContext(rCursor);
4044 rCursor.MakeBoxSels();
4045 { // these braces are important
4046 UnoActionContext aAction(pFrameFormat->GetDoc());
4047 pFrameFormat->GetDoc()->DeleteRow(*pUnoCursor);
4048 pUnoCursor.reset();
4051 // invalidate all actions - TODO: why?
4052 UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc());
4056 void SwXTableRows::Impl::Notify( const SfxHint& rHint)
4058 if(rHint.GetId() == SfxHintId::Dying)
4059 m_pFrameFormat = nullptr;
4062 // SwXTableColumns
4064 class SwXTableColumns::Impl : public SvtListener
4066 SwFrameFormat* m_pFrameFormat;
4067 public:
4068 explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat)
4070 StartListening(rFrameFormat.GetNotifier());
4072 SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
4073 virtual void Notify(const SfxHint&) override;
4076 OUString SwXTableColumns::getImplementationName()
4077 { return "SwXTableColumns"; }
4079 sal_Bool SwXTableColumns::supportsService(const OUString& rServiceName)
4080 { return cppu::supportsService(this, rServiceName); }
4082 uno::Sequence< OUString > SwXTableColumns::getSupportedServiceNames()
4083 { return { "com.sun.star.text.TableColumns"}; }
4086 SwXTableColumns::SwXTableColumns(SwFrameFormat& rFrameFormat) :
4087 m_pImpl(new SwXTableColumns::Impl(rFrameFormat))
4090 SwXTableColumns::~SwXTableColumns()
4093 SwFrameFormat* SwXTableColumns::GetFrameFormat() const
4095 return m_pImpl->GetFrameFormat();
4098 sal_Int32 SwXTableColumns::getCount()
4100 SolarMutexGuard aGuard;
4101 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
4102 SwTable* pTable = SwTable::FindTable( pFrameFormat );
4103 // if(!pTable->IsTableComplex())
4104 // throw uno::RuntimeException("Table too complex", static_cast<cppu::OWeakObject*>(this));
4105 SwTableLines& rLines = pTable->GetTabLines();
4106 SwTableLine* pLine = rLines.front();
4107 return pLine->GetTabBoxes().size();
4110 uno::Any SwXTableColumns::getByIndex(sal_Int32 nIndex)
4112 SolarMutexGuard aGuard;
4113 if(nIndex < 0 || getCount() <= nIndex)
4114 throw lang::IndexOutOfBoundsException();
4115 return uno::makeAny(uno::Reference<uno::XInterface>()); // i#21699 not supported
4118 uno::Type SAL_CALL SwXTableColumns::getElementType()
4120 return cppu::UnoType<uno::XInterface>::get();
4123 sal_Bool SwXTableColumns::hasElements()
4125 SolarMutexGuard aGuard;
4126 lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this));
4127 return true;
4130 ///@see SwXTableRows::insertByIndex (TODO: seems to be copy and paste programming here)
4131 void SwXTableColumns::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount)
4133 SolarMutexGuard aGuard;
4134 if (nCount == 0)
4135 return;
4136 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
4137 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this));
4138 SwTableLines& rLines = pTable->GetTabLines();
4139 SwTableLine* pLine = rLines.front();
4140 const size_t nColCount = pLine->GetTabBoxes().size();
4141 if (nCount <= 0 || !(0 <= nIndex && static_cast<size_t>(nIndex) <= nColCount))
4142 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
4143 const OUString sTLName = sw_GetCellName(nIndex, 0);
4144 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
4145 bool bAppend = false;
4146 if(!pTLBox)
4148 bAppend = true;
4149 // to append at the end the cursor must be in the last line
4150 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
4151 pTLBox = rBoxes.back();
4153 if(!pTLBox)
4154 throw uno::RuntimeException("Illegal arguments", static_cast<cppu::OWeakObject*>(this));
4155 const SwStartNode* pSttNd = pTLBox->GetSttNd();
4156 SwPosition aPos(*pSttNd);
4157 UnoActionContext aAction(pFrameFormat->GetDoc());
4158 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
4159 pUnoCursor->Move(fnMoveForward, GoInNode);
4162 // remove actions - TODO: why?
4163 UnoActionRemoveContext aRemoveContext(pUnoCursor->GetDoc());
4166 pFrameFormat->GetDoc()->InsertCol(*pUnoCursor, static_cast<sal_uInt16>(nCount), bAppend);
4169 ///@see SwXTableRows::removeByIndex (TODO: seems to be copy and paste programming here)
4170 void SwXTableColumns::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount)
4172 SolarMutexGuard aGuard;
4173 if (nCount == 0)
4174 return;
4175 SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), static_cast<cppu::OWeakObject*>(this)));
4176 if(nIndex < 0 || nCount <=0 )
4177 throw uno::RuntimeException();
4178 SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), static_cast<cppu::OWeakObject*>(this));
4179 const OUString sTLName = sw_GetCellName(nIndex, 0);
4180 const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
4181 if(!pTLBox)
4182 throw uno::RuntimeException("Cell not found", static_cast<cppu::OWeakObject*>(this));
4183 const SwStartNode* pSttNd = pTLBox->GetSttNd();
4184 SwPosition aPos(*pSttNd);
4185 // set cursor to the upper-left cell of the range
4186 auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
4187 pUnoCursor->Move(fnMoveForward, GoInNode);
4188 pUnoCursor->SetRemainInSection(false);
4189 const OUString sTRName = sw_GetCellName(nIndex + nCount - 1, 0);
4190 const SwTableBox* pTRBox = pTable->GetTableBox(sTRName);
4191 if(!pTRBox)
4192 throw uno::RuntimeException("Cell not found", static_cast<cppu::OWeakObject*>(this));
4193 pUnoCursor->SetMark();
4194 pUnoCursor->GetPoint()->nNode = *pTRBox->GetSttNd();
4195 pUnoCursor->Move(fnMoveForward, GoInNode);
4196 SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
4198 // HACK: remove pending actions for selecting old style tables
4199 UnoActionRemoveContext aRemoveContext(rCursor);
4201 rCursor.MakeBoxSels();
4202 { // these braces are important
4203 UnoActionContext aAction(pFrameFormat->GetDoc());
4204 pFrameFormat->GetDoc()->DeleteCol(*pUnoCursor);
4205 pUnoCursor.reset();
4208 // invalidate all actions - TODO: why?
4209 UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc());
4213 void SwXTableColumns::Impl::Notify(const SfxHint& rHint)
4215 if(rHint.GetId() == SfxHintId::Dying)
4216 m_pFrameFormat = nullptr;
4219 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */