summaryrefslogtreecommitdiffstats
path: root/sw/source/core/unocore/unotbl.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/unocore/unotbl.cxx
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/unocore/unotbl.cxx')
-rw-r--r--sw/source/core/unocore/unotbl.cxx4116
1 files changed, 4116 insertions, 0 deletions
diff --git a/sw/source/core/unocore/unotbl.cxx b/sw/source/core/unocore/unotbl.cxx
new file mode 100644
index 0000000000..c2f92df7f1
--- /dev/null
+++ b/sw/source/core/unocore/unotbl.cxx
@@ -0,0 +1,4116 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tuple>
+#include <utility>
+#include <memory>
+#include <vector>
+#include <algorithm>
+#include <limits>
+
+#include <comphelper/interfacecontainer4.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <tools/UnitConversion.hxx>
+#include <editeng/memberids.h>
+#include <float.h>
+#include <swtypes.hxx>
+#include <cmdid.h>
+#include <unocoll.hxx>
+#include <unomid.h>
+#include <unomap.hxx>
+#include <unotbl.hxx>
+#include <section.hxx>
+#include <unocrsr.hxx>
+#include <hints.hxx>
+#include <swtblfmt.hxx>
+#include <doc.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <IDocumentContentOperations.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentRedlineAccess.hxx>
+#include <IDocumentState.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <shellres.hxx>
+#include <docary.hxx>
+#include <ndole.hxx>
+#include <ndtxt.hxx>
+#include <frame.hxx>
+#include <vcl/svapp.hxx>
+#include <fmtfsize.hxx>
+#include <tblafmt.hxx>
+#include <tabcol.hxx>
+#include <cellatr.hxx>
+#include <fmtpdsc.hxx>
+#include <pagedesc.hxx>
+#include <viewsh.hxx>
+#include <rootfrm.hxx>
+#include <tabfrm.hxx>
+#include <redline.hxx>
+#include <unoport.hxx>
+#include <unocrsrhelper.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/TableColumnSeparator.hpp>
+#include <com/sun/star/text/VertOrientation.hpp>
+#include <com/sun/star/text/XTextSection.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/TableBorder2.hpp>
+#include <com/sun/star/table/BorderLine2.hpp>
+#include <com/sun/star/table/TableBorderDistances.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/chart/XChartDataChangeEventListener.hpp>
+#include <com/sun/star/chart/ChartDataChangeEvent.hpp>
+#include <com/sun/star/table/CellContentType.hpp>
+#include <unotextrange.hxx>
+#include <unotextcursor.hxx>
+#include <unoparagraph.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <editeng/formatbreakitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <fmtornt.hxx>
+#include <editeng/keepitem.hxx>
+#include <fmtlsplt.hxx>
+#include <swundo.hxx>
+#include <SwStyleNameMapper.hxx>
+#include <frmatr.hxx>
+#include <sortopt.hxx>
+#include <sal/log.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/string.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <swtable.hxx>
+#include <docsh.hxx>
+#include <fesh.hxx>
+#include <itabenum.hxx>
+#include <frameformats.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star;
+using ::editeng::SvxBorderLine;
+
+namespace
+{
+ template<typename Tcoretype, typename Tunotype>
+ struct FindUnoInstanceHint final : SfxHint
+ {
+ FindUnoInstanceHint(Tcoretype* pCore) : m_pCore(pCore), m_pResult(nullptr) {};
+ const Tcoretype* const m_pCore;
+ mutable rtl::Reference<Tunotype> m_pResult;
+ };
+ SwFrameFormat* lcl_EnsureCoreConnected(SwFrameFormat* pFormat, cppu::OWeakObject* pObject)
+ {
+ if(!pFormat)
+ throw uno::RuntimeException("Lost connection to core objects", pObject);
+ return pFormat;
+ }
+ SwTable* lcl_EnsureTableNotComplex(SwTable* pTable, cppu::OWeakObject* pObject)
+ {
+ if(pTable->IsTableComplex())
+ throw uno::RuntimeException("Table too complex", pObject);
+ return pTable;
+ }
+
+ chart::ChartDataChangeEvent createChartEvent(uno::Reference<uno::XInterface> const& xSource)
+ {
+ //TODO: find appropriate settings of the Event
+ chart::ChartDataChangeEvent event;
+ event.Source = xSource;
+ event.Type = chart::ChartDataChangeType_ALL;
+ event.StartColumn = 0;
+ event.EndColumn = 1;
+ event.StartRow = 0;
+ event.EndRow = 1;
+ return event;
+ }
+
+ void lcl_SendChartEvent(std::unique_lock<std::mutex>& rGuard,
+ uno::Reference<uno::XInterface> const& xSource,
+ ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> & rListeners)
+ {
+ if (rListeners.getLength(rGuard))
+ rListeners.notifyEach(rGuard,
+ &chart::XChartDataChangeEventListener::chartDataChanged,
+ createChartEvent(xSource));
+ }
+}
+
+#define UNO_TABLE_COLUMN_SUM 10000
+
+
+static bool lcl_LineToSvxLine(const table::BorderLine& rLine, SvxBorderLine& rSvxLine)
+{
+ rSvxLine.SetColor(Color(ColorTransparency, rLine.Color));
+
+ rSvxLine.GuessLinesWidths( SvxBorderLineStyle::NONE,
+ o3tl::toTwips(rLine.OuterLineWidth, o3tl::Length::mm100),
+ o3tl::toTwips(rLine.InnerLineWidth, o3tl::Length::mm100),
+ o3tl::toTwips(rLine.LineDistance, o3tl::Length::mm100) );
+
+ return rLine.InnerLineWidth > 0 || rLine.OuterLineWidth > 0;
+}
+
+/// @throws lang::IllegalArgumentException
+/// @throws uno::RuntimeException
+static void lcl_SetSpecialProperty(SwFrameFormat* pFormat,
+ const SfxItemPropertyMapEntry* pEntry,
+ const uno::Any& aValue)
+{
+ // special treatment for "non-items"
+ switch(pEntry->nWID)
+ {
+ case FN_TABLE_HEADLINE_REPEAT:
+ case FN_TABLE_HEADLINE_COUNT:
+ {
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ UnoActionContext aAction(pFormat->GetDoc());
+ if( pEntry->nWID == FN_TABLE_HEADLINE_REPEAT)
+ {
+ pFormat->GetDoc()->SetRowsToRepeat( *pTable, aValue.get<bool>() ? 1 : 0 );
+ }
+ else
+ {
+ sal_Int32 nRepeat = 0;
+ aValue >>= nRepeat;
+ if( nRepeat >= 0 && nRepeat < SAL_MAX_UINT16 )
+ pFormat->GetDoc()->SetRowsToRepeat( *pTable, o3tl::narrowing<sal_uInt16>(nRepeat) );
+ }
+ }
+ break;
+
+ case FN_TABLE_IS_RELATIVE_WIDTH:
+ case FN_TABLE_WIDTH:
+ case FN_TABLE_RELATIVE_WIDTH:
+ {
+ SwFormatFrameSize aSz( pFormat->GetFrameSize() );
+ if(FN_TABLE_WIDTH == pEntry->nWID)
+ {
+ sal_Int32 nWidth = 0;
+ aValue >>= nWidth;
+ aSz.SetWidthPercent(0);
+ aSz.SetWidth ( o3tl::toTwips(nWidth, o3tl::Length::mm100) );
+ }
+ else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID)
+ {
+ sal_Int16 nSet = 0;
+ aValue >>= nSet;
+ if(nSet && nSet <=100)
+ aSz.SetWidthPercent( static_cast<sal_uInt8>(nSet) );
+ }
+ else if(FN_TABLE_IS_RELATIVE_WIDTH == pEntry->nWID)
+ {
+ if(!aValue.get<bool>())
+ aSz.SetWidthPercent(0);
+ else
+ {
+ throw lang::IllegalArgumentException("relative width cannot be switched on with this property", nullptr, 0);
+ }
+ }
+ pFormat->GetDoc()->SetAttr(aSz, *pFormat);
+ }
+ break;
+
+ case RES_PAGEDESC:
+ {
+ OUString sPageStyle;
+ aValue >>= sPageStyle;
+ const SwPageDesc* pDesc = nullptr;
+ if (!sPageStyle.isEmpty())
+ {
+ SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc);
+ pDesc = SwPageDesc::GetByName(*pFormat->GetDoc(), sPageStyle);
+ }
+ SwFormatPageDesc aDesc( pDesc );
+ pFormat->GetDoc()->SetAttr(aDesc, *pFormat);
+ }
+ break;
+
+ default:
+ throw lang::IllegalArgumentException();
+ }
+}
+
+static uno::Any lcl_GetSpecialProperty(SwFrameFormat* pFormat, const SfxItemPropertyMapEntry* pEntry )
+{
+ switch(pEntry->nWID)
+ {
+ case FN_TABLE_HEADLINE_REPEAT:
+ case FN_TABLE_HEADLINE_COUNT:
+ {
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ const sal_uInt16 nRepeat = pTable->GetRowsToRepeat();
+ if(pEntry->nWID == FN_TABLE_HEADLINE_REPEAT)
+ return uno::Any(nRepeat > 0);
+ return uno::Any(sal_Int32(nRepeat));
+ }
+
+ case FN_TABLE_WIDTH:
+ case FN_TABLE_IS_RELATIVE_WIDTH:
+ case FN_TABLE_RELATIVE_WIDTH:
+ {
+ uno::Any aRet;
+ const SwFormatFrameSize& rSz = pFormat->GetFrameSize();
+ if(FN_TABLE_WIDTH == pEntry->nWID)
+ rSz.QueryValue(aRet, MID_FRMSIZE_WIDTH|CONVERT_TWIPS);
+ else if(FN_TABLE_RELATIVE_WIDTH == pEntry->nWID)
+ rSz.QueryValue(aRet, MID_FRMSIZE_REL_WIDTH);
+ else
+ aRet <<= (0 != rSz.GetWidthPercent());
+ return aRet;
+ }
+
+ case RES_PAGEDESC:
+ {
+ const SfxItemSet& rSet = pFormat->GetAttrSet();
+ if(const SwFormatPageDesc* pItem = rSet.GetItemIfSet(RES_PAGEDESC, false))
+ {
+ const SwPageDesc* pDsc = pItem->GetPageDesc();
+ if(pDsc)
+ return uno::Any(SwStyleNameMapper::GetProgName(pDsc->GetName(), SwGetPoolIdFromName::PageDesc ));
+ }
+ return uno::Any(OUString());
+ }
+
+ case RES_ANCHOR:
+ return uno::Any(text::TextContentAnchorType_AT_PARAGRAPH);
+
+ case FN_UNO_ANCHOR_TYPES:
+ {
+ uno::Sequence<text::TextContentAnchorType> aTypes{text::TextContentAnchorType_AT_PARAGRAPH};
+ return uno::Any(aTypes);
+ }
+
+ case FN_UNO_WRAP :
+ return uno::Any(text::WrapTextMode_NONE);
+
+ case FN_PARAM_LINK_DISPLAY_NAME :
+ return uno::Any(pFormat->GetName());
+
+ case FN_UNO_REDLINE_NODE_START:
+ case FN_UNO_REDLINE_NODE_END:
+ {
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ SwNode* pTableNode = pTable->GetTableNode();
+ if(FN_UNO_REDLINE_NODE_END == pEntry->nWID)
+ pTableNode = pTableNode->EndOfSectionNode();
+ for(const SwRangeRedline* pRedline : pFormat->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable())
+ {
+ const SwNode& rRedPointNode = pRedline->GetPointNode();
+ const SwNode& rRedMarkNode = pRedline->GetMarkNode();
+ if(rRedPointNode == *pTableNode || rRedMarkNode == *pTableNode)
+ {
+ const SwNode& rStartOfRedline = SwNodeIndex(rRedPointNode) <= SwNodeIndex(rRedMarkNode) ?
+ rRedPointNode : rRedMarkNode;
+ bool bIsStart = &rStartOfRedline == pTableNode;
+ return uno::Any(SwXRedlinePortion::CreateRedlineProperties(*pRedline, bIsStart));
+ }
+ }
+ }
+ }
+ return uno::Any();
+}
+
+/** get position of a cell with a given name
+ *
+ * If everything was OK, the indices for column and row are changed (both >= 0).
+ * In case of errors, at least one of them is < 0.
+ *
+ * Also since the implementations of tables does not really have columns using
+ * this function is appropriate only for tables that are not complex (i.e.
+ * where IsTableComplex() returns false).
+ *
+ * @param rCellName e.g. A1..Z1, a1..z1, AA1..AZ1, Aa1..Az1, BA1..BZ1, Ba1..Bz1, ...
+ * @param [IN,OUT] o_rColumn (0-based)
+ * @param [IN,OUT] o_rRow (0-based)
+ */
+//TODO: potential for throwing proper exceptions instead of having every caller to check for errors
+void SwXTextTable::GetCellPosition(std::u16string_view aCellName, sal_Int32& o_rColumn, sal_Int32& o_rRow)
+{
+ o_rColumn = o_rRow = -1; // default return values indicating failure
+ const sal_Int32 nLen = aCellName.size();
+ if(!nLen)
+ {
+ SAL_WARN("sw.uno", "failed to get column or row index");
+ return;
+ }
+ sal_Int32 nRowPos = 0;
+ while (nRowPos<nLen)
+ {
+ if (aCellName[nRowPos]>='0' && aCellName[nRowPos]<='9')
+ {
+ break;
+ }
+ ++nRowPos;
+ }
+ if (nRowPos<=0 || nRowPos>=nLen)
+ return;
+
+ sal_Int32 nColIdx = 0;
+ for (sal_Int32 i = 0; i < nRowPos; ++i)
+ {
+ nColIdx *= 52;
+ if (i < nRowPos - 1)
+ ++nColIdx;
+ const sal_Unicode cChar = aCellName[i];
+ if ('A' <= cChar && cChar <= 'Z')
+ nColIdx += cChar - 'A';
+ else if ('a' <= cChar && cChar <= 'z')
+ nColIdx += 26 + cChar - 'a';
+ else
+ {
+ nColIdx = -1; // sth failed
+ break;
+ }
+ }
+
+ o_rColumn = nColIdx;
+ o_rRow = o3tl::toInt32(aCellName.substr(nRowPos)) - 1; // - 1 because indices ought to be 0 based
+}
+
+/** compare position of two cells (check rows first)
+ *
+ * @note this function probably also make sense only
+ * for cell names of non-complex tables
+ *
+ * @param rCellName1 e.g. "A1" (non-empty string with valid cell name)
+ * @param rCellName2 e.g. "A1" (non-empty string with valid cell name)
+ * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2
+ */
+int sw_CompareCellsByRowFirst( std::u16string_view aCellName1, std::u16string_view aCellName2 )
+{
+ sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
+ SwXTextTable::GetCellPosition( aCellName1, nCol1, nRow1 );
+ SwXTextTable::GetCellPosition( aCellName2, nCol2, nRow2 );
+
+ if (nRow1 < nRow2 || (nRow1 == nRow2 && nCol1 < nCol2))
+ return -1;
+ else if (nCol1 == nCol2 && nRow1 == nRow2)
+ return 0;
+ else
+ return +1;
+}
+
+/** compare position of two cells (check columns first)
+ *
+ * @note this function probably also make sense only
+ * for cell names of non-complex tables
+ *
+ * @param rCellName1 e.g. "A1" (non-empty string with valid cell name)
+ * @param rCellName2 e.g. "A1" (non-empty string with valid cell name)
+ * @return -1 if cell_1 < cell_2; 0 if both cells are equal; +1 if cell_1 > cell_2
+ */
+int sw_CompareCellsByColFirst( std::u16string_view aCellName1, std::u16string_view aCellName2 )
+{
+ sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
+ SwXTextTable::GetCellPosition( aCellName1, nCol1, nRow1 );
+ SwXTextTable::GetCellPosition( aCellName2, nCol2, nRow2 );
+
+ if (nCol1 < nCol2 || (nCol1 == nCol2 && nRow1 < nRow2))
+ return -1;
+ else if (nRow1 == nRow2 && nCol1 == nCol2)
+ return 0;
+ else
+ return +1;
+}
+
+/** compare position of two cell ranges
+ *
+ * @note this function probably also make sense only
+ * for cell names of non-complex tables
+ *
+ * @param rRange1StartCell e.g. "A1" (non-empty string with valid cell name)
+ * @param rRange1EndCell e.g. "A1" (non-empty string with valid cell name)
+ * @param rRange2StartCell e.g. "A1" (non-empty string with valid cell name)
+ * @param rRange2EndCell e.g. "A1" (non-empty string with valid cell name)
+ * @param bCmpColsFirst if <true> position in columns will be compared first before rows
+ *
+ * @return -1 if cell_range_1 < cell_range_2; 0 if both cell ranges are equal; +1 if cell_range_1 > cell_range_2
+ */
+int sw_CompareCellRanges(
+ std::u16string_view aRange1StartCell, std::u16string_view aRange1EndCell,
+ std::u16string_view aRange2StartCell, std::u16string_view aRange2EndCell,
+ bool bCmpColsFirst )
+{
+ int (*pCompareCells)( std::u16string_view, std::u16string_view ) =
+ bCmpColsFirst ? &sw_CompareCellsByColFirst : &sw_CompareCellsByRowFirst;
+
+ int nCmpResStartCells = pCompareCells( aRange1StartCell, aRange2StartCell );
+ if ((-1 == nCmpResStartCells ) ||
+ ( 0 == nCmpResStartCells &&
+ -1 == pCompareCells( aRange1EndCell, aRange2EndCell ) ))
+ return -1;
+ else if (0 == nCmpResStartCells &&
+ 0 == pCompareCells( aRange1EndCell, aRange2EndCell ))
+ return 0;
+ else
+ return +1;
+}
+
+/** get cell name at a specified coordinate
+ *
+ * @param nColumn column index (0-based)
+ * @param nRow row index (0-based)
+ * @return the cell name
+ */
+OUString sw_GetCellName( sal_Int32 nColumn, sal_Int32 nRow )
+{
+ if (nColumn < 0 || nRow < 0)
+ return OUString();
+ OUString sCellName;
+ sw_GetTableBoxColStr( static_cast< sal_uInt16 >(nColumn), sCellName );
+ return sCellName + OUString::number( nRow + 1 );
+}
+
+/** Find the top left or bottom right corner box in given table.
+ Consider nested lines when finding the box.
+
+ @param rTableLines the table
+ @param i_bTopLeft if true, find top left box, otherwise find bottom
+ right box
+ */
+static const SwTableBox* lcl_FindCornerTableBox(const SwTableLines& rTableLines, const bool i_bTopLeft)
+{
+ const SwTableLines* pLines(&rTableLines);
+ while(true)
+ {
+ assert(!pLines->empty());
+ if(pLines->empty())
+ return nullptr;
+ const SwTableLine* pLine(i_bTopLeft ? pLines->front() : pLines->back());
+ assert(pLine);
+ const SwTableBoxes& rBoxes(pLine->GetTabBoxes());
+ assert(rBoxes.size() != 0);
+ const SwTableBox* pBox = i_bTopLeft ? rBoxes.front() : rBoxes.back();
+ assert(pBox);
+ if (pBox->GetSttNd())
+ return pBox;
+ pLines = &pBox->GetTabLines();
+ }
+}
+
+/** cleanup order in a range
+ *
+ * Sorts the input to a uniform format. I.e. for the four possible representation
+ * A1:C5, C5:A1, A5:C1, C1:A5
+ * the result will be always A1:C5.
+ *
+ * @param [IN,OUT] rCell1 cell name (will be modified to upper-left corner), e.g. "A1" (non-empty string with valid cell name)
+ * @param [IN,OUT] rCell2 cell name (will be modified to lower-right corner), e.g. "A1" (non-empty string with valid cell name)
+ */
+void sw_NormalizeRange(OUString &rCell1, OUString &rCell2)
+{
+ sal_Int32 nCol1 = -1, nRow1 = -1, nCol2 = -1, nRow2 = -1;
+ SwXTextTable::GetCellPosition( rCell1, nCol1, nRow1 );
+ SwXTextTable::GetCellPosition( rCell2, nCol2, nRow2 );
+ if (nCol2 < nCol1 || nRow2 < nRow1)
+ {
+ rCell1 = sw_GetCellName( std::min(nCol1, nCol2), std::min(nRow1, nRow2) );
+ rCell2 = sw_GetCellName( std::max(nCol1, nCol2), std::max(nRow1, nRow2) );
+ }
+}
+
+void SwRangeDescriptor::Normalize()
+{
+ if (nTop > nBottom)
+ std::swap(nBottom, nTop);
+ if (nLeft > nRight)
+ std::swap(nLeft, nRight);
+}
+
+static rtl::Reference<SwXCell> lcl_CreateXCell(SwFrameFormat* pFormat, sal_Int32 nColumn, sal_Int32 nRow)
+{
+ const OUString sCellName = sw_GetCellName(nColumn, nRow);
+ SwTable* pTable = SwTable::FindTable(pFormat);
+ SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
+ if(!pBox)
+ return nullptr;
+ return SwXCell::CreateXCell(pFormat, pBox, pTable);
+}
+
+static void lcl_InspectLines(SwTableLines& rLines, std::vector<OUString>& rAllNames)
+{
+ for(auto pLine : rLines)
+ {
+ for(auto pBox : pLine->GetTabBoxes())
+ {
+ if(!pBox->GetName().isEmpty() && pBox->getRowSpan() > 0)
+ rAllNames.push_back(pBox->GetName());
+ SwTableLines& rBoxLines = pBox->GetTabLines();
+ if(!rBoxLines.empty())
+ lcl_InspectLines(rBoxLines, rAllNames);
+ }
+ }
+}
+
+static bool lcl_FormatTable(SwFrameFormat const * pTableFormat)
+{
+ bool bHasFrames = false;
+ SwIterator<SwFrame,SwFormat> aIter( *pTableFormat );
+ for(SwFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+ {
+ vcl::RenderContext* pRenderContext = pFrame->getRootFrame()->GetCurrShell()->GetOut();
+ // mba: no TYPEINFO for SwTabFrame
+ if(!pFrame->IsTabFrame())
+ continue;
+ DisableCallbackAction a(*pFrame->getRootFrame());
+ SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pFrame);
+ if(pTabFrame->isFrameAreaDefinitionValid())
+ pTabFrame->InvalidatePos();
+ pTabFrame->SetONECalcLowers();
+ pTabFrame->Calc(pRenderContext);
+ bHasFrames = true;
+ }
+ return bHasFrames;
+}
+
+static void lcl_CursorSelect(SwPaM& rCursor, bool bExpand)
+{
+ if(bExpand)
+ {
+ if(!rCursor.HasMark())
+ rCursor.SetMark();
+ }
+ else if(rCursor.HasMark())
+ rCursor.DeleteMark();
+}
+
+static void lcl_GetTableSeparators(uno::Any& rRet, SwTable const * pTable, SwTableBox const * pBox, bool bRow)
+{
+ SwTabCols aCols;
+ aCols.SetLeftMin ( 0 );
+ aCols.SetLeft ( 0 );
+ aCols.SetRight ( UNO_TABLE_COLUMN_SUM );
+ aCols.SetRightMax( UNO_TABLE_COLUMN_SUM );
+
+ pTable->GetTabCols( aCols, pBox, false, bRow );
+
+ const size_t nSepCount = aCols.Count();
+ uno::Sequence< text::TableColumnSeparator> aColSeq(nSepCount);
+ text::TableColumnSeparator* pArray = aColSeq.getArray();
+ bool bError = false;
+ for(size_t i = 0; i < nSepCount; ++i)
+ {
+ pArray[i].Position = static_cast< sal_Int16 >(aCols[i]);
+ pArray[i].IsVisible = !aCols.IsHidden(i);
+ if(!bRow && !pArray[i].IsVisible)
+ {
+ bError = true;
+ break;
+ }
+ }
+ if(!bError)
+ rRet <<= aColSeq;
+
+}
+
+static void lcl_SetTableSeparators(const uno::Any& rVal, SwTable* pTable, SwTableBox const * pBox, bool bRow, SwDoc* pDoc)
+{
+ SwTabCols aOldCols;
+
+ aOldCols.SetLeftMin ( 0 );
+ aOldCols.SetLeft ( 0 );
+ aOldCols.SetRight ( UNO_TABLE_COLUMN_SUM );
+ aOldCols.SetRightMax( UNO_TABLE_COLUMN_SUM );
+
+ pTable->GetTabCols( aOldCols, pBox, false, bRow );
+ const size_t nOldCount = aOldCols.Count();
+ // there is no use in setting tab cols if there is only one column
+ if( !nOldCount )
+ return;
+
+ auto pSepSeq =
+ o3tl::tryAccess<uno::Sequence<text::TableColumnSeparator>>(rVal);
+ if(!pSepSeq || static_cast<size_t>(pSepSeq->getLength()) != nOldCount)
+ return;
+ SwTabCols aCols(aOldCols);
+ const text::TableColumnSeparator* pArray = pSepSeq->getConstArray();
+ tools::Long nLastValue = 0;
+ //sal_Int32 nTableWidth = aCols.GetRight() - aCols.GetLeft();
+ for(size_t i = 0; i < nOldCount; ++i)
+ {
+ aCols[i] = pArray[i].Position;
+ if(bool(pArray[i].IsVisible) == aCols.IsHidden(i) ||
+ (!bRow && aCols.IsHidden(i)) ||
+ aCols[i] < nLastValue ||
+ UNO_TABLE_COLUMN_SUM < aCols[i] )
+ return; // probably this should assert()
+ nLastValue = aCols[i];
+ }
+ pDoc->SetTabCols(*pTable, aCols, aOldCols, pBox, bRow );
+}
+
+/* non UNO function call to set string in SwXCell */
+void sw_setString( SwXCell &rCell, const OUString &rText,
+ bool bKeepNumberFormat = false )
+{
+ if(rCell.IsValid())
+ {
+ SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat();
+ pBoxFormat->LockModify();
+ pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMULA );
+ pBoxFormat->ResetFormatAttr( RES_BOXATR_VALUE );
+ if (!bKeepNumberFormat)
+ pBoxFormat->SetFormatAttr( SwTableBoxNumFormat(/*default Text*/) );
+ pBoxFormat->UnlockModify();
+ }
+ rCell.SwXText::setString(rText);
+}
+
+
+/* non UNO function call to set value in SwXCell */
+void sw_setValue( SwXCell &rCell, double nVal )
+{
+ if(!rCell.IsValid())
+ return;
+ // first this text (maybe) needs to be deleted
+ SwNodeOffset nNdPos = rCell.m_pBox->IsValidNumTextNd();
+ if(NODE_OFFSET_MAX != nNdPos)
+ sw_setString( rCell, OUString(), true ); // true == keep number format
+ SwDoc* pDoc = rCell.GetDoc();
+ UnoActionContext aAction(pDoc);
+ SwFrameFormat* pBoxFormat = rCell.m_pBox->ClaimFrameFormat();
+ SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_VALUE> aSet(pDoc->GetAttrPool());
+
+ //!! do we need to set a new number format? Yes, if
+ // - there is no current number format
+ // - the current number format is not a number format according to the number formatter, but rather a text format
+ const SwTableBoxNumFormat* pNumFormat = pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT);
+ if(!pNumFormat
+ || pDoc->GetNumberFormatter()->IsTextFormat(pNumFormat->GetValue()))
+ {
+ aSet.Put(SwTableBoxNumFormat(0));
+ }
+
+ SwTableBoxValue aVal(nVal);
+ aSet.Put(aVal);
+ pDoc->SetTableBoxFormulaAttrs( *rCell.m_pBox, aSet );
+ // update table
+ pDoc->getIDocumentFieldsAccess().UpdateTableFields(SwTable::FindTable(rCell.GetFrameFormat()));
+}
+
+
+SwXCell::SwXCell(SwFrameFormat* pTableFormat, SwTableBox* pBx, size_t const nPos) :
+ SwXText(pTableFormat->GetDoc(), CursorType::TableText),
+ m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)),
+ m_pBox(pBx),
+ m_pStartNode(nullptr),
+ m_pTableFormat(pTableFormat),
+ m_nFndPos(nPos)
+{
+ StartListening(pTableFormat->GetNotifier());
+}
+
+SwXCell::SwXCell(SwFrameFormat* pTableFormat, const SwStartNode& rStartNode) :
+ SwXText(pTableFormat->GetDoc(), CursorType::TableText),
+ m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_CELL)),
+ m_pBox(nullptr),
+ m_pStartNode(&rStartNode),
+ m_pTableFormat(pTableFormat),
+ m_nFndPos(NOTFOUND)
+{
+ StartListening(pTableFormat->GetNotifier());
+}
+
+SwXCell::~SwXCell()
+{
+ SolarMutexGuard aGuard;
+ EndListeningAll();
+}
+
+uno::Sequence< uno::Type > SAL_CALL SwXCell::getTypes( )
+{
+ return comphelper::concatSequences(
+ SwXCellBaseClass::getTypes(),
+ SwXText::getTypes()
+ );
+}
+
+uno::Sequence< sal_Int8 > SAL_CALL SwXCell::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void SAL_CALL SwXCell::acquire( ) noexcept
+{
+ SwXCellBaseClass::acquire();
+}
+
+void SAL_CALL SwXCell::release( ) noexcept
+{
+ SolarMutexGuard aGuard;
+
+ SwXCellBaseClass::release();
+}
+
+uno::Any SAL_CALL SwXCell::queryInterface( const uno::Type& aType )
+{
+ uno::Any aRet = SwXText::queryInterface(aType);
+ if(aRet.getValueType() == cppu::UnoType<void>::get())
+ aRet = SwXCellBaseClass::queryInterface(aType);
+ return aRet;
+}
+
+const SwStartNode *SwXCell::GetStartNode() const
+{
+ const SwStartNode* pSttNd = nullptr;
+
+ if( m_pStartNode || IsValid() )
+ pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
+
+ return pSttNd;
+}
+
+bool SwXCell::IsValid() const
+{
+ // FIXME: this is now a const method, to make SwXText::IsValid invisible
+ // but the const_cast here are still ridiculous. TODO: find a better way.
+ SwFrameFormat* pTableFormat = m_pBox ? GetFrameFormat() : nullptr;
+ if(!pTableFormat)
+ {
+ const_cast<SwXCell*>(this)->m_pBox = nullptr;
+ }
+ else
+ {
+ SwTable* pTable = SwTable::FindTable( pTableFormat );
+ SwTableBox const*const pFoundBox =
+ const_cast<SwXCell*>(this)->FindBox(pTable, m_pBox);
+ if (!pFoundBox)
+ {
+ const_cast<SwXCell*>(this)->m_pBox = nullptr;
+ }
+ }
+ return nullptr != m_pBox;
+}
+
+OUString SwXCell::getFormula()
+{
+ SolarMutexGuard aGuard;
+ if(!IsValid())
+ return OUString();
+ SwTableBoxFormula aFormula( m_pBox->GetFrameFormat()->GetTableBoxFormula() );
+ SwTable* pTable = SwTable::FindTable( GetFrameFormat() );
+ aFormula.PtrToBoxNm( pTable );
+ return aFormula.GetFormula();
+}
+
+///@see sw_setValue (TODO: seems to be copy and paste programming here)
+void SwXCell::setFormula(const OUString& rFormula)
+{
+ SolarMutexGuard aGuard;
+ if(!IsValid())
+ return;
+ // first this text (maybe) needs to be deleted
+ SwNodeOffset nNdPos = m_pBox->IsValidNumTextNd();
+ if(SwNodeOffset(USHRT_MAX) == nNdPos)
+ sw_setString( *this, OUString(), true );
+ OUString sFormula(comphelper::string::stripStart(rFormula, ' '));
+ if( !sFormula.isEmpty() && '=' == sFormula[0] )
+ sFormula = sFormula.copy( 1 );
+ SwTableBoxFormula aFormula( sFormula );
+ SwDoc* pMyDoc = GetDoc();
+ UnoActionContext aAction(pMyDoc);
+ SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_FORMULA> aSet(pMyDoc->GetAttrPool());
+ SwFrameFormat* pBoxFormat = m_pBox->GetFrameFormat();
+ const SwTableBoxNumFormat* pNumFormat =
+ pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT);
+ if(!pNumFormat
+ || pMyDoc->GetNumberFormatter()->IsTextFormat(pNumFormat->GetValue()))
+ {
+ aSet.Put(SwTableBoxNumFormat(0));
+ }
+ aSet.Put(aFormula);
+ GetDoc()->SetTableBoxFormulaAttrs( *m_pBox, aSet );
+ // update table
+ pMyDoc->getIDocumentFieldsAccess().UpdateTableFields(SwTable::FindTable(GetFrameFormat()));
+}
+
+double SwXCell::getValue()
+{
+ SolarMutexGuard aGuard;
+ // #i112652# a table cell may contain NaN as a value, do not filter that
+ if(IsValid() && !getString().isEmpty())
+ return m_pBox->GetFrameFormat()->GetTableBoxValue().GetValue();
+ return std::numeric_limits<double>::quiet_NaN();
+}
+
+void SwXCell::setValue(double rValue)
+{
+ SolarMutexGuard aGuard;
+ sw_setValue( *this, rValue );
+}
+
+table::CellContentType SwXCell::getType()
+{
+ SolarMutexGuard aGuard;
+
+ table::CellContentType nRes = table::CellContentType_EMPTY;
+ sal_uInt32 nNdPos = m_pBox->IsFormulaOrValueBox();
+ switch (nNdPos)
+ {
+ case 0 : nRes = table::CellContentType_TEXT; break;
+ case USHRT_MAX : nRes = table::CellContentType_EMPTY; break;
+ case RES_BOXATR_VALUE : nRes = table::CellContentType_VALUE; break;
+ case RES_BOXATR_FORMULA : nRes = table::CellContentType_FORMULA; break;
+ default :
+ OSL_FAIL( "unexpected case" );
+ }
+ return nRes;
+}
+
+void SwXCell::setString(const OUString& aString)
+{
+ SolarMutexGuard aGuard;
+ sw_setString( *this, aString );
+}
+
+sal_Int32 SwXCell::getError()
+{
+ SolarMutexGuard aGuard;
+ OUString sContent = getString();
+ return sal_Int32(sContent == SwViewShell::GetShellRes()->aCalc_Error);
+}
+
+rtl::Reference< SwXTextCursor > SwXCell::createXTextCursor()
+{
+ if(!m_pStartNode && !IsValid())
+ throw uno::RuntimeException();
+ const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ rtl::Reference<SwXTextCursor> const pXCursor =
+ new SwXTextCursor(*GetDoc(), this, CursorType::TableText, aPos);
+ auto& rUnoCursor(pXCursor->GetCursor());
+ rUnoCursor.Move(fnMoveForward, GoInNode);
+ return pXCursor;
+}
+
+rtl::Reference<SwXTextCursor> SwXCell::createXTextCursorByRange(const uno::Reference< text::XTextRange > & xTextPosition)
+{
+ SwUnoInternalPaM aPam(*GetDoc());
+ if((!m_pStartNode && !IsValid()) || !::sw::XTextRangeToSwPaM(aPam, xTextPosition))
+ throw uno::RuntimeException();
+ const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
+ // skip sections
+ SwStartNode* p1 = aPam.GetPointNode().StartOfSectionNode();
+ while(p1->IsSectionNode())
+ p1 = p1->StartOfSectionNode();
+ if( p1 != pSttNd )
+ return nullptr;
+ return new SwXTextCursor(*GetDoc(), this, CursorType::TableText,
+ *aPam.GetPoint(), aPam.GetMark());
+}
+
+uno::Reference< beans::XPropertySetInfo > SwXCell::getPropertySetInfo()
+{
+ static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo();
+ return xRef;
+}
+
+void SwXCell::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
+{
+ SolarMutexGuard aGuard;
+ if(!IsValid())
+ return;
+ // Hack to support hidden property to transfer textDirection
+ if(rPropertyName == "FRMDirection")
+ {
+ SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, RES_FRAMEDIR);
+ aItem.PutValue(aValue, 0);
+ m_pBox->GetFrameFormat()->SetFormatAttr(aItem);
+ }
+ else if(rPropertyName == "TableRedlineParams")
+ {
+ // Get the table row properties
+ uno::Sequence<beans::PropertyValue> tableCellProperties = aValue.get< uno::Sequence< beans::PropertyValue > >();
+ comphelper::SequenceAsHashMap aPropMap(tableCellProperties);
+ OUString sRedlineType;
+ if(!(aPropMap.getValue("RedlineType") >>= sRedlineType))
+ throw beans::UnknownPropertyException("No redline type property: ", getXWeak());
+
+ // Create a 'Table Cell Redline' object
+ SwUnoCursorHelper::makeTableCellRedline(*m_pBox, sRedlineType, tableCellProperties);
+
+
+ }
+ else if (rPropertyName == "VerticalMerge")
+ {
+ //Hack to allow clearing of numbering from the paragraphs in the merged cells.
+ SwNodeIndex aIdx(*GetStartNode(), 1);
+ const SwNode* pEndNd = aIdx.GetNode().EndOfSectionNode();
+ while (&aIdx.GetNode() != pEndNd)
+ {
+ SwTextNode* pNd = aIdx.GetNode().GetTextNode();
+ if (pNd)
+ pNd->SetCountedInList(false);
+ ++aIdx;
+ }
+ }
+ else
+ {
+ auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
+ if ( !pEntry )
+ {
+ // not a table property: ignore it, if it is a paragraph/character property
+ const SfxItemPropertySet& rParaPropSet = *aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARAGRAPH);
+ pEntry = rParaPropSet.getPropertyMap().getByName(rPropertyName);
+
+ if ( pEntry )
+ return;
+ }
+
+ if(!pEntry)
+ throw beans::UnknownPropertyException(rPropertyName, getXWeak());
+ if(pEntry->nWID != FN_UNO_CELL_ROW_SPAN)
+ {
+ SwFrameFormat* pBoxFormat = m_pBox->ClaimFrameFormat();
+ SwAttrSet aSet(pBoxFormat->GetAttrSet());
+ m_pPropSet->setPropertyValue(rPropertyName, aValue, aSet);
+ pBoxFormat->GetDoc()->SetAttr(aSet, *pBoxFormat);
+ }
+ else if(aValue.isExtractableTo(cppu::UnoType<sal_Int32>::get()))
+ m_pBox->setRowSpan(aValue.get<sal_Int32>());
+ }
+}
+
+uno::Any SwXCell::getPropertyValue(const OUString& rPropertyName)
+{
+ SolarMutexGuard aGuard;
+ if(!IsValid())
+ return uno::Any();
+ auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
+ if(!pEntry)
+ throw beans::UnknownPropertyException(rPropertyName, getXWeak());
+ switch(pEntry->nWID)
+ {
+ case FN_UNO_CELL_ROW_SPAN:
+ return uno::Any(m_pBox->getRowSpan());
+ case FN_UNO_TEXT_SECTION:
+ {
+ SwFrameFormat* pTableFormat = GetFrameFormat();
+ SwTable* pTable = SwTable::FindTable(pTableFormat);
+ SwTableNode* pTableNode = pTable->GetTableNode();
+ SwSectionNode* pSectionNode = pTableNode->FindSectionNode();
+ if(!pSectionNode)
+ return uno::Any();
+ SwSection& rSect = pSectionNode->GetSection();
+ return uno::Any(SwXTextSections::GetObject(*rSect.GetFormat()));
+ }
+ break;
+ case FN_UNO_CELL_NAME:
+ return uno::Any(m_pBox->GetName());
+ case FN_UNO_REDLINE_NODE_START:
+ case FN_UNO_REDLINE_NODE_END:
+ {
+ //redline can only be returned if it's a living object
+ return SwXText::getPropertyValue(rPropertyName);
+ }
+ break;
+ case FN_UNO_PARENT_TEXT:
+ {
+ if (!m_xParentText.is())
+ {
+ const SwStartNode* pSttNd = m_pBox->GetSttNd();
+ if (!pSttNd)
+ return uno::Any();
+
+ const SwTableNode* pTableNode = pSttNd->FindTableNode();
+ if (!pTableNode)
+ return uno::Any();
+
+ SwPosition aPos(*pTableNode);
+ SwDoc& rDoc = aPos.GetDoc();
+ m_xParentText = sw::CreateParentXText(rDoc, aPos);
+ }
+
+ return uno::Any(m_xParentText);
+ }
+ break;
+ default:
+ {
+ const SwAttrSet& rSet = m_pBox->GetFrameFormat()->GetAttrSet();
+ uno::Any aResult;
+ m_pPropSet->getPropertyValue(rPropertyName, rSet, aResult);
+ return aResult;
+ }
+ }
+}
+
+void SwXCell::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXCell::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXCell::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXCell::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+uno::Reference<container::XEnumeration> SwXCell::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if(!IsValid())
+ return uno::Reference<container::XEnumeration>();
+ const SwStartNode* pSttNd = m_pBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ auto pUnoCursor(GetDoc()->CreateUnoCursor(aPos));
+ pUnoCursor->Move(fnMoveForward, GoInNode);
+ // remember table and start node for later travelling
+ // (used in export of tables in tables)
+ return SwXParagraphEnumeration::Create(this, pUnoCursor, CursorType::TableText, m_pBox);
+}
+
+uno::Type SAL_CALL SwXCell::getElementType()
+{
+ return cppu::UnoType<text::XTextRange>::get();
+}
+
+sal_Bool SwXCell::hasElements()
+{
+ return true;
+}
+
+void SwXCell::Notify(const SfxHint& rHint)
+{
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pTableFormat = nullptr;
+ }
+ else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableBox, SwXCell>*>(&rHint))
+ {
+ if(!pFindHint->m_pResult && pFindHint->m_pCore == GetTableBox())
+ pFindHint->m_pResult = this;
+ }
+}
+
+rtl::Reference<SwXCell> SwXCell::CreateXCell(SwFrameFormat* pTableFormat, SwTableBox* pBox, SwTable *pTable )
+{
+ if(!pTableFormat || !pBox)
+ return nullptr;
+ if(!pTable)
+ pTable = SwTable::FindTable(pTableFormat);
+ SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find(pBox);
+ if(it == pTable->GetTabSortBoxes().end())
+ return nullptr;
+ size_t const nPos = it - pTable->GetTabSortBoxes().begin();
+ FindUnoInstanceHint<SwTableBox, SwXCell> aHint{pBox};
+ pTableFormat->GetNotifier().Broadcast(aHint);
+ return aHint.m_pResult ? aHint.m_pResult.get() : new SwXCell(pTableFormat, pBox, nPos);
+}
+
+/** search if a box exists in a table
+ *
+ * @param pTable the table to search in
+ * @param pBox2 box model to find
+ * @return the box if existent in pTable, 0 (!!!) if not found
+ */
+SwTableBox* SwXCell::FindBox(SwTable* pTable, SwTableBox* pBox2)
+{
+ // check if nFndPos happens to point to the right table box
+ if( m_nFndPos < pTable->GetTabSortBoxes().size() &&
+ pBox2 == pTable->GetTabSortBoxes()[ m_nFndPos ] )
+ return pBox2;
+
+ // if not, seek the entry (and return, if successful)
+ SwTableSortBoxes::const_iterator it = pTable->GetTabSortBoxes().find( pBox2 );
+ if( it != pTable->GetTabSortBoxes().end() )
+ {
+ m_nFndPos = it - pTable->GetTabSortBoxes().begin();
+ return pBox2;
+ }
+
+ // box not found: reset nFndPos pointer
+ m_nFndPos = NOTFOUND;
+ return nullptr;
+}
+
+double SwXCell::GetForcedNumericalValue() const
+{
+ if(table::CellContentType_TEXT != const_cast<SwXCell*>(this)->getType())
+ return getValue();
+ // now we'll try to get a useful numerical value
+ // from the text in the cell...
+ sal_uInt32 nFIndex;
+ SvNumberFormatter* pNumFormatter(const_cast<SvNumberFormatter*>(GetDoc()->GetNumberFormatter()));
+ // look for SwTableBoxNumFormat value in parents as well
+ auto pBoxFormat(GetTableBox()->GetFrameFormat());
+ const SwTableBoxNumFormat* pNumFormat = pBoxFormat->GetAttrSet().GetItemIfSet(RES_BOXATR_FORMAT);
+
+ if (pNumFormat)
+ {
+ // please note that the language of the numberformat
+ // is implicitly coded into the below value as well
+ nFIndex = pNumFormat->GetValue();
+
+ // since the current value indicates a text format but the call
+ // to 'IsNumberFormat' below won't work for text formats
+ // we need to get rid of the part that indicates the text format.
+ // According to ER this can be done like this:
+ nFIndex -= (nFIndex % SV_COUNTRY_LANGUAGE_OFFSET);
+ }
+ else
+ {
+ // system language is probably not the best possible choice
+ // but since we have to guess anyway (because the language of at
+ // the text is NOT the one used for the number format!)
+ // it is at least conform to what is used in
+ // SwTableShell::Execute when
+ // SID_ATTR_NUMBERFORMAT_VALUE is set...
+ LanguageType eLang = LANGUAGE_SYSTEM;
+ nFIndex = pNumFormatter->GetStandardIndex( eLang );
+ }
+ double fTmp;
+ if (!const_cast<SwDoc*>(GetDoc())->IsNumberFormat(const_cast<SwXCell*>(this)->getString(), nFIndex, fTmp))
+ return std::numeric_limits<double>::quiet_NaN();
+ return fTmp;
+}
+
+uno::Any SwXCell::GetAny() const
+{
+ if(!m_pBox)
+ throw uno::RuntimeException();
+ // check if table box value item is set
+ auto pBoxFormat(m_pBox->GetFrameFormat());
+ const bool bIsNum = pBoxFormat->GetItemState(RES_BOXATR_VALUE, false) == SfxItemState::SET;
+ return bIsNum ? uno::Any(getValue()) : uno::Any(const_cast<SwXCell*>(this)->getString());
+}
+
+OUString SwXCell::getImplementationName()
+ { return "SwXCell"; }
+
+sal_Bool SwXCell::supportsService(const OUString& rServiceName)
+ { return cppu::supportsService(this, rServiceName); }
+
+uno::Sequence< OUString > SwXCell::getSupportedServiceNames()
+ { return {"com.sun.star.text.CellProperties"}; }
+
+OUString SwXTextTableRow::getImplementationName()
+ { return "SwXTextTableRow"; }
+
+sal_Bool SwXTextTableRow::supportsService(const OUString& rServiceName)
+ { return cppu::supportsService(this, rServiceName); }
+
+uno::Sequence< OUString > SwXTextTableRow::getSupportedServiceNames()
+ { return {"com.sun.star.text.TextTableRow"}; }
+
+
+SwXTextTableRow::SwXTextTableRow(SwFrameFormat* pFormat, SwTableLine* pLn) :
+ m_pFormat(pFormat),
+ m_pLine(pLn),
+ m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_ROW))
+{
+ StartListening(m_pFormat->GetNotifier());
+}
+
+SwXTextTableRow::~SwXTextTableRow()
+{
+ SolarMutexGuard aGuard;
+ EndListeningAll();
+}
+
+uno::Reference< beans::XPropertySetInfo > SwXTextTableRow::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> xRef = m_pPropSet->getPropertySetInfo();
+ return xRef;
+}
+
+void SwXTextTableRow::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, m_pLine);
+ if(!pLn)
+ return;
+
+ // Check for a specific property
+ if ( rPropertyName == "TableRedlineParams" )
+ {
+ // Get the table row properties
+ uno::Sequence< beans::PropertyValue > tableRowProperties = aValue.get< uno::Sequence< beans::PropertyValue > >();
+ comphelper::SequenceAsHashMap aPropMap( tableRowProperties );
+ OUString sRedlineType;
+ if( !(aPropMap.getValue("RedlineType") >>= sRedlineType) )
+ {
+ throw beans::UnknownPropertyException("No redline type property: ", getXWeak() );
+ }
+
+ // Create a 'Table Row Redline' object
+ SwUnoCursorHelper::makeTableRowRedline( *pLn, sRedlineType, tableRowProperties);
+
+ }
+ else
+ {
+ const SfxItemPropertyMapEntry* pEntry =
+ m_pPropSet->getPropertyMap().getByName(rPropertyName);
+ SwDoc* pDoc = pFormat->GetDoc();
+ if (!pEntry)
+ throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
+ if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
+ throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() );
+
+ switch(pEntry->nWID)
+ {
+ case FN_UNO_ROW_HEIGHT:
+ case FN_UNO_ROW_AUTO_HEIGHT:
+ {
+ SwFormatFrameSize aFrameSize(pLn->GetFrameFormat()->GetFrameSize());
+ if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID)
+ {
+ bool bSet = *o3tl::doAccess<bool>(aValue);
+ aFrameSize.SetHeightSizeType(bSet ? SwFrameSize::Variable : SwFrameSize::Fixed);
+ }
+ else
+ {
+ sal_Int32 nHeight = 0;
+ aValue >>= nHeight;
+ Size aSz(aFrameSize.GetSize());
+ aSz.setHeight( o3tl::toTwips(nHeight, o3tl::Length::mm100) );
+ aFrameSize.SetSize(aSz);
+ }
+ pDoc->SetAttr(aFrameSize, *pLn->ClaimFrameFormat());
+ }
+ break;
+
+ case FN_UNO_TABLE_COLUMN_SEPARATORS:
+ {
+ UnoActionContext aContext(pDoc);
+ SwTable* pTable2 = SwTable::FindTable( pFormat );
+ lcl_SetTableSeparators(aValue, pTable2, m_pLine->GetTabBoxes()[0], true, pDoc);
+ }
+ break;
+
+ default:
+ {
+ SwFrameFormat* pLnFormat = pLn->ClaimFrameFormat();
+ SwAttrSet aSet(pLnFormat->GetAttrSet());
+ m_pPropSet->setPropertyValue(*pEntry, aValue, aSet);
+ pDoc->SetAttr(aSet, *pLnFormat);
+ }
+ }
+ }
+}
+
+uno::Any SwXTextTableRow::getPropertyValue(const OUString& rPropertyName)
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ SwTableLine* pLn = SwXTextTableRow::FindLine(pTable, m_pLine);
+ if(pLn)
+ {
+ const SfxItemPropertyMapEntry* pEntry =
+ m_pPropSet->getPropertyMap().getByName(rPropertyName);
+ if (!pEntry)
+ throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
+
+ switch(pEntry->nWID)
+ {
+ case FN_UNO_ROW_HEIGHT:
+ case FN_UNO_ROW_AUTO_HEIGHT:
+ {
+ const SwFormatFrameSize& rSize = pLn->GetFrameFormat()->GetFrameSize();
+ if(FN_UNO_ROW_AUTO_HEIGHT== pEntry->nWID)
+ {
+ aRet <<= SwFrameSize::Variable == rSize.GetHeightSizeType();
+ }
+ else
+ aRet <<= static_cast<sal_Int32>(convertTwipToMm100(rSize.GetSize().Height()));
+ }
+ break;
+
+ case FN_UNO_TABLE_COLUMN_SEPARATORS:
+ {
+ lcl_GetTableSeparators(aRet, pTable, m_pLine->GetTabBoxes()[0], true);
+ }
+ break;
+
+ default:
+ {
+ const SwAttrSet& rSet = pLn->GetFrameFormat()->GetAttrSet();
+ m_pPropSet->getPropertyValue(*pEntry, rSet, aRet);
+ }
+ }
+ }
+ return aRet;
+}
+
+void SwXTextTableRow::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXTextTableRow::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXTextTableRow::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXTextTableRow::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXTextTableRow::Notify(const SfxHint& rHint)
+{
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pFormat = nullptr;
+ } else if(auto pFindHint = dynamic_cast<const FindUnoInstanceHint<SwTableLine, SwXTextTableRow>*>(&rHint))
+ {
+ if(!pFindHint->m_pCore && pFindHint->m_pCore == m_pLine)
+ pFindHint->m_pResult = this;
+ }
+}
+
+SwTableLine* SwXTextTableRow::FindLine(SwTable* pTable, SwTableLine const * pLine)
+{
+ for(const auto& pCurrentLine : pTable->GetTabLines())
+ if(pCurrentLine == pLine)
+ return pCurrentLine;
+ return nullptr;
+}
+
+// SwXTextTableCursor
+
+OUString SwXTextTableCursor::getImplementationName()
+ { return "SwXTextTableCursor"; }
+
+sal_Bool SwXTextTableCursor::supportsService(const OUString& rServiceName)
+ { return cppu::supportsService(this, rServiceName); }
+
+void SwXTextTableCursor::release() noexcept
+{
+ SolarMutexGuard aGuard;
+ SwXTextTableCursor_Base::release();
+}
+
+const SwPaM* SwXTextTableCursor::GetPaM() const { return &GetCursor(); }
+SwPaM* SwXTextTableCursor::GetPaM() { return &GetCursor(); }
+const SwDoc* SwXTextTableCursor::GetDoc() const { return GetFrameFormat()->GetDoc(); }
+SwDoc* SwXTextTableCursor::GetDoc() { return GetFrameFormat()->GetDoc(); }
+const SwUnoCursor& SwXTextTableCursor::GetCursor() const { return *m_pUnoCursor; }
+SwUnoCursor& SwXTextTableCursor::GetCursor() { return *m_pUnoCursor; }
+
+uno::Sequence<OUString> SwXTextTableCursor::getSupportedServiceNames()
+ { return {"com.sun.star.text.TextTableCursor"}; }
+
+SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat* pFrameFormat, SwTableBox const* pBox)
+ : m_pFrameFormat(pFrameFormat)
+ , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
+{
+ StartListening(m_pFrameFormat->GetNotifier());
+ SwDoc* pDoc = m_pFrameFormat->GetDoc();
+ const SwStartNode* pSttNd = pBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ m_pUnoCursor = pDoc->CreateUnoCursor(aPos, true);
+ m_pUnoCursor->Move( fnMoveForward, GoInNode );
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor);
+ rTableCursor.MakeBoxSels();
+}
+
+SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat& rTableFormat, const SwTableCursor* pTableSelection)
+ : m_pFrameFormat(&rTableFormat)
+ , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
+{
+ StartListening(m_pFrameFormat->GetNotifier());
+ m_pUnoCursor = pTableSelection->GetDoc().CreateUnoCursor(*pTableSelection->GetPoint(), true);
+ if(pTableSelection->HasMark())
+ {
+ m_pUnoCursor->SetMark();
+ *m_pUnoCursor->GetMark() = *pTableSelection->GetMark();
+ }
+ const SwSelBoxes& rBoxes = pTableSelection->GetSelectedBoxes();
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pUnoCursor);
+ for(auto pBox : rBoxes)
+ rTableCursor.InsertBox(*pBox);
+ rTableCursor.MakeBoxSels();
+}
+
+OUString SwXTextTableCursor::getRangeName()
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ SwUnoTableCursor* pTableCursor = dynamic_cast<SwUnoTableCursor*>(&rUnoCursor);
+ //!! see also SwChartDataSequence::getSourceRangeRepresentation
+ if(!pTableCursor)
+ return OUString();
+ pTableCursor->MakeBoxSels();
+ const SwStartNode* pNode = pTableCursor->GetPoint()->GetNode().FindTableBoxStartNode();
+ const SwTable* pTable = SwTable::FindTable(GetFrameFormat());
+ const SwTableBox* pEndBox = pTable->GetTableBox(pNode->GetIndex());
+ if(pTableCursor->HasMark())
+ {
+ pNode = pTableCursor->GetMark()->GetNode().FindTableBoxStartNode();
+ const SwTableBox* pStartBox = pTable->GetTableBox(pNode->GetIndex());
+ if(pEndBox != pStartBox)
+ {
+ // need to switch start and end?
+ if(*pTableCursor->GetPoint() < *pTableCursor->GetMark())
+ std::swap(pStartBox, pEndBox);
+ return pStartBox->GetName() + ":" + pEndBox->GetName();
+ }
+ }
+ return pEndBox->GetName();
+}
+
+sal_Bool SwXTextTableCursor::gotoCellByName(const OUString& sCellName, sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ lcl_CursorSelect(rTableCursor, bExpand);
+ return rTableCursor.GotoTableBox(sCellName);
+}
+
+sal_Bool SwXTextTableCursor::goLeft(sal_Int16 Count, sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ lcl_CursorSelect(rTableCursor, bExpand);
+ return rTableCursor.Left(Count);
+}
+
+sal_Bool SwXTextTableCursor::goRight(sal_Int16 Count, sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ lcl_CursorSelect(rTableCursor, bExpand);
+ return rTableCursor.Right(Count);
+}
+
+sal_Bool SwXTextTableCursor::goUp(sal_Int16 Count, sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ lcl_CursorSelect(rTableCursor, bExpand);
+ return rTableCursor.UpDown(true, Count, nullptr, 0,
+ *rUnoCursor.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout());
+}
+
+sal_Bool SwXTextTableCursor::goDown(sal_Int16 Count, sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ lcl_CursorSelect(rTableCursor, bExpand);
+ return rTableCursor.UpDown(false, Count, nullptr, 0,
+ *rUnoCursor.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout());
+}
+
+void SwXTextTableCursor::gotoStart(sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ lcl_CursorSelect(rTableCursor, bExpand);
+ rTableCursor.MoveTable(GotoCurrTable, fnTableStart);
+}
+
+void SwXTextTableCursor::gotoEnd(sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ lcl_CursorSelect(rTableCursor, bExpand);
+ rTableCursor.MoveTable(GotoCurrTable, fnTableEnd);
+}
+
+sal_Bool SwXTextTableCursor::mergeRange()
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ {
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rTableCursor);
+ }
+ rTableCursor.MakeBoxSels();
+ bool bResult;
+ {
+ UnoActionContext aContext(&rUnoCursor.GetDoc());
+ bResult = TableMergeErr::Ok == rTableCursor.GetDoc().MergeTable(rTableCursor);
+ }
+ if(bResult)
+ {
+ size_t nCount = rTableCursor.GetSelectedBoxesCount();
+ while (nCount--)
+ rTableCursor.DeleteBox(nCount);
+ }
+ rTableCursor.MakeBoxSels();
+ return bResult;
+}
+
+sal_Bool SwXTextTableCursor::splitRange(sal_Int16 Count, sal_Bool Horizontal)
+{
+ SolarMutexGuard aGuard;
+ if (Count <= 0)
+ throw uno::RuntimeException("Illegal first argument: needs to be > 0", getXWeak());
+ SwUnoCursor& rUnoCursor = GetCursor();
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ {
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rTableCursor);
+ }
+ rTableCursor.MakeBoxSels();
+ bool bResult;
+ {
+ UnoActionContext aContext(&rUnoCursor.GetDoc());
+ bResult = rTableCursor.GetDoc().SplitTable(rTableCursor.GetSelectedBoxes(), !Horizontal, Count);
+ }
+ rTableCursor.MakeBoxSels();
+ return bResult;
+}
+
+uno::Reference< beans::XPropertySetInfo > SwXTextTableCursor::getPropertySetInfo()
+{
+ static uno::Reference< beans::XPropertySetInfo > xRef = m_pPropSet->getPropertySetInfo();
+ return xRef;
+}
+
+void SwXTextTableCursor::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
+ if(!pEntry)
+ throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak());
+ if(pEntry->nFlags & beans::PropertyAttribute::READONLY)
+ throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak());
+ {
+ auto pSttNode = rUnoCursor.GetPointNode().StartOfSectionNode();
+ const SwTableNode* pTableNode = pSttNode->FindTableNode();
+ lcl_FormatTable(pTableNode->GetTable().GetFrameFormat());
+ }
+ auto& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ rTableCursor.MakeBoxSels();
+ SwDoc& rDoc = rUnoCursor.GetDoc();
+ switch(pEntry->nWID)
+ {
+ case FN_UNO_TABLE_CELL_BACKGROUND:
+ {
+ std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
+ SwDoc::GetBoxAttr(rUnoCursor, aBrush);
+ aBrush->PutValue(aValue, pEntry->nMemberId);
+ rDoc.SetBoxAttr(rUnoCursor, *aBrush);
+
+ }
+ break;
+ case RES_BOXATR_FORMAT:
+ {
+ SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT);
+ aNumberFormat.PutValue(aValue, 0);
+ rDoc.SetBoxAttr(rUnoCursor, aNumberFormat);
+ }
+ break;
+ case FN_UNO_PARA_STYLE:
+ SwUnoCursorHelper::SetTextFormatColl(aValue, rUnoCursor);
+ break;
+ default:
+ {
+ SfxItemSet aItemSet(rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID);
+ SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(),
+ aItemSet);
+
+ if (!SwUnoCursorHelper::SetCursorPropertyValue(
+ *pEntry, aValue, rTableCursor.GetSelRing(), aItemSet))
+ {
+ m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet);
+ }
+ SwUnoCursorHelper::SetCursorAttr(rTableCursor.GetSelRing(),
+ aItemSet, SetAttrMode::DEFAULT, true);
+ }
+ }
+}
+
+uno::Any SwXTextTableCursor::getPropertyValue(const OUString& rPropertyName)
+{
+ SolarMutexGuard aGuard;
+ SwUnoCursor& rUnoCursor = GetCursor();
+ {
+ auto pSttNode = rUnoCursor.GetPointNode().StartOfSectionNode();
+ const SwTableNode* pTableNode = pSttNode->FindTableNode();
+ lcl_FormatTable(pTableNode->GetTable().GetFrameFormat());
+ }
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(rUnoCursor);
+ auto pEntry(m_pPropSet->getPropertyMap().getByName(rPropertyName));
+ if(!pEntry)
+ throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak());
+ rTableCursor.MakeBoxSels();
+ uno::Any aResult;
+ switch(pEntry->nWID)
+ {
+ case FN_UNO_TABLE_CELL_BACKGROUND:
+ {
+ std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
+ if (SwDoc::GetBoxAttr(rUnoCursor, aBrush))
+ aBrush->QueryValue(aResult, pEntry->nMemberId);
+ }
+ break;
+ case RES_BOXATR_FORMAT:
+ // TODO: GetAttr for table selections in a Doc is missing
+ throw uno::RuntimeException("Unknown property: " + rPropertyName, getXWeak());
+ break;
+ case FN_UNO_PARA_STYLE:
+ {
+ auto pFormat(SwUnoCursorHelper::GetCurTextFormatColl(rUnoCursor, false));
+ if(pFormat)
+ aResult <<= pFormat->GetName();
+ }
+ break;
+ default:
+ {
+ SfxItemSetFixed
+ <RES_CHRATR_BEGIN, RES_FRMATR_END-1,
+ RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER>
+ aSet(rTableCursor.GetDoc().GetAttrPool());
+ SwUnoCursorHelper::GetCursorAttr(rTableCursor.GetSelRing(), aSet);
+ m_pPropSet->getPropertyValue(*pEntry, aSet, aResult);
+ }
+ }
+ return aResult;
+}
+
+void SwXTextTableCursor::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXTextTableCursor::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXTextTableCursor::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXTextTableCursor::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("not implemented", getXWeak()); };
+
+void SwXTextTableCursor::Notify( const SfxHint& rHint )
+{
+ if(rHint.GetId() == SfxHintId::Dying)
+ m_pFrameFormat = nullptr;
+}
+
+
+// SwXTextTable ===========================================================
+
+namespace {
+
+class SwTableProperties_Impl
+{
+ SwUnoCursorHelper::SwAnyMapHelper m_aAnyMap;
+
+public:
+ SwTableProperties_Impl();
+
+ void SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& aVal);
+ bool GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny);
+ void AddItemToSet(SfxItemSet& rSet, std::function<std::unique_ptr<SfxPoolItem>()> aItemFactory,
+ sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips = false);
+ void ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc);
+};
+
+}
+
+SwTableProperties_Impl::SwTableProperties_Impl()
+ { }
+
+void SwTableProperties_Impl::SetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rVal)
+ {
+ m_aAnyMap.SetValue(nWhichId, nMemberId, rVal);
+ }
+
+bool SwTableProperties_Impl::GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& rpAny )
+ {
+ return m_aAnyMap.FillValue(nWhichId, nMemberId, rpAny);
+ }
+
+void SwTableProperties_Impl::AddItemToSet(SfxItemSet& rSet,
+ std::function<std::unique_ptr<SfxPoolItem>()> aItemFactory,
+ sal_uInt16 nWhich, std::initializer_list<sal_uInt16> vMember, bool bAddTwips)
+{
+ std::vector< std::pair<sal_uInt16, const uno::Any* > > vMemberAndAny;
+ for(sal_uInt16 nMember : vMember)
+ {
+ const uno::Any* pAny = nullptr;
+ GetProperty(nWhich, nMember, pAny);
+ if(pAny)
+ vMemberAndAny.emplace_back(nMember, pAny);
+ }
+ if(!vMemberAndAny.empty())
+ {
+ std::unique_ptr<SfxPoolItem> aItem(aItemFactory());
+ for(const auto& aMemberAndAny : vMemberAndAny)
+ aItem->PutValue(*aMemberAndAny.second, aMemberAndAny.first | (bAddTwips ? CONVERT_TWIPS : 0) );
+ rSet.Put(std::move(aItem));
+ }
+}
+void SwTableProperties_Impl::ApplyTableAttr(const SwTable& rTable, SwDoc& rDoc)
+{
+ SfxItemSetFixed<
+ RES_FRM_SIZE, RES_BREAK,
+ RES_HORI_ORIENT, RES_HORI_ORIENT,
+ RES_BACKGROUND, RES_BACKGROUND,
+ RES_SHADOW, RES_SHADOW,
+ RES_KEEP, RES_KEEP,
+ RES_LAYOUT_SPLIT, RES_LAYOUT_SPLIT>
+ aSet(rDoc.GetAttrPool());
+ const uno::Any* pRepHead;
+ const SwFrameFormat &rFrameFormat = *rTable.GetFrameFormat();
+ if(GetProperty(FN_TABLE_HEADLINE_REPEAT, 0xff, pRepHead ))
+ {
+ bool bVal(pRepHead->get<bool>());
+ const_cast<SwTable&>(rTable).SetRowsToRepeat( bVal ? 1 : 0 ); // TODO: MULTIHEADER
+ }
+
+ AddItemToSet(aSet, [&rFrameFormat]() { return rFrameFormat.makeBackgroundBrushItem(); }, RES_BACKGROUND, {
+ MID_BACK_COLOR,
+ MID_GRAPHIC_TRANSPARENT,
+ MID_GRAPHIC_POSITION,
+ MID_GRAPHIC,
+ MID_GRAPHIC_FILTER });
+
+ bool bPutBreak = true;
+ const uno::Any* pPage;
+ if(GetProperty(FN_UNO_PAGE_STYLE, 0, pPage) || GetProperty(RES_PAGEDESC, 0xff, pPage))
+ {
+ OUString sPageStyle = pPage->get<OUString>();
+ if(!sPageStyle.isEmpty())
+ {
+ SwStyleNameMapper::FillUIName(sPageStyle, sPageStyle, SwGetPoolIdFromName::PageDesc);
+ const SwPageDesc* pDesc = SwPageDesc::GetByName(rDoc, sPageStyle);
+ if(pDesc)
+ {
+ SwFormatPageDesc aDesc(pDesc);
+ const uno::Any* pPgNo;
+ if(GetProperty(RES_PAGEDESC, MID_PAGEDESC_PAGENUMOFFSET, pPgNo))
+ {
+ aDesc.SetNumOffset(pPgNo->get<sal_Int16>());
+ }
+ aSet.Put(aDesc);
+ bPutBreak = false;
+ }
+
+ }
+ }
+
+ if(bPutBreak)
+ AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetBreak().Clone()); }, RES_BREAK, {0});
+ AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetShadow().Clone()); }, RES_SHADOW, {0}, true);
+ AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetKeep().Clone()); }, RES_KEEP, {0});
+ AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetHoriOrient().Clone()); }, RES_HORI_ORIENT, {MID_HORIORIENT_ORIENT}, true);
+
+ const uno::Any* pSzRel(nullptr);
+ GetProperty(FN_TABLE_IS_RELATIVE_WIDTH, 0xff, pSzRel);
+ const uno::Any* pRelWidth(nullptr);
+ GetProperty(FN_TABLE_RELATIVE_WIDTH, 0xff, pRelWidth);
+ const uno::Any* pWidth(nullptr);
+ GetProperty(FN_TABLE_WIDTH, 0xff, pWidth);
+
+ bool bPutSize = pWidth != nullptr;
+ SwFormatFrameSize aSz(SwFrameSize::Variable);
+ if(pWidth)
+ {
+ aSz.PutValue(*pWidth, MID_FRMSIZE_WIDTH);
+ bPutSize = true;
+ }
+ if(pSzRel && pSzRel->get<bool>() && pRelWidth)
+ {
+ aSz.PutValue(*pRelWidth, MID_FRMSIZE_REL_WIDTH|CONVERT_TWIPS);
+ bPutSize = true;
+ }
+ if(bPutSize)
+ {
+ if(!aSz.GetWidth())
+ aSz.SetWidth(MINLAY);
+ aSet.Put(aSz);
+ }
+ AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetLRSpace().Clone()); }, RES_LR_SPACE, {
+ MID_L_MARGIN|CONVERT_TWIPS,
+ MID_R_MARGIN|CONVERT_TWIPS });
+ AddItemToSet(aSet, [&rFrameFormat]() { return std::unique_ptr<SfxPoolItem>(rFrameFormat.GetULSpace().Clone()); }, RES_UL_SPACE, {
+ MID_UP_MARGIN|CONVERT_TWIPS,
+ MID_LO_MARGIN|CONVERT_TWIPS });
+ const::uno::Any* pSplit(nullptr);
+ if(GetProperty(RES_LAYOUT_SPLIT, 0, pSplit))
+ {
+ SwFormatLayoutSplit aSp(pSplit->get<bool>());
+ aSet.Put(aSp);
+ }
+ if(aSet.Count())
+ {
+ rDoc.SetAttr(aSet, *rTable.GetFrameFormat());
+ }
+}
+
+class SwXTextTable::Impl
+ : public SvtListener
+{
+private:
+ SwFrameFormat* m_pFrameFormat;
+
+public:
+ unotools::WeakReference<SwXTextTable> m_wThis;
+ std::mutex m_Mutex; // just for OInterfaceContainerHelper4
+ ::comphelper::OInterfaceContainerHelper4<css::lang::XEventListener> m_EventListeners;
+ ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> m_ChartListeners;
+
+ const SfxItemPropertySet * m_pPropSet;
+
+ css::uno::WeakReference<css::table::XTableRows> m_xRows;
+ css::uno::WeakReference<css::table::XTableColumns> m_xColumns;
+
+ bool m_bFirstRowAsLabel;
+ bool m_bFirstColumnAsLabel;
+
+ // Descriptor-interface
+ std::unique_ptr<SwTableProperties_Impl> m_pTableProps;
+ OUString m_sTableName;
+ unsigned short m_nRows;
+ unsigned short m_nColumns;
+
+ explicit Impl(SwFrameFormat* const pFrameFormat)
+ : m_pFrameFormat(pFrameFormat)
+ , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE))
+ , m_bFirstRowAsLabel(false)
+ , m_bFirstColumnAsLabel(false)
+ , m_pTableProps(pFrameFormat ? nullptr : new SwTableProperties_Impl)
+ , m_nRows(pFrameFormat ? 0 : 2)
+ , m_nColumns(pFrameFormat ? 0 : 2)
+ {
+ if(m_pFrameFormat)
+ StartListening(m_pFrameFormat->GetNotifier());
+ }
+
+ SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
+ void SetFrameFormat(SwFrameFormat& rFrameFormat)
+ {
+ EndListeningAll();
+ m_pFrameFormat = &rFrameFormat;
+ StartListening(m_pFrameFormat->GetNotifier());
+ }
+
+ bool IsDescriptor() const { return m_pTableProps != nullptr; }
+
+ // note: lock mutex before calling this to avoid concurrent update
+ static std::pair<sal_uInt16, sal_uInt16> ThrowIfComplex(SwXTextTable &rThis)
+ {
+ sal_uInt16 const nRowCount(rThis.m_pImpl->GetRowCount());
+ sal_uInt16 const nColCount(rThis.m_pImpl->GetColumnCount());
+ if (!nRowCount || !nColCount)
+ {
+ throw uno::RuntimeException("Table too complex", rThis.getXWeak());
+ }
+ return std::make_pair(nRowCount, nColCount);
+ }
+
+ sal_uInt16 GetRowCount();
+ sal_uInt16 GetColumnCount();
+
+ virtual void Notify(const SfxHint&) override;
+
+};
+
+SwXTextTable::SwXTextTable()
+ : m_pImpl(new Impl(nullptr))
+{
+}
+
+SwXTextTable::SwXTextTable(SwFrameFormat& rFrameFormat)
+ : m_pImpl(new Impl(&rFrameFormat))
+{
+}
+
+SwXTextTable::~SwXTextTable()
+{
+}
+
+rtl::Reference<SwXTextTable> SwXTextTable::CreateXTextTable(SwFrameFormat* const pFrameFormat)
+{
+ rtl::Reference<SwXTextTable> xTable;
+ if(pFrameFormat)
+ xTable = dynamic_cast<SwXTextTable*>(pFrameFormat->GetXObject().get().get()); // cached?
+ if(xTable.is())
+ return xTable;
+ xTable = pFrameFormat ? new SwXTextTable(*pFrameFormat) : new SwXTextTable();
+ if(pFrameFormat)
+ pFrameFormat->SetXObject(xTable->getXWeak());
+ // need a permanent Reference to initialize m_wThis
+ xTable->m_pImpl->m_wThis = xTable.get();
+ return xTable;
+}
+
+SwFrameFormat* SwXTextTable::GetFrameFormat()
+{
+ return m_pImpl->GetFrameFormat();
+}
+
+void SwXTextTable::initialize(sal_Int32 nR, sal_Int32 nC)
+{
+ if (!m_pImpl->IsDescriptor() || nR <= 0 || nC <= 0 || nR >= SAL_MAX_UINT16 || nC >= SAL_MAX_UINT16)
+ throw uno::RuntimeException();
+ m_pImpl->m_nRows = o3tl::narrowing<sal_uInt16>(nR);
+ m_pImpl->m_nColumns = o3tl::narrowing<sal_uInt16>(nC);
+}
+
+uno::Reference<table::XTableRows> SAL_CALL SwXTextTable::getRows()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XTableRows> xResult(m_pImpl->m_xRows);
+ if(xResult.is())
+ return xResult;
+ if(SwFrameFormat* pFormat = GetFrameFormat())
+ m_pImpl->m_xRows = xResult = new SwXTableRows(*pFormat);
+ if(!xResult.is())
+ throw uno::RuntimeException();
+ return xResult;
+}
+
+uno::Reference<table::XTableColumns> SAL_CALL SwXTextTable::getColumns()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XTableColumns> xResult(m_pImpl->m_xColumns);
+ if(xResult.is())
+ return xResult;
+ if(SwFrameFormat* pFormat = GetFrameFormat())
+ m_pImpl->m_xColumns = xResult = new SwXTableColumns(*pFormat);
+ if(!xResult.is())
+ throw uno::RuntimeException();
+ return xResult;
+}
+
+uno::Reference<table::XCell> SwXTextTable::getCellByName(const OUString& sCellName)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
+ SwTable* pTable = SwTable::FindTable(pFormat);
+ SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
+ if(!pBox)
+ return nullptr;
+ return SwXCell::CreateXCell(pFormat, pBox);
+}
+
+uno::Sequence<OUString> SwXTextTable::getCellNames()
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat(GetFrameFormat());
+ if(!pFormat)
+ return {};
+ SwTable* pTable = SwTable::FindTable(pFormat);
+ // exists at the table and at all boxes
+ SwTableLines& rTableLines = pTable->GetTabLines();
+ std::vector<OUString> aAllNames;
+ lcl_InspectLines(rTableLines, aAllNames);
+ return comphelper::containerToSequence(aAllNames);
+}
+
+uno::Reference<text::XTextTableCursor> SwXTextTable::createCursorByCellName(const OUString& sCellName)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
+ SwTable* pTable = SwTable::FindTable(pFormat);
+ SwTableBox* pBox = const_cast<SwTableBox*>(pTable->GetTableBox(sCellName));
+ if(!pBox || pBox->getRowSpan() == 0)
+ throw uno::RuntimeException();
+ return new SwXTextTableCursor(pFormat, pBox);
+}
+
+void SAL_CALL
+SwXTextTable::attach(const uno::Reference<text::XTextRange> & xTextRange)
+{
+ SolarMutexGuard aGuard;
+
+ // attach() must only be called once
+ if (!m_pImpl->IsDescriptor()) /* already attached ? */
+ throw uno::RuntimeException("SwXTextTable: already attached to range.", getXWeak());
+
+ SwXTextRange* pRange(dynamic_cast<SwXTextRange*>(xTextRange.get()));
+ OTextCursorHelper* pCursor(dynamic_cast<OTextCursorHelper*>(xTextRange.get()));
+ SwDoc* pDoc = pRange ? &pRange->GetDoc() : pCursor ? pCursor->GetDoc() : nullptr;
+ if (!pDoc || !m_pImpl->m_nRows || !m_pImpl->m_nColumns)
+ throw lang::IllegalArgumentException();
+ SwUnoInternalPaM aPam(*pDoc);
+ // this now needs to return TRUE
+ ::sw::XTextRangeToSwPaM(aPam, xTextRange);
+ {
+ UnoActionContext aCont(pDoc);
+
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
+ const SwTable* pTable(nullptr);
+ if( 0 != aPam.Start()->GetContentIndex() )
+ {
+ pDoc->getIDocumentContentOperations().SplitNode(*aPam.Start(), false);
+ }
+ //TODO: if it is the last paragraph than add another one!
+ if(aPam.HasMark())
+ {
+ pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam);
+ aPam.DeleteMark();
+ }
+
+ OUString tableName;
+ if (const::uno::Any* pName;
+ m_pImpl->m_pTableProps->GetProperty(FN_UNO_TABLE_NAME, 0, pName))
+ {
+ tableName = pName->get<OUString>();
+ }
+ else if (!m_pImpl->m_sTableName.isEmpty())
+ {
+ sal_uInt16 nIndex = 1;
+ tableName = m_pImpl->m_sTableName;
+ while (pDoc->FindTableFormatByName(tableName, true) && nIndex < USHRT_MAX)
+ tableName = m_pImpl->m_sTableName + OUString::number(nIndex++);
+ }
+
+ pTable = pDoc->InsertTable(SwInsertTableOptions( SwInsertTableFlags::Headline | SwInsertTableFlags::DefaultBorder | SwInsertTableFlags::SplitLayout, 0 ),
+ *aPam.GetPoint(),
+ m_pImpl->m_nRows,
+ m_pImpl->m_nColumns,
+ text::HoriOrientation::FULL,
+ nullptr, nullptr, false, true,
+ tableName);
+ if(pTable)
+ {
+ // here, the properties of the descriptor need to be analyzed
+ m_pImpl->m_pTableProps->ApplyTableAttr(*pTable, *pDoc);
+ SwFrameFormat* pTableFormat(pTable->GetFrameFormat());
+ lcl_FormatTable(pTableFormat);
+
+ m_pImpl->SetFrameFormat(*pTableFormat);
+
+ m_pImpl->m_pTableProps.reset();
+ }
+ pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
+ }
+}
+
+uno::Reference<text::XTextRange> SwXTextTable::getAnchor()
+{
+ SolarMutexGuard aGuard;
+ SwTableFormat *const pFormat = static_cast<SwTableFormat*>(
+ lcl_EnsureCoreConnected(GetFrameFormat(), this));
+ return new SwXTextRange(*pFormat);
+}
+
+void SwXTextTable::dispose()
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
+ SwTable* pTable = SwTable::FindTable(pFormat);
+ SwSelBoxes aSelBoxes;
+ for(auto& rBox : pTable->GetTabSortBoxes() )
+ aSelBoxes.insert(rBox);
+ pFormat->GetDoc()->DeleteRowCol(aSelBoxes, SwDoc::RowColMode::DeleteProtected);
+}
+
+void SAL_CALL SwXTextTable::addEventListener(
+ const uno::Reference<lang::XEventListener> & xListener)
+{
+ // no need to lock here as m_pImpl is const and container threadsafe
+ std::unique_lock aGuard(m_pImpl->m_Mutex);
+ m_pImpl->m_EventListeners.addInterface(aGuard, xListener);
+}
+
+void SAL_CALL SwXTextTable::removeEventListener(
+ const uno::Reference< lang::XEventListener > & xListener)
+{
+ // no need to lock here as m_pImpl is const and container threadsafe
+ std::unique_lock aGuard(m_pImpl->m_Mutex);
+ m_pImpl->m_EventListeners.removeInterface(aGuard, xListener);
+}
+
+uno::Reference<table::XCell> SwXTextTable::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat(GetFrameFormat());
+ // sheet is unimportant
+ if(nColumn >= 0 && nRow >= 0 && pFormat)
+ {
+ auto pXCell = lcl_CreateXCell(pFormat, nColumn, nRow);
+ if(pXCell)
+ return pXCell;
+ }
+ throw lang::IndexOutOfBoundsException();
+}
+
+namespace {
+
+rtl::Reference<SwXCellRange> GetRangeByName(
+ SwFrameFormat* pFormat, SwTable const * pTable,
+ const OUString& rTLName, const OUString& rBRName,
+ SwRangeDescriptor const & rDesc)
+{
+ const SwTableBox* pTLBox = pTable->GetTableBox(rTLName);
+ if(!pTLBox)
+ return nullptr;
+ const SwStartNode* pSttNd = pTLBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ // set cursor to the upper-left cell of the range
+ auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true));
+ pUnoCursor->Move(fnMoveForward, GoInNode);
+ pUnoCursor->SetRemainInSection(false);
+ const SwTableBox* pBRBox(pTable->GetTableBox(rBRName));
+ if(!pBRBox)
+ return nullptr;
+ pUnoCursor->SetMark();
+ pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
+ pUnoCursor->Move( fnMoveForward, GoInNode );
+ SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rCursor);
+ rCursor.MakeBoxSels();
+ // pUnoCursor will be provided and will not be deleted
+ return SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, rDesc);
+}
+
+} // namespace
+
+uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByPosition(sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat(GetFrameFormat());
+ if(pFormat &&
+ nLeft <= nRight && nTop <= nBottom &&
+ nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 )
+ {
+ SwTable* pTable = SwTable::FindTable(pFormat);
+ if(!pTable->IsTableComplex())
+ {
+ SwRangeDescriptor aDesc;
+ aDesc.nTop = nTop;
+ aDesc.nBottom = nBottom;
+ aDesc.nLeft = nLeft;
+ aDesc.nRight = nRight;
+ const OUString sTLName = sw_GetCellName(aDesc.nLeft, aDesc.nTop);
+ const OUString sBRName = sw_GetCellName(aDesc.nRight, aDesc.nBottom);
+ // please note that according to the 'if' statement at the begin
+ // sTLName:sBRName already denotes the normalized range string
+ return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc);
+ }
+ }
+ throw lang::IndexOutOfBoundsException();
+}
+
+uno::Reference<table::XCellRange> SwXTextTable::getCellRangeByName(const OUString& sRange)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
+ SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), this);
+ sal_Int32 nPos = 0;
+ const OUString sTLName(sRange.getToken(0, ':', nPos));
+ const OUString sBRName(sRange.getToken(0, ':', nPos));
+ if(sTLName.isEmpty() || sBRName.isEmpty())
+ throw uno::RuntimeException();
+ SwRangeDescriptor aDesc;
+ aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1;
+ SwXTextTable::GetCellPosition(sTLName, aDesc.nLeft, aDesc.nTop );
+ SwXTextTable::GetCellPosition(sBRName, aDesc.nRight, aDesc.nBottom );
+
+ // we should normalize the range now (e.g. A5:C1 will become A1:C5)
+ // since (depending on what is done later) it will be troublesome
+ // elsewhere when the cursor in the implementation does not
+ // point to the top-left and bottom-right cells
+ aDesc.Normalize();
+ return GetRangeByName(pFormat, pTable, sTLName, sBRName, aDesc);
+}
+
+uno::Sequence< uno::Sequence< uno::Any > > SAL_CALL SwXTextTable::getDataArray()
+{
+ SolarMutexGuard aGuard;
+ std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
+ uno::Reference<sheet::XCellRangeData> const xAllRange(
+ getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
+ uno::UNO_QUERY_THROW);
+ return xAllRange->getDataArray();
+}
+
+void SAL_CALL SwXTextTable::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray)
+{
+ SolarMutexGuard aGuard;
+ std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
+ uno::Reference<sheet::XCellRangeData> const xAllRange(
+ getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
+ uno::UNO_QUERY_THROW);
+ return xAllRange->setDataArray(rArray);
+}
+
+uno::Sequence< uno::Sequence< double > > SwXTextTable::getData()
+{
+ SolarMutexGuard aGuard;
+ std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
+ uno::Reference<chart::XChartDataArray> const xAllRange(
+ getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
+ uno::UNO_QUERY_THROW);
+ static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
+ m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
+ return xAllRange->getData();
+}
+
+void SwXTextTable::setData(const uno::Sequence< uno::Sequence< double > >& rData)
+{
+ SolarMutexGuard aGuard;
+ std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
+ uno::Reference<chart::XChartDataArray> const xAllRange(
+ getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
+ uno::UNO_QUERY_THROW);
+ static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
+ m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
+ xAllRange->setData(rData);
+ // this is rather inconsistent: setData on XTextTable sends events, but e.g. CellRanges do not
+ std::unique_lock aGuard2(m_pImpl->m_Mutex);
+ lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
+}
+
+uno::Sequence<OUString> SwXTextTable::getRowDescriptions()
+{
+ SolarMutexGuard aGuard;
+ std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
+ uno::Reference<chart::XChartDataArray> const xAllRange(
+ getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
+ uno::UNO_QUERY_THROW);
+ static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
+ m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
+ return xAllRange->getRowDescriptions();
+}
+
+void SwXTextTable::setRowDescriptions(const uno::Sequence<OUString>& rRowDesc)
+{
+ SolarMutexGuard aGuard;
+ std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
+ uno::Reference<chart::XChartDataArray> const xAllRange(
+ getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
+ uno::UNO_QUERY_THROW);
+ static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
+ m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
+ xAllRange->setRowDescriptions(rRowDesc);
+}
+
+uno::Sequence<OUString> SwXTextTable::getColumnDescriptions()
+{
+ SolarMutexGuard aGuard;
+ std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
+ uno::Reference<chart::XChartDataArray> const xAllRange(
+ getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
+ uno::UNO_QUERY_THROW);
+ static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
+ m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
+ return xAllRange->getColumnDescriptions();
+}
+
+void SwXTextTable::setColumnDescriptions(const uno::Sequence<OUString>& rColumnDesc)
+{
+ SolarMutexGuard aGuard;
+ std::pair<sal_uInt16, sal_uInt16> const RowsAndColumns(SwXTextTable::Impl::ThrowIfComplex(*this));
+ uno::Reference<chart::XChartDataArray> const xAllRange(
+ getCellRangeByPosition(0, 0, RowsAndColumns.second-1, RowsAndColumns.first-1),
+ uno::UNO_QUERY_THROW);
+ static_cast<SwXCellRange*>(xAllRange.get())->SetLabels(
+ m_pImpl->m_bFirstRowAsLabel, m_pImpl->m_bFirstColumnAsLabel);
+ return xAllRange->setColumnDescriptions(rColumnDesc);
+}
+
+void SAL_CALL SwXTextTable::addChartDataChangeEventListener(
+ const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
+{
+ // no need to lock here as m_pImpl is const and container threadsafe
+ std::unique_lock aGuard(m_pImpl->m_Mutex);
+ m_pImpl->m_ChartListeners.addInterface(aGuard, xListener);
+}
+
+void SAL_CALL SwXTextTable::removeChartDataChangeEventListener(
+ const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
+{
+ // no need to lock here as m_pImpl is const and container threadsafe
+ std::unique_lock aGuard(m_pImpl->m_Mutex);
+ m_pImpl->m_ChartListeners.removeInterface(aGuard, xListener);
+}
+
+sal_Bool SwXTextTable::isNotANumber(double nNumber)
+{
+ // We use DBL_MIN because starcalc does (which uses it because chart
+ // wants it that way!)
+ return ( nNumber == DBL_MIN );
+}
+
+double SwXTextTable::getNotANumber()
+{
+ // We use DBL_MIN because starcalc does (which uses it because chart
+ // wants it that way!)
+ return DBL_MIN;
+}
+
+uno::Sequence< beans::PropertyValue > SwXTextTable::createSortDescriptor()
+{
+ SolarMutexGuard aGuard;
+
+ return SwUnoCursorHelper::CreateSortDescriptor(true);
+}
+
+void SwXTextTable::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
+{
+ SolarMutexGuard aGuard;
+ SwSortOptions aSortOpt;
+ SwFrameFormat* pFormat = GetFrameFormat();
+ if(!(pFormat &&
+ SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt)))
+ return;
+
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ SwSelBoxes aBoxes;
+ const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes();
+ for (size_t n = 0; n < rTBoxes.size(); ++n)
+ {
+ SwTableBox* pBox = rTBoxes[ n ];
+ aBoxes.insert( pBox );
+ }
+ UnoActionContext aContext( pFormat->GetDoc() );
+ pFormat->GetDoc()->SortTable(aBoxes, aSortOpt);
+}
+
+void SwXTextTable::autoFormat(const OUString& sAutoFormatName)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = lcl_EnsureCoreConnected(GetFrameFormat(), this);
+ SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFormat), this);
+ SwTableAutoFormatTable aAutoFormatTable;
+ aAutoFormatTable.Load();
+ for (size_t i = aAutoFormatTable.size(); i;)
+ if( sAutoFormatName == aAutoFormatTable[ --i ].GetName() )
+ {
+ SwSelBoxes aBoxes;
+ const SwTableSortBoxes& rTBoxes = pTable->GetTabSortBoxes();
+ for (size_t n = 0; n < rTBoxes.size(); ++n)
+ {
+ SwTableBox* pBox = rTBoxes[ n ];
+ aBoxes.insert( pBox );
+ }
+ UnoActionContext aContext( pFormat->GetDoc() );
+ pFormat->GetDoc()->SetTableAutoFormat( aBoxes, aAutoFormatTable[i] );
+ break;
+ }
+}
+
+uno::Reference< beans::XPropertySetInfo > SwXTextTable::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo();
+ return xRef;
+}
+
+void SwXTextTable::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = GetFrameFormat();
+ if(!aValue.hasValue())
+ throw lang::IllegalArgumentException();
+ const SfxItemPropertyMapEntry* pEntry =
+ m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
+ if( !pEntry )
+ throw lang::IllegalArgumentException();
+ if(pFormat)
+ {
+ if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
+ throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() );
+
+ if(0xBF == pEntry->nMemberId)
+ {
+ lcl_SetSpecialProperty(pFormat, pEntry, aValue);
+ }
+ else
+ {
+ switch(pEntry->nWID)
+ {
+ case FN_UNO_TABLE_NAME :
+ {
+ OUString sName;
+ aValue >>= sName;
+ setName( sName );
+ }
+ break;
+
+ case FN_UNO_RANGE_ROW_LABEL:
+ {
+ bool bTmp = *o3tl::doAccess<bool>(aValue);
+ if (m_pImpl->m_bFirstRowAsLabel != bTmp)
+ {
+ std::unique_lock aGuard2(m_pImpl->m_Mutex);
+ lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
+ m_pImpl->m_bFirstRowAsLabel = bTmp;
+ }
+ }
+ break;
+
+ case FN_UNO_RANGE_COL_LABEL:
+ {
+ bool bTmp = *o3tl::doAccess<bool>(aValue);
+ if (m_pImpl->m_bFirstColumnAsLabel != bTmp)
+ {
+ std::unique_lock aGuard2(m_pImpl->m_Mutex);
+ lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
+ m_pImpl->m_bFirstColumnAsLabel = bTmp;
+ }
+ }
+ break;
+
+ case FN_UNO_TABLE_BORDER:
+ case FN_UNO_TABLE_BORDER2:
+ {
+ table::TableBorder oldBorder;
+ table::TableBorder2 aBorder;
+ SvxBorderLine aTopLine;
+ SvxBorderLine aBottomLine;
+ SvxBorderLine aLeftLine;
+ SvxBorderLine aRightLine;
+ SvxBorderLine aHoriLine;
+ SvxBorderLine aVertLine;
+ if (aValue >>= oldBorder)
+ {
+ aBorder.IsTopLineValid = oldBorder.IsTopLineValid;
+ aBorder.IsBottomLineValid = oldBorder.IsBottomLineValid;
+ aBorder.IsLeftLineValid = oldBorder.IsLeftLineValid;
+ aBorder.IsRightLineValid = oldBorder.IsRightLineValid;
+ aBorder.IsHorizontalLineValid = oldBorder.IsHorizontalLineValid;
+ aBorder.IsVerticalLineValid = oldBorder.IsVerticalLineValid;
+ aBorder.Distance = oldBorder.Distance;
+ aBorder.IsDistanceValid = oldBorder.IsDistanceValid;
+ lcl_LineToSvxLine(
+ oldBorder.TopLine, aTopLine);
+ lcl_LineToSvxLine(
+ oldBorder.BottomLine, aBottomLine);
+ lcl_LineToSvxLine(
+ oldBorder.LeftLine, aLeftLine);
+ lcl_LineToSvxLine(
+ oldBorder.RightLine, aRightLine);
+ lcl_LineToSvxLine(
+ oldBorder.HorizontalLine, aHoriLine);
+ lcl_LineToSvxLine(
+ oldBorder.VerticalLine, aVertLine);
+ }
+ else if (aValue >>= aBorder)
+ {
+ SvxBoxItem::LineToSvxLine(
+ aBorder.TopLine, aTopLine, true);
+ SvxBoxItem::LineToSvxLine(
+ aBorder.BottomLine, aBottomLine, true);
+ SvxBoxItem::LineToSvxLine(
+ aBorder.LeftLine, aLeftLine, true);
+ SvxBoxItem::LineToSvxLine(
+ aBorder.RightLine, aRightLine, true);
+ SvxBoxItem::LineToSvxLine(
+ aBorder.HorizontalLine, aHoriLine, true);
+ SvxBoxItem::LineToSvxLine(
+ aBorder.VerticalLine, aVertLine, true);
+ }
+ else
+ {
+ break; // something else
+ }
+ SwDoc* pDoc = pFormat->GetDoc();
+ if(!lcl_FormatTable(pFormat))
+ break;
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ SwTableLines &rLines = pTable->GetTabLines();
+
+ const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true);
+ const SwStartNode* pSttNd = pTLBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ // set cursor to top left cell
+ auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true));
+ pUnoCursor->Move( fnMoveForward, GoInNode );
+ pUnoCursor->SetRemainInSection( false );
+
+ const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false);
+ pUnoCursor->SetMark();
+ pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
+ pUnoCursor->Move( fnMoveForward, GoInNode );
+ SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rCursor);
+ rCursor.MakeBoxSels();
+
+ SfxItemSetFixed<RES_BOX, RES_BOX,
+ SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
+ aSet(pDoc->GetAttrPool());
+
+ SvxBoxItem aBox( RES_BOX );
+ SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
+
+ aBox.SetLine(aTopLine.isEmpty() ? nullptr : &aTopLine, SvxBoxItemLine::TOP);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, aBorder.IsTopLineValid);
+
+ aBox.SetLine(aBottomLine.isEmpty() ? nullptr : &aBottomLine, SvxBoxItemLine::BOTTOM);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::BOTTOM, aBorder.IsBottomLineValid);
+
+ aBox.SetLine(aLeftLine.isEmpty() ? nullptr : &aLeftLine, SvxBoxItemLine::LEFT);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, aBorder.IsLeftLineValid);
+
+ aBox.SetLine(aRightLine.isEmpty() ? nullptr : &aRightLine, SvxBoxItemLine::RIGHT);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::RIGHT, aBorder.IsRightLineValid);
+
+ aBoxInfo.SetLine(aHoriLine.isEmpty() ? nullptr : &aHoriLine, SvxBoxInfoItemLine::HORI);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::HORI, aBorder.IsHorizontalLineValid);
+
+ aBoxInfo.SetLine(aVertLine.isEmpty() ? nullptr : &aVertLine, SvxBoxInfoItemLine::VERT);
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::VERT, aBorder.IsVerticalLineValid);
+
+ aBox.SetAllDistances(o3tl::toTwips(aBorder.Distance, o3tl::Length::mm100));
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::DISTANCE, aBorder.IsDistanceValid);
+
+ aSet.Put(aBox);
+ aSet.Put(aBoxInfo);
+
+ pDoc->SetTabBorders(rCursor, aSet);
+ }
+ break;
+
+ case FN_UNO_TABLE_BORDER_DISTANCES:
+ {
+ table::TableBorderDistances aTableBorderDistances;
+ if( !(aValue >>= aTableBorderDistances) ||
+ (!aTableBorderDistances.IsLeftDistanceValid &&
+ !aTableBorderDistances.IsRightDistanceValid &&
+ !aTableBorderDistances.IsTopDistanceValid &&
+ !aTableBorderDistances.IsBottomDistanceValid ))
+ break;
+
+ const sal_uInt16 nLeftDistance = o3tl::toTwips(aTableBorderDistances.LeftDistance, o3tl::Length::mm100);
+ const sal_uInt16 nRightDistance = o3tl::toTwips(aTableBorderDistances.RightDistance, o3tl::Length::mm100);
+ const sal_uInt16 nTopDistance = o3tl::toTwips(aTableBorderDistances.TopDistance, o3tl::Length::mm100);
+ const sal_uInt16 nBottomDistance = o3tl::toTwips(aTableBorderDistances.BottomDistance, o3tl::Length::mm100);
+ SwDoc* pDoc = pFormat->GetDoc();
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ SwTableLines &rLines = pTable->GetTabLines();
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr);
+ for(size_t i = 0; i < rLines.size(); ++i)
+ {
+ SwTableLine* pLine = rLines[i];
+ SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+ for(size_t k = 0; k < rBoxes.size(); ++k)
+ {
+ SwTableBox* pBox = rBoxes[k];
+ const SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
+ const SvxBoxItem& rBox = pBoxFormat->GetBox();
+ if(
+ (aTableBorderDistances.IsLeftDistanceValid && nLeftDistance != rBox.GetDistance( SvxBoxItemLine::LEFT )) ||
+ (aTableBorderDistances.IsRightDistanceValid && nRightDistance != rBox.GetDistance( SvxBoxItemLine::RIGHT )) ||
+ (aTableBorderDistances.IsTopDistanceValid && nTopDistance != rBox.GetDistance( SvxBoxItemLine::TOP )) ||
+ (aTableBorderDistances.IsBottomDistanceValid && nBottomDistance != rBox.GetDistance( SvxBoxItemLine::BOTTOM )))
+ {
+ SvxBoxItem aSetBox( rBox );
+ SwFrameFormat* pSetBoxFormat = pBox->ClaimFrameFormat();
+ if( aTableBorderDistances.IsLeftDistanceValid )
+ aSetBox.SetDistance( nLeftDistance, SvxBoxItemLine::LEFT );
+ if( aTableBorderDistances.IsRightDistanceValid )
+ aSetBox.SetDistance( nRightDistance, SvxBoxItemLine::RIGHT );
+ if( aTableBorderDistances.IsTopDistanceValid )
+ aSetBox.SetDistance( nTopDistance, SvxBoxItemLine::TOP );
+ if( aTableBorderDistances.IsBottomDistanceValid )
+ aSetBox.SetDistance( nBottomDistance, SvxBoxItemLine::BOTTOM );
+ pDoc->SetAttr( aSetBox, *pSetBoxFormat );
+ }
+ }
+ }
+ pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::END, nullptr);
+ }
+ break;
+
+ case FN_UNO_TABLE_COLUMN_SEPARATORS:
+ {
+ UnoActionContext aContext(pFormat->GetDoc());
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ lcl_SetTableSeparators(aValue, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false, pFormat->GetDoc());
+ }
+ break;
+
+ case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:/*_readonly_*/ break;
+
+ case FN_UNO_TABLE_TEMPLATE_NAME:
+ {
+ SwTable* pTable = SwTable::FindTable(pFormat);
+ OUString sName;
+ if (!(aValue >>= sName))
+ break;
+ SwStyleNameMapper::FillUIName(sName, sName, SwGetPoolIdFromName::TabStyle);
+ pTable->SetTableStyleName(sName);
+ SwDoc* pDoc = pFormat->GetDoc();
+ if (SwFEShell* pFEShell = pDoc->GetDocShell()->GetFEShell())
+ pFEShell->UpdateTableStyleFormatting(pTable->GetTableNode());
+ }
+ break;
+
+ default:
+ {
+ SwAttrSet aSet(pFormat->GetAttrSet());
+ m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aSet);
+ pFormat->GetDoc()->SetAttr(aSet, *pFormat);
+ }
+ }
+ }
+ }
+ else if (m_pImpl->IsDescriptor())
+ {
+ m_pImpl->m_pTableProps->SetProperty(pEntry->nWID, pEntry->nMemberId, aValue);
+ }
+ else
+ throw uno::RuntimeException();
+}
+
+uno::Any SwXTextTable::getPropertyValue(const OUString& rPropertyName)
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ SwFrameFormat* pFormat = GetFrameFormat();
+ const SfxItemPropertyMapEntry* pEntry =
+ m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
+
+ if (!pEntry)
+ throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
+
+ if(pFormat)
+ {
+ if(0xBF == pEntry->nMemberId)
+ {
+ aRet = lcl_GetSpecialProperty(pFormat, pEntry );
+ }
+ else
+ {
+ switch(pEntry->nWID)
+ {
+ case FN_UNO_TABLE_NAME:
+ {
+ aRet <<= getName();
+ }
+ break;
+
+ case FN_UNO_ANCHOR_TYPES:
+ case FN_UNO_TEXT_WRAP:
+ case FN_UNO_ANCHOR_TYPE:
+ ::sw::GetDefaultTextContentValue(
+ aRet, u"", pEntry->nWID);
+ break;
+
+ case FN_UNO_RANGE_ROW_LABEL:
+ {
+ aRet <<= m_pImpl->m_bFirstRowAsLabel;
+ }
+ break;
+
+ case FN_UNO_RANGE_COL_LABEL:
+ aRet <<= m_pImpl->m_bFirstColumnAsLabel;
+ break;
+
+ case FN_UNO_TABLE_BORDER:
+ case FN_UNO_TABLE_BORDER2:
+ {
+ SwDoc* pDoc = pFormat->GetDoc();
+ // tables without layout (invisible header/footer?)
+ if(!lcl_FormatTable(pFormat))
+ break;
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ SwTableLines &rLines = pTable->GetTabLines();
+
+ const SwTableBox* pTLBox = lcl_FindCornerTableBox(rLines, true);
+ const SwStartNode* pSttNd = pTLBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ // set cursor to top left cell
+ auto pUnoCursor(pDoc->CreateUnoCursor(aPos, true));
+ pUnoCursor->Move( fnMoveForward, GoInNode );
+ pUnoCursor->SetRemainInSection( false );
+
+ const SwTableBox* pBRBox = lcl_FindCornerTableBox(rLines, false);
+ pUnoCursor->SetMark();
+ const SwStartNode* pLastNd = pBRBox->GetSttNd();
+ pUnoCursor->GetPoint()->Assign( *pLastNd );
+
+ pUnoCursor->Move( fnMoveForward, GoInNode );
+ SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rCursor);
+ rCursor.MakeBoxSels();
+
+ SfxItemSetFixed<RES_BOX, RES_BOX,
+ SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
+ aSet(pDoc->GetAttrPool());
+ aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER ));
+ SwDoc::GetTabBorders(rCursor, aSet);
+ const SvxBoxInfoItem& rBoxInfoItem = aSet.Get(SID_ATTR_BORDER_INNER);
+ const SvxBoxItem& rBox = aSet.Get(RES_BOX);
+
+ if (FN_UNO_TABLE_BORDER == pEntry->nWID)
+ {
+ table::TableBorder aTableBorder;
+ aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true);
+ aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
+ aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true);
+ aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
+ aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true);
+ aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
+ aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true);
+ aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
+ aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true);
+ aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
+ aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true);
+ aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
+ aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance());
+ aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
+ aRet <<= aTableBorder;
+ }
+ else
+ {
+ table::TableBorder2 aTableBorder;
+ aTableBorder.TopLine = SvxBoxItem::SvxLineToLine(rBox.GetTop(), true);
+ aTableBorder.IsTopLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::TOP);
+ aTableBorder.BottomLine = SvxBoxItem::SvxLineToLine(rBox.GetBottom(), true);
+ aTableBorder.IsBottomLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
+ aTableBorder.LeftLine = SvxBoxItem::SvxLineToLine(rBox.GetLeft(), true);
+ aTableBorder.IsLeftLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::LEFT);
+ aTableBorder.RightLine = SvxBoxItem::SvxLineToLine(rBox.GetRight(), true);
+ aTableBorder.IsRightLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::RIGHT );
+ aTableBorder.HorizontalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetHori(), true);
+ aTableBorder.IsHorizontalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::HORI);
+ aTableBorder.VerticalLine = SvxBoxItem::SvxLineToLine(rBoxInfoItem.GetVert(), true);
+ aTableBorder.IsVerticalLineValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::VERT);
+ aTableBorder.Distance = convertTwipToMm100(rBox.GetSmallestDistance());
+ aTableBorder.IsDistanceValid = rBoxInfoItem.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
+ aRet <<= aTableBorder;
+ }
+ }
+ break;
+
+ case FN_UNO_TABLE_BORDER_DISTANCES :
+ {
+ table::TableBorderDistances aTableBorderDistances( 0, true, 0, true, 0, true, 0, true ) ;
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ const SwTableLines &rLines = pTable->GetTabLines();
+ bool bFirst = true;
+ sal_uInt16 nLeftDistance = 0;
+ sal_uInt16 nRightDistance = 0;
+ sal_uInt16 nTopDistance = 0;
+ sal_uInt16 nBottomDistance = 0;
+
+ for(size_t i = 0; i < rLines.size(); ++i)
+ {
+ const SwTableLine* pLine = rLines[i];
+ const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+ for(size_t k = 0; k < rBoxes.size(); ++k)
+ {
+ const SwTableBox* pBox = rBoxes[k];
+ SwFrameFormat* pBoxFormat = pBox->GetFrameFormat();
+ const SvxBoxItem& rBox = pBoxFormat->GetBox();
+ if( bFirst )
+ {
+ nLeftDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT ));
+ nRightDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT ));
+ nTopDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP ));
+ nBottomDistance = convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM ));
+ bFirst = false;
+ }
+ else
+ {
+ if( aTableBorderDistances.IsLeftDistanceValid &&
+ nLeftDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::LEFT )))
+ aTableBorderDistances.IsLeftDistanceValid = false;
+ if( aTableBorderDistances.IsRightDistanceValid &&
+ nRightDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::RIGHT )))
+ aTableBorderDistances.IsRightDistanceValid = false;
+ if( aTableBorderDistances.IsTopDistanceValid &&
+ nTopDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::TOP )))
+ aTableBorderDistances.IsTopDistanceValid = false;
+ if( aTableBorderDistances.IsBottomDistanceValid &&
+ nBottomDistance != convertTwipToMm100( rBox.GetDistance( SvxBoxItemLine::BOTTOM )))
+ aTableBorderDistances.IsBottomDistanceValid = false;
+ }
+
+ }
+ if( !aTableBorderDistances.IsLeftDistanceValid &&
+ !aTableBorderDistances.IsRightDistanceValid &&
+ !aTableBorderDistances.IsTopDistanceValid &&
+ !aTableBorderDistances.IsBottomDistanceValid )
+ break;
+ }
+ if( aTableBorderDistances.IsLeftDistanceValid)
+ aTableBorderDistances.LeftDistance = nLeftDistance;
+ if( aTableBorderDistances.IsRightDistanceValid)
+ aTableBorderDistances.RightDistance = nRightDistance;
+ if( aTableBorderDistances.IsTopDistanceValid)
+ aTableBorderDistances.TopDistance = nTopDistance;
+ if( aTableBorderDistances.IsBottomDistanceValid)
+ aTableBorderDistances.BottomDistance = nBottomDistance;
+
+ aRet <<= aTableBorderDistances;
+ }
+ break;
+
+ case FN_UNO_TABLE_COLUMN_SEPARATORS:
+ {
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ lcl_GetTableSeparators(aRet, pTable, pTable->GetTabLines()[0]->GetTabBoxes()[0], false);
+ }
+ break;
+
+ case FN_UNO_TABLE_COLUMN_RELATIVE_SUM:
+ aRet <<= sal_Int16(UNO_TABLE_COLUMN_SUM);
+ break;
+
+ case RES_ANCHOR:
+ // AnchorType is readonly and might be void (no return value)
+ break;
+
+ case FN_UNO_TEXT_SECTION:
+ {
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ SwTableNode* pTableNode = pTable->GetTableNode();
+ SwSectionNode* pSectionNode = pTableNode->FindSectionNode();
+ if(pSectionNode)
+ {
+ SwSection& rSect = pSectionNode->GetSection();
+ uno::Reference< text::XTextSection > xSect =
+ SwXTextSections::GetObject( *rSect.GetFormat() );
+ aRet <<= xSect;
+ }
+ }
+ break;
+
+ case FN_UNO_TABLE_TEMPLATE_NAME:
+ {
+ SwTable* pTable = SwTable::FindTable(pFormat);
+ OUString sName;
+ SwStyleNameMapper::FillProgName(pTable->GetTableStyleName(), sName, SwGetPoolIdFromName::TabStyle);
+ aRet <<= sName;
+ }
+ break;
+
+ default:
+ {
+ const SwAttrSet& rSet = pFormat->GetAttrSet();
+ m_pImpl->m_pPropSet->getPropertyValue(*pEntry, rSet, aRet);
+ }
+ }
+ }
+ }
+ else if (m_pImpl->IsDescriptor())
+ {
+ const uno::Any* pAny = nullptr;
+ if (!m_pImpl->m_pTableProps->GetProperty(pEntry->nWID, pEntry->nMemberId, pAny))
+ throw lang::IllegalArgumentException();
+ else if(pAny)
+ aRet = *pAny;
+ }
+ else
+ throw uno::RuntimeException();
+ return aRet;
+}
+
+void SwXTextTable::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+void SwXTextTable::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+void SwXTextTable::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+void SwXTextTable::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+OUString SwXTextTable::getName()
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = GetFrameFormat();
+ if (!pFormat && !m_pImpl->IsDescriptor())
+ throw uno::RuntimeException();
+ if(pFormat)
+ {
+ return pFormat->GetName();
+ }
+ return m_pImpl->m_sTableName;
+}
+
+void SwXTextTable::setName(const OUString& rName)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFormat = GetFrameFormat();
+ if ((!pFormat && !m_pImpl->IsDescriptor()) ||
+ rName.isEmpty() ||
+ rName.indexOf('.')>=0 ||
+ rName.indexOf(' ')>=0 )
+ throw uno::RuntimeException();
+
+ if(pFormat)
+ {
+ const OUString aOldName( pFormat->GetName() );
+ const sw::TableFrameFormats* pFrameFormats = pFormat->GetDoc()->GetTableFrameFormats();
+ for (size_t i = pFrameFormats->size(); i;)
+ {
+ const SwTableFormat* pTmpFormat = (*pFrameFormats)[--i];
+ if( !pTmpFormat->IsDefault() &&
+ pTmpFormat->GetName() == rName &&
+ pFormat->GetDoc()->IsUsed( *pTmpFormat ))
+ {
+ throw uno::RuntimeException();
+ }
+ }
+
+ pFormat->SetFormatName( rName );
+
+ SwStartNode *pStNd;
+ SwNodeIndex aIdx( *pFormat->GetDoc()->GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
+ while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
+ {
+ ++aIdx;
+ SwNode *const pNd = & aIdx.GetNode();
+ if ( pNd->IsOLENode() &&
+ aOldName == static_cast<const SwOLENode*>(pNd)->GetChartTableName() )
+ {
+ static_cast<SwOLENode*>(pNd)->SetChartTableName( rName );
+
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ //TL_CHART2: chart needs to be notified about name changes
+ pFormat->GetDoc()->UpdateCharts( pTable->GetFrameFormat()->GetName() );
+ }
+ aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
+ }
+ pFormat->GetDoc()->getIDocumentState().SetModified();
+ }
+ else
+ m_pImpl->m_sTableName = rName;
+}
+
+sal_uInt16 SwXTextTable::Impl::GetRowCount()
+{
+ sal_uInt16 nRet = 0;
+ SwFrameFormat* pFormat = GetFrameFormat();
+ if(pFormat)
+ {
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ if(!pTable->IsTableComplex())
+ {
+ nRet = pTable->GetTabLines().size();
+ }
+ }
+ return nRet;
+}
+
+sal_uInt16 SwXTextTable::Impl::GetColumnCount()
+{
+ SwFrameFormat* pFormat = GetFrameFormat();
+ sal_uInt16 nRet = 0;
+ if(pFormat)
+ {
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ if(!pTable->IsTableComplex())
+ {
+ SwTableLines& rLines = pTable->GetTabLines();
+ SwTableLine* pLine = rLines.front();
+ nRet = pLine->GetTabBoxes().size();
+ }
+ }
+ return nRet;
+}
+
+void SwXTextTable::Impl::Notify(const SfxHint& rHint)
+{
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pFrameFormat = nullptr;
+ EndListeningAll();
+ }
+ std::unique_lock aGuard(m_Mutex);
+ if (m_EventListeners.getLength(aGuard) == 0 && m_ChartListeners.getLength(aGuard) == 0)
+ return;
+ uno::Reference<uno::XInterface> const xThis(m_wThis);
+ // fdo#72695: if UNO object is already dead, don't revive it with event
+ if (!xThis)
+ return;
+ if(!m_pFrameFormat)
+ {
+ lang::EventObject const ev(xThis);
+ m_EventListeners.disposeAndClear(aGuard, ev);
+ m_ChartListeners.disposeAndClear(aGuard, ev);
+ }
+ else
+ {
+ lcl_SendChartEvent(aGuard, xThis, m_ChartListeners);
+ }
+}
+
+OUString SAL_CALL SwXTextTable::getImplementationName()
+ { return "SwXTextTable"; }
+
+sal_Bool SwXTextTable::supportsService(const OUString& rServiceName)
+ { return cppu::supportsService(this, rServiceName); }
+
+uno::Sequence<OUString> SwXTextTable::getSupportedServiceNames()
+{
+ return {
+ "com.sun.star.document.LinkTarget",
+ "com.sun.star.text.TextTable",
+ "com.sun.star.text.TextContent",
+ "com.sun.star.text.TextSortable" };
+}
+
+
+class SwXCellRange::Impl
+ : public SvtListener
+{
+private:
+ SwFrameFormat* m_pFrameFormat;
+
+public:
+ uno::WeakReference<uno::XInterface> m_wThis;
+ std::mutex m_Mutex; // just for OInterfaceContainerHelper4
+ ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> m_ChartListeners;
+
+ sw::UnoCursorPointer m_pTableCursor;
+
+ SwRangeDescriptor m_RangeDescriptor;
+ const SfxItemPropertySet* m_pPropSet;
+
+ bool m_bFirstRowAsLabel;
+ bool m_bFirstColumnAsLabel;
+
+ Impl(sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat, SwRangeDescriptor const& rDesc)
+ : m_pFrameFormat(&rFrameFormat)
+ , m_pTableCursor(pCursor)
+ , m_RangeDescriptor(rDesc)
+ , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TABLE_RANGE))
+ , m_bFirstRowAsLabel(false)
+ , m_bFirstColumnAsLabel(false)
+ {
+ StartListening(rFrameFormat.GetNotifier());
+ m_RangeDescriptor.Normalize();
+ }
+
+ SwFrameFormat* GetFrameFormat()
+ {
+ return m_pFrameFormat;
+ }
+
+ std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32> GetLabelCoordinates(bool bRow);
+
+ uno::Sequence<OUString> GetLabelDescriptions(SwXCellRange & rThis, bool bRow);
+
+ void SetLabelDescriptions(SwXCellRange & rThis,
+ const css::uno::Sequence<OUString>& rDesc, bool bRow);
+
+ sal_Int32 GetRowCount() const;
+ sal_Int32 GetColumnCount() const;
+
+ virtual void Notify(const SfxHint& ) override;
+
+};
+
+OUString SwXCellRange::getImplementationName()
+ { return "SwXCellRange"; }
+
+sal_Bool SwXCellRange::supportsService(const OUString& rServiceName)
+ { return cppu::supportsService(this, rServiceName); }
+
+uno::Sequence<OUString> SwXCellRange::getSupportedServiceNames()
+{
+ return {
+ "com.sun.star.text.CellRange",
+ "com.sun.star.style.CharacterProperties",
+ "com.sun.star.style.CharacterPropertiesAsian",
+ "com.sun.star.style.CharacterPropertiesComplex",
+ "com.sun.star.style.ParagraphProperties",
+ "com.sun.star.style.ParagraphPropertiesAsian",
+ "com.sun.star.style.ParagraphPropertiesComplex" };
+}
+
+SwXCellRange::SwXCellRange(sw::UnoCursorPointer const& pCursor,
+ SwFrameFormat& rFrameFormat, SwRangeDescriptor const & rDesc)
+ : m_pImpl(new Impl(pCursor, rFrameFormat, rDesc))
+{
+}
+
+SwXCellRange::~SwXCellRange()
+{
+}
+
+rtl::Reference<SwXCellRange> SwXCellRange::CreateXCellRange(
+ sw::UnoCursorPointer const& pCursor, SwFrameFormat& rFrameFormat,
+ SwRangeDescriptor const & rDesc)
+{
+ rtl::Reference<SwXCellRange> pCellRange(new SwXCellRange(pCursor, rFrameFormat, rDesc));
+ // need a permanent Reference to initialize m_wThis
+ pCellRange->m_pImpl->m_wThis = uno::Reference<table::XCellRange>(pCellRange);
+ return pCellRange;
+}
+
+void SwXCellRange::SetLabels(bool bFirstRowAsLabel, bool bFirstColumnAsLabel)
+{
+ m_pImpl->m_bFirstRowAsLabel = bFirstRowAsLabel;
+ m_pImpl->m_bFirstColumnAsLabel = bFirstColumnAsLabel;
+}
+
+std::vector< uno::Reference< table::XCell > > SwXCellRange::GetCells()
+{
+ SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
+ const sal_Int32 nRowCount(m_pImpl->GetRowCount());
+ const sal_Int32 nColCount(m_pImpl->GetColumnCount());
+ std::vector< uno::Reference< table::XCell > > vResult;
+ vResult.reserve(static_cast<size_t>(nRowCount)*static_cast<size_t>(nColCount));
+ for(sal_Int32 nRow = 0; nRow < nRowCount; ++nRow)
+ for(sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
+ vResult.emplace_back(lcl_CreateXCell(pFormat, m_pImpl->m_RangeDescriptor.nLeft + nCol, m_pImpl->m_RangeDescriptor.nTop + nRow));
+ return vResult;
+}
+
+uno::Reference<table::XCell> SAL_CALL
+SwXCellRange::getCellByPosition(sal_Int32 nColumn, sal_Int32 nRow)
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< table::XCell > aRet;
+ SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
+ if(pFormat)
+ {
+ if(nColumn >= 0 && nRow >= 0 &&
+ m_pImpl->GetColumnCount() > nColumn && m_pImpl->GetRowCount() > nRow )
+ {
+ rtl::Reference<SwXCell> pXCell = lcl_CreateXCell(pFormat,
+ m_pImpl->m_RangeDescriptor.nLeft + nColumn,
+ m_pImpl->m_RangeDescriptor.nTop + nRow);
+ if(pXCell)
+ aRet = pXCell;
+ }
+ }
+ if(!aRet.is())
+ throw lang::IndexOutOfBoundsException();
+ return aRet;
+}
+
+uno::Reference<table::XCellRange> SAL_CALL
+SwXCellRange::getCellRangeByPosition(
+ sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom)
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference< SwXCellRange > aRet;
+ SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
+ if (pFormat && m_pImpl->GetColumnCount() > nRight
+ && m_pImpl->GetRowCount() > nBottom &&
+ nLeft <= nRight && nTop <= nBottom
+ && nLeft >= 0 && nRight >= 0 && nTop >= 0 && nBottom >= 0 )
+ {
+ SwTable* pTable = SwTable::FindTable( pFormat );
+ if(!pTable->IsTableComplex())
+ {
+ SwRangeDescriptor aNewDesc;
+ aNewDesc.nTop = nTop + m_pImpl->m_RangeDescriptor.nTop;
+ aNewDesc.nBottom = nBottom + m_pImpl->m_RangeDescriptor.nTop;
+ aNewDesc.nLeft = nLeft + m_pImpl->m_RangeDescriptor.nLeft;
+ aNewDesc.nRight = nRight + m_pImpl->m_RangeDescriptor.nLeft;
+ aNewDesc.Normalize();
+ const OUString sTLName = sw_GetCellName(aNewDesc.nLeft, aNewDesc.nTop);
+ const OUString sBRName = sw_GetCellName(aNewDesc.nRight, aNewDesc.nBottom);
+ const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
+ if(pTLBox)
+ {
+ const SwStartNode* pSttNd = pTLBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ // set cursor in the upper-left cell of the range
+ auto pUnoCursor(pFormat->GetDoc()->CreateUnoCursor(aPos, true));
+ pUnoCursor->Move( fnMoveForward, GoInNode );
+ pUnoCursor->SetRemainInSection( false );
+ const SwTableBox* pBRBox = pTable->GetTableBox( sBRName );
+ if(pBRBox)
+ {
+ pUnoCursor->SetMark();
+ pUnoCursor->GetPoint()->Assign( *pBRBox->GetSttNd() );
+ pUnoCursor->Move( fnMoveForward, GoInNode );
+ SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rCursor);
+ rCursor.MakeBoxSels();
+ // pUnoCursor will be provided and will not be deleted
+ aRet = SwXCellRange::CreateXCellRange(pUnoCursor, *pFormat, aNewDesc).get();
+ }
+ }
+ }
+ }
+ if(!aRet.is())
+ throw lang::IndexOutOfBoundsException();
+ return aRet;
+}
+
+uno::Reference<table::XCellRange> SAL_CALL
+SwXCellRange::getCellRangeByName(const OUString& rRange)
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nPos = 0;
+ const OUString sTLName(rRange.getToken(0, ':', nPos));
+ const OUString sBRName(rRange.getToken(0, ':', nPos));
+ if(sTLName.isEmpty() || sBRName.isEmpty())
+ throw uno::RuntimeException();
+ SwRangeDescriptor aDesc;
+ aDesc.nTop = aDesc.nLeft = aDesc.nBottom = aDesc.nRight = -1;
+ SwXTextTable::GetCellPosition( sTLName, aDesc.nLeft, aDesc.nTop );
+ SwXTextTable::GetCellPosition( sBRName, aDesc.nRight, aDesc.nBottom );
+ aDesc.Normalize();
+ return getCellRangeByPosition(
+ aDesc.nLeft - m_pImpl->m_RangeDescriptor.nLeft,
+ aDesc.nTop - m_pImpl->m_RangeDescriptor.nTop,
+ aDesc.nRight - m_pImpl->m_RangeDescriptor.nLeft,
+ aDesc.nBottom - m_pImpl->m_RangeDescriptor.nTop);
+}
+
+uno::Reference< beans::XPropertySetInfo > SwXCellRange::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> xRef = m_pImpl->m_pPropSet->getPropertySetInfo();
+ return xRef;
+}
+
+void SAL_CALL
+SwXCellRange::setPropertyValue(const OUString& rPropertyName, const uno::Any& aValue)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
+ if(!pFormat)
+ return;
+
+ const SfxItemPropertyMapEntry *const pEntry =
+ m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
+ if(!pEntry)
+ throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
+
+ if ( pEntry->nFlags & beans::PropertyAttribute::READONLY)
+ throw beans::PropertyVetoException("Property is read-only: " + rPropertyName, getXWeak() );
+
+ SwDoc& rDoc = m_pImpl->m_pTableCursor->GetDoc();
+ SwUnoTableCursor& rCursor(dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor));
+ {
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rCursor);
+ }
+ rCursor.MakeBoxSels();
+ switch(pEntry->nWID )
+ {
+ case FN_UNO_TABLE_CELL_BACKGROUND:
+ {
+ std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
+ SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush);
+ aBrush->PutValue(aValue, pEntry->nMemberId);
+ rDoc.SetBoxAttr(*m_pImpl->m_pTableCursor, *aBrush);
+
+ }
+ break;
+ case RES_BOX :
+ {
+ SfxItemSetFixed<RES_BOX, RES_BOX,
+ SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
+ aSet(rDoc.GetAttrPool());
+ SvxBoxInfoItem aBoxInfo( SID_ATTR_BORDER_INNER );
+ aBoxInfo.SetValid(SvxBoxInfoItemValidFlags::ALL, false);
+ SvxBoxInfoItemValidFlags nValid = SvxBoxInfoItemValidFlags::NONE;
+ switch(pEntry->nMemberId & ~CONVERT_TWIPS)
+ {
+ case LEFT_BORDER : nValid = SvxBoxInfoItemValidFlags::LEFT; break;
+ case RIGHT_BORDER: nValid = SvxBoxInfoItemValidFlags::RIGHT; break;
+ case TOP_BORDER : nValid = SvxBoxInfoItemValidFlags::TOP; break;
+ case BOTTOM_BORDER: nValid = SvxBoxInfoItemValidFlags::BOTTOM; break;
+ case LEFT_BORDER_DISTANCE :
+ case RIGHT_BORDER_DISTANCE:
+ case TOP_BORDER_DISTANCE :
+ case BOTTOM_BORDER_DISTANCE:
+ nValid = SvxBoxInfoItemValidFlags::DISTANCE;
+ break;
+ }
+ aBoxInfo.SetValid(nValid);
+
+ aSet.Put(aBoxInfo);
+ SwDoc::GetTabBorders(rCursor, aSet);
+
+ aSet.Put(aBoxInfo);
+ SvxBoxItem aBoxItem(aSet.Get(RES_BOX));
+ static_cast<SfxPoolItem&>(aBoxItem).PutValue(aValue, pEntry->nMemberId);
+ aSet.Put(aBoxItem);
+ rDoc.SetTabBorders(*m_pImpl->m_pTableCursor, aSet);
+ }
+ break;
+ case RES_BOXATR_FORMAT:
+ {
+ SfxUInt32Item aNumberFormat(RES_BOXATR_FORMAT);
+ static_cast<SfxPoolItem&>(aNumberFormat).PutValue(aValue, 0);
+ rDoc.SetBoxAttr(rCursor, aNumberFormat);
+ }
+ break;
+ case FN_UNO_RANGE_ROW_LABEL:
+ {
+ bool bTmp = *o3tl::doAccess<bool>(aValue);
+ if (m_pImpl->m_bFirstRowAsLabel != bTmp)
+ {
+ std::unique_lock aGuard2(m_pImpl->m_Mutex);
+ lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
+ m_pImpl->m_bFirstRowAsLabel = bTmp;
+ }
+ }
+ break;
+ case FN_UNO_RANGE_COL_LABEL:
+ {
+ bool bTmp = *o3tl::doAccess<bool>(aValue);
+ if (m_pImpl->m_bFirstColumnAsLabel != bTmp)
+ {
+ std::unique_lock aGuard2(m_pImpl->m_Mutex);
+ lcl_SendChartEvent(aGuard2, *this, m_pImpl->m_ChartListeners);
+ m_pImpl->m_bFirstColumnAsLabel = bTmp;
+ }
+ }
+ break;
+ case RES_VERT_ORIENT:
+ {
+ sal_Int16 nAlign = -1;
+ aValue >>= nAlign;
+ if( nAlign >= text::VertOrientation::NONE && nAlign <= text::VertOrientation::BOTTOM)
+ rDoc.SetBoxAlign( rCursor, nAlign );
+ }
+ break;
+ default:
+ {
+ SfxItemSet aItemSet( rDoc.GetAttrPool(), pEntry->nWID, pEntry->nWID );
+ SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(),
+ aItemSet);
+
+ if (!SwUnoCursorHelper::SetCursorPropertyValue(
+ *pEntry, aValue, rCursor.GetSelRing(), aItemSet))
+ {
+ m_pImpl->m_pPropSet->setPropertyValue(*pEntry, aValue, aItemSet);
+ }
+ SwUnoCursorHelper::SetCursorAttr(rCursor.GetSelRing(),
+ aItemSet, SetAttrMode::DEFAULT, true);
+ }
+ }
+}
+
+uno::Any SAL_CALL SwXCellRange::getPropertyValue(const OUString& rPropertyName)
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
+ if(pFormat)
+ {
+ const SfxItemPropertyMapEntry *const pEntry =
+ m_pImpl->m_pPropSet->getPropertyMap().getByName(rPropertyName);
+ if(!pEntry)
+ throw beans::UnknownPropertyException("Unknown property: " + rPropertyName, getXWeak() );
+
+ switch(pEntry->nWID )
+ {
+ case FN_UNO_TABLE_CELL_BACKGROUND:
+ {
+ std::unique_ptr<SfxPoolItem> aBrush(std::make_unique<SvxBrushItem>(RES_BACKGROUND));
+ if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aBrush))
+ aBrush->QueryValue(aRet, pEntry->nMemberId);
+
+ }
+ break;
+ case RES_BOX :
+ {
+ SwDoc& rDoc = m_pImpl->m_pTableCursor->GetDoc();
+ SfxItemSetFixed<RES_BOX, RES_BOX,
+ SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER>
+ aSet(rDoc.GetAttrPool());
+ aSet.Put(SvxBoxInfoItem( SID_ATTR_BORDER_INNER ));
+ SwDoc::GetTabBorders(*m_pImpl->m_pTableCursor, aSet);
+ const SvxBoxItem& rBoxItem = aSet.Get(RES_BOX);
+ rBoxItem.QueryValue(aRet, pEntry->nMemberId);
+ }
+ break;
+ case RES_BOXATR_FORMAT:
+ OSL_FAIL("not implemented");
+ break;
+ case FN_UNO_PARA_STYLE:
+ {
+ SwFormatColl *const pTmpFormat =
+ SwUnoCursorHelper::GetCurTextFormatColl(*m_pImpl->m_pTableCursor, false);
+ OUString sRet;
+ if (pTmpFormat)
+ sRet = pTmpFormat->GetName();
+ aRet <<= sRet;
+ }
+ break;
+ case FN_UNO_RANGE_ROW_LABEL:
+ aRet <<= m_pImpl->m_bFirstRowAsLabel;
+ break;
+ case FN_UNO_RANGE_COL_LABEL:
+ aRet <<= m_pImpl->m_bFirstColumnAsLabel;
+ break;
+ case RES_VERT_ORIENT:
+ {
+ std::unique_ptr<SfxPoolItem> aVertOrient(
+ std::make_unique<SwFormatVertOrient>(RES_VERT_ORIENT));
+ if (SwDoc::GetBoxAttr(*m_pImpl->m_pTableCursor, aVertOrient))
+ {
+ aVertOrient->QueryValue( aRet, pEntry->nMemberId );
+ }
+ }
+ break;
+ default:
+ {
+ SfxItemSetFixed<
+ RES_CHRATR_BEGIN, RES_FRMATR_END - 1,
+ RES_UNKNOWNATR_CONTAINER,
+ RES_UNKNOWNATR_CONTAINER>
+ aSet(m_pImpl->m_pTableCursor->GetDoc().GetAttrPool());
+ // first look at the attributes of the cursor
+ SwUnoTableCursor& rCursor =
+ dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor);
+ SwUnoCursorHelper::GetCursorAttr(rCursor.GetSelRing(), aSet);
+ m_pImpl->m_pPropSet->getPropertyValue(*pEntry, aSet, aRet);
+ }
+ }
+
+ }
+ return aRet;
+}
+
+void SwXCellRange::addPropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+void SwXCellRange::removePropertyChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+void SwXCellRange::addVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+void SwXCellRange::removeVetoableChangeListener(const OUString& /*PropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+///@see SwXCellRange::getData
+uno::Sequence<uno::Sequence<uno::Any>> SAL_CALL SwXCellRange::getDataArray()
+{
+ SolarMutexGuard aGuard;
+ const sal_Int32 nRowCount = m_pImpl->GetRowCount();
+ const sal_Int32 nColCount = m_pImpl->GetColumnCount();
+ if(!nRowCount || !nColCount)
+ throw uno::RuntimeException("Table too complex", getXWeak());
+ lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), this);
+ uno::Sequence< uno::Sequence< uno::Any > > aRowSeq(nRowCount);
+ auto vCells(GetCells());
+ auto pCurrentCell(vCells.begin());
+ for(auto& rRow : asNonConstRange(aRowSeq))
+ {
+ rRow = uno::Sequence< uno::Any >(nColCount);
+ for(auto& rCellAny : asNonConstRange(rRow))
+ {
+ auto pCell(static_cast<SwXCell*>(pCurrentCell->get()));
+ if(!pCell)
+ throw uno::RuntimeException("Table too complex", getXWeak());
+ rCellAny = pCell->GetAny();
+ ++pCurrentCell;
+ }
+ }
+ return aRowSeq;
+}
+
+///@see SwXCellRange::setData
+void SAL_CALL SwXCellRange::setDataArray(const uno::Sequence< uno::Sequence< uno::Any > >& rArray)
+{
+ SolarMutexGuard aGuard;
+ const sal_Int32 nRowCount = m_pImpl->GetRowCount();
+ const sal_Int32 nColCount = m_pImpl->GetColumnCount();
+ if(!nRowCount || !nColCount)
+ throw uno::RuntimeException("Table too complex", getXWeak());
+ SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
+ if(!pFormat)
+ return;
+ if(rArray.getLength() != nRowCount)
+ throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rArray.getLength()), getXWeak());
+ auto vCells(GetCells());
+ auto pCurrentCell(vCells.begin());
+ for(const auto& rColSeq : rArray)
+ {
+ if(rColSeq.getLength() != nColCount)
+ throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rColSeq.getLength()), getXWeak());
+ for(const auto& aValue : rColSeq)
+ {
+ auto pCell(static_cast<SwXCell*>(pCurrentCell->get()));
+ if(!pCell || !pCell->GetTableBox())
+ throw uno::RuntimeException("Box for cell missing", getXWeak());
+ if(aValue.isExtractableTo(cppu::UnoType<OUString>::get()))
+ sw_setString(*pCell, aValue.get<OUString>());
+ else if(aValue.isExtractableTo(cppu::UnoType<double>::get()))
+ sw_setValue(*pCell, aValue.get<double>());
+ else
+ sw_setString(*pCell, OUString(), true);
+ ++pCurrentCell;
+ }
+ }
+}
+
+uno::Sequence<uno::Sequence<double>> SAL_CALL
+SwXCellRange::getData()
+{
+ SolarMutexGuard aGuard;
+ const sal_Int32 nRowCount = m_pImpl->GetRowCount();
+ const sal_Int32 nColCount = m_pImpl->GetColumnCount();
+ if(!nRowCount || !nColCount)
+ throw uno::RuntimeException("Table too complex", getXWeak());
+ if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel)
+ {
+ uno::Reference<chart::XChartDataArray> const xDataRange(
+ getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0,
+ (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0,
+ nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW);
+ return xDataRange->getData();
+ }
+ uno::Sequence< uno::Sequence< double > > vRows(nRowCount);
+ auto vCells(GetCells());
+ auto pCurrentCell(vCells.begin());
+ for(auto& rRow : asNonConstRange(vRows))
+ {
+ rRow = uno::Sequence<double>(nColCount);
+ for(auto& rValue : asNonConstRange(rRow))
+ {
+ if(!(*pCurrentCell))
+ throw uno::RuntimeException("Table too complex", getXWeak());
+ rValue = (*pCurrentCell)->getValue();
+ ++pCurrentCell;
+ }
+ }
+ return vRows;
+}
+
+void SAL_CALL
+SwXCellRange::setData(const uno::Sequence< uno::Sequence<double> >& rData)
+{
+ SolarMutexGuard aGuard;
+ const sal_Int32 nRowCount = m_pImpl->GetRowCount();
+ const sal_Int32 nColCount = m_pImpl->GetColumnCount();
+ if(!nRowCount || !nColCount)
+ throw uno::RuntimeException("Table too complex", getXWeak());
+ if (m_pImpl->m_bFirstColumnAsLabel || m_pImpl->m_bFirstRowAsLabel)
+ {
+ uno::Reference<chart::XChartDataArray> const xDataRange(
+ getCellRangeByPosition((m_pImpl->m_bFirstColumnAsLabel) ? 1 : 0,
+ (m_pImpl->m_bFirstRowAsLabel) ? 1 : 0,
+ nColCount-1, nRowCount-1), uno::UNO_QUERY_THROW);
+ return xDataRange->setData(rData);
+ }
+ lcl_EnsureCoreConnected(m_pImpl->GetFrameFormat(), this);
+ if(rData.getLength() != nRowCount)
+ throw uno::RuntimeException("Row count mismatch. expected: " + OUString::number(nRowCount) + " got: " + OUString::number(rData.getLength()), getXWeak());
+ auto vCells(GetCells());
+ auto pCurrentCell(vCells.begin());
+ for(const auto& rRow : rData)
+ {
+ if(rRow.getLength() != nColCount)
+ throw uno::RuntimeException("Column count mismatch. expected: " + OUString::number(nColCount) + " got: " + OUString::number(rRow.getLength()), getXWeak());
+ for(const auto& rValue : rRow)
+ {
+ uno::Reference<table::XCell>(*pCurrentCell, uno::UNO_SET_THROW)->setValue(rValue);
+ ++pCurrentCell;
+ }
+ }
+}
+
+std::tuple<sal_uInt32, sal_uInt32, sal_uInt32, sal_uInt32>
+SwXCellRange::Impl::GetLabelCoordinates(bool bRow)
+{
+ sal_uInt32 nLeft, nTop, nRight, nBottom;
+ nLeft = nTop = nRight = nBottom = 0;
+ if(bRow)
+ {
+ nTop = m_bFirstRowAsLabel ? 1 : 0;
+ nBottom = GetRowCount() - 1;
+ }
+ else
+ {
+ nLeft = m_bFirstColumnAsLabel ? 1 : 0;
+ nRight = GetColumnCount() - 1;
+ }
+ return std::make_tuple(nLeft, nTop, nRight, nBottom);
+}
+
+uno::Sequence<OUString>
+SwXCellRange::Impl::GetLabelDescriptions(SwXCellRange & rThis, bool bRow)
+{
+ SolarMutexGuard aGuard;
+ sal_uInt32 nLeft, nTop, nRight, nBottom;
+ std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow);
+ if(!nRight && !nBottom)
+ throw uno::RuntimeException("Table too complex", rThis.getXWeak());
+ lcl_EnsureCoreConnected(GetFrameFormat(), &rThis);
+ if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel))
+ return {}; // without labels we have no descriptions
+ auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom));
+ auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells());
+ uno::Sequence<OUString> vResult(vCells.size());
+ std::transform(vCells.begin(), vCells.end(), vResult.getArray(),
+ [](uno::Reference<table::XCell> xCell) -> OUString { return uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->getString(); });
+ return vResult;
+}
+
+uno::Sequence<OUString> SAL_CALL SwXCellRange::getRowDescriptions()
+{
+ return m_pImpl->GetLabelDescriptions(*this, true);
+}
+
+uno::Sequence<OUString> SAL_CALL SwXCellRange::getColumnDescriptions()
+{
+ return m_pImpl->GetLabelDescriptions(*this, false);
+}
+
+void SwXCellRange::Impl::SetLabelDescriptions(SwXCellRange & rThis,
+ const uno::Sequence<OUString>& rDesc, bool bRow)
+{
+ SolarMutexGuard aGuard;
+ lcl_EnsureCoreConnected(GetFrameFormat(), &rThis);
+ if (!(bRow ? m_bFirstColumnAsLabel : m_bFirstRowAsLabel))
+ return; // if there are no labels we cannot set descriptions
+ sal_uInt32 nLeft, nTop, nRight, nBottom;
+ std::tie(nLeft, nTop, nRight, nBottom) = GetLabelCoordinates(bRow);
+ if(!nRight && !nBottom)
+ throw uno::RuntimeException("Table too complex", rThis.getXWeak());
+ auto xLabelRange(rThis.getCellRangeByPosition(nLeft, nTop, nRight, nBottom));
+ if (!xLabelRange.is())
+ throw uno::RuntimeException("Missing Cell Range", rThis.getXWeak());
+ auto vCells(static_cast<SwXCellRange*>(xLabelRange.get())->GetCells());
+ if (sal::static_int_cast<sal_uInt32>(rDesc.getLength()) != vCells.size())
+ throw uno::RuntimeException("Too few or too many descriptions", rThis.getXWeak());
+ auto pDescIterator(rDesc.begin());
+ for(auto& xCell : vCells)
+ uno::Reference<text::XText>(xCell, uno::UNO_QUERY_THROW)->setString(*pDescIterator++);
+}
+
+void SAL_CALL SwXCellRange::setRowDescriptions(
+ const uno::Sequence<OUString>& rRowDesc)
+{
+ m_pImpl->SetLabelDescriptions(*this, rRowDesc, true);
+}
+
+void SAL_CALL SwXCellRange::setColumnDescriptions(
+ const uno::Sequence<OUString>& rColumnDesc)
+{
+ m_pImpl->SetLabelDescriptions(*this, rColumnDesc, false);
+}
+
+void SAL_CALL SwXCellRange::addChartDataChangeEventListener(
+ const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
+{
+ // no need to lock here as m_pImpl is const and container threadsafe
+ std::unique_lock aGuard(m_pImpl->m_Mutex);
+ m_pImpl->m_ChartListeners.addInterface(aGuard, xListener);
+}
+
+void SAL_CALL SwXCellRange::removeChartDataChangeEventListener(
+ const uno::Reference<chart::XChartDataChangeEventListener> & xListener)
+{
+ // no need to lock here as m_pImpl is const and container threadsafe
+ std::unique_lock aGuard(m_pImpl->m_Mutex);
+ m_pImpl->m_ChartListeners.removeInterface(aGuard, xListener);
+}
+
+sal_Bool SwXCellRange::isNotANumber(double /*fNumber*/)
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+double SwXCellRange::getNotANumber()
+ { throw uno::RuntimeException("Not implemented", getXWeak()); }
+
+uno::Sequence< beans::PropertyValue > SwXCellRange::createSortDescriptor()
+{
+ SolarMutexGuard aGuard;
+ return SwUnoCursorHelper::CreateSortDescriptor(true);
+}
+
+void SAL_CALL SwXCellRange::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
+{
+ SolarMutexGuard aGuard;
+ SwSortOptions aSortOpt;
+ SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
+ if(pFormat && SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt))
+ {
+ SwUnoTableCursor& rTableCursor = dynamic_cast<SwUnoTableCursor&>(*m_pImpl->m_pTableCursor);
+ rTableCursor.MakeBoxSels();
+ UnoActionContext aContext(pFormat->GetDoc());
+ pFormat->GetDoc()->SortTable(rTableCursor.GetSelectedBoxes(), aSortOpt);
+ }
+}
+
+sal_Int32 SwXCellRange::Impl::GetColumnCount() const
+{
+ return m_RangeDescriptor.nRight - m_RangeDescriptor.nLeft + 1;
+}
+
+sal_Int32 SwXCellRange::Impl::GetRowCount() const
+{
+ return m_RangeDescriptor.nBottom - m_RangeDescriptor.nTop + 1;
+}
+
+const SwUnoCursor* SwXCellRange::GetTableCursor() const
+{
+ SwFrameFormat *const pFormat = m_pImpl->GetFrameFormat();
+ return pFormat ? &(*m_pImpl->m_pTableCursor) : nullptr;
+}
+
+void SwXCellRange::Impl::Notify( const SfxHint& rHint )
+{
+ uno::Reference<uno::XInterface> const xThis(m_wThis);
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pFrameFormat = nullptr;
+ m_pTableCursor.reset(nullptr);
+ }
+ if (xThis.is())
+ { // fdo#72695: if UNO object is already dead, don't revive it with event
+ if(m_pFrameFormat)
+ {
+ std::unique_lock aGuard(m_Mutex);
+ lcl_SendChartEvent(aGuard, xThis, m_ChartListeners);
+ }
+ else
+ {
+ std::unique_lock aGuard(m_Mutex);
+ m_ChartListeners.disposeAndClear(aGuard, lang::EventObject(xThis));
+ }
+ }
+}
+
+class SwXTableRows::Impl : public SvtListener
+{
+private:
+ SwFrameFormat* m_pFrameFormat;
+
+public:
+ explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat)
+ {
+ StartListening(rFrameFormat.GetNotifier());
+ }
+ SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
+ virtual void Notify(const SfxHint&) override;
+};
+
+// SwXTableRows
+
+OUString SwXTableRows::getImplementationName()
+ { return "SwXTableRows"; }
+
+sal_Bool SwXTableRows::supportsService(const OUString& rServiceName)
+ { return cppu::supportsService(this, rServiceName); }
+
+uno::Sequence< OUString > SwXTableRows::getSupportedServiceNames()
+ { return { "com.sun.star.text.TableRows" }; }
+
+
+SwXTableRows::SwXTableRows(SwFrameFormat& rFrameFormat) :
+ m_pImpl(new SwXTableRows::Impl(rFrameFormat))
+{ }
+
+SwXTableRows::~SwXTableRows()
+{ }
+
+SwFrameFormat* SwXTableRows::GetFrameFormat()
+{
+ return m_pImpl->GetFrameFormat();
+}
+
+sal_Int32 SwXTableRows::getCount()
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFrameFormat = GetFrameFormat();
+ if(!pFrameFormat)
+ throw uno::RuntimeException();
+ SwTable* pTable = SwTable::FindTable(pFrameFormat);
+ return pTable->GetTabLines().size();
+}
+
+///@see SwXCell::CreateXCell (TODO: seems to be copy and paste programming here)
+uno::Any SwXTableRows::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
+ if(nIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+ SwTable* pTable = SwTable::FindTable( pFrameFormat );
+ if(o3tl::make_unsigned(nIndex) >= pTable->GetTabLines().size())
+ throw lang::IndexOutOfBoundsException();
+ SwTableLine* pLine = pTable->GetTabLines()[nIndex];
+ FindUnoInstanceHint<SwTableLine,SwXTextTableRow> aHint{pLine};
+ pFrameFormat->GetNotifier().Broadcast(aHint);
+ if(!aHint.m_pResult)
+ aHint.m_pResult = new SwXTextTableRow(pFrameFormat, pLine);
+ uno::Reference<beans::XPropertySet> xRet = static_cast<beans::XPropertySet*>(aHint.m_pResult.get());
+ return uno::Any(xRet);
+}
+
+uno::Type SAL_CALL SwXTableRows::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SwXTableRows::hasElements()
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFrameFormat = GetFrameFormat();
+ if(!pFrameFormat)
+ throw uno::RuntimeException();
+ // a table always has rows
+ return true;
+}
+
+void SwXTableRows::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount)
+{
+ SolarMutexGuard aGuard;
+ if (nCount == 0)
+ return;
+ SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
+ SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this);
+ const size_t nRowCount = pTable->GetTabLines().size();
+ if (nCount <= 0 || 0 > nIndex || o3tl::make_unsigned(nIndex) > nRowCount)
+ throw uno::RuntimeException("Illegal arguments", getXWeak());
+ const OUString sTLName = sw_GetCellName(0, nIndex);
+ const SwTableBox* pTLBox = pTable->GetTableBox(sTLName);
+ bool bAppend = false;
+ if(!pTLBox)
+ {
+ bAppend = true;
+ // to append at the end the cursor must be in the last line
+ SwTableLines& rLines = pTable->GetTabLines();
+ SwTableLine* pLine = rLines.back();
+ SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+ pTLBox = rBoxes.front();
+ }
+ if(!pTLBox)
+ throw uno::RuntimeException("Illegal arguments", getXWeak());
+ const SwStartNode* pSttNd = pTLBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ // set cursor to the upper-left cell of the range
+ UnoActionContext aAction(pFrameFormat->GetDoc());
+ std::shared_ptr<SwUnoTableCursor> const pUnoCursor(
+ std::dynamic_pointer_cast<SwUnoTableCursor>(
+ pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true)));
+ pUnoCursor->Move( fnMoveForward, GoInNode );
+ {
+ // remove actions - TODO: why?
+ UnoActionRemoveContext aRemoveContext(&pUnoCursor->GetDoc());
+ }
+ pFrameFormat->GetDoc()->InsertRow(*pUnoCursor, o3tl::narrowing<sal_uInt16>(nCount), bAppend);
+}
+
+void SwXTableRows::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount)
+{
+ SolarMutexGuard aGuard;
+ if (nCount == 0)
+ return;
+ SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
+ if(nIndex < 0 || nCount <=0 )
+ throw uno::RuntimeException();
+ SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this);
+ OUString sTLName = sw_GetCellName(0, nIndex);
+ const SwTableBox* pTLBox = pTable->GetTableBox(sTLName);
+ if(!pTLBox)
+ throw uno::RuntimeException("Illegal arguments", getXWeak());
+ const SwStartNode* pSttNd = pTLBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ // set cursor to the upper-left cell of the range
+ auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
+ pUnoCursor->Move(fnMoveForward, GoInNode);
+ pUnoCursor->SetRemainInSection( false );
+ const OUString sBLName = sw_GetCellName(0, nIndex + nCount - 1);
+ const SwTableBox* pBLBox = pTable->GetTableBox( sBLName );
+ if(!pBLBox)
+ throw uno::RuntimeException("Illegal arguments", getXWeak());
+ pUnoCursor->SetMark();
+ pUnoCursor->GetPoint()->Assign( *pBLBox->GetSttNd() );
+ pUnoCursor->Move(fnMoveForward, GoInNode);
+ SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
+ {
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rCursor);
+ }
+ rCursor.MakeBoxSels();
+ { // these braces are important
+ UnoActionContext aAction(pFrameFormat->GetDoc());
+ pFrameFormat->GetDoc()->DeleteRow(*pUnoCursor);
+ pUnoCursor.reset();
+ }
+ {
+ // invalidate all actions - TODO: why?
+ UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc());
+ }
+}
+
+void SwXTableRows::Impl::Notify( const SfxHint& rHint)
+{
+ if(rHint.GetId() == SfxHintId::Dying)
+ m_pFrameFormat = nullptr;
+}
+
+// SwXTableColumns
+
+class SwXTableColumns::Impl : public SvtListener
+{
+ SwFrameFormat* m_pFrameFormat;
+ public:
+ explicit Impl(SwFrameFormat& rFrameFormat) : m_pFrameFormat(&rFrameFormat)
+ {
+ StartListening(rFrameFormat.GetNotifier());
+ }
+ SwFrameFormat* GetFrameFormat() { return m_pFrameFormat; }
+ virtual void Notify(const SfxHint&) override;
+};
+
+OUString SwXTableColumns::getImplementationName()
+ { return "SwXTableColumns"; }
+
+sal_Bool SwXTableColumns::supportsService(const OUString& rServiceName)
+ { return cppu::supportsService(this, rServiceName); }
+
+uno::Sequence< OUString > SwXTableColumns::getSupportedServiceNames()
+ { return { "com.sun.star.text.TableColumns"}; }
+
+
+SwXTableColumns::SwXTableColumns(SwFrameFormat& rFrameFormat) :
+ m_pImpl(new SwXTableColumns::Impl(rFrameFormat))
+{ }
+
+SwXTableColumns::~SwXTableColumns()
+{ }
+
+SwFrameFormat* SwXTableColumns::GetFrameFormat() const
+{
+ return m_pImpl->GetFrameFormat();
+}
+
+sal_Int32 SwXTableColumns::getCount()
+{
+ SolarMutexGuard aGuard;
+ SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
+ SwTable* pTable = SwTable::FindTable( pFrameFormat );
+// if(!pTable->IsTableComplex())
+// throw uno::RuntimeException("Table too complex", getXWeak());
+ SwTableLines& rLines = pTable->GetTabLines();
+ SwTableLine* pLine = rLines.front();
+ return pLine->GetTabBoxes().size();
+}
+
+uno::Any SwXTableColumns::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if(nIndex < 0 || getCount() <= nIndex)
+ throw lang::IndexOutOfBoundsException();
+ return uno::Any(uno::Reference<uno::XInterface>()); // i#21699 not supported
+}
+
+uno::Type SAL_CALL SwXTableColumns::getElementType()
+{
+ return cppu::UnoType<uno::XInterface>::get();
+}
+
+sal_Bool SwXTableColumns::hasElements()
+{
+ SolarMutexGuard aGuard;
+ lcl_EnsureCoreConnected(GetFrameFormat(), this);
+ return true;
+}
+
+///@see SwXTableRows::insertByIndex (TODO: seems to be copy and paste programming here)
+void SwXTableColumns::insertByIndex(sal_Int32 nIndex, sal_Int32 nCount)
+{
+ SolarMutexGuard aGuard;
+ if (nCount == 0)
+ return;
+ SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
+ SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this);
+ SwTableLines& rLines = pTable->GetTabLines();
+ SwTableLine* pLine = rLines.front();
+ const size_t nColCount = pLine->GetTabBoxes().size();
+ if (nCount <= 0 || 0 > nIndex || o3tl::make_unsigned(nIndex) > nColCount)
+ throw uno::RuntimeException("Illegal arguments", getXWeak());
+ const OUString sTLName = sw_GetCellName(nIndex, 0);
+ const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
+ bool bAppend = false;
+ if(!pTLBox)
+ {
+ bAppend = true;
+ // to append at the end the cursor must be in the last line
+ SwTableBoxes& rBoxes = pLine->GetTabBoxes();
+ pTLBox = rBoxes.back();
+ }
+ if(!pTLBox)
+ throw uno::RuntimeException("Illegal arguments", getXWeak());
+ const SwStartNode* pSttNd = pTLBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ UnoActionContext aAction(pFrameFormat->GetDoc());
+ auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
+ pUnoCursor->Move(fnMoveForward, GoInNode);
+
+ {
+ // remove actions - TODO: why?
+ UnoActionRemoveContext aRemoveContext(&pUnoCursor->GetDoc());
+ }
+
+ pFrameFormat->GetDoc()->InsertCol(*pUnoCursor, o3tl::narrowing<sal_uInt16>(nCount), bAppend);
+}
+
+///@see SwXTableRows::removeByIndex (TODO: seems to be copy and paste programming here)
+void SwXTableColumns::removeByIndex(sal_Int32 nIndex, sal_Int32 nCount)
+{
+ SolarMutexGuard aGuard;
+ if (nCount == 0)
+ return;
+ SwFrameFormat* pFrameFormat(lcl_EnsureCoreConnected(GetFrameFormat(), this));
+ if(nIndex < 0 || nCount <=0 )
+ throw uno::RuntimeException();
+ SwTable* pTable = lcl_EnsureTableNotComplex(SwTable::FindTable(pFrameFormat), this);
+ const OUString sTLName = sw_GetCellName(nIndex, 0);
+ const SwTableBox* pTLBox = pTable->GetTableBox( sTLName );
+ if(!pTLBox)
+ throw uno::RuntimeException("Cell not found", getXWeak());
+ const SwStartNode* pSttNd = pTLBox->GetSttNd();
+ SwPosition aPos(*pSttNd);
+ // set cursor to the upper-left cell of the range
+ auto pUnoCursor(pFrameFormat->GetDoc()->CreateUnoCursor(aPos, true));
+ pUnoCursor->Move(fnMoveForward, GoInNode);
+ pUnoCursor->SetRemainInSection(false);
+ const OUString sTRName = sw_GetCellName(nIndex + nCount - 1, 0);
+ const SwTableBox* pTRBox = pTable->GetTableBox(sTRName);
+ if(!pTRBox)
+ throw uno::RuntimeException("Cell not found", getXWeak());
+ pUnoCursor->SetMark();
+ pUnoCursor->GetPoint()->Assign( *pTRBox->GetSttNd() );
+ pUnoCursor->Move(fnMoveForward, GoInNode);
+ SwUnoTableCursor& rCursor = dynamic_cast<SwUnoTableCursor&>(*pUnoCursor);
+ {
+ // HACK: remove pending actions for selecting old style tables
+ UnoActionRemoveContext aRemoveContext(rCursor);
+ }
+ rCursor.MakeBoxSels();
+ { // these braces are important
+ UnoActionContext aAction(pFrameFormat->GetDoc());
+ pFrameFormat->GetDoc()->DeleteCol(*pUnoCursor);
+ pUnoCursor.reset();
+ }
+ {
+ // invalidate all actions - TODO: why?
+ UnoActionRemoveContext aRemoveContext(pFrameFormat->GetDoc());
+ }
+}
+
+void SwXTableColumns::Impl::Notify(const SfxHint& rHint)
+{
+ if(rHint.GetId() == SfxHintId::Dying)
+ m_pFrameFormat = nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */