Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/source/core/unocore/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 158 kB image not shown  

Quelle  unotbl.cxx   Sprache: C

 
/* -*- 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 <swmodule.hxx>
#include <swtypes.hxx>
#include <cmdid.h>
#include <unocoll.hxx>
#include <unomid.h>
#include <unomap.hxx>
#include <unotbl.hxx>
#include <unosection.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 <names.hxx>
#include <o3tl/string_view.hxx>

using namespace ::com::sun::star;
using ::editeng::SvxBorderLine;

namespace
{
    struct FindUnoCellInstanceHint final : SfxHint
    {
        FindUnoCellInstanceHint(const SwTableBox* pCore) : SfxHint(SfxHintId::SwFindUnoCellInstance), m_pCore(pCore) {};
        const SwTableBox* const m_pCore;
        mutable rtl::Reference<SwXCell> m_pResult;
    };
    struct FindUnoTextTableRowInstanceHint final : SfxHint
    {
        FindUnoTextTableRowInstanceHint(const SwTableLine* pCore) : SfxHint(SfxHintId::SwFindUnoTextTableRowInstance), m_pCore(pCore) {};
        const SwTableLine* const m_pCore;
        mutable rtl::Reference<SwXTextTableRow> m_pResult;
    };
    SwFrameFormat* lcl_EnsureCoreConnected(SwFrameFormat* pFormat, cppu::OWeakObject* pObject)
    {
        if(!pFormat)
            throw uno::RuntimeException(u"Lost connection to core objects"_ustr, pObject);
        return pFormat;
    }
    SwTable* lcl_EnsureTableNotComplex(SwTable* pTable, cppu::OWeakObject* pObject)
    {
        if(pTable->IsTableComplex())
            throw uno::RuntimeException(u"Table too complex"_ustr, pObject);
        return pTable;
    }

    chart::ChartDataChangeEvent createChartEvent(uno::Reference<uno::XInterface> const&&nbsp;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,
            const ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> & rListeners)
    {
        if (rListeners.getLength(rGuard))
            rListeners.notifyEach(rGuard,
                    &chart::XChartDataChangeEventListener::chartDataChanged,
                    createChartEvent(xSource));
    }

    void lcl_SendChartEvent(std::mutex& rMutex,
            uno::Reference<uno::XInterface> const& xSource,
            const ::comphelper::OInterfaceContainerHelper4<chart::XChartDataChangeEventListener> & rListeners)
    {
        std::unique_lock aGuard(rMutex);
        lcl_SendChartEvent(aGuard, xSource, rListeners);
    }
}

#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 if (aSz.GetWidthPercent() == 0) // If it's already enabled, just ignore it
                {
                    throw lang::IllegalArgumentException(u"relative width cannot be switched on with this property"_ustr, nullptr, 0);
                }
            }
            pFormat->GetDoc().SetAttr(aSz, *pFormat);
        }
        break;

        case RES_PAGEDESC:
        {
            OUString sPageStyle;
            aValue >>= sPageStyle;
            const SwPageDesc* pDesc = nullptr;
            if (!sPageStyle.isEmpty())
            {
                UIName sPageStyleUIName;
                SwStyleNameMapper::FillUIName(ProgName(sPageStyle), sPageStyleUIName, SwGetPoolIdFromName::PageDesc);
                pDesc = SwPageDesc::GetByName(pFormat->GetDoc(), sPageStyleUIName);
            }
            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 ).toString());
            }
            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().toString());

        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.empty());
        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, SwTableBoconst * 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, SwTableBoconst * pBox, bool bRow, SwDoc& rDoc)
{
    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];
    }
    rDoc.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(!::sw::XTextRangeToSwPaM(aPam, xTextPosition))
        throw uno::RuntimeException();
    return createXTextCursorByRangeImpl(aPam);
}

rtl::Reference< SwXTextCursor > SwXCell::createXTextCursorByRangeImpl(
        SwUnoInternalPaM& rPam)
{
    if(!m_pStartNode && !IsValid())
        throw uno::RuntimeException();
    const SwStartNode* pSttNd = m_pStartNode ? m_pStartNode : m_pBox->GetSttNd();
    // skip sections
    SwStartNode* p1 = rPam.GetPointNode().StartOfSectionNode();
    while(p1->IsSectionNode())
        p1 = p1->StartOfSectionNode();
    if( p1 != pSttNd )
        return nullptr;
    return new SwXTextCursor(*GetDoc(), this, CursorType::TableText,
                *rPam.GetPoint(), rPam.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(u"RedlineType"_ustr) >>= sRedlineType))
            throw beans::UnknownPropertyException(u"No redline type property: "_ustr, 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();
            rtl::Reference< SwXTextSection > xSect = SwXTextSections::GetObject(*rSect.GetFormat());
            return uno::Any(uno::Reference< text::XTextSection >(xSect));
        }
        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(u"not implemented"_ustr, getXWeak()); };

void SwXCell::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXCell::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXCell::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

uno::Reference<container::XEnumeration> SwXCell::createEnumeration()
{
    return createSwEnumeration();
}

rtl::Reference<SwXParagraphEnumeration> SwXCell::createSwEnumeration()
{
    SolarMutexGuard aGuard;
    if(!IsValid())
        return {};
    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(rHint.GetId() == SfxHintId::SwFindUnoCellInstance)
    {
        auto pFindHint = static_cast<const FindUnoCellInstanceHint*>(&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();
    FindUnoCellInstanceHint 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 u"SwXCell"_ustr; }

sal_Bool SwXCell::supportsService(const OUString& rServiceName)
    { return cppu::supportsService(this, rServiceName); }

uno::Sequence< OUString > SwXCell::getSupportedServiceNames()
    { return {u"com.sun.star.text.CellProperties"_ustr}; }

OUString SwXTextTableRow::getImplementationName()
    { return u"SwXTextTableRow"_ustr; }

sal_Bool SwXTextTableRow::supportsService(const OUString& rServiceName)
    { return cppu::supportsService(this, rServiceName); }

uno::Sequence< OUString > SwXTextTableRow::getSupportedServiceNames()
    { return {u"com.sun.star.text.TextTableRow"_ustr}; }


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(u"RedlineType"_ustr) >>= sRedlineType) )
        {
            throw beans::UnknownPropertyException(u"No redline type property: "_ustr, getXWeak() );
        }

        // Create a 'Table Row Redline' object
        SwUnoCursorHelper::makeTableRowRedline( *pLn, sRedlineType, tableRowProperties);

    }
    else
    {
        const SfxItemPropertyMapEntry* pEntry =
            m_pPropSet->getPropertyMap().getByName(rPropertyName);
        SwDoc& rDoc = 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);
                }
                rDoc.SetAttr(aFrameSize, *pLn->ClaimFrameFormat());
            }
            break;

            case FN_UNO_TABLE_COLUMN_SEPARATORS:
            {
                UnoActionContext aContext(&rDoc);
                SwTable* pTable2 = SwTable::FindTable( pFormat );
                lcl_SetTableSeparators(aValue, pTable2, m_pLine->GetTabBoxes()[0], true, rDoc);
            }
            break;

            default:
            {
                SwFrameFormat* pLnFormat = pLn->ClaimFrameFormat();
                SwAttrSet aSet(pLnFormat->GetAttrSet());
                SfxItemPropertySet::setPropertyValue(*pEntry, aValue, aSet);
                rDoc.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();
                SfxItemPropertySet::getPropertyValue(*pEntry, rSet, aRet);
            }
        }
    }
    return aRet;
}

void SwXTextTableRow::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXTextTableRow::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXTextTableRow::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXTextTableRow::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXTextTableRow::Notify(const SfxHint& rHint)
{
    if(rHint.GetId() == SfxHintId::Dying)
    {
        m_pFormat = nullptr;
    }
    else if(rHint.GetId() == SfxHintId::SwFindUnoTextTableRowInstance)
    {
        auto pFindHint = static_cast<const FindUnoTextTableRowInstanceHint*>(&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 u"SwXTextTableCursor"_ustr; }

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 {u"com.sun.star.text.TextTableCursor"_ustr}; }

SwXTextTableCursor::SwXTextTableCursor(SwFrameFormat* pFrameFormat, SwTableBox const* pBox)
    : m_pFrameFormat(pFrameFormat)
    , m_pPropSet(aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_TABLE_CURSOR))
{
    StartListening(m_pFrameFormat->GetNotifier());
    SwDoc& rDoc = m_pFrameFormat->GetDoc();
    const SwStartNode* pSttNd = pBox->GetSttNd();
    SwPosition aPos(*pSttNd);
    m_pUnoCursor.reset(rDoc.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.reset(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(u"Illegal first argument: needs to be > 0"_ustr, 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))
            {
                SfxItemPropertySet::setPropertyValue(*pEntry, aValue, aItemSet);
            }
            SwUnoCursorHelper::SetCursorAttr(rTableCursor.GetSelRing(),
                    aItemSet, SetAttrMode::DEFAULTtrue);
        }
    }
}

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)
            {
                ProgName ret;
                SwStyleNameMapper::FillProgName(pFormat->GetName(), ret, SwGetPoolIdFromName::TxtColl);
                aResult <<= ret.toString();
            }
        }
        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);
            SfxItemPropertySet::getPropertyValue(*pEntry, aSet, aResult);
        }
    }
    return aResult;
}

void SwXTextTableCursor::addPropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXTextTableCursor::removePropertyChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XPropertyChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXTextTableCursor::addVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, getXWeak()); };

void SwXTextTableCursor::removeVetoableChangeListener(const OUString& /*rPropertyName*/, const uno::Reference< beans::XVetoableChangeListener > & /*xListener*/)
    { throw uno::RuntimeException(u"not implemented"_ustr, 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);
    const uno::Any* GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId);
    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);
    }

const uno::Any* SwTableProperties_Impl::GetProperty(sal_uInt16 nWhichId, sal_uInt16 nMemberId)
    {
        const uno::Any* pAny = nullptr;
        m_aAnyMap.FillValue(nWhichId, nMemberId, pAny);
        return pAny;
    }

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)
    {
        if (const uno::Any* pAny = GetProperty(nWhich, nMember))
            vMemberAndAny.emplace_back(nMember, pAny);
    }
    if(!vMemberAndAny.empty())
    {
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=62 G=80

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.