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