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

Quelle  svdotable.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 <memory>
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
#include <comphelper/configuration.hxx>
#include <vcl/canvastools.hxx>
#include <vcl/ptrstyle.hxx>
#include <com/sun/star/style/XStyle.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <svl/style.hxx>
#include <editeng/editstat.hxx>
#include <editeng/outlobj.hxx>
#include <sdr/properties/textproperties.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdotable.hxx>
#include <svx/svdhdl.hxx>
#include "viewcontactoftableobj.hxx"
#include <svx/svdoutl.hxx>
#include <svx/svddrag.hxx>
#include <tablemodel.hxx>
#include <cell.hxx>
#include "tablelayouter.hxx"
#include "tablehandles.hxx"
#include <svx/sdr/table/tabledesign.hxx>
#include <svx/svdundo.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
#include <editeng/writingmodeitem.hxx>
#include <editeng/frmdiritem.hxx>
#include <libxml/xmlwriter.h>
#include <comphelper/diagnose_ex.hxx>

#include <boost/property_tree/ptree.hpp>

#include "sdrtableobjimpl.hxx"

using ::com::sun::star::uno::Any;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::UNO_QUERY;
using ::com::sun::star::uno::UNO_QUERY_THROW;
using ::com::sun::star::uno::Exception;
using ::com::sun::star::container::XIndexAccess;
using ::com::sun::star::style::XStyle;
using ::com::sun::star::table::XTableRows;
using ::com::sun::star::table::XTableColumns;
using ::com::sun::star::table::XTable;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::util::XModifyBroadcaster;
using sdr::properties::TextProperties;
using sdr::properties::BaseProperties;
using namespace ::com::sun::star;
using namespace ::com::sun::star::text;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::style;

namespace sdr::table {

namespace {

class TableProperties : public TextProperties
{
protected:
    // create a new itemset
    SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;

public:
    // basic constructor
    explicit TableProperties(SdrObject& rObj );

    // constructor for copying, but using new object
    TableProperties(const TableProperties& rProps, SdrObject& rObj );

    // Clone() operator, normally just calls the local copy constructor
    std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;

    virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) override;
};

}

TableProperties::TableProperties(SdrObject& rObj)
: TextProperties(rObj)
{
}

TableProperties::TableProperties(const TableProperties& rProps, SdrObject& rObj)
: TextProperties(rProps, rObj)
{
}

std::unique_ptr<BaseProperties> TableProperties::Clone(SdrObject& rObj) const
{
    return std::unique_ptr<BaseProperties>(new TableProperties(*this, rObj));
}

void TableProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
{
    if( nWhich == SDRATTR_TEXTDIRECTION )
        AttributeProperties::ItemChange( nWhich, pNewItem );
    else
        TextProperties::ItemChange( nWhich, pNewItem );
}

// create a new itemset
SfxItemSet TableProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
{
    return SfxItemSet(rPool,

        // range from SdrAttrObj
        svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
        SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
        SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,

        // range for SdrTableObj
        SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST,

        // range from SdrTextObj
        EE_ITEMS_START, EE_ITEMS_END>);
}

namespace {

class TableObjectGeoData : public SdrTextObjGeoData
{
public:
    tools::Rectangle   maLogicRect;
};

}

TableStyleSettings::TableStyleSettings()
: mbUseFirstRow(true)
, mbUseLastRow(false)
, mbUseFirstColumn(false)
, mbUseLastColumn(false)
, mbUseRowBanding(true)
, mbUseColumnBanding(false)
{
}

TableStyleSettings::TableStyleSettings( const TableStyleSettings& rStyle )
{
    (*this) = rStyle;
}

TableStyleSettings& TableStyleSettings::operator=(const TableStyleSettings& ;rStyle)
{
    mbUseFirstRow = rStyle.mbUseFirstRow;
    mbUseLastRow = rStyle.mbUseLastRow;
    mbUseFirstColumn = rStyle.mbUseFirstColumn;
    mbUseLastColumn = rStyle.mbUseLastColumn;
    mbUseRowBanding = rStyle.mbUseRowBanding;
    mbUseColumnBanding = rStyle.mbUseColumnBanding;
    return *this;
}

bool TableStyleSettings::operator==( const TableStyleSettings& rStyle ) const
{
    return
        (mbUseFirstRow == rStyle.mbUseFirstRow) &&
        (mbUseLastRow == rStyle.mbUseLastRow) &&
        (mbUseFirstColumn == rStyle.mbUseFirstColumn) &&
        (mbUseLastColumn == rStyle.mbUseLastColumn) &&
        (mbUseRowBanding == rStyle.mbUseRowBanding) &&
        (mbUseColumnBanding == rStyle.mbUseColumnBanding);
}


SdrTableObjImpl* SdrTableObjImpl::lastLayoutTable = nullptr;
tools::Rectangle SdrTableObjImpl::lastLayoutInputRectangle;
tools::Rectangle SdrTableObjImpl::lastLayoutResultRectangle;
bool SdrTableObjImpl::lastLayoutFitWidth;
bool SdrTableObjImpl::lastLayoutFitHeight;
WritingMode SdrTableObjImpl::lastLayoutMode;
sal_Int32 SdrTableObjImpl::lastRowCount;
sal_Int32 SdrTableObjImpl::lastColCount;
bool SdrTableObjImpl::rowSizeChanged = false;
std::vector<sal_Int32> SdrTableObjImpl::lastColWidths;

SdrTableObjImpl::SdrTableObjImpl()
: mpTableObj( nullptr )
, mbSkipChangeLayout(false)
{
}


SdrTableObjImpl::~SdrTableObjImpl()
{
    if( lastLayoutTable == this )
        lastLayoutTable = nullptr;
}


void SdrTableObjImpl::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
{
    if(!mxTable.is())
    {
        return;
    }

    const sal_Int32 nColumns(rEnd.mnCol - rStart.mnCol + 1);
    const sal_Int32 nRows(rEnd.mnRow - rStart.mnRow + 1);

    if(nColumns < 1 || nRows < 1 || nColumns > getColumnCount() || nRows > getRowCount())
    {
        return;
    }

    // tdf#116977 First thought was to create the new TableModel, copy data to it and then exchange
    // mxTable and dispose old one. This does *not* work, even when all stuff looks nicely referenced
    // and safe *because* Cell::create gets handed over the current SdrTableObj, hands it to
    // ::Cell and there the local mxTable is initialized using rTableObj.getTable() (!). Due to This,
    // the new created Cells in a new created TableModel based on given mpTableObj *will be disposed*
    // when the old mxTable gets disposed - ARGH!
    // To avoid, change strategy: Remember old TableModel, reset mxTable immediately - this is the
    // SdrTableObjImpl of the current SdrTableObj anyways. Luckily, this works as intended...

    // remember old TableModel
    TableModelRef xOldTable(mxTable);

    // immediately create new one and initialize. This creates ::Cell's which then will use
    // the correct TableModel (accessed through SdrTableObj, but using local mxTable)
    mxTable = new TableModel(mpTableObj);
    mxTable->init(nColumns, nRows);

    // copy cells
    for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
    {
        for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol ) try
        {
            CellRef xTargetCell( mxTable->getCell( nCol, nRow ) );
            if( xTargetCell.is() )
                xTargetCell->cloneFrom( xOldTable->getCell( rStart.mnCol + nCol, rStart.mnRow + nRow ) );
        }
        catch( Exception& )
        {
            TOOLS_WARN_EXCEPTION("svx.table""");
        }
    }

    // copy row heights
    Reference< XTableRows > xNewRows(mxTable->getRows(), css::uno::UNO_SET_THROW );
    static constexpr OUStringLiteral sHeight( u"Height" );
    for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
    {
        Reference< XPropertySet > xNewSet( xNewRows->getByIndex( nRow ), UNO_QUERY_THROW );
        xNewSet->setPropertyValue( sHeight, Any( mpLayouter->getRowHeight( rStart.mnRow + nRow ) ) );
    }

    // copy column widths
    Reference< XTableColumns > xNewColumns( mxTable->getColumns(), css::uno::UNO_SET_THROW );
    static constexpr OUStringLiteral sWidth( u"Width" );
    for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol )
    {
        Reference< XPropertySet > xNewSet( xNewColumns->getByIndex( nCol ), UNO_QUERY_THROW );
        xNewSet->setPropertyValue( sWidth, Any( mpLayouter->getColumnWidth( rStart.mnCol + nCol ) ) );
    }

    // reset layouter which still holds a copy to old TableModel
    mpLayouter.reset();

    // cleanup old TableModel
    {
        Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
        xOldTable->removeModifyListener( xListener );
        xOldTable->dispose();
        xOldTable.clear();
    }

    // create and hand over to new TableLayouter
    mpLayouter.reset(new TableLayouter( mxTable ));

    // add needed listener to react on changes
    Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
    mxTable->addModifyListener( xListener );

    // Apply Style to Cells
    ApplyCellStyles();

    // layout cropped table
    auto aRectangle = mpTableObj->getRectangle();
    LayoutTable(aRectangle, falsefalse);
    mpTableObj->setRectangle(aRectangle);
}

void SdrTableObjImpl::init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows )
{
    mpTableObj = pTable;
    mxTable = new TableModel( pTable );
    mxTable->init( nColumns, nRows );
    Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
    mxTable->addModifyListener( xListener );
    mpLayouter.reset(new TableLayouter( mxTable ));
    auto aRectangle = mpTableObj->getRectangle();
    LayoutTable(aRectangle, truetrue);
    mpTableObj->setRectangle(aRectangle);
    mpTableObj->maLogicRect = aRectangle;
}


SdrTableObjImpl& SdrTableObjImpl::operator=( const SdrTableObjImpl& rSource )
{
    if(this == &rSource)
    {
        return *this;
    }

    if(nullptr == mpTableObj || nullptr == rSource.mpTableObj)
    {
        // error: need both SdrObjects to successfully copy data
        return *this;
    }

    // remove evtl. listeners from local
    disconnectTableStyle();

    // reset layouter which holds a copy
    mpLayouter.reset();

    // cleanup local mxTable if used
    if( mxTable.is() )
    {
        Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
        mxTable->removeModifyListener( xListener );
        mxTable->dispose();
        mxTable.clear();
    }

    // tdf#127481: reset active cell reference
    mxActiveCell.clear();

    // copy TableStyle (short internal data)
    maTableStyle = rSource.maTableStyle;

    // create/copy new mxTable. This will copy all needed cells, too
    mxTable = new TableModel( mpTableObj, rSource.mxTable );

    // create and hand over to new TableLayouter
    mpLayouter.reset(new TableLayouter( mxTable ));

    // add needed listener to react on changes
    Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
    mxTable->addModifyListener( xListener );

    // handle TableStyle
    Reference< XIndexAccess > xNewTableStyle;
    SdrModel& rSourceSdrModel(rSource.mpTableObj->getSdrModelFromSdrObject());
    SdrModel& rTargetSdrModel(mpTableObj->getSdrModelFromSdrObject());

    if(rSource.mxTableStyle.is() && &rSourceSdrModel == &rTargetSdrModel)
    {
        // source and target model the same -> keep current TableStyle
        xNewTableStyle = rSource.mxTableStyle;
    }

    if(!xNewTableStyle.is() && rSource.mxTableStyle.is()) try
    {
        // search in target SdrModel for that TableStyle
        const OUString sStyleName( Reference< XNamed >( rSource.mxTableStyle, UNO_QUERY_THROW )->getName() );
        Reference< XStyleFamiliesSupplier > xSFS(rTargetSdrModel.getUnoModel(), UNO_QUERY_THROW );
        Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), css::uno::UNO_SET_THROW );
        Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( u"table"_ustr ), UNO_QUERY_THROW );

        if( xTableFamilyAccess->hasByName( sStyleName ) )
        {
            // found table style with the same name
            xTableFamilyAccess->getByName( sStyleName ) >>= xNewTableStyle;
        }
        else
        {
            // copy or? Not found, use 1st existing TableStyle (or none)
            Reference< XIndexAccess > xIndexAccess( xTableFamilyAccess, UNO_QUERY_THROW );
            xIndexAccess->getByIndex( 0 ) >>= xNewTableStyle;
        }
    }
    catch( Exception& )
    {
        TOOLS_WARN_EXCEPTION("svx.table""");
    }

    // set that TableStyle
    mxTableStyle = std::move(xNewTableStyle);

    // Apply Style to Cells
    ApplyCellStyles();

    // copy geometry
    mpTableObj->setRectangle(mpTableObj->maLogicRect);

    // layout cloned table
    auto aRectangle = mpTableObj->getRectangle();
    LayoutTable(aRectangle, falsefalse);
    mpTableObj->setRectangle(aRectangle);

    // re-connect to styles (evtl. in new SdrModel)
    connectTableStyle();

    return *this;
}

void SdrTableObjImpl::ApplyCellStyles()
{
    if( !mxTable.is() || !mxTableStyle.is() )
        return;

    const sal_Int32 nColCount = getColumnCount();
    const sal_Int32 nRowCount = getRowCount();

    const TableStyleSettings& rStyle = maTableStyle;

    CellPos aPos;
    for( aPos.mnRow = 0; aPos.mnRow < nRowCount; ++aPos.mnRow )
    {
        const bool bFirstRow = (aPos.mnRow == 0) && rStyle.mbUseFirstRow;
        const bool bLastRow = (aPos.mnRow == nRowCount-1) && rStyle.mbUseLastRow;

        for( aPos.mnCol = 0; aPos.mnCol < nColCount; ++aPos.mnCol )
        {
            Reference< XStyle > xStyle;

            // first and last row win first, if used and available
            if( bFirstRow )
            {
                mxTableStyle->getByIndex(first_row_style) >>= xStyle;
            }
            else if( bLastRow )
            {
                mxTableStyle->getByIndex(last_row_style) >>= xStyle;
            }

            if( !xStyle.is() )
            {
                // next come first and last column, if used and available
                if( rStyle.mbUseFirstColumn && (aPos.mnCol == 0)  )
                {
                    mxTableStyle->getByIndex(first_column_style) >>= xStyle;
                }
                else if( rStyle.mbUseLastColumn && (aPos.mnCol == nColCount-1) )
                {
                    mxTableStyle->getByIndex(last_column_style) >>= xStyle;
                }
            }

            if( !xStyle.is() && rStyle.mbUseRowBanding )
            {
                if( (aPos.mnRow & 1) == 0 )
                {
                    mxTableStyle->getByIndex(even_rows_style) >>= xStyle;
                }
                else
                {
                    mxTableStyle->getByIndex(odd_rows_style) >>= xStyle;
                }
            }

            if( !xStyle.is() && rStyle.mbUseColumnBanding )
            {
                if( (aPos.mnCol & 1) == 0 )
                {
                    mxTableStyle->getByIndex(even_columns_style) >>= xStyle;
                }
                else
                {
                    mxTableStyle->getByIndex(odd_columns_style) >>= xStyle;
                }
            }

            if( !xStyle.is() )
            {
                // use default cell style if non found yet
                mxTableStyle->getByIndex(body_style) >>= xStyle;
            }


            if( xStyle.is() )
            {
                SfxUnoStyleSheet* pStyle = SfxUnoStyleSheet::getUnoStyleSheet(xStyle);

                if( pStyle )
                {
                    CellRef xCell( getCell( aPos ) );
                    if( xCell.is() && ( xCell->GetStyleSheet() != pStyle ) )
                    {
                        xCell->SetStyleSheet( pStyle, true );
                    }
                }
            }
        }
    }
}


void SdrTableObjImpl::dispose()
{
    disconnectTableStyle();
    mxTableStyle.clear();

    mpLayouter.reset();

    if( mxTable.is() )
    {
        Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
        mxTable->removeModifyListener( xListener );
        mxTable->dispose();
        mxTable.clear();
    }
}


void SdrTableObjImpl::DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset )
{
    if( !((nEdge >= 0) && mxTable.is()))
        return;

    try
    {
        static constexpr OUString sSize( u"Size"_ustr );
        if( mbHorizontal )
        {
            if (nEdge <= getRowCount())
            {
                sal_Int32 nHeight = mpLayouter->getRowHeight( (!nEdge)?nEdge:(nEdge-1) );
                if(nEdge==0)
                    nHeight -= nOffset;
                else
                    nHeight += nOffset;
                Reference< XIndexAccess > xRows( mxTable->getRows(), UNO_QUERY_THROW );
                Reference< XPropertySet > xRowSet( xRows->getByIndex( (!nEdge)?nEdge:(nEdge-1) ), UNO_QUERY_THROW );
                xRowSet->setPropertyValue( sSize, Any( nHeight ) );
                rowSizeChanged = true;
            }
        }
        else
        {
            /*
            fixes fdo#59889 and resizing of table in edge dragging
            Total vertical edges in a NxN table is N+1, indexed from 0 to N and total Columns is N, indexed from 0 to N-1
            In LTR table vertical edge responsible for dragging of column x(x=0 to N-1) is, Edge x+1
            But in RTL table vertical edge responsible for dragging of column x(x=0 to N-1, but from right to left)is, Edge x
            In LTR table dragging of edge 0(for RTL table edge N) does nothing.
            */

            //Todo: Implement Dragging functionality for leftmost edge of table.
            if (nEdge <= getColumnCount())
            {
                const bool bRTL = mpTableObj != nullptr && (mpTableObj->GetWritingMode() == WritingMode_RL_TB);
                sal_Int32 nWidth;
                if(bRTL)
                {
                    nWidth = mpLayouter->getColumnWidth( nEdge );
                }
                else
                {
                    nWidth = mpLayouter->getColumnWidth( (!nEdge)?nEdge:(nEdge-1) );
                }
                Reference< XIndexAccess > xCols( mxTable->getColumns(), UNO_QUERY_THROW );
                nWidth += nOffset;
                if(bRTL && nEdge<getColumnCount())
                {
                    Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge ), UNO_QUERY_THROW );
                    xColSet->setPropertyValue( sSize, Any( nWidth ) );
                }
                else if(!bRTL && nEdge>0)
                {
                    Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge-1 ), UNO_QUERY_THROW );
                    xColSet->setPropertyValue( sSize, Any( nWidth ) );
                }
                /* To prevent the table resizing on edge dragging */
                if( nEdge > 0 && nEdge < mxTable->getColumnCount() )
                {
                    if( bRTL )
                        nEdge--;

                    nWidth = mpLayouter->getColumnWidth(nEdge);
                    nWidth = std::max(static_cast<sal_Int32>(nWidth - nOffset), sal_Int32(0));

                    Reference<XPropertySet> xColSet(xCols->getByIndex(nEdge), UNO_QUERY_THROW);
                    xColSet->setPropertyValue(sSize, Any(nWidth));
                }
            }
        }
    }
    catch( Exception& )
    {
        TOOLS_WARN_EXCEPTION("svx.table""");
    }
}


// XModifyListener


void SAL_CALL SdrTableObjImpl::modified( const css::lang::EventObject& aEvent )
{
    if (aEvent.Source == mxTableStyle && mpTableObj)
        static_cast<TextProperties&>(mpTableObj->GetProperties()).increaseVersion();

    update();
}

void SdrTableObjImpl::update()
{
    // source can be the table model itself or the assigned table template
    TableModelNotifyGuard aGuard( mxTable.get() );
    if( !mpTableObj )
        return;

    if( (maEditPos.mnRow >= getRowCount()) || (maEditPos.mnCol >= getColumnCount()) || (getCell( maEditPos ) != mxActiveCell) )
    {
        if(maEditPos.mnRow >= getRowCount())
            maEditPos.mnRow = getRowCount()-1;

        if(maEditPos.mnCol >= getColumnCount())
            maEditPos.mnCol = getColumnCount()-1;

        mpTableObj->setActiveCell( maEditPos );
    }

    ApplyCellStyles();

    mpTableObj->setRectangle(mpTableObj->maLogicRect);
    auto aRectangle = mpTableObj->getRectangle();
    LayoutTable(aRectangle, falsefalse);
    mpTableObj->setRectangle(aRectangle);

    mpTableObj->SetBoundAndSnapRectsDirty();
    mpTableObj->ActionChanged();
    mpTableObj->BroadcastObjectChange();
}


void SdrTableObjImpl::connectTableStyle()
{
    if( mxTableStyle.is() )
    {
        Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
        if( xBroadcaster.is() )
        {
            Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
            xBroadcaster->addModifyListener( xListener );
        }
    }
}


void SdrTableObjImpl::disconnectTableStyle()
{
    if( mxTableStyle.is() )
    {
        Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
        if( xBroadcaster.is() )
        {
            Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
            xBroadcaster->removeModifyListener( xListener );
        }
    }
}


bool SdrTableObjImpl::isInUse()
{
    return mpTableObj && mpTableObj->IsInserted();
}

void SdrTableObjImpl::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObjImpl"));
    if (mpLayouter)
        mpLayouter->dumpAsXml(pWriter);
    mxTable->dumpAsXml(pWriter);
    (void)xmlTextWriterEndElement(pWriter);
}


// XEventListener


void SAL_CALL SdrTableObjImpl::disposing( const css::lang::EventObject& Source )
{
    assert(Source.Source == mxTableStyle);
    (void)Source;

    Reference<XIndexAccess> xDefaultStyle;
    try
    {
        Reference<XStyleFamiliesSupplier> xSupplier(mpTableObj->getSdrModelFromSdrObject().getUnoModel(), UNO_QUERY_THROW);
        Reference<XNameAccess> xTableFamily(xSupplier->getStyleFamilies()->getByName(u"table"_ustr), UNO_QUERY_THROW);
        xDefaultStyle.set(xTableFamily->getByName(u"default"_ustr), UNO_QUERY_THROW);
    }
    catch( Exception& )
    {
        TOOLS_WARN_EXCEPTION("svx.table""");
    }

    mpTableObj->setTableStyle(xDefaultStyle);
}


CellRef SdrTableObjImpl::getCell(  const CellPos& rPos  ) const
{
    CellRef xCell;
    if( mxTable.is() ) try
    {
        xCell = mxTable->getCell( rPos.mnCol, rPos.mnRow );
    }
    catch( Exception& )
    {
        TOOLS_WARN_EXCEPTION("svx.table""");
    }
    return xCell;
}


sal_Int32 SdrTableObjImpl::getColumnCount() const
{
    return mxTable.is() ? mxTable->getColumnCount() : 0;
}

std::vector<sal_Int32> SdrTableObjImpl::getColumnWidths() const
{
    std::vector<sal_Int32> aRet;

    if (mxTable.is())
        aRet = mxTable->getColumnWidths();

    return aRet;
}

sal_Int32 SdrTableObjImpl::getRowCount() const
{
    return mxTable.is() ? mxTable->getRowCount() : 0;
}

void SdrTableObjImpl::LayoutTable( tools::Rectangle& rArea, bool bFitWidth, bool bFitHeight )
{
    if (comphelper::IsFuzzing())
        return;
    if(!mpLayouter)
        return;

    // Optimization: SdrTableObj::SetChanged() can call this very often, repeatedly
    // with the same settings, noticeably increasing load time. Skip if already done.
    bool bInteractiveMightGrowBecauseTextChanged =
        mpTableObj->IsReallyEdited() && (mpTableObj->IsAutoGrowHeight() || mpTableObj->IsAutoGrowWidth());
    WritingMode writingMode = mpTableObj->GetWritingMode();
    if( bInteractiveMightGrowBecauseTextChanged
        || lastLayoutTable != this || lastLayoutInputRectangle != rArea
        || lastLayoutFitWidth != bFitWidth || lastLayoutFitHeight != bFitHeight
        || lastLayoutMode != writingMode
        || lastRowCount != getRowCount()
        || lastColCount != getColumnCount()
        || lastColWidths != getColumnWidths()
        || rowSizeChanged )
    {
        lastLayoutTable = this;
        lastLayoutInputRectangle = rArea;
        lastLayoutFitWidth = bFitWidth;
        lastLayoutFitHeight = bFitHeight;
        lastLayoutMode = writingMode;
        lastRowCount = getRowCount();
        lastColCount = getColumnCount();
        // Column resize, when the total width and column count of the
        // table is unchanged, but re-layout is still needed.
        lastColWidths = getColumnWidths();
        TableModelNotifyGuard aGuard( mxTable.get() );
        mpLayouter->LayoutTable( rArea, bFitWidth, bFitHeight );
        lastLayoutResultRectangle = rArea;
        rowSizeChanged = false;
    }
    else
    {
        rArea = lastLayoutResultRectangle;
        mpLayouter->UpdateBorderLayout();
    }
}

void SdrTableObjImpl::UpdateCells( tools::Rectangle const & rArea )
{
    if( mpLayouter && mxTable.is() )
    {
        TableModelNotifyGuard aGuard( mxTable.get() );
        mpLayouter->updateCells( rArea );
        mxTable->setModified(true);
    }
}


// BaseProperties section


std::unique_ptr<sdr::properties::BaseProperties> SdrTableObj::CreateObjectSpecificProperties()
{
    return std::make_unique<TableProperties>(*this);
}


// DrawContact section


std::unique_ptr<sdr::contact::ViewContact> SdrTableObj::CreateObjectSpecificViewContact()
{
    return std::make_unique<sdr::contact::ViewContactOfTableObj>(*this);
}

SdrTableObj::SdrTableObj(SdrModel& rSdrModel)
:   SdrTextObj(rSdrModel)
{
    osl_atomic_increment(&m_refCount); // other I get deleted during construction
    init( 1, 1 );
    osl_atomic_decrement(&m_refCount);
}

SdrTableObj::SdrTableObj(SdrModel& rSdrModel, SdrTableObj const & rSource)
:   SdrTextObj(rSdrModel, rSource)
{
    osl_atomic_increment(&m_refCount);

    init( 1, 1 );

    TableModelNotifyGuard aGuard( mpImpl.is() ? mpImpl->mxTable.get() : nullptr );

    maLogicRect = rSource.maLogicRect;
    maRectangle = rSource.maRectangle;
    maGeo = rSource.maGeo;
    meTextKind = rSource.meTextKind;
    mbTextFrame = rSource.mbTextFrame;
    maTextSize = rSource.maTextSize;
    mbTextSizeDirty = rSource.mbTextSizeDirty;
    mbNoShear = rSource.mbNoShear;
    mbDisableAutoWidthOnDragging = rSource.mbDisableAutoWidthOnDragging;

    // use SdrTableObjImpl::operator= now to
    // copy model data and other stuff (see there)
    *mpImpl = *rSource.mpImpl;

    osl_atomic_decrement(&m_refCount);
}

SdrTableObj::SdrTableObj(
    SdrModel& rSdrModel,
    const ::tools::Rectangle& rNewRect,
    sal_Int32 nColumns,
    sal_Int32 nRows)
:   SdrTextObj(rSdrModel, rNewRect)
    ,maLogicRect(rNewRect)
{
    osl_atomic_increment(&m_refCount);

    if( nColumns <= 0 )
        nColumns = 1;

    if( nRows <= 0 )
        nRows = 1;

    init( nColumns, nRows );

    osl_atomic_decrement(&m_refCount);
}


void SdrTableObj::init( sal_Int32 nColumns, sal_Int32 nRows )
{
    m_bClosedObj = true;

    mpImpl = new SdrTableObjImpl;
    mpImpl->init( this, nColumns, nRows );

    // Stuff done from old SetModel:
    if( !maLogicRect.IsEmpty() )
    {
        setRectangle(maLogicRect);
        auto aRectangle = getRectangle();
        mpImpl->LayoutTable(aRectangle, falsefalse);
        setRectangle(aRectangle);
    }
}


SdrTableObj::~SdrTableObj()
{
    mpImpl->dispose();
}


// table stuff


Reference< XTable > SdrTableObj::getTable() const
{
    return mpImpl->mxTable;
}

const rtl::Reference< TableModel > & SdrTableObj::getUnoTable() const
{
    return mpImpl->mxTable;
}

bool SdrTableObj::isValid( const CellPos& rPos ) const
{
    return (rPos.mnCol >= 0) && (rPos.mnCol < mpImpl->getColumnCount()) && (rPos.mnRow >= 0) && (rPos.mnRow < mpImpl->getRowCount());
}


CellPos SdrTableObj::getFirstCell()
{
    return CellPos( 0,0 );
}


CellPos SdrTableObj::getLastCell() const
{
    CellPos aPos;
    if( mpImpl->mxTable.is() )
    {
        aPos.mnCol = mpImpl->getColumnCount()-1;
        aPos.mnRow = mpImpl->getRowCount()-1;
    }
    return aPos;
}


CellPos SdrTableObj::getLeftCell( const CellPos& rPos, bool bEdgeTravel ) const
{
    switch( GetWritingMode() )
    {
    default:
    case WritingMode_LR_TB:
        return getPreviousCell( rPos, bEdgeTravel );
    case WritingMode_RL_TB:
        return getNextCell( rPos, bEdgeTravel );
    case WritingMode_TB_RL:
        return getPreviousRow( rPos, bEdgeTravel );
    }
}


CellPos SdrTableObj::getRightCell( const CellPos& rPos, bool bEdgeTravel  ) const
{
    switch( GetWritingMode() )
    {
    default:
    case WritingMode_LR_TB:
        return getNextCell( rPos, bEdgeTravel );
    case WritingMode_RL_TB:
        return getPreviousCell( rPos, bEdgeTravel );
    case WritingMode_TB_RL:
        return getNextRow( rPos, bEdgeTravel );
    }
}


CellPos SdrTableObj::getUpCell( const CellPos& rPos, bool bEdgeTravel ) const
{
    switch( GetWritingMode() )
    {
    default:
    case WritingMode_LR_TB:
    case WritingMode_RL_TB:
        return getPreviousRow( rPos, bEdgeTravel );
    case WritingMode_TB_RL:
        return getPreviousCell( rPos, bEdgeTravel );
    }
}


CellPos SdrTableObj::getDownCell( const CellPos& rPos, bool bEdgeTravel ) const
{
    switch( GetWritingMode() )
    {
    default:
    case WritingMode_LR_TB:
    case WritingMode_RL_TB:
        return getNextRow( rPos, bEdgeTravel );
    case WritingMode_TB_RL:
        return getNextCell( rPos, bEdgeTravel );
    }
}


CellPos SdrTableObj::getPreviousCell( const CellPos& rPos, bool bEdgeTravel ) const
{
    CellPos aPos( rPos );
    if( mpImpl.is() )
    {
        CellRef xCell( mpImpl->getCell( aPos ) );
        if( xCell.is() && xCell->isMerged() )
        {
            sal_Int32 nTemp = 0;
            findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, nTemp );
        }

        if( aPos.mnCol > 0 )
        {
            --aPos.mnCol;
        }

        else if( bEdgeTravel && (aPos.mnRow > 0) )
        {
            aPos.mnCol = mpImpl->mxTable->getColumnCount()-1;
            --aPos.mnRow;
        }
    }
    return aPos;
}


CellPos SdrTableObj::getNextCell( const CellPos& rPos, bool bEdgeTravel ) const
{
    CellPos aPos( rPos );
    if( mpImpl.is() )
    {
        CellRef xCell( mpImpl->getCell( aPos ) );
        if( xCell.is() )
        {
            if( xCell->isMerged() )
            {
                findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );

                xCell = mpImpl->getCell(aPos);

                if( xCell.is() )
                {
                    aPos.mnCol += xCell->getColumnSpan();
                    aPos.mnRow = rPos.mnRow;
                }
            }
            else
            {
                aPos.mnCol += xCell->getColumnSpan();
            }

            if( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
                return aPos;

            if( bEdgeTravel && ((aPos.mnRow + 1) < mpImpl->getRowCount()) )
            {
                aPos.mnCol = 0;
                aPos.mnRow += 1;
                return aPos;
            }
        }
    }

    // last cell reached, no traveling possible
    return rPos;
}


CellPos SdrTableObj::getPreviousRow( const CellPos& rPos, bool bEdgeTravel ) const
{
    CellPos aPos( rPos );
    if( mpImpl.is() )
    {
        CellRef xCell( mpImpl->getCell( aPos ) );
        if( xCell.is() && xCell->isMerged() )
        {
            sal_Int32 nTemp = 0;
            findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, nTemp, aPos.mnRow );
        }

        if( aPos.mnRow > 0 )
        {
            --aPos.mnRow;
        }
        else if( bEdgeTravel && (aPos.mnCol > 0) )
        {
            aPos.mnRow = mpImpl->mxTable->getRowCount()-1;
            --aPos.mnCol;
        }
    }
    return aPos;
}


CellPos SdrTableObj::getNextRow( const CellPos& rPos, bool bEdgeTravel ) const
{
    CellPos aPos( rPos );

    if( mpImpl.is() )
    {
        CellRef xCell( mpImpl->getCell( rPos ) );
        if( xCell.is() )
        {
            if( xCell->isMerged() )
            {
                findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
                xCell = mpImpl->getCell(aPos);
                aPos.mnCol = rPos.mnCol;
            }

            if( xCell.is() )
                aPos.mnRow += xCell->getRowSpan();

            if( aPos.mnRow < mpImpl->mxTable->getRowCount() )
                return aPos;

            if( bEdgeTravel && (aPos.mnCol + 1) < mpImpl->mxTable->getColumnCount() )
            {
                aPos.mnRow = 0;
                aPos.mnCol += 1;

                while( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
                {
                    xCell = mpImpl->getCell( aPos );
                    if( xCell.is() && !xCell->isMerged() )
                        return aPos;
                    aPos.mnCol += 1;
                }
            }
        }
    }

    // last position reached, no more traveling possible
    return rPos;
}


const TableStyleSettings& SdrTableObj::getTableStyleSettings() const
{
    if( mpImpl.is())
    {
        return mpImpl->maTableStyle;
    }
    else
    {
        static TableStyleSettings aTmp;
        return aTmp;
    }
}


void SdrTableObj::setTableStyleSettings( const TableStyleSettings& rStyle )
{
    if( mpImpl.is() )
    {
        mpImpl->maTableStyle = rStyle;
        mpImpl->update();
    }
}


TableHitKind SdrTableObj::CheckTableHit( const Point& rPos, sal_Int32& rnX, sal_Int32& rnY, const sal_uInt16 aTol ) const
{
    if( !mpImpl.is() || !mpImpl->mxTable.is() )
        return TableHitKind::NONE;

    rnX = 0;
    rnY = 0;

    const sal_Int32 nColCount = mpImpl->getColumnCount();
    const sal_Int32 nRowCount = mpImpl->getRowCount();

    sal_Int32 nX = rPos.X() - getRectangle().Left();
    sal_Int32 nY = rPos.Y() - getRectangle().Top();

    if( (nX < 0) || (nX > getRectangle().GetWidth()) || (nY < 0) || (nY > getRectangle().GetHeight() ) )
        return TableHitKind::NONE;

    // get vertical edge number and check for a hit
    const bool bRTL = (GetWritingMode() == WritingMode_RL_TB);
    bool bVrtHit = false;
    if( !bRTL )
    {
        while( rnX <= nColCount )
        {
            if( nX - aTol <= 0 )
            {
                bVrtHit = true;
                break;
            }

            if( rnX == nColCount )
                break;

            nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
            if( nX < 0 )
                break;
            rnX++;
        }
    }
    else
    {
        rnX = nColCount;
        while( rnX >= 0 )
        {
            if( nX - aTol <= 0 )
            {
                bVrtHit = true;
                break;
            }

            if( rnX == 0 )
                break;

            rnX--;
            nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
            if( nX < 0 )
                break;
        }
    }

    // rnX is now the edge number left to the pointer, if it was hit bHrzHit is also true

    // get vertical edge number and check for a hit
    bool bHrzHit = false;
    while( rnY <= nRowCount )
    {
        if( nY - aTol <= 0 )
        {
            bHrzHit = true;
            break;
        }

        if( rnY == nRowCount )
            break;

        nY -= mpImpl->mpLayouter->getRowHeight(rnY);
        if( nY < 0 )
            break;
        rnY++;
    }

    // rnY is now the edge number above the pointer, if it was hit bVrtHit is also true

    if( bVrtHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, false ) )
        return TableHitKind::VerticallBorder;

    if( bHrzHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, true ) )
        return TableHitKind::HorizontalBorder;

    CellRef xCell( mpImpl->getCell( CellPos( rnX, rnY ) ) );
    if( xCell.is() && xCell->isMerged() )
        findMergeOrigin( mpImpl->mxTable, rnX, rnY, rnX, rnY );

    if( xCell.is() )
    {
        nX += mpImpl->mpLayouter->getColumnWidth( rnX );
        //Fix for fdo#62673 : non-editable cell in table on cell merge
        sal_Int32 i=0;
        while(xCell.is() && xCell->isMerged())
        {
            nX += mpImpl->mpLayouter->getColumnWidth( rnX+i );
            i++;
            if(rnX+i < nColCount)
                xCell=mpImpl->getCell( CellPos( rnX+i, rnY) );
            else
                break;
        }

        if( nX < xCell->GetTextLeftDistance() )
            return TableHitKind::Cell;
    }

    return TableHitKind::CellTextArea;
}

const SfxItemSet& SdrTableObj::GetActiveCellItemSet() const
{
    return getActiveCell()->GetItemSet();
}

void SdrTableObj::setTableStyle( const Reference< XIndexAccess >& xTableStyle )
{
    if( mpImpl.is() && (mpImpl->mxTableStyle != xTableStyle) )
    {
        mpImpl->disconnectTableStyle();
        mpImpl->mxTableStyle = xTableStyle;
        mpImpl->connectTableStyle();
        mpImpl->update();
    }
}


const Reference< XIndexAccess >& SdrTableObj::getTableStyle() const
{
    if( mpImpl.is() )
    {
        return mpImpl->mxTableStyle;
    }
    else
    {
        static Reference< XIndexAccess > aTmp;
        return aTmp;
    }
}


// text stuff


/** returns the currently active text. */
SdrText* SdrTableObj::getActiveText() const
{
    return getActiveCell().get();
}


/** returns the nth available text. */
SdrText* SdrTableObj::getText( sal_Int32 nIndex ) const
{
    if( mpImpl->mxTable.is() )
    {
        const sal_Int32 nColCount = mpImpl->getColumnCount();
        if( nColCount )
        {
            CellPos aPos( nIndex % nColCount, nIndex / nColCount );

            CellRef xCell( mpImpl->getCell( aPos ) );
            return xCell.get();
        }
    }
    return nullptr;
}


/** returns the number of texts available for this object. */
sal_Int32 SdrTableObj::getTextCount() const
{
    if( mpImpl->mxTable.is() )
    {
        const sal_Int32 nColCount = mpImpl->getColumnCount();
        const sal_Int32 nRowCount = mpImpl->getRowCount();

        return nColCount * nRowCount;
    }
    else
    {
        return 0;
    }
}


/** changes the current active text */
void SdrTableObj::setActiveText( sal_Int32 nIndex )
{
    if( mpImpl.is() && mpImpl->mxTable.is() )
    {
        const sal_Int32 nColCount = mpImpl->mxTable->getColumnCount();
        if( nColCount )
        {
            CellPos aPos( nIndex % nColCount, nIndex / nColCount );
            if( isValid( aPos ) )
                setActiveCell( aPos );
        }
    }
}


/** returns the index of the text that contains the given point or -1 */
sal_Int32 SdrTableObj::CheckTextHit(const Point& rPnt) const
{
    if( mpImpl.is() && mpImpl->mxTable.is() )
    {
        CellPos aPos;
        if( CheckTableHit( rPnt, aPos.mnCol, aPos.mnRow ) == TableHitKind::CellTextArea )
            return aPos.mnRow * mpImpl->mxTable->getColumnCount() + aPos.mnCol;
    }

    return 0;
}

SdrOutliner* SdrTableObj::GetCellTextEditOutliner( const Cell& rCell ) const
{
    if( mpImpl.is() && (mpImpl->getCell( mpImpl->maEditPos ).get() == &rCell) )
        return mpEditingOutliner;
    else
        return nullptr;
}

const TableLayouter& SdrTableObj::getTableLayouter() const
{
    assert(mpImpl.is() && mpImpl->mpLayouter && "getTableLayouter() error: no mpImpl or mpLayouter (!)");
    return *(mpImpl->mpLayouter);
}

bool SdrTableObj::IsAutoGrowHeight() const
{
    return true;
}

bool SdrTableObj::IsAutoGrowWidth() const
{
    return true;
}

bool SdrTableObj::HasText() const
{
    return true;
}

bool SdrTableObj::IsTextEditActive( const CellPos& rPos )
{
    return mpEditingOutliner && mpImpl.is() && (rPos == mpImpl->maEditPos);
}


void SdrTableObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus )
{
    if( (pEditStatus->GetStatusWord() & EditStatusFlags::TextHeightChanged) && mpImpl.is() && mpImpl->mpLayouter )
    {
        tools::Rectangle aRect0(getRectangle());
        setRectangle(maLogicRect);
        auto aRectangle = getRectangle();
        mpImpl->LayoutTable(aRectangle, falsefalse);
        setRectangle(aRectangle);
        SetBoundAndSnapRectsDirty();
        ActionChanged();
        BroadcastObjectChange();
        if (aRect0 != getRectangle())
            SendUserCall(SdrUserCallType::Resize,aRect0);
    }
}


void SdrTableObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
{
    rInfo.bResizeFreeAllowed=true;
    rInfo.bResizePropAllowed=true;
    rInfo.bRotateFreeAllowed=false;
    rInfo.bRotate90Allowed  =false;
    rInfo.bMirrorFreeAllowed=false;
    rInfo.bMirror45Allowed  =false;
    rInfo.bMirror90Allowed  =false;

    // allow transparence
    rInfo.bTransparenceAllowed = true;

    rInfo.bShearAllowed     =false;
    rInfo.bEdgeRadiusAllowed=false;
    rInfo.bCanConvToPath    =false;
    rInfo.bCanConvToPoly    =false;
    rInfo.bCanConvToPathLineToArea=false;
    rInfo.bCanConvToPolyLineToArea=false;
    rInfo.bCanConvToContour = false;
}

SdrObjKind SdrTableObj::GetObjIdentifier() const
{
    return SdrObjKind::Table;
}

void SdrTableObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect, bool /*bLineWidth*/ ) const
{
    if( mpImpl.is() )
        TakeTextRect( mpImpl->maEditPos, rOutliner, rTextRect, bNoEditText, pAnchorRect );
}


void SdrTableObj::TakeTextRect( const CellPos& rPos, SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect ) const
{
    if( !mpImpl.is())
        return;

    CellRef xCell( mpImpl->getCell( rPos ) );
    if( !xCell.is() )
        return;

    tools::Rectangle aAnkRect;
    TakeTextAnchorRect( rPos, aAnkRect );

    SdrTextVertAdjust eVAdj=xCell->GetTextVerticalAdjust();

    EEControlBits nStat0=rOutliner.GetControlWord();
    nStat0 |= EEControlBits::AUTOPAGESIZE;
    rOutliner.SetControlWord(nStat0);
    rOutliner.SetMinAutoPaperSize(Size());
    rOutliner.SetMaxAutoPaperSize(aAnkRect.GetSize());
    rOutliner.SetPaperSize(aAnkRect.GetSize());

    // #103516# New try with _BLOCK for hor and ver after completely
    // supporting full width for vertical text.
//  if( SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
//  {
    rOutliner.SetMinAutoPaperSize(Size(aAnkRect.GetWidth(), 0));
//  }
//  else if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
//  {
//      rOutliner.SetMinAutoPaperSize(Size(0, aAnkRect.GetHeight()));
//  }


    // set text at outliner, maybe from edit outliner
    std::optional<OutlinerParaObject> pPara;
    if (xCell->GetOutlinerParaObject())
        pPara = *xCell->GetOutlinerParaObject();
    if (mpEditingOutliner && !bNoEditText && mpImpl->mxActiveCell == xCell )
        pPara = mpEditingOutliner->CreateParaObject();

    if (pPara)
    {
        const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
        const SdrTextObj* pTestObj(rOutliner.GetTextObj());

        if( !pTestObj || !bHitTest || (pTestObj != this) || (pTestObj->GetOutlinerParaObject() != xCell->GetOutlinerParaObject()) )
        {
            if( bHitTest ) // #i33696# take back fix #i27510#
                rOutliner.SetTextObj( this );

            rOutliner.SetUpdateLayout(true);
            rOutliner.SetText(*pPara);
        }
    }
    else
    {
        rOutliner.SetTextObj( nullptr );
    }

    rOutliner.SetUpdateLayout(true);
    rOutliner.SetControlWord(nStat0);

    Point aTextPos(aAnkRect.TopLeft());
    Size aTextSiz(rOutliner.GetPaperSize());
    if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
    {
        tools::Long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
        if (eVAdj==SDRTEXTVERTADJUST_CENTER)
            aTextPos.AdjustY(nFreeHgt/2 );
        if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
            aTextPos.AdjustY(nFreeHgt );
    }

    if (pAnchorRect)
        *pAnchorRect=aAnkRect;

    rTextRect=tools::Rectangle(aTextPos,aTextSiz);
}

const CellRef& SdrTableObj::getActiveCell() const
{
    if( mpImpl.is() )
    {
        if( !mpImpl->mxActiveCell.is() )
        {
            CellPos aPos;
            const_cast< SdrTableObj* >(this)->setActiveCell( aPos );
        }
        return mpImpl->mxActiveCell;
    }
    else
    {
        static CellRef xCell;
        return xCell;
    }
}


sal_Int32 SdrTableObj::getColumnCount() const
{
    return mpImpl.is() ? mpImpl->getColumnCount() : 0;
}

sal_Int32 SdrTableObj::getRowCount() const
{
    return mpImpl.is() ? mpImpl->getRowCount() : 0;
}

void SdrTableObj::changeEdge(bool bHorizontal, int nEdge, sal_Int32 nOffset)
{
    if (mpImpl.is())
        mpImpl->DragEdge(bHorizontal, nEdge, nOffset);
}

void SdrTableObj::setActiveCell( const CellPos& rPos )
{
    if( !(mpImpl.is() && mpImpl->mxTable.is()) )
        return;

    try
    {
        mpImpl->mxActiveCell = mpImpl->mxTable->getCell( rPos.mnCol, rPos.mnRow );
        if( mpImpl->mxActiveCell.is() && mpImpl->mxActiveCell->isMerged() )
        {
            CellPos aOrigin;
            findMergeOrigin( mpImpl->mxTable, rPos.mnCol, rPos.mnRow, aOrigin.mnCol, aOrigin.mnRow );
            mpImpl->mxActiveCell = mpImpl->mxTable->getCell( aOrigin.mnCol, aOrigin.mnRow );
            mpImpl->maEditPos = aOrigin;
        }
        else
        {
            mpImpl->maEditPos = rPos;
        }
    }
    catch( Exception& )
    {
        TOOLS_WARN_EXCEPTION("svx.table""");
    }
}


void SdrTableObj::getActiveCellPos( CellPos& rPos ) const
{
    rPos = mpImpl->maEditPos;
}


void SdrTableObj::getCellBounds( const CellPos& rPos, ::tools::Rectangle& rCellRect )
{
    if( mpImpl.is() )
    {
        CellRef xCell( mpImpl->getCell( rPos ) );
        if( xCell.is() )
            rCellRect = xCell->getCellRect();
    }
}


void SdrTableObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
{
    if( mpImpl.is() )
        TakeTextAnchorRect( mpImpl->maEditPos, rAnchorRect );
}


void SdrTableObj::TakeTextAnchorRect( const CellPos& rPos, tools::Rectangle& rAnchorRect ) const
{
    tools::Rectangle aAnkRect(getRectangle());

    if( mpImpl.is() )
    {
        CellRef xCell( mpImpl->getCell( rPos ) );
        if( xCell.is() )
            xCell->TakeTextAnchorRect( aAnkRect );
    }

    ImpJustifyRect(aAnkRect);
    rAnchorRect=aAnkRect;
}


void SdrTableObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
{
    if( mpImpl.is() )
        TakeTextEditArea( mpImpl->maEditPos, pPaperMin, pPaperMax, pViewInit, pViewMin );
}


void SdrTableObj::TakeTextEditArea( const CellPos& rPos, Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin ) const
{
    Size aPaperMin,aPaperMax;
    tools::Rectangle aViewInit;
    TakeTextAnchorRect( rPos, aViewInit );

    Size aAnkSiz(aViewInit.GetSize());
    aAnkSiz.AdjustWidth( -1 ); aAnkSiz.AdjustHeight( -1 ); // because GetSize() increments by one

    Size aMaxSiz(aAnkSiz.Width(),1000000);
    Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
    if (aTmpSiz.Height()!=0)
        aMaxSiz.setHeight(aTmpSiz.Height() );

    CellRef xCell( mpImpl->getCell( rPos ) );
    SdrTextVertAdjust eVAdj = xCell.is() ? xCell->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_TOP;

    aPaperMax=aMaxSiz;

    aPaperMin.setWidth( aAnkSiz.Width() );

    if (pViewMin!=nullptr)
    {
        *pViewMin=aViewInit;
        tools::Long nYFree=aAnkSiz.Height()-aPaperMin.Height();

        if (eVAdj==SDRTEXTVERTADJUST_TOP)
        {
            pViewMin->AdjustBottom( -nYFree );
        }
        else if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
        {
            pViewMin->AdjustTop(nYFree );
        }
        else
        {
            pViewMin->AdjustTop(nYFree/2 );
            pViewMin->SetBottom(pViewMin->Top()+aPaperMin.Height() );
        }
    }


    if(IsVerticalWriting())
        aPaperMin.setWidth( 0 );
    else
        aPaperMin.setHeight( 0 );

    if (pPaperMin!=nullptr) *pPaperMin=aPaperMin;
    if (pPaperMax!=nullptr) *pPaperMax=aPaperMax;
    if (pViewInit!=nullptr) *pViewInit=aViewInit;
}


EEAnchorMode SdrTableObj::GetOutlinerViewAnchorMode() const
{
    EEAnchorMode eRet=EEAnchorMode::TopLeft;
    CellRef xCell( getActiveCell() );
    if( xCell.is() )
    {
        SdrTextVertAdjust eV=xCell->GetTextVerticalAdjust();

        {
            if (eV==SDRTEXTVERTADJUST_TOP)
            {
                eRet=EEAnchorMode::TopLeft;
            }
            else if (eV==SDRTEXTVERTADJUST_BOTTOM)
            {
                eRet=EEAnchorMode::BottomLeft;
            }
            else
            {
                eRet=EEAnchorMode::VCenterLeft;
            }
        }
    }
    return eRet;
}


OUString SdrTableObj::TakeObjNameSingul() const
{
    OUString sName(SvxResId(STR_ObjNameSingulTable));

    OUString aName(GetName());
    if (!aName.isEmpty())
        sName += " '" + aName + "'";

    return sName;
}


OUString SdrTableObj::TakeObjNamePlural() const
{
    return SvxResId(STR_ObjNamePluralTable);
}


rtl::Reference<SdrObject> SdrTableObj::CloneSdrObject(SdrModel& rTargetModel) const
{
    return new SdrTableObj(rTargetModel, *this);
}


const tools::Rectangle& SdrTableObj::GetSnapRect() const
{
    return getRectangle();
}


void SdrTableObj::NbcSetSnapRect(const tools::Rectangle& rRect)
{
    NbcSetLogicRect( rRect );
}


const tools::Rectangle& SdrTableObj::GetLogicRect() const
{
    return maLogicRect;
}


void SdrTableObj::RecalcSnapRect()
{
}


bool SdrTableObj::BegTextEdit(SdrOutliner& rOutl)
{
    if( mpEditingOutliner != nullptr )
        return false;

    mpEditingOutliner=&rOutl;

    mbInEditMode = true;

    rOutl.Init( OutlinerMode::TextObject );
    rOutl.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());

    bool bUpdateMode = rOutl.SetUpdateLayout(false);
    Size aPaperMin;
    Size aPaperMax;
    tools::Rectangle aEditArea;
    TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,nullptr);

    rOutl.SetMinAutoPaperSize(aPaperMin);
    rOutl.SetMaxAutoPaperSize(aPaperMax);
    rOutl.SetPaperSize(aPaperMax);

    if (bUpdateMode) rOutl.SetUpdateLayout(true);

    EEControlBits nStat=rOutl.GetControlWord();
    nStat   |= EEControlBits::AUTOPAGESIZE;
    nStat   &=~EEControlBits::STRETCHING;
    rOutl.SetControlWord(nStat);

    OutlinerParaObject* pPara = GetOutlinerParaObject();
    if(pPara)
        rOutl.SetText(*pPara);

    rOutl.UpdateFields();
    rOutl.ClearModifyFlag();

    return true;
}


void SdrTableObj::EndTextEdit(SdrOutliner& rOutl)
{

    if (getSdrModelFromSdrObject().IsUndoEnabled() && !mpImpl->maUndos.empty())
    {
        // These actions should be on the undo stack after text edit.
        for (std::unique_ptr<SdrUndoAction>& pAction : mpImpl->maUndos)
            getSdrModelFromSdrObject().AddUndo( std::move(pAction));
        mpImpl->maUndos.clear();

        getSdrModelFromSdrObject().AddUndo(getSdrModelFromSdrObject().GetSdrUndoFactory().CreateUndoGeoObject(*this));
    }

    if(rOutl.IsModified())
    {
        std::optional<OutlinerParaObject> pNewText;
        Paragraph* p1stPara = rOutl.GetParagraph( 0 );
        sal_Int32 nParaCnt = rOutl.GetParagraphCount();

        if(p1stPara)
        {
            // to remove the grey field background
            rOutl.UpdateFields();

            // create new text object
            pNewText = rOutl.CreateParaObject( 0, nParaCnt );
        }
        SetOutlinerParaObject(std::move(pNewText));
    }

    mpEditingOutliner = nullptr;
    rOutl.Clear();
    EEControlBits nStat = rOutl.GetControlWord();
    nStat &= ~EEControlBits::AUTOPAGESIZE;
    rOutl.SetControlWord(nStat);

    mbInEditMode = false;
}


OutlinerParaObject* SdrTableObj::GetOutlinerParaObject() const
{
    CellRef xCell( getActiveCell() );
    if( xCell.is() )
        return xCell->GetOutlinerParaObject();
    else
        return nullptr;
}


void SdrTableObj::NbcSetOutlinerParaObject( std::optional<OutlinerParaObject> pTextObject, bool bAdjustTextFrameWidthAndHeight )
{
    CellRef xCell( getActiveCell() );
    if( !xCell.is() )
        return;

    // Update HitTestOutliner
    const SdrTextObj* pTestObj(getSdrModelFromSdrObject().GetHitTestOutliner().GetTextObj());

    if(pTestObj && pTestObj->GetOutlinerParaObject() == xCell->GetOutlinerParaObject())
    {
        getSdrModelFromSdrObject().GetHitTestOutliner().SetTextObj(nullptr);
    }

    xCell->SetOutlinerParaObject( std::move(pTextObject) );
    SetTextSizeDirty();
    if (bAdjustTextFrameWidthAndHeight)
        NbcAdjustTextFrameWidthAndHeight();
}


void SdrTableObj::NbcSetLogicRect(const tools::Rectangle& rRect, bool /*bAdaptTextMinSize*/)
{
    maLogicRect=rRect;
    ImpJustifyRect(maLogicRect);
    const bool bWidth = maLogicRect.getOpenWidth() != getRectangle().getOpenWidth();
    const bool bHeight = maLogicRect.getOpenHeight() != getRectangle().getOpenHeight();
    setRectangle(maLogicRect);
    if (mpImpl->mbSkipChangeLayout)
        // Avoid distributing newly available space between existing cells.
        NbcAdjustTextFrameWidthAndHeight();
    else
        NbcAdjustTextFrameWidthAndHeight(!bHeight, !bWidth);
    SetBoundAndSnapRectsDirty();
}


void SdrTableObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
{
    tools::Rectangle aAdjustRect( rMaxRect );
    aAdjustRect.setHeight( GetLogicRect().getOpenHeight() );
    SetLogicRect( aAdjustRect );
}


void SdrTableObj::NbcMove(const Size& rSiz)
{
    maLogicRect.Move(rSiz);
    SdrTextObj::NbcMove( rSiz );
    if( mpImpl.is() )
        mpImpl->UpdateCells(getRectangle());
}


void SdrTableObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
{
    tools::Rectangle aOldRect( maLogicRect );
    ResizeRect(maLogicRect,rRef,xFact,yFact);

    setRectangle(maLogicRect);
    NbcAdjustTextFrameWidthAndHeight( maLogicRect.GetHeight() == aOldRect.GetHeight(), maLogicRect.GetWidth() == aOldRect.GetWidth() );
    SetBoundAndSnapRectsDirty();
}


bool SdrTableObj::AdjustTextFrameWidthAndHeight()
{
    tools::Rectangle aNewRect(maLogicRect);
    bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
    if (bRet)
    {
        tools::Rectangle aBoundRect0;
        if (m_pUserCall!=nullptr)
            aBoundRect0=GetLastBoundRect();
        setRectangle(aNewRect);
        SetBoundAndSnapRectsDirty();
        SetChanged();
        BroadcastObjectChange();
        SendUserCall(SdrUserCallType::Resize,aBoundRect0);
    }
    return bRet;
}


bool SdrTableObj::AdjustTextFrameWidthAndHeight(tools::Rectangle& rR, bool bHeight, bool bWidth) const
{
    if(rR.IsEmpty() || !mpImpl.is() || !mpImpl->mxTable.is())
        return false;

    tools::Rectangle aRectangle( rR );
    mpImpl->LayoutTable( aRectangle, !bWidth, !bHeight );

    if( aRectangle != rR )
    {
        rR = aRectangle;
        return true;
    }
    else
    {
        return false;
    }
}


void SdrTableObj::NbcReformatText()
{
    NbcAdjustTextFrameWidthAndHeight();
}


bool SdrTableObj::IsVerticalWriting() const
{
    const SvxWritingModeItem& rModeItem = GetObjectItem( SDRATTR_TEXTDIRECTION );
    return rModeItem.GetValue() == css::text::WritingMode_TB_RL;
}


void SdrTableObj::SetVerticalWriting(bool bVertical)
{
    if(bVertical != IsVerticalWriting() )
    {
        SvxWritingModeItem aModeItem( css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION );
        SetObjectItem( aModeItem );
    }
}


WritingMode SdrTableObj::GetWritingMode() const
{
    SfxStyleSheet* pStyle = GetStyleSheet();
    if ( !pStyle )
        return WritingMode_LR_TB;

    WritingMode eWritingMode = WritingMode_LR_TB;
    const SfxItemSet &rSet = pStyle->GetItemSet();

    if ( const SvxWritingModeItem *pItem = rSet.GetItemIfSet( SDRATTR_TEXTDIRECTION ))
        eWritingMode = pItem->GetValue();

    if ( const SvxFrameDirectionItem *pItem;
        ( eWritingMode != WritingMode_TB_RL ) &&
         ( pItem = rSet.GetItemIfSet( EE_PARA_WRITINGDIR, false ) ) )
    {
        if ( pItem->GetValue() == SvxFrameDirection::Horizontal_LR_TB )
            eWritingMode = WritingMode_LR_TB;
        else
            eWritingMode = WritingMode_RL_TB;
    }

    return eWritingMode;
}

void SdrTableObj::AddUndo(SdrUndoAction* pUndo)
{
    mpImpl->maUndos.push_back(std::unique_ptr<SdrUndoAction>(pUndo));
}

void SdrTableObj::SetSkipChangeLayout(bool bSkipChangeLayout)
{
    mpImpl->mbSkipChangeLayout = bSkipChangeLayout;
}

bool SdrTableObj::IsReallyEdited() const
{
    return mpEditingOutliner && mpEditingOutliner->IsModified();
}

bool SdrTableObj::IsFontwork() const
{
    return false;
}

sal_uInt32 SdrTableObj::GetHdlCount() const
{
    sal_uInt32 nCount = SdrTextObj::GetHdlCount();
    const sal_Int32 nRowCount = mpImpl->getRowCount();
    const sal_Int32 nColCount = mpImpl->getColumnCount();

    if( nRowCount && nColCount )
        nCount += nRowCount + nColCount + 2 + 1;

    return nCount;
}

void SdrTableObj::AddToHdlList(SdrHdlList& rHdlList) const
{
    const sal_Int32 nRowCount = mpImpl->getRowCount();
    const sal_Int32 nColCount = mpImpl->getColumnCount();

    // first add row handles
    std::vector<TableEdgeHdl*> aRowEdges(nRowCount + 1);
    for (auto const & rEdge : mpImpl->mpLayouter->getHorizontalEdges())
    {
        Point aPoint(getRectangle().TopLeft());
        aPoint.AdjustY(rEdge.nPosition);

        std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, true, rEdge.nMin, rEdge.nMax, nColCount + 1));
        pHdl->SetPointNum(rEdge.nIndex);
        aRowEdges[rEdge.nIndex] = pHdl.get();
        rHdlList.AddHdl(std::move(pHdl));
    }

    // second add column handles
    std::vector<TableEdgeHdl*> aColEdges(nColCount + 1);
    for (auto const & rEdge : mpImpl->mpLayouter->getVerticalEdges())
    {
        Point aPoint(getRectangle().TopLeft());
        aPoint.AdjustX(rEdge.nPosition);

        std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, false, rEdge.nMin, rEdge.nMax, nRowCount + 1));
        pHdl->SetPointNum(rEdge.nIndex);
        aColEdges[rEdge.nIndex] = pHdl.get();
        rHdlList.AddHdl(std::move(pHdl));
    }

    // now add visible edges to row and column handles
    if( mpImpl->mpLayouter )
    {
        TableLayouter& rLayouter = *mpImpl->mpLayouter;

        sal_Int32 nY = 0;

        for( sal_Int32 nRow = 0; nRow <= nRowCount; ++nRow )
        {
            const sal_Int32 nRowHeight = (nRow == nRowCount) ? 0 : rLayouter.getRowHeight(nRow);
            sal_Int32 nX = 0;

            for( sal_Int32 nCol = 0; nCol <= nColCount; ++nCol )
            {
                const sal_Int32 nColWidth = (nCol == nColCount) ? 0 : rLayouter.getColumnWidth(nCol);

                if( nRowHeight > 0 )
                {
                    if( rLayouter.isEdgeVisible( nCol, nRow, false ) )
                        aColEdges[nCol]->SetEdge( nRow, nY, nY + nRowHeight, (rLayouter.getBorderLine( nCol, nRowfalse ) == nullptr) ? Visible : Invisible);
                }

                if( nColWidth > 0 )
                {
                    if( rLayouter.isEdgeVisible( nCol, nRow, true ) )
                        aRowEdges[nRow]->SetEdge( nCol, nX, nX + nColWidth, (rLayouter.getBorderLine( nCol, nRow, true ) == nullptr) ? Visible : Invisible);
                }

                nX += nColWidth;
            }

            nY += nRowHeight;
        }
    }

    // add remaining handles
    SdrHdlList tempList(nullptr);
    auto aRectangle = getRectangle();
    tempList.AddHdl( std::make_unique<TableBorderHdl>(aRectangle, !IsTextEditActive() ) );
    tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopLeft(),SdrHdlKind::UpperLeft) );
    tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopCenter(),SdrHdlKind::Upper) );
    tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopRight(),SdrHdlKind::UpperRight) );
    tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.LeftCenter(),SdrHdlKind::Left) );
    tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.RightCenter(),SdrHdlKind::Right) );
    tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomLeft(),SdrHdlKind::LowerLeft) );
    tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomCenter(),SdrHdlKind::Lower) );
    tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomRight(),SdrHdlKind::LowerRight) );
    for( size_t nHdl = 0; nHdl < tempList.GetHdlCount(); ++nHdl )
        tempList.GetHdl(nHdl)->SetMoveOutside(true);
    tempList.MoveTo(rHdlList);

    const size_t nHdlCount = rHdlList.GetHdlCount();
    for( size_t nHdl = 0; nHdl < nHdlCount; ++nHdl )
        rHdlList.GetHdl(nHdl)->SetObj(const_cast<SdrTableObj*>(this));
}

// Dragging

bool SdrTableObj::hasSpecialDrag() const
{
    return true;
}

bool SdrTableObj::beginSpecialDrag(SdrDragStat& rDrag) const
{
    const SdrHdl* pHdl = rDrag.GetHdl();
    const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());

    switch( eHdl )
    {
        case SdrHdlKind::UpperLeft:
        case SdrHdlKind::Upper:
        case SdrHdlKind::UpperRight:
        case SdrHdlKind::Left:
        case SdrHdlKind::Right:
        case SdrHdlKind::LowerLeft:
        case SdrHdlKind::Lower:
        case SdrHdlKind::LowerRight:
        case SdrHdlKind::Move:
        {
            break;
        }

        case SdrHdlKind::User:
        {
            rDrag.SetEndDragChangesAttributes(false);
            rDrag.SetNoSnap();
            break;
        }

        default:
        {
            return false;
        }
    }

    return true;
}

bool SdrTableObj::applySpecialDrag(SdrDragStat& rDrag)
{
    bool bRet(true);
    const SdrHdl* pHdl = rDrag.GetHdl();
    const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());

    switch( eHdl )
    {
        case SdrHdlKind::UpperLeft:
        case SdrHdlKind::Upper:
        case SdrHdlKind::UpperRight:
        case SdrHdlKind::Left:
        case SdrHdlKind::Right:
        case SdrHdlKind::LowerLeft:
        case SdrHdlKind::Lower:
        case SdrHdlKind::LowerRight:
        {
            const tools::Rectangle aNewRectangle(ImpDragCalcRect(rDrag));

            if (aNewRectangle != getRectangle())
            {
                   NbcSetLogicRect(aNewRectangle);
            }

            break;
        }

        case SdrHdlKind::Move:
        {
            NbcMove( Size( rDrag.GetDX(), rDrag.GetDY() ) );
            break;
        }

        case SdrHdlKind::User:
        {
            rDrag.SetEndDragChangesAttributes(false);
            rDrag.SetNoSnap();
            const TableEdgeHdl* pEdgeHdl = dynamic_castconst TableEdgeHdl* >( pHdl );

            if( pEdgeHdl )
            {
                if( IsInserted() )
                {
                    rDrag.SetEndDragChangesAttributes(true);
                    rDrag.SetEndDragChangesLayout(true);
                }

                mpImpl->DragEdge( pEdgeHdl->IsHorizontalEdge(), pEdgeHdl->GetPointNum(), pEdgeHdl->GetValidDragOffset( rDrag ) );
            }
            break;
        }

        default:
        {
            bRet = false;
        }
    }

    return bRet;
}

basegfx::B2DPolyPolygon SdrTableObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
{
    basegfx::B2DPolyPolygon aRetval;
    const SdrHdl* pHdl = rDrag.GetHdl();

    if( pHdl && (SdrHdlKind::User == pHdl->GetKind()) )
    {
        const TableEdgeHdl* pEdgeHdl = dynamic_castconst TableEdgeHdl* >( pHdl );

        if( pEdgeHdl )
        {
            aRetval = pEdgeHdl->getSpecialDragPoly( rDrag );
        }
    }

    return aRetval;
}


// Create


bool SdrTableObj::BegCreate(SdrDragStat& rStat)
{
    rStat.SetOrtho4Possible();
    tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
    aRect1.Normalize();
    rStat.SetActionRect(aRect1);
    setRectangle(aRect1);
    return true;
}


bool SdrTableObj::MovCreate(SdrDragStat& rStat)
{
    tools::Rectangle aRect1;
    rStat.TakeCreateRect(aRect1);
    ImpJustifyRect(aRect1);
    rStat.SetActionRect(aRect1);
    setRectangle(aRect1); // for ObjName
    SetBoundRectDirty();
    m_bSnapRectDirty=true;
    return true;
}


bool SdrTableObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
{
    auto aRectangle = getRectangle();
    rStat.TakeCreateRect(aRectangle);
    ImpJustifyRect(aRectangle);
    setRectangle(aRectangle);
--> --------------------

--> maximum size reached

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

Messung V0.5
C=96 H=96 G=95

¤ Dauer der Verarbeitung: 0.11 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.