use insert function instead of for loop
[LibreOffice.git] / svx / source / table / svdotable.cxx
blob974b06c302191e975fb3de8ccb17b0d0e3bd2eca
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
22 #include <com/sun/star/container/XNamed.hpp>
23 #include <com/sun/star/container/XNameAccess.hpp>
24 #include <com/sun/star/container/XIndexAccess.hpp>
25 #include <comphelper/configuration.hxx>
26 #include <vcl/canvastools.hxx>
27 #include <vcl/ptrstyle.hxx>
28 #include <com/sun/star/style/XStyle.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <basegfx/polygon/b2dpolygontools.hxx>
31 #include <basegfx/polygon/b2dpolypolygon.hxx>
32 #include <basegfx/polygon/b2dpolygon.hxx>
33 #include <svl/style.hxx>
34 #include <editeng/editstat.hxx>
35 #include <editeng/outlobj.hxx>
36 #include <sdr/properties/textproperties.hxx>
37 #include <svx/svdmodel.hxx>
38 #include <svx/svdotable.hxx>
39 #include <svx/svdhdl.hxx>
40 #include "viewcontactoftableobj.hxx"
41 #include <svx/svdoutl.hxx>
42 #include <svx/svddrag.hxx>
43 #include <tablemodel.hxx>
44 #include <cell.hxx>
45 #include "tablelayouter.hxx"
46 #include "tablehandles.hxx"
47 #include <svx/sdr/table/tabledesign.hxx>
48 #include <svx/svdundo.hxx>
49 #include <svx/strings.hrc>
50 #include <svx/dialmgr.hxx>
51 #include <editeng/writingmodeitem.hxx>
52 #include <editeng/frmdiritem.hxx>
53 #include <libxml/xmlwriter.h>
54 #include <comphelper/diagnose_ex.hxx>
56 #include <boost/property_tree/ptree.hpp>
58 #include "sdrtableobjimpl.hxx"
60 using ::com::sun::star::uno::Any;
61 using ::com::sun::star::uno::Reference;
62 using ::com::sun::star::uno::UNO_QUERY;
63 using ::com::sun::star::uno::UNO_QUERY_THROW;
64 using ::com::sun::star::uno::Exception;
65 using ::com::sun::star::container::XIndexAccess;
66 using ::com::sun::star::style::XStyle;
67 using ::com::sun::star::table::XTableRows;
68 using ::com::sun::star::table::XTableColumns;
69 using ::com::sun::star::table::XTable;
70 using ::com::sun::star::beans::XPropertySet;
71 using ::com::sun::star::util::XModifyBroadcaster;
72 using sdr::properties::TextProperties;
73 using sdr::properties::BaseProperties;
74 using namespace ::com::sun::star;
75 using namespace ::com::sun::star::text;
76 using namespace ::com::sun::star::container;
77 using namespace ::com::sun::star::style;
79 namespace sdr::table {
81 namespace {
83 class TableProperties : public TextProperties
85 protected:
86 // create a new itemset
87 SfxItemSet CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
89 public:
90 // basic constructor
91 explicit TableProperties(SdrObject& rObj );
93 // constructor for copying, but using new object
94 TableProperties(const TableProperties& rProps, SdrObject& rObj );
96 // Clone() operator, normally just calls the local copy constructor
97 std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
99 virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) override;
104 TableProperties::TableProperties(SdrObject& rObj)
105 : TextProperties(rObj)
109 TableProperties::TableProperties(const TableProperties& rProps, SdrObject& rObj)
110 : TextProperties(rProps, rObj)
114 std::unique_ptr<BaseProperties> TableProperties::Clone(SdrObject& rObj) const
116 return std::unique_ptr<BaseProperties>(new TableProperties(*this, rObj));
119 void TableProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
121 if( nWhich == SDRATTR_TEXTDIRECTION )
122 AttributeProperties::ItemChange( nWhich, pNewItem );
123 else
124 TextProperties::ItemChange( nWhich, pNewItem );
127 // create a new itemset
128 SfxItemSet TableProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
130 return SfxItemSet(rPool,
132 // range from SdrAttrObj
133 svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
134 SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
135 SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
137 // range for SdrTableObj
138 SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST,
140 // range from SdrTextObj
141 EE_ITEMS_START, EE_ITEMS_END>);
144 namespace {
146 class TableObjectGeoData : public SdrTextObjGeoData
148 public:
149 tools::Rectangle maLogicRect;
154 TableStyleSettings::TableStyleSettings()
155 : mbUseFirstRow(true)
156 , mbUseLastRow(false)
157 , mbUseFirstColumn(false)
158 , mbUseLastColumn(false)
159 , mbUseRowBanding(true)
160 , mbUseColumnBanding(false)
164 TableStyleSettings::TableStyleSettings( const TableStyleSettings& rStyle )
166 (*this) = rStyle;
169 TableStyleSettings& TableStyleSettings::operator=(const TableStyleSettings& rStyle)
171 mbUseFirstRow = rStyle.mbUseFirstRow;
172 mbUseLastRow = rStyle.mbUseLastRow;
173 mbUseFirstColumn = rStyle.mbUseFirstColumn;
174 mbUseLastColumn = rStyle.mbUseLastColumn;
175 mbUseRowBanding = rStyle.mbUseRowBanding;
176 mbUseColumnBanding = rStyle.mbUseColumnBanding;
177 return *this;
180 bool TableStyleSettings::operator==( const TableStyleSettings& rStyle ) const
182 return
183 (mbUseFirstRow == rStyle.mbUseFirstRow) &&
184 (mbUseLastRow == rStyle.mbUseLastRow) &&
185 (mbUseFirstColumn == rStyle.mbUseFirstColumn) &&
186 (mbUseLastColumn == rStyle.mbUseLastColumn) &&
187 (mbUseRowBanding == rStyle.mbUseRowBanding) &&
188 (mbUseColumnBanding == rStyle.mbUseColumnBanding);
192 SdrTableObjImpl* SdrTableObjImpl::lastLayoutTable = nullptr;
193 tools::Rectangle SdrTableObjImpl::lastLayoutInputRectangle;
194 tools::Rectangle SdrTableObjImpl::lastLayoutResultRectangle;
195 bool SdrTableObjImpl::lastLayoutFitWidth;
196 bool SdrTableObjImpl::lastLayoutFitHeight;
197 WritingMode SdrTableObjImpl::lastLayoutMode;
198 sal_Int32 SdrTableObjImpl::lastRowCount;
199 sal_Int32 SdrTableObjImpl::lastColCount;
200 bool SdrTableObjImpl::rowSizeChanged = false;
201 std::vector<sal_Int32> SdrTableObjImpl::lastColWidths;
203 SdrTableObjImpl::SdrTableObjImpl()
204 : mpTableObj( nullptr )
205 , mbSkipChangeLayout(false)
210 SdrTableObjImpl::~SdrTableObjImpl()
212 if( lastLayoutTable == this )
213 lastLayoutTable = nullptr;
217 void SdrTableObjImpl::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
219 if(!mxTable.is())
221 return;
224 const sal_Int32 nColumns(rEnd.mnCol - rStart.mnCol + 1);
225 const sal_Int32 nRows(rEnd.mnRow - rStart.mnRow + 1);
227 if(nColumns < 1 || nRows < 1 || nColumns > getColumnCount() || nRows > getRowCount())
229 return;
232 // tdf#116977 First thought was to create the new TableModel, copy data to it and then exchange
233 // mxTable and dispose old one. This does *not* work, even when all stuff looks nicely referenced
234 // and safe *because* Cell::create gets handed over the current SdrTableObj, hands it to
235 // ::Cell and there the local mxTable is initialized using rTableObj.getTable() (!). Due to This,
236 // the new created Cells in a new created TableModel based on given mpTableObj *will be disposed*
237 // when the old mxTable gets disposed - ARGH!
238 // To avoid, change strategy: Remember old TableModel, reset mxTable immediately - this is the
239 // SdrTableObjImpl of the current SdrTableObj anyways. Luckily, this works as intended...
241 // remember old TableModel
242 TableModelRef xOldTable(mxTable);
244 // immediately create new one and initialize. This creates ::Cell's which then will use
245 // the correct TableModel (accessed through SdrTableObj, but using local mxTable)
246 mxTable = new TableModel(mpTableObj);
247 mxTable->init(nColumns, nRows);
249 // copy cells
250 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
252 for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol ) try
254 CellRef xTargetCell( mxTable->getCell( nCol, nRow ) );
255 if( xTargetCell.is() )
256 xTargetCell->cloneFrom( xOldTable->getCell( rStart.mnCol + nCol, rStart.mnRow + nRow ) );
258 catch( Exception& )
260 TOOLS_WARN_EXCEPTION("svx.table", "");
264 // copy row heights
265 Reference< XTableRows > xNewRows(mxTable->getRows(), css::uno::UNO_SET_THROW );
266 static constexpr OUStringLiteral sHeight( u"Height" );
267 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
269 Reference< XPropertySet > xNewSet( xNewRows->getByIndex( nRow ), UNO_QUERY_THROW );
270 xNewSet->setPropertyValue( sHeight, Any( mpLayouter->getRowHeight( rStart.mnRow + nRow ) ) );
273 // copy column widths
274 Reference< XTableColumns > xNewColumns( mxTable->getColumns(), css::uno::UNO_SET_THROW );
275 static constexpr OUStringLiteral sWidth( u"Width" );
276 for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol )
278 Reference< XPropertySet > xNewSet( xNewColumns->getByIndex( nCol ), UNO_QUERY_THROW );
279 xNewSet->setPropertyValue( sWidth, Any( mpLayouter->getColumnWidth( rStart.mnCol + nCol ) ) );
282 // reset layouter which still holds a copy to old TableModel
283 mpLayouter.reset();
285 // cleanup old TableModel
287 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
288 xOldTable->removeModifyListener( xListener );
289 xOldTable->dispose();
290 xOldTable.clear();
293 // create and hand over to new TableLayouter
294 mpLayouter.reset(new TableLayouter( mxTable ));
296 // add needed listener to react on changes
297 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
298 mxTable->addModifyListener( xListener );
300 // Apply Style to Cells
301 ApplyCellStyles();
303 // layout cropped table
304 auto aRectangle = mpTableObj->getRectangle();
305 LayoutTable(aRectangle, false, false);
306 mpTableObj->setRectangle(aRectangle);
309 void SdrTableObjImpl::init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows )
311 mpTableObj = pTable;
312 mxTable = new TableModel( pTable );
313 mxTable->init( nColumns, nRows );
314 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
315 mxTable->addModifyListener( xListener );
316 mpLayouter.reset(new TableLayouter( mxTable ));
317 auto aRectangle = mpTableObj->getRectangle();
318 LayoutTable(aRectangle, true, true);
319 mpTableObj->setRectangle(aRectangle);
320 mpTableObj->maLogicRect = aRectangle;
324 SdrTableObjImpl& SdrTableObjImpl::operator=( const SdrTableObjImpl& rSource )
326 if(this == &rSource)
328 return *this;
331 if(nullptr == mpTableObj || nullptr == rSource.mpTableObj)
333 // error: need both SdrObjects to successfully copy data
334 return *this;
337 // remove evtl. listeners from local
338 disconnectTableStyle();
340 // reset layouter which holds a copy
341 mpLayouter.reset();
343 // cleanup local mxTable if used
344 if( mxTable.is() )
346 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
347 mxTable->removeModifyListener( xListener );
348 mxTable->dispose();
349 mxTable.clear();
352 // tdf#127481: reset active cell reference
353 mxActiveCell.clear();
355 // copy TableStyle (short internal data)
356 maTableStyle = rSource.maTableStyle;
358 // create/copy new mxTable. This will copy all needed cells, too
359 mxTable = new TableModel( mpTableObj, rSource.mxTable );
361 // create and hand over to new TableLayouter
362 mpLayouter.reset(new TableLayouter( mxTable ));
364 // add needed listener to react on changes
365 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
366 mxTable->addModifyListener( xListener );
368 // handle TableStyle
369 Reference< XIndexAccess > xNewTableStyle;
370 SdrModel& rSourceSdrModel(rSource.mpTableObj->getSdrModelFromSdrObject());
371 SdrModel& rTargetSdrModel(mpTableObj->getSdrModelFromSdrObject());
373 if(rSource.mxTableStyle.is() && &rSourceSdrModel == &rTargetSdrModel)
375 // source and target model the same -> keep current TableStyle
376 xNewTableStyle = rSource.mxTableStyle;
379 if(!xNewTableStyle.is() && rSource.mxTableStyle.is()) try
381 // search in target SdrModel for that TableStyle
382 const OUString sStyleName( Reference< XNamed >( rSource.mxTableStyle, UNO_QUERY_THROW )->getName() );
383 Reference< XStyleFamiliesSupplier > xSFS(rTargetSdrModel.getUnoModel(), UNO_QUERY_THROW );
384 Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), css::uno::UNO_SET_THROW );
385 Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( u"table"_ustr ), UNO_QUERY_THROW );
387 if( xTableFamilyAccess->hasByName( sStyleName ) )
389 // found table style with the same name
390 xTableFamilyAccess->getByName( sStyleName ) >>= xNewTableStyle;
392 else
394 // copy or? Not found, use 1st existing TableStyle (or none)
395 Reference< XIndexAccess > xIndexAccess( xTableFamilyAccess, UNO_QUERY_THROW );
396 xIndexAccess->getByIndex( 0 ) >>= xNewTableStyle;
399 catch( Exception& )
401 TOOLS_WARN_EXCEPTION("svx.table", "");
404 // set that TableStyle
405 mxTableStyle = std::move(xNewTableStyle);
407 // Apply Style to Cells
408 ApplyCellStyles();
410 // copy geometry
411 mpTableObj->setRectangle(mpTableObj->maLogicRect);
413 // layout cloned table
414 auto aRectangle = mpTableObj->getRectangle();
415 LayoutTable(aRectangle, false, false);
416 mpTableObj->setRectangle(aRectangle);
418 // re-connect to styles (evtl. in new SdrModel)
419 connectTableStyle();
421 return *this;
424 void SdrTableObjImpl::ApplyCellStyles()
426 if( !mxTable.is() || !mxTableStyle.is() )
427 return;
429 const sal_Int32 nColCount = getColumnCount();
430 const sal_Int32 nRowCount = getRowCount();
432 const TableStyleSettings& rStyle = maTableStyle;
434 CellPos aPos;
435 for( aPos.mnRow = 0; aPos.mnRow < nRowCount; ++aPos.mnRow )
437 const bool bFirstRow = (aPos.mnRow == 0) && rStyle.mbUseFirstRow;
438 const bool bLastRow = (aPos.mnRow == nRowCount-1) && rStyle.mbUseLastRow;
440 for( aPos.mnCol = 0; aPos.mnCol < nColCount; ++aPos.mnCol )
442 Reference< XStyle > xStyle;
444 // first and last row win first, if used and available
445 if( bFirstRow )
447 mxTableStyle->getByIndex(first_row_style) >>= xStyle;
449 else if( bLastRow )
451 mxTableStyle->getByIndex(last_row_style) >>= xStyle;
454 if( !xStyle.is() )
456 // next come first and last column, if used and available
457 if( rStyle.mbUseFirstColumn && (aPos.mnCol == 0) )
459 mxTableStyle->getByIndex(first_column_style) >>= xStyle;
461 else if( rStyle.mbUseLastColumn && (aPos.mnCol == nColCount-1) )
463 mxTableStyle->getByIndex(last_column_style) >>= xStyle;
467 if( !xStyle.is() && rStyle.mbUseRowBanding )
469 if( (aPos.mnRow & 1) == 0 )
471 mxTableStyle->getByIndex(even_rows_style) >>= xStyle;
473 else
475 mxTableStyle->getByIndex(odd_rows_style) >>= xStyle;
479 if( !xStyle.is() && rStyle.mbUseColumnBanding )
481 if( (aPos.mnCol & 1) == 0 )
483 mxTableStyle->getByIndex(even_columns_style) >>= xStyle;
485 else
487 mxTableStyle->getByIndex(odd_columns_style) >>= xStyle;
491 if( !xStyle.is() )
493 // use default cell style if non found yet
494 mxTableStyle->getByIndex(body_style) >>= xStyle;
498 if( xStyle.is() )
500 SfxUnoStyleSheet* pStyle = SfxUnoStyleSheet::getUnoStyleSheet(xStyle);
502 if( pStyle )
504 CellRef xCell( getCell( aPos ) );
505 if( xCell.is() && ( xCell->GetStyleSheet() != pStyle ) )
507 xCell->SetStyleSheet( pStyle, true );
516 void SdrTableObjImpl::dispose()
518 disconnectTableStyle();
519 mxTableStyle.clear();
521 mpLayouter.reset();
523 if( mxTable.is() )
525 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
526 mxTable->removeModifyListener( xListener );
527 mxTable->dispose();
528 mxTable.clear();
533 void SdrTableObjImpl::DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset )
535 if( !((nEdge >= 0) && mxTable.is()))
536 return;
540 static constexpr OUString sSize( u"Size"_ustr );
541 if( mbHorizontal )
543 if (nEdge <= getRowCount())
545 sal_Int32 nHeight = mpLayouter->getRowHeight( (!nEdge)?nEdge:(nEdge-1) );
546 if(nEdge==0)
547 nHeight -= nOffset;
548 else
549 nHeight += nOffset;
550 Reference< XIndexAccess > xRows( mxTable->getRows(), UNO_QUERY_THROW );
551 Reference< XPropertySet > xRowSet( xRows->getByIndex( (!nEdge)?nEdge:(nEdge-1) ), UNO_QUERY_THROW );
552 xRowSet->setPropertyValue( sSize, Any( nHeight ) );
553 rowSizeChanged = true;
556 else
559 fixes fdo#59889 and resizing of table in edge dragging
560 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
561 In LTR table vertical edge responsible for dragging of column x(x=0 to N-1) is, Edge x+1
562 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
563 In LTR table dragging of edge 0(for RTL table edge N) does nothing.
565 //Todo: Implement Dragging functionality for leftmost edge of table.
566 if (nEdge <= getColumnCount())
568 const bool bRTL = mpTableObj != nullptr && (mpTableObj->GetWritingMode() == WritingMode_RL_TB);
569 sal_Int32 nWidth;
570 if(bRTL)
572 nWidth = mpLayouter->getColumnWidth( nEdge );
574 else
576 nWidth = mpLayouter->getColumnWidth( (!nEdge)?nEdge:(nEdge-1) );
578 Reference< XIndexAccess > xCols( mxTable->getColumns(), UNO_QUERY_THROW );
579 nWidth += nOffset;
580 if(bRTL && nEdge<getColumnCount())
582 Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge ), UNO_QUERY_THROW );
583 xColSet->setPropertyValue( sSize, Any( nWidth ) );
585 else if(!bRTL && nEdge>0)
587 Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge-1 ), UNO_QUERY_THROW );
588 xColSet->setPropertyValue( sSize, Any( nWidth ) );
590 /* To prevent the table resizing on edge dragging */
591 if( nEdge > 0 && nEdge < mxTable->getColumnCount() )
593 if( bRTL )
594 nEdge--;
596 nWidth = mpLayouter->getColumnWidth(nEdge);
597 nWidth = std::max(static_cast<sal_Int32>(nWidth - nOffset), sal_Int32(0));
599 Reference<XPropertySet> xColSet(xCols->getByIndex(nEdge), UNO_QUERY_THROW);
600 xColSet->setPropertyValue(sSize, Any(nWidth));
605 catch( Exception& )
607 TOOLS_WARN_EXCEPTION("svx.table", "");
612 // XModifyListener
615 void SAL_CALL SdrTableObjImpl::modified( const css::lang::EventObject& aEvent )
617 if (aEvent.Source == mxTableStyle && mpTableObj)
618 static_cast<TextProperties&>(mpTableObj->GetProperties()).increaseVersion();
620 update();
623 void SdrTableObjImpl::update()
625 // source can be the table model itself or the assigned table template
626 TableModelNotifyGuard aGuard( mxTable.get() );
627 if( !mpTableObj )
628 return;
630 if( (maEditPos.mnRow >= getRowCount()) || (maEditPos.mnCol >= getColumnCount()) || (getCell( maEditPos ) != mxActiveCell) )
632 if(maEditPos.mnRow >= getRowCount())
633 maEditPos.mnRow = getRowCount()-1;
635 if(maEditPos.mnCol >= getColumnCount())
636 maEditPos.mnCol = getColumnCount()-1;
638 mpTableObj->setActiveCell( maEditPos );
641 ApplyCellStyles();
643 mpTableObj->setRectangle(mpTableObj->maLogicRect);
644 auto aRectangle = mpTableObj->getRectangle();
645 LayoutTable(aRectangle, false, false);
646 mpTableObj->setRectangle(aRectangle);
648 mpTableObj->SetBoundAndSnapRectsDirty();
649 mpTableObj->ActionChanged();
650 mpTableObj->BroadcastObjectChange();
654 void SdrTableObjImpl::connectTableStyle()
656 if( mxTableStyle.is() )
658 Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
659 if( xBroadcaster.is() )
661 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
662 xBroadcaster->addModifyListener( xListener );
668 void SdrTableObjImpl::disconnectTableStyle()
670 if( mxTableStyle.is() )
672 Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
673 if( xBroadcaster.is() )
675 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
676 xBroadcaster->removeModifyListener( xListener );
682 bool SdrTableObjImpl::isInUse()
684 return mpTableObj && mpTableObj->IsInserted();
687 void SdrTableObjImpl::dumpAsXml(xmlTextWriterPtr pWriter) const
689 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObjImpl"));
690 if (mpLayouter)
691 mpLayouter->dumpAsXml(pWriter);
692 mxTable->dumpAsXml(pWriter);
693 (void)xmlTextWriterEndElement(pWriter);
697 // XEventListener
700 void SAL_CALL SdrTableObjImpl::disposing( const css::lang::EventObject& Source )
702 assert(Source.Source == mxTableStyle);
703 (void)Source;
705 Reference<XIndexAccess> xDefaultStyle;
708 Reference<XStyleFamiliesSupplier> xSupplier(mpTableObj->getSdrModelFromSdrObject().getUnoModel(), UNO_QUERY_THROW);
709 Reference<XNameAccess> xTableFamily(xSupplier->getStyleFamilies()->getByName(u"table"_ustr), UNO_QUERY_THROW);
710 xDefaultStyle.set(xTableFamily->getByName(u"default"_ustr), UNO_QUERY_THROW);
712 catch( Exception& )
714 TOOLS_WARN_EXCEPTION("svx.table", "");
717 mpTableObj->setTableStyle(xDefaultStyle);
721 CellRef SdrTableObjImpl::getCell( const CellPos& rPos ) const
723 CellRef xCell;
724 if( mxTable.is() ) try
726 xCell = mxTable->getCell( rPos.mnCol, rPos.mnRow );
728 catch( Exception& )
730 TOOLS_WARN_EXCEPTION("svx.table", "");
732 return xCell;
736 sal_Int32 SdrTableObjImpl::getColumnCount() const
738 return mxTable.is() ? mxTable->getColumnCount() : 0;
741 std::vector<sal_Int32> SdrTableObjImpl::getColumnWidths() const
743 std::vector<sal_Int32> aRet;
745 if (mxTable.is())
746 aRet = mxTable->getColumnWidths();
748 return aRet;
751 sal_Int32 SdrTableObjImpl::getRowCount() const
753 return mxTable.is() ? mxTable->getRowCount() : 0;
756 void SdrTableObjImpl::LayoutTable( tools::Rectangle& rArea, bool bFitWidth, bool bFitHeight )
758 if (comphelper::IsFuzzing())
759 return;
760 if(!mpLayouter)
761 return;
763 // Optimization: SdrTableObj::SetChanged() can call this very often, repeatedly
764 // with the same settings, noticeably increasing load time. Skip if already done.
765 bool bInteractiveMightGrowBecauseTextChanged =
766 mpTableObj->IsReallyEdited() && (mpTableObj->IsAutoGrowHeight() || mpTableObj->IsAutoGrowWidth());
767 WritingMode writingMode = mpTableObj->GetWritingMode();
768 if( bInteractiveMightGrowBecauseTextChanged
769 || lastLayoutTable != this || lastLayoutInputRectangle != rArea
770 || lastLayoutFitWidth != bFitWidth || lastLayoutFitHeight != bFitHeight
771 || lastLayoutMode != writingMode
772 || lastRowCount != getRowCount()
773 || lastColCount != getColumnCount()
774 || lastColWidths != getColumnWidths()
775 || rowSizeChanged )
777 lastLayoutTable = this;
778 lastLayoutInputRectangle = rArea;
779 lastLayoutFitWidth = bFitWidth;
780 lastLayoutFitHeight = bFitHeight;
781 lastLayoutMode = writingMode;
782 lastRowCount = getRowCount();
783 lastColCount = getColumnCount();
784 // Column resize, when the total width and column count of the
785 // table is unchanged, but re-layout is still needed.
786 lastColWidths = getColumnWidths();
787 TableModelNotifyGuard aGuard( mxTable.get() );
788 mpLayouter->LayoutTable( rArea, bFitWidth, bFitHeight );
789 lastLayoutResultRectangle = rArea;
790 rowSizeChanged = false;
792 else
794 rArea = lastLayoutResultRectangle;
795 mpLayouter->UpdateBorderLayout();
799 void SdrTableObjImpl::UpdateCells( tools::Rectangle const & rArea )
801 if( mpLayouter && mxTable.is() )
803 TableModelNotifyGuard aGuard( mxTable.get() );
804 mpLayouter->updateCells( rArea );
805 mxTable->setModified(true);
810 // BaseProperties section
813 std::unique_ptr<sdr::properties::BaseProperties> SdrTableObj::CreateObjectSpecificProperties()
815 return std::make_unique<TableProperties>(*this);
819 // DrawContact section
822 std::unique_ptr<sdr::contact::ViewContact> SdrTableObj::CreateObjectSpecificViewContact()
824 return std::make_unique<sdr::contact::ViewContactOfTableObj>(*this);
827 SdrTableObj::SdrTableObj(SdrModel& rSdrModel)
828 : SdrTextObj(rSdrModel)
830 osl_atomic_increment(&m_refCount); // other I get deleted during construction
831 init( 1, 1 );
832 osl_atomic_decrement(&m_refCount);
835 SdrTableObj::SdrTableObj(SdrModel& rSdrModel, SdrTableObj const & rSource)
836 : SdrTextObj(rSdrModel, rSource)
838 osl_atomic_increment(&m_refCount);
840 init( 1, 1 );
842 TableModelNotifyGuard aGuard( mpImpl.is() ? mpImpl->mxTable.get() : nullptr );
844 maLogicRect = rSource.maLogicRect;
845 maRectangle = rSource.maRectangle;
846 maGeo = rSource.maGeo;
847 meTextKind = rSource.meTextKind;
848 mbTextFrame = rSource.mbTextFrame;
849 maTextSize = rSource.maTextSize;
850 mbTextSizeDirty = rSource.mbTextSizeDirty;
851 mbNoShear = rSource.mbNoShear;
852 mbDisableAutoWidthOnDragging = rSource.mbDisableAutoWidthOnDragging;
854 // use SdrTableObjImpl::operator= now to
855 // copy model data and other stuff (see there)
856 *mpImpl = *rSource.mpImpl;
858 osl_atomic_decrement(&m_refCount);
861 SdrTableObj::SdrTableObj(
862 SdrModel& rSdrModel,
863 const ::tools::Rectangle& rNewRect,
864 sal_Int32 nColumns,
865 sal_Int32 nRows)
866 : SdrTextObj(rSdrModel, rNewRect)
867 ,maLogicRect(rNewRect)
869 osl_atomic_increment(&m_refCount);
871 if( nColumns <= 0 )
872 nColumns = 1;
874 if( nRows <= 0 )
875 nRows = 1;
877 init( nColumns, nRows );
879 osl_atomic_decrement(&m_refCount);
883 void SdrTableObj::init( sal_Int32 nColumns, sal_Int32 nRows )
885 m_bClosedObj = true;
887 mpImpl = new SdrTableObjImpl;
888 mpImpl->init( this, nColumns, nRows );
890 // Stuff done from old SetModel:
891 if( !maLogicRect.IsEmpty() )
893 setRectangle(maLogicRect);
894 auto aRectangle = getRectangle();
895 mpImpl->LayoutTable(aRectangle, false, false);
896 setRectangle(aRectangle);
901 SdrTableObj::~SdrTableObj()
903 mpImpl->dispose();
907 // table stuff
910 Reference< XTable > SdrTableObj::getTable() const
912 return mpImpl->mxTable;
915 const rtl::Reference< TableModel > & SdrTableObj::getUnoTable() const
917 return mpImpl->mxTable;
920 bool SdrTableObj::isValid( const CellPos& rPos ) const
922 return (rPos.mnCol >= 0) && (rPos.mnCol < mpImpl->getColumnCount()) && (rPos.mnRow >= 0) && (rPos.mnRow < mpImpl->getRowCount());
926 CellPos SdrTableObj::getFirstCell()
928 return CellPos( 0,0 );
932 CellPos SdrTableObj::getLastCell() const
934 CellPos aPos;
935 if( mpImpl->mxTable.is() )
937 aPos.mnCol = mpImpl->getColumnCount()-1;
938 aPos.mnRow = mpImpl->getRowCount()-1;
940 return aPos;
944 CellPos SdrTableObj::getLeftCell( const CellPos& rPos, bool bEdgeTravel ) const
946 switch( GetWritingMode() )
948 default:
949 case WritingMode_LR_TB:
950 return getPreviousCell( rPos, bEdgeTravel );
951 case WritingMode_RL_TB:
952 return getNextCell( rPos, bEdgeTravel );
953 case WritingMode_TB_RL:
954 return getPreviousRow( rPos, bEdgeTravel );
959 CellPos SdrTableObj::getRightCell( const CellPos& rPos, bool bEdgeTravel ) const
961 switch( GetWritingMode() )
963 default:
964 case WritingMode_LR_TB:
965 return getNextCell( rPos, bEdgeTravel );
966 case WritingMode_RL_TB:
967 return getPreviousCell( rPos, bEdgeTravel );
968 case WritingMode_TB_RL:
969 return getNextRow( rPos, bEdgeTravel );
974 CellPos SdrTableObj::getUpCell( const CellPos& rPos, bool bEdgeTravel ) const
976 switch( GetWritingMode() )
978 default:
979 case WritingMode_LR_TB:
980 case WritingMode_RL_TB:
981 return getPreviousRow( rPos, bEdgeTravel );
982 case WritingMode_TB_RL:
983 return getPreviousCell( rPos, bEdgeTravel );
988 CellPos SdrTableObj::getDownCell( const CellPos& rPos, bool bEdgeTravel ) const
990 switch( GetWritingMode() )
992 default:
993 case WritingMode_LR_TB:
994 case WritingMode_RL_TB:
995 return getNextRow( rPos, bEdgeTravel );
996 case WritingMode_TB_RL:
997 return getNextCell( rPos, bEdgeTravel );
1002 CellPos SdrTableObj::getPreviousCell( const CellPos& rPos, bool bEdgeTravel ) const
1004 CellPos aPos( rPos );
1005 if( mpImpl.is() )
1007 CellRef xCell( mpImpl->getCell( aPos ) );
1008 if( xCell.is() && xCell->isMerged() )
1010 sal_Int32 nTemp = 0;
1011 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, nTemp );
1014 if( aPos.mnCol > 0 )
1016 --aPos.mnCol;
1019 else if( bEdgeTravel && (aPos.mnRow > 0) )
1021 aPos.mnCol = mpImpl->mxTable->getColumnCount()-1;
1022 --aPos.mnRow;
1025 return aPos;
1029 CellPos SdrTableObj::getNextCell( const CellPos& rPos, bool bEdgeTravel ) const
1031 CellPos aPos( rPos );
1032 if( mpImpl.is() )
1034 CellRef xCell( mpImpl->getCell( aPos ) );
1035 if( xCell.is() )
1037 if( xCell->isMerged() )
1039 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
1041 xCell = mpImpl->getCell(aPos);
1043 if( xCell.is() )
1045 aPos.mnCol += xCell->getColumnSpan();
1046 aPos.mnRow = rPos.mnRow;
1049 else
1051 aPos.mnCol += xCell->getColumnSpan();
1054 if( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
1055 return aPos;
1057 if( bEdgeTravel && ((aPos.mnRow + 1) < mpImpl->getRowCount()) )
1059 aPos.mnCol = 0;
1060 aPos.mnRow += 1;
1061 return aPos;
1066 // last cell reached, no traveling possible
1067 return rPos;
1071 CellPos SdrTableObj::getPreviousRow( const CellPos& rPos, bool bEdgeTravel ) const
1073 CellPos aPos( rPos );
1074 if( mpImpl.is() )
1076 CellRef xCell( mpImpl->getCell( aPos ) );
1077 if( xCell.is() && xCell->isMerged() )
1079 sal_Int32 nTemp = 0;
1080 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, nTemp, aPos.mnRow );
1083 if( aPos.mnRow > 0 )
1085 --aPos.mnRow;
1087 else if( bEdgeTravel && (aPos.mnCol > 0) )
1089 aPos.mnRow = mpImpl->mxTable->getRowCount()-1;
1090 --aPos.mnCol;
1093 return aPos;
1097 CellPos SdrTableObj::getNextRow( const CellPos& rPos, bool bEdgeTravel ) const
1099 CellPos aPos( rPos );
1101 if( mpImpl.is() )
1103 CellRef xCell( mpImpl->getCell( rPos ) );
1104 if( xCell.is() )
1106 if( xCell->isMerged() )
1108 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
1109 xCell = mpImpl->getCell(aPos);
1110 aPos.mnCol = rPos.mnCol;
1113 if( xCell.is() )
1114 aPos.mnRow += xCell->getRowSpan();
1116 if( aPos.mnRow < mpImpl->mxTable->getRowCount() )
1117 return aPos;
1119 if( bEdgeTravel && (aPos.mnCol + 1) < mpImpl->mxTable->getColumnCount() )
1121 aPos.mnRow = 0;
1122 aPos.mnCol += 1;
1124 while( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
1126 xCell = mpImpl->getCell( aPos );
1127 if( xCell.is() && !xCell->isMerged() )
1128 return aPos;
1129 aPos.mnCol += 1;
1135 // last position reached, no more traveling possible
1136 return rPos;
1140 const TableStyleSettings& SdrTableObj::getTableStyleSettings() const
1142 if( mpImpl.is())
1144 return mpImpl->maTableStyle;
1146 else
1148 static TableStyleSettings aTmp;
1149 return aTmp;
1154 void SdrTableObj::setTableStyleSettings( const TableStyleSettings& rStyle )
1156 if( mpImpl.is() )
1158 mpImpl->maTableStyle = rStyle;
1159 mpImpl->update();
1164 TableHitKind SdrTableObj::CheckTableHit( const Point& rPos, sal_Int32& rnX, sal_Int32& rnY, const sal_uInt16 aTol ) const
1166 if( !mpImpl.is() || !mpImpl->mxTable.is() )
1167 return TableHitKind::NONE;
1169 rnX = 0;
1170 rnY = 0;
1172 const sal_Int32 nColCount = mpImpl->getColumnCount();
1173 const sal_Int32 nRowCount = mpImpl->getRowCount();
1175 sal_Int32 nX = rPos.X() - getRectangle().Left();
1176 sal_Int32 nY = rPos.Y() - getRectangle().Top();
1178 if( (nX < 0) || (nX > getRectangle().GetWidth()) || (nY < 0) || (nY > getRectangle().GetHeight() ) )
1179 return TableHitKind::NONE;
1181 // get vertical edge number and check for a hit
1182 const bool bRTL = (GetWritingMode() == WritingMode_RL_TB);
1183 bool bVrtHit = false;
1184 if( !bRTL )
1186 while( rnX <= nColCount )
1188 if( nX - aTol <= 0 )
1190 bVrtHit = true;
1191 break;
1194 if( rnX == nColCount )
1195 break;
1197 nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
1198 if( nX < 0 )
1199 break;
1200 rnX++;
1203 else
1205 rnX = nColCount;
1206 while( rnX >= 0 )
1208 if( nX - aTol <= 0 )
1210 bVrtHit = true;
1211 break;
1214 if( rnX == 0 )
1215 break;
1217 rnX--;
1218 nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
1219 if( nX < 0 )
1220 break;
1224 // rnX is now the edge number left to the pointer, if it was hit bHrzHit is also true
1226 // get vertical edge number and check for a hit
1227 bool bHrzHit = false;
1228 while( rnY <= nRowCount )
1230 if( nY - aTol <= 0 )
1232 bHrzHit = true;
1233 break;
1236 if( rnY == nRowCount )
1237 break;
1239 nY -= mpImpl->mpLayouter->getRowHeight(rnY);
1240 if( nY < 0 )
1241 break;
1242 rnY++;
1245 // rnY is now the edge number above the pointer, if it was hit bVrtHit is also true
1247 if( bVrtHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, false ) )
1248 return TableHitKind::VerticallBorder;
1250 if( bHrzHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, true ) )
1251 return TableHitKind::HorizontalBorder;
1253 CellRef xCell( mpImpl->getCell( CellPos( rnX, rnY ) ) );
1254 if( xCell.is() && xCell->isMerged() )
1255 findMergeOrigin( mpImpl->mxTable, rnX, rnY, rnX, rnY );
1257 if( xCell.is() )
1259 nX += mpImpl->mpLayouter->getColumnWidth( rnX );
1260 //Fix for fdo#62673 : non-editable cell in table on cell merge
1261 sal_Int32 i=0;
1262 while(xCell.is() && xCell->isMerged())
1264 nX += mpImpl->mpLayouter->getColumnWidth( rnX+i );
1265 i++;
1266 if(rnX+i < nColCount)
1267 xCell=mpImpl->getCell( CellPos( rnX+i, rnY) );
1268 else
1269 break;
1272 if( nX < xCell->GetTextLeftDistance() )
1273 return TableHitKind::Cell;
1276 return TableHitKind::CellTextArea;
1279 const SfxItemSet& SdrTableObj::GetActiveCellItemSet() const
1281 return getActiveCell()->GetItemSet();
1284 void SdrTableObj::setTableStyle( const Reference< XIndexAccess >& xTableStyle )
1286 if( mpImpl.is() && (mpImpl->mxTableStyle != xTableStyle) )
1288 mpImpl->disconnectTableStyle();
1289 mpImpl->mxTableStyle = xTableStyle;
1290 mpImpl->connectTableStyle();
1291 mpImpl->update();
1296 const Reference< XIndexAccess >& SdrTableObj::getTableStyle() const
1298 if( mpImpl.is() )
1300 return mpImpl->mxTableStyle;
1302 else
1304 static Reference< XIndexAccess > aTmp;
1305 return aTmp;
1310 // text stuff
1313 /** returns the currently active text. */
1314 SdrText* SdrTableObj::getActiveText() const
1316 return getActiveCell().get();
1320 /** returns the nth available text. */
1321 SdrText* SdrTableObj::getText( sal_Int32 nIndex ) const
1323 if( mpImpl->mxTable.is() )
1325 const sal_Int32 nColCount = mpImpl->getColumnCount();
1326 if( nColCount )
1328 CellPos aPos( nIndex % nColCount, nIndex / nColCount );
1330 CellRef xCell( mpImpl->getCell( aPos ) );
1331 return xCell.get();
1334 return nullptr;
1338 /** returns the number of texts available for this object. */
1339 sal_Int32 SdrTableObj::getTextCount() const
1341 if( mpImpl->mxTable.is() )
1343 const sal_Int32 nColCount = mpImpl->getColumnCount();
1344 const sal_Int32 nRowCount = mpImpl->getRowCount();
1346 return nColCount * nRowCount;
1348 else
1350 return 0;
1355 /** changes the current active text */
1356 void SdrTableObj::setActiveText( sal_Int32 nIndex )
1358 if( mpImpl.is() && mpImpl->mxTable.is() )
1360 const sal_Int32 nColCount = mpImpl->mxTable->getColumnCount();
1361 if( nColCount )
1363 CellPos aPos( nIndex % nColCount, nIndex / nColCount );
1364 if( isValid( aPos ) )
1365 setActiveCell( aPos );
1371 /** returns the index of the text that contains the given point or -1 */
1372 sal_Int32 SdrTableObj::CheckTextHit(const Point& rPnt) const
1374 if( mpImpl.is() && mpImpl->mxTable.is() )
1376 CellPos aPos;
1377 if( CheckTableHit( rPnt, aPos.mnCol, aPos.mnRow ) == TableHitKind::CellTextArea )
1378 return aPos.mnRow * mpImpl->mxTable->getColumnCount() + aPos.mnCol;
1381 return 0;
1384 SdrOutliner* SdrTableObj::GetCellTextEditOutliner( const Cell& rCell ) const
1386 if( mpImpl.is() && (mpImpl->getCell( mpImpl->maEditPos ).get() == &rCell) )
1387 return mpEditingOutliner;
1388 else
1389 return nullptr;
1392 const TableLayouter& SdrTableObj::getTableLayouter() const
1394 assert(mpImpl.is() && mpImpl->mpLayouter && "getTableLayouter() error: no mpImpl or mpLayouter (!)");
1395 return *(mpImpl->mpLayouter);
1398 bool SdrTableObj::IsAutoGrowHeight() const
1400 return true;
1403 bool SdrTableObj::IsAutoGrowWidth() const
1405 return true;
1408 bool SdrTableObj::HasText() const
1410 return true;
1413 bool SdrTableObj::IsTextEditActive( const CellPos& rPos )
1415 return mpEditingOutliner && mpImpl.is() && (rPos == mpImpl->maEditPos);
1419 void SdrTableObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus )
1421 if( (pEditStatus->GetStatusWord() & EditStatusFlags::TextHeightChanged) && mpImpl.is() && mpImpl->mpLayouter )
1423 tools::Rectangle aRect0(getRectangle());
1424 setRectangle(maLogicRect);
1425 auto aRectangle = getRectangle();
1426 mpImpl->LayoutTable(aRectangle, false, false);
1427 setRectangle(aRectangle);
1428 SetBoundAndSnapRectsDirty();
1429 ActionChanged();
1430 BroadcastObjectChange();
1431 if (aRect0 != getRectangle())
1432 SendUserCall(SdrUserCallType::Resize,aRect0);
1437 void SdrTableObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
1439 rInfo.bResizeFreeAllowed=true;
1440 rInfo.bResizePropAllowed=true;
1441 rInfo.bRotateFreeAllowed=false;
1442 rInfo.bRotate90Allowed =false;
1443 rInfo.bMirrorFreeAllowed=false;
1444 rInfo.bMirror45Allowed =false;
1445 rInfo.bMirror90Allowed =false;
1447 // allow transparence
1448 rInfo.bTransparenceAllowed = true;
1450 rInfo.bShearAllowed =false;
1451 rInfo.bEdgeRadiusAllowed=false;
1452 rInfo.bCanConvToPath =false;
1453 rInfo.bCanConvToPoly =false;
1454 rInfo.bCanConvToPathLineToArea=false;
1455 rInfo.bCanConvToPolyLineToArea=false;
1456 rInfo.bCanConvToContour = false;
1459 SdrObjKind SdrTableObj::GetObjIdentifier() const
1461 return SdrObjKind::Table;
1464 void SdrTableObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect, bool /*bLineWidth*/ ) const
1466 if( mpImpl.is() )
1467 TakeTextRect( mpImpl->maEditPos, rOutliner, rTextRect, bNoEditText, pAnchorRect );
1471 void SdrTableObj::TakeTextRect( const CellPos& rPos, SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect ) const
1473 if( !mpImpl.is())
1474 return;
1476 CellRef xCell( mpImpl->getCell( rPos ) );
1477 if( !xCell.is() )
1478 return;
1480 tools::Rectangle aAnkRect;
1481 TakeTextAnchorRect( rPos, aAnkRect );
1483 SdrTextVertAdjust eVAdj=xCell->GetTextVerticalAdjust();
1485 EEControlBits nStat0=rOutliner.GetControlWord();
1486 nStat0 |= EEControlBits::AUTOPAGESIZE;
1487 rOutliner.SetControlWord(nStat0);
1488 rOutliner.SetMinAutoPaperSize(Size());
1489 rOutliner.SetMaxAutoPaperSize(aAnkRect.GetSize());
1490 rOutliner.SetPaperSize(aAnkRect.GetSize());
1492 // #103516# New try with _BLOCK for hor and ver after completely
1493 // supporting full width for vertical text.
1494 // if( SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
1495 // {
1496 rOutliner.SetMinAutoPaperSize(Size(aAnkRect.GetWidth(), 0));
1497 // }
1498 // else if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
1499 // {
1500 // rOutliner.SetMinAutoPaperSize(Size(0, aAnkRect.GetHeight()));
1501 // }
1504 // set text at outliner, maybe from edit outliner
1505 std::optional<OutlinerParaObject> pPara;
1506 if (xCell->GetOutlinerParaObject())
1507 pPara = *xCell->GetOutlinerParaObject();
1508 if (mpEditingOutliner && !bNoEditText && mpImpl->mxActiveCell == xCell )
1509 pPara = mpEditingOutliner->CreateParaObject();
1511 if (pPara)
1513 const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
1514 const SdrTextObj* pTestObj(rOutliner.GetTextObj());
1516 if( !pTestObj || !bHitTest || (pTestObj != this) || (pTestObj->GetOutlinerParaObject() != xCell->GetOutlinerParaObject()) )
1518 if( bHitTest ) // #i33696# take back fix #i27510#
1519 rOutliner.SetTextObj( this );
1521 rOutliner.SetUpdateLayout(true);
1522 rOutliner.SetText(*pPara);
1525 else
1527 rOutliner.SetTextObj( nullptr );
1530 rOutliner.SetUpdateLayout(true);
1531 rOutliner.SetControlWord(nStat0);
1533 Point aTextPos(aAnkRect.TopLeft());
1534 Size aTextSiz(rOutliner.GetPaperSize());
1535 if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1537 tools::Long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
1538 if (eVAdj==SDRTEXTVERTADJUST_CENTER)
1539 aTextPos.AdjustY(nFreeHgt/2 );
1540 if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1541 aTextPos.AdjustY(nFreeHgt );
1544 if (pAnchorRect)
1545 *pAnchorRect=aAnkRect;
1547 rTextRect=tools::Rectangle(aTextPos,aTextSiz);
1550 const CellRef& SdrTableObj::getActiveCell() const
1552 if( mpImpl.is() )
1554 if( !mpImpl->mxActiveCell.is() )
1556 CellPos aPos;
1557 const_cast< SdrTableObj* >(this)->setActiveCell( aPos );
1559 return mpImpl->mxActiveCell;
1561 else
1563 static CellRef xCell;
1564 return xCell;
1569 sal_Int32 SdrTableObj::getColumnCount() const
1571 return mpImpl.is() ? mpImpl->getColumnCount() : 0;
1574 sal_Int32 SdrTableObj::getRowCount() const
1576 return mpImpl.is() ? mpImpl->getRowCount() : 0;
1579 void SdrTableObj::changeEdge(bool bHorizontal, int nEdge, sal_Int32 nOffset)
1581 if (mpImpl.is())
1582 mpImpl->DragEdge(bHorizontal, nEdge, nOffset);
1585 void SdrTableObj::setActiveCell( const CellPos& rPos )
1587 if( !(mpImpl.is() && mpImpl->mxTable.is()) )
1588 return;
1592 mpImpl->mxActiveCell = mpImpl->mxTable->getCell( rPos.mnCol, rPos.mnRow );
1593 if( mpImpl->mxActiveCell.is() && mpImpl->mxActiveCell->isMerged() )
1595 CellPos aOrigin;
1596 findMergeOrigin( mpImpl->mxTable, rPos.mnCol, rPos.mnRow, aOrigin.mnCol, aOrigin.mnRow );
1597 mpImpl->mxActiveCell = mpImpl->mxTable->getCell( aOrigin.mnCol, aOrigin.mnRow );
1598 mpImpl->maEditPos = aOrigin;
1600 else
1602 mpImpl->maEditPos = rPos;
1605 catch( Exception& )
1607 TOOLS_WARN_EXCEPTION("svx.table", "");
1612 void SdrTableObj::getActiveCellPos( CellPos& rPos ) const
1614 rPos = mpImpl->maEditPos;
1618 void SdrTableObj::getCellBounds( const CellPos& rPos, ::tools::Rectangle& rCellRect )
1620 if( mpImpl.is() )
1622 CellRef xCell( mpImpl->getCell( rPos ) );
1623 if( xCell.is() )
1624 rCellRect = xCell->getCellRect();
1629 void SdrTableObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
1631 if( mpImpl.is() )
1632 TakeTextAnchorRect( mpImpl->maEditPos, rAnchorRect );
1636 void SdrTableObj::TakeTextAnchorRect( const CellPos& rPos, tools::Rectangle& rAnchorRect ) const
1638 tools::Rectangle aAnkRect(getRectangle());
1640 if( mpImpl.is() )
1642 CellRef xCell( mpImpl->getCell( rPos ) );
1643 if( xCell.is() )
1644 xCell->TakeTextAnchorRect( aAnkRect );
1647 ImpJustifyRect(aAnkRect);
1648 rAnchorRect=aAnkRect;
1652 void SdrTableObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
1654 if( mpImpl.is() )
1655 TakeTextEditArea( mpImpl->maEditPos, pPaperMin, pPaperMax, pViewInit, pViewMin );
1659 void SdrTableObj::TakeTextEditArea( const CellPos& rPos, Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin ) const
1661 Size aPaperMin,aPaperMax;
1662 tools::Rectangle aViewInit;
1663 TakeTextAnchorRect( rPos, aViewInit );
1665 Size aAnkSiz(aViewInit.GetSize());
1666 aAnkSiz.AdjustWidth( -1 ); aAnkSiz.AdjustHeight( -1 ); // because GetSize() increments by one
1668 Size aMaxSiz(aAnkSiz.Width(),1000000);
1669 Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
1670 if (aTmpSiz.Height()!=0)
1671 aMaxSiz.setHeight(aTmpSiz.Height() );
1673 CellRef xCell( mpImpl->getCell( rPos ) );
1674 SdrTextVertAdjust eVAdj = xCell.is() ? xCell->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_TOP;
1676 aPaperMax=aMaxSiz;
1678 aPaperMin.setWidth( aAnkSiz.Width() );
1680 if (pViewMin!=nullptr)
1682 *pViewMin=aViewInit;
1683 tools::Long nYFree=aAnkSiz.Height()-aPaperMin.Height();
1685 if (eVAdj==SDRTEXTVERTADJUST_TOP)
1687 pViewMin->AdjustBottom( -nYFree );
1689 else if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1691 pViewMin->AdjustTop(nYFree );
1693 else
1695 pViewMin->AdjustTop(nYFree/2 );
1696 pViewMin->SetBottom(pViewMin->Top()+aPaperMin.Height() );
1701 if(IsVerticalWriting())
1702 aPaperMin.setWidth( 0 );
1703 else
1704 aPaperMin.setHeight( 0 );
1706 if (pPaperMin!=nullptr) *pPaperMin=aPaperMin;
1707 if (pPaperMax!=nullptr) *pPaperMax=aPaperMax;
1708 if (pViewInit!=nullptr) *pViewInit=aViewInit;
1712 EEAnchorMode SdrTableObj::GetOutlinerViewAnchorMode() const
1714 EEAnchorMode eRet=EEAnchorMode::TopLeft;
1715 CellRef xCell( getActiveCell() );
1716 if( xCell.is() )
1718 SdrTextVertAdjust eV=xCell->GetTextVerticalAdjust();
1721 if (eV==SDRTEXTVERTADJUST_TOP)
1723 eRet=EEAnchorMode::TopLeft;
1725 else if (eV==SDRTEXTVERTADJUST_BOTTOM)
1727 eRet=EEAnchorMode::BottomLeft;
1729 else
1731 eRet=EEAnchorMode::VCenterLeft;
1735 return eRet;
1739 OUString SdrTableObj::TakeObjNameSingul() const
1741 OUString sName(SvxResId(STR_ObjNameSingulTable));
1743 OUString aName(GetName());
1744 if (!aName.isEmpty())
1745 sName += " '" + aName + "'";
1747 return sName;
1751 OUString SdrTableObj::TakeObjNamePlural() const
1753 return SvxResId(STR_ObjNamePluralTable);
1757 rtl::Reference<SdrObject> SdrTableObj::CloneSdrObject(SdrModel& rTargetModel) const
1759 return new SdrTableObj(rTargetModel, *this);
1763 const tools::Rectangle& SdrTableObj::GetSnapRect() const
1765 return getRectangle();
1769 void SdrTableObj::NbcSetSnapRect(const tools::Rectangle& rRect)
1771 NbcSetLogicRect( rRect );
1775 const tools::Rectangle& SdrTableObj::GetLogicRect() const
1777 return maLogicRect;
1781 void SdrTableObj::RecalcSnapRect()
1786 bool SdrTableObj::BegTextEdit(SdrOutliner& rOutl)
1788 if( mpEditingOutliner != nullptr )
1789 return false;
1791 mpEditingOutliner=&rOutl;
1793 mbInEditMode = true;
1795 rOutl.Init( OutlinerMode::TextObject );
1796 rOutl.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());
1798 bool bUpdateMode = rOutl.SetUpdateLayout(false);
1799 Size aPaperMin;
1800 Size aPaperMax;
1801 tools::Rectangle aEditArea;
1802 TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,nullptr);
1804 rOutl.SetMinAutoPaperSize(aPaperMin);
1805 rOutl.SetMaxAutoPaperSize(aPaperMax);
1806 rOutl.SetPaperSize(aPaperMax);
1808 if (bUpdateMode) rOutl.SetUpdateLayout(true);
1810 EEControlBits nStat=rOutl.GetControlWord();
1811 nStat |= EEControlBits::AUTOPAGESIZE;
1812 nStat &=~EEControlBits::STRETCHING;
1813 rOutl.SetControlWord(nStat);
1815 OutlinerParaObject* pPara = GetOutlinerParaObject();
1816 if(pPara)
1817 rOutl.SetText(*pPara);
1819 rOutl.UpdateFields();
1820 rOutl.ClearModifyFlag();
1822 return true;
1826 void SdrTableObj::EndTextEdit(SdrOutliner& rOutl)
1829 if (getSdrModelFromSdrObject().IsUndoEnabled() && !mpImpl->maUndos.empty())
1831 // These actions should be on the undo stack after text edit.
1832 for (std::unique_ptr<SdrUndoAction>& pAction : mpImpl->maUndos)
1833 getSdrModelFromSdrObject().AddUndo( std::move(pAction));
1834 mpImpl->maUndos.clear();
1836 getSdrModelFromSdrObject().AddUndo(getSdrModelFromSdrObject().GetSdrUndoFactory().CreateUndoGeoObject(*this));
1839 if(rOutl.IsModified())
1841 std::optional<OutlinerParaObject> pNewText;
1842 Paragraph* p1stPara = rOutl.GetParagraph( 0 );
1843 sal_Int32 nParaCnt = rOutl.GetParagraphCount();
1845 if(p1stPara)
1847 // to remove the grey field background
1848 rOutl.UpdateFields();
1850 // create new text object
1851 pNewText = rOutl.CreateParaObject( 0, nParaCnt );
1853 SetOutlinerParaObject(std::move(pNewText));
1856 mpEditingOutliner = nullptr;
1857 rOutl.Clear();
1858 EEControlBits nStat = rOutl.GetControlWord();
1859 nStat &= ~EEControlBits::AUTOPAGESIZE;
1860 rOutl.SetControlWord(nStat);
1862 mbInEditMode = false;
1866 OutlinerParaObject* SdrTableObj::GetOutlinerParaObject() const
1868 CellRef xCell( getActiveCell() );
1869 if( xCell.is() )
1870 return xCell->GetOutlinerParaObject();
1871 else
1872 return nullptr;
1876 void SdrTableObj::NbcSetOutlinerParaObject( std::optional<OutlinerParaObject> pTextObject, bool bAdjustTextFrameWidthAndHeight )
1878 CellRef xCell( getActiveCell() );
1879 if( !xCell.is() )
1880 return;
1882 // Update HitTestOutliner
1883 const SdrTextObj* pTestObj(getSdrModelFromSdrObject().GetHitTestOutliner().GetTextObj());
1885 if(pTestObj && pTestObj->GetOutlinerParaObject() == xCell->GetOutlinerParaObject())
1887 getSdrModelFromSdrObject().GetHitTestOutliner().SetTextObj(nullptr);
1890 xCell->SetOutlinerParaObject( std::move(pTextObject) );
1891 SetTextSizeDirty();
1892 if (bAdjustTextFrameWidthAndHeight)
1893 NbcAdjustTextFrameWidthAndHeight();
1897 void SdrTableObj::NbcSetLogicRect(const tools::Rectangle& rRect, bool /*bAdaptTextMinSize*/)
1899 maLogicRect=rRect;
1900 ImpJustifyRect(maLogicRect);
1901 const bool bWidth = maLogicRect.getOpenWidth() != getRectangle().getOpenWidth();
1902 const bool bHeight = maLogicRect.getOpenHeight() != getRectangle().getOpenHeight();
1903 setRectangle(maLogicRect);
1904 if (mpImpl->mbSkipChangeLayout)
1905 // Avoid distributing newly available space between existing cells.
1906 NbcAdjustTextFrameWidthAndHeight();
1907 else
1908 NbcAdjustTextFrameWidthAndHeight(!bHeight, !bWidth);
1909 SetBoundAndSnapRectsDirty();
1913 void SdrTableObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
1915 tools::Rectangle aAdjustRect( rMaxRect );
1916 aAdjustRect.setHeight( GetLogicRect().getOpenHeight() );
1917 SetLogicRect( aAdjustRect );
1921 void SdrTableObj::NbcMove(const Size& rSiz)
1923 maLogicRect.Move(rSiz);
1924 SdrTextObj::NbcMove( rSiz );
1925 if( mpImpl.is() )
1926 mpImpl->UpdateCells(getRectangle());
1930 void SdrTableObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1932 tools::Rectangle aOldRect( maLogicRect );
1933 ResizeRect(maLogicRect,rRef,xFact,yFact);
1935 setRectangle(maLogicRect);
1936 NbcAdjustTextFrameWidthAndHeight( maLogicRect.GetHeight() == aOldRect.GetHeight(), maLogicRect.GetWidth() == aOldRect.GetWidth() );
1937 SetBoundAndSnapRectsDirty();
1941 bool SdrTableObj::AdjustTextFrameWidthAndHeight()
1943 tools::Rectangle aNewRect(maLogicRect);
1944 bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
1945 if (bRet)
1947 tools::Rectangle aBoundRect0;
1948 if (m_pUserCall!=nullptr)
1949 aBoundRect0=GetLastBoundRect();
1950 setRectangle(aNewRect);
1951 SetBoundAndSnapRectsDirty();
1952 SetChanged();
1953 BroadcastObjectChange();
1954 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1956 return bRet;
1960 bool SdrTableObj::AdjustTextFrameWidthAndHeight(tools::Rectangle& rR, bool bHeight, bool bWidth) const
1962 if(rR.IsEmpty() || !mpImpl.is() || !mpImpl->mxTable.is())
1963 return false;
1965 tools::Rectangle aRectangle( rR );
1966 mpImpl->LayoutTable( aRectangle, !bWidth, !bHeight );
1968 if( aRectangle != rR )
1970 rR = aRectangle;
1971 return true;
1973 else
1975 return false;
1980 void SdrTableObj::NbcReformatText()
1982 NbcAdjustTextFrameWidthAndHeight();
1986 bool SdrTableObj::IsVerticalWriting() const
1988 const SvxWritingModeItem& rModeItem = GetObjectItem( SDRATTR_TEXTDIRECTION );
1989 return rModeItem.GetValue() == css::text::WritingMode_TB_RL;
1993 void SdrTableObj::SetVerticalWriting(bool bVertical)
1995 if(bVertical != IsVerticalWriting() )
1997 SvxWritingModeItem aModeItem( css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION );
1998 SetObjectItem( aModeItem );
2003 WritingMode SdrTableObj::GetWritingMode() const
2005 SfxStyleSheet* pStyle = GetStyleSheet();
2006 if ( !pStyle )
2007 return WritingMode_LR_TB;
2009 WritingMode eWritingMode = WritingMode_LR_TB;
2010 const SfxItemSet &rSet = pStyle->GetItemSet();
2012 if ( const SvxWritingModeItem *pItem = rSet.GetItemIfSet( SDRATTR_TEXTDIRECTION ))
2013 eWritingMode = pItem->GetValue();
2015 if ( const SvxFrameDirectionItem *pItem;
2016 ( eWritingMode != WritingMode_TB_RL ) &&
2017 ( pItem = rSet.GetItemIfSet( EE_PARA_WRITINGDIR, false ) ) )
2019 if ( pItem->GetValue() == SvxFrameDirection::Horizontal_LR_TB )
2020 eWritingMode = WritingMode_LR_TB;
2021 else
2022 eWritingMode = WritingMode_RL_TB;
2025 return eWritingMode;
2028 void SdrTableObj::AddUndo(SdrUndoAction* pUndo)
2030 mpImpl->maUndos.push_back(std::unique_ptr<SdrUndoAction>(pUndo));
2033 void SdrTableObj::SetSkipChangeLayout(bool bSkipChangeLayout)
2035 mpImpl->mbSkipChangeLayout = bSkipChangeLayout;
2038 bool SdrTableObj::IsReallyEdited() const
2040 return mpEditingOutliner && mpEditingOutliner->IsModified();
2043 bool SdrTableObj::IsFontwork() const
2045 return false;
2048 sal_uInt32 SdrTableObj::GetHdlCount() const
2050 sal_uInt32 nCount = SdrTextObj::GetHdlCount();
2051 const sal_Int32 nRowCount = mpImpl->getRowCount();
2052 const sal_Int32 nColCount = mpImpl->getColumnCount();
2054 if( nRowCount && nColCount )
2055 nCount += nRowCount + nColCount + 2 + 1;
2057 return nCount;
2060 void SdrTableObj::AddToHdlList(SdrHdlList& rHdlList) const
2062 const sal_Int32 nRowCount = mpImpl->getRowCount();
2063 const sal_Int32 nColCount = mpImpl->getColumnCount();
2065 // first add row handles
2066 std::vector<TableEdgeHdl*> aRowEdges(nRowCount + 1);
2067 for (auto const & rEdge : mpImpl->mpLayouter->getHorizontalEdges())
2069 Point aPoint(getRectangle().TopLeft());
2070 aPoint.AdjustY(rEdge.nPosition);
2072 std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, true, rEdge.nMin, rEdge.nMax, nColCount + 1));
2073 pHdl->SetPointNum(rEdge.nIndex);
2074 aRowEdges[rEdge.nIndex] = pHdl.get();
2075 rHdlList.AddHdl(std::move(pHdl));
2078 // second add column handles
2079 std::vector<TableEdgeHdl*> aColEdges(nColCount + 1);
2080 for (auto const & rEdge : mpImpl->mpLayouter->getVerticalEdges())
2082 Point aPoint(getRectangle().TopLeft());
2083 aPoint.AdjustX(rEdge.nPosition);
2085 std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, false, rEdge.nMin, rEdge.nMax, nRowCount + 1));
2086 pHdl->SetPointNum(rEdge.nIndex);
2087 aColEdges[rEdge.nIndex] = pHdl.get();
2088 rHdlList.AddHdl(std::move(pHdl));
2091 // now add visible edges to row and column handles
2092 if( mpImpl->mpLayouter )
2094 TableLayouter& rLayouter = *mpImpl->mpLayouter;
2096 sal_Int32 nY = 0;
2098 for( sal_Int32 nRow = 0; nRow <= nRowCount; ++nRow )
2100 const sal_Int32 nRowHeight = (nRow == nRowCount) ? 0 : rLayouter.getRowHeight(nRow);
2101 sal_Int32 nX = 0;
2103 for( sal_Int32 nCol = 0; nCol <= nColCount; ++nCol )
2105 const sal_Int32 nColWidth = (nCol == nColCount) ? 0 : rLayouter.getColumnWidth(nCol);
2107 if( nRowHeight > 0 )
2109 if( rLayouter.isEdgeVisible( nCol, nRow, false ) )
2110 aColEdges[nCol]->SetEdge( nRow, nY, nY + nRowHeight, (rLayouter.getBorderLine( nCol, nRow, false ) == nullptr) ? Visible : Invisible);
2113 if( nColWidth > 0 )
2115 if( rLayouter.isEdgeVisible( nCol, nRow, true ) )
2116 aRowEdges[nRow]->SetEdge( nCol, nX, nX + nColWidth, (rLayouter.getBorderLine( nCol, nRow, true ) == nullptr) ? Visible : Invisible);
2119 nX += nColWidth;
2122 nY += nRowHeight;
2126 // add remaining handles
2127 SdrHdlList tempList(nullptr);
2128 auto aRectangle = getRectangle();
2129 tempList.AddHdl( std::make_unique<TableBorderHdl>(aRectangle, !IsTextEditActive() ) );
2130 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopLeft(),SdrHdlKind::UpperLeft) );
2131 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopCenter(),SdrHdlKind::Upper) );
2132 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopRight(),SdrHdlKind::UpperRight) );
2133 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.LeftCenter(),SdrHdlKind::Left) );
2134 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.RightCenter(),SdrHdlKind::Right) );
2135 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomLeft(),SdrHdlKind::LowerLeft) );
2136 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomCenter(),SdrHdlKind::Lower) );
2137 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomRight(),SdrHdlKind::LowerRight) );
2138 for( size_t nHdl = 0; nHdl < tempList.GetHdlCount(); ++nHdl )
2139 tempList.GetHdl(nHdl)->SetMoveOutside(true);
2140 tempList.MoveTo(rHdlList);
2142 const size_t nHdlCount = rHdlList.GetHdlCount();
2143 for( size_t nHdl = 0; nHdl < nHdlCount; ++nHdl )
2144 rHdlList.GetHdl(nHdl)->SetObj(const_cast<SdrTableObj*>(this));
2147 // Dragging
2149 bool SdrTableObj::hasSpecialDrag() const
2151 return true;
2154 bool SdrTableObj::beginSpecialDrag(SdrDragStat& rDrag) const
2156 const SdrHdl* pHdl = rDrag.GetHdl();
2157 const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2159 switch( eHdl )
2161 case SdrHdlKind::UpperLeft:
2162 case SdrHdlKind::Upper:
2163 case SdrHdlKind::UpperRight:
2164 case SdrHdlKind::Left:
2165 case SdrHdlKind::Right:
2166 case SdrHdlKind::LowerLeft:
2167 case SdrHdlKind::Lower:
2168 case SdrHdlKind::LowerRight:
2169 case SdrHdlKind::Move:
2171 break;
2174 case SdrHdlKind::User:
2176 rDrag.SetEndDragChangesAttributes(false);
2177 rDrag.SetNoSnap();
2178 break;
2181 default:
2183 return false;
2187 return true;
2190 bool SdrTableObj::applySpecialDrag(SdrDragStat& rDrag)
2192 bool bRet(true);
2193 const SdrHdl* pHdl = rDrag.GetHdl();
2194 const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2196 switch( eHdl )
2198 case SdrHdlKind::UpperLeft:
2199 case SdrHdlKind::Upper:
2200 case SdrHdlKind::UpperRight:
2201 case SdrHdlKind::Left:
2202 case SdrHdlKind::Right:
2203 case SdrHdlKind::LowerLeft:
2204 case SdrHdlKind::Lower:
2205 case SdrHdlKind::LowerRight:
2207 const tools::Rectangle aNewRectangle(ImpDragCalcRect(rDrag));
2209 if (aNewRectangle != getRectangle())
2211 NbcSetLogicRect(aNewRectangle);
2214 break;
2217 case SdrHdlKind::Move:
2219 NbcMove( Size( rDrag.GetDX(), rDrag.GetDY() ) );
2220 break;
2223 case SdrHdlKind::User:
2225 rDrag.SetEndDragChangesAttributes(false);
2226 rDrag.SetNoSnap();
2227 const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
2229 if( pEdgeHdl )
2231 if( IsInserted() )
2233 rDrag.SetEndDragChangesAttributes(true);
2234 rDrag.SetEndDragChangesLayout(true);
2237 mpImpl->DragEdge( pEdgeHdl->IsHorizontalEdge(), pEdgeHdl->GetPointNum(), pEdgeHdl->GetValidDragOffset( rDrag ) );
2239 break;
2242 default:
2244 bRet = false;
2248 return bRet;
2251 basegfx::B2DPolyPolygon SdrTableObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
2253 basegfx::B2DPolyPolygon aRetval;
2254 const SdrHdl* pHdl = rDrag.GetHdl();
2256 if( pHdl && (SdrHdlKind::User == pHdl->GetKind()) )
2258 const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
2260 if( pEdgeHdl )
2262 aRetval = pEdgeHdl->getSpecialDragPoly( rDrag );
2266 return aRetval;
2270 // Create
2273 bool SdrTableObj::BegCreate(SdrDragStat& rStat)
2275 rStat.SetOrtho4Possible();
2276 tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
2277 aRect1.Normalize();
2278 rStat.SetActionRect(aRect1);
2279 setRectangle(aRect1);
2280 return true;
2284 bool SdrTableObj::MovCreate(SdrDragStat& rStat)
2286 tools::Rectangle aRect1;
2287 rStat.TakeCreateRect(aRect1);
2288 ImpJustifyRect(aRect1);
2289 rStat.SetActionRect(aRect1);
2290 setRectangle(aRect1); // for ObjName
2291 SetBoundRectDirty();
2292 m_bSnapRectDirty=true;
2293 return true;
2297 bool SdrTableObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
2299 auto aRectangle = getRectangle();
2300 rStat.TakeCreateRect(aRectangle);
2301 ImpJustifyRect(aRectangle);
2302 setRectangle(aRectangle);
2303 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
2306 void SdrTableObj::BrkCreate(SdrDragStat& /*rStat*/)
2311 bool SdrTableObj::BckCreate(SdrDragStat& /*rStat*/)
2313 return true;
2317 basegfx::B2DPolyPolygon SdrTableObj::TakeCreatePoly(const SdrDragStat& rDrag) const
2319 tools::Rectangle aRect1;
2320 rDrag.TakeCreateRect(aRect1);
2321 aRect1.Normalize();
2323 basegfx::B2DPolyPolygon aRetval;
2324 const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aRect1);
2325 aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
2326 return aRetval;
2330 PointerStyle SdrTableObj::GetCreatePointer() const
2332 return PointerStyle::Cross;
2336 void SdrTableObj::createCell( CellRef& xNewCell )
2338 xNewCell = Cell::create( *this );
2342 std::unique_ptr<SdrObjGeoData> SdrTableObj::NewGeoData() const
2344 return std::make_unique<TableObjectGeoData>();
2348 void SdrTableObj::SaveGeoData(SdrObjGeoData& rGeo) const
2350 DBG_ASSERT( dynamic_cast< TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" );
2351 SdrTextObj::SaveGeoData (rGeo);
2353 static_cast<TableObjectGeoData &>(rGeo).maLogicRect = maLogicRect;
2357 void SdrTableObj::RestoreGeoData(const SdrObjGeoData& rGeo)
2359 DBG_ASSERT( dynamic_cast< const TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::RestoreGeoData(), illegal geo data!" );
2361 maLogicRect = static_cast<const TableObjectGeoData &>(rGeo).maLogicRect;
2363 SdrTextObj::RestoreGeoData (rGeo);
2365 if( mpImpl.is() )
2367 auto aRectangle = getRectangle();
2368 mpImpl->LayoutTable(aRectangle, false, false);
2369 setRectangle(aRectangle);
2371 ActionChanged();
2374 void SdrTableObj::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
2376 if(!mpImpl.is())
2378 return;
2381 mpImpl->CropTableModelToSelection(rStart, rEnd);
2384 void SdrTableObj::LayoutTableHeight(tools::Rectangle& rArea)
2386 if( mpImpl.is() && mpImpl->mpLayouter)
2388 mpImpl->mpLayouter->LayoutTableHeight(rArea, /*bFit*/false);
2392 void SdrTableObj::DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn, const bool bOptimize, const bool bMinimize )
2394 if( mpImpl.is() && mpImpl->mpLayouter )
2396 TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
2397 auto aRectangle = getRectangle();
2398 mpImpl->mpLayouter->DistributeColumns(aRectangle, nFirstColumn, nLastColumn, bOptimize, bMinimize);
2399 setRectangle(aRectangle);
2404 void SdrTableObj::DistributeRows( sal_Int32 nFirstRow, sal_Int32 nLastRow, const bool bOptimize, const bool bMinimize )
2406 if( mpImpl.is() && mpImpl->mpLayouter )
2408 TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
2409 auto aRectangle = getRectangle();
2410 mpImpl->mpLayouter->DistributeRows(aRectangle, nFirstRow, nLastRow, bOptimize, bMinimize);
2411 setRectangle(aRectangle);
2416 void SdrTableObj::SetChanged()
2418 if( mpImpl.is() )
2420 auto aRectangle = getRectangle();
2421 mpImpl->LayoutTable(aRectangle, false, false);
2422 setRectangle(aRectangle);
2425 ::SdrTextObj::SetChanged();
2429 void SdrTableObj::uno_lock()
2431 if( mpImpl.is() && mpImpl->mxTable.is() )
2432 mpImpl->mxTable->lockBroadcasts();
2436 void SdrTableObj::uno_unlock()
2438 if( mpImpl.is() && mpImpl->mxTable.is() )
2439 mpImpl->mxTable->unlockBroadcasts();
2442 void SdrTableObj::dumpAsXml(xmlTextWriterPtr pWriter) const
2444 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObj"));
2445 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
2447 SdrObject::dumpAsXml(pWriter);
2449 mpImpl->dumpAsXml(pWriter);
2451 (void)xmlTextWriterEndElement(pWriter);
2454 bool SdrTableObj::createTableEdgesJson(boost::property_tree::ptree & rJsonRoot)
2456 if (!mpImpl.is() || !mpImpl->mxTable.is())
2457 return false;
2459 tools::Rectangle aRect = GetCurrentBoundRect();
2460 boost::property_tree::ptree aTableColumns;
2462 aTableColumns.put("tableOffset", o3tl::toTwips(aRect.Left(), o3tl::Length::mm100));
2464 boost::property_tree::ptree aEntries;
2465 auto const aEdges = mpImpl->mpLayouter->getVerticalEdges();
2466 for (auto & rEdge : aEdges)
2468 if (rEdge.nIndex == 0)
2470 aTableColumns.put("left", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2472 else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
2474 aTableColumns.put("right", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2476 else
2478 boost::property_tree::ptree aEntry;
2479 aEntry.put("position", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2480 aEntry.put("min", o3tl::toTwips(rEdge.nPosition + rEdge.nMin, o3tl::Length::mm100));
2481 aEntry.put("max", o3tl::toTwips(rEdge.nPosition + rEdge.nMax, o3tl::Length::mm100));
2482 aEntry.put("hidden", false);
2483 aEntries.push_back(std::make_pair("", aEntry));
2486 aTableColumns.push_back(std::make_pair("entries", aEntries));
2488 rJsonRoot.add_child("columns", aTableColumns);
2490 boost::property_tree::ptree aTableRows;
2492 aTableRows.put("tableOffset", o3tl::toTwips(aRect.Top(), o3tl::Length::mm100));
2494 boost::property_tree::ptree aEntries;
2495 auto const aEdges = mpImpl->mpLayouter->getHorizontalEdges();
2496 for (auto & rEdge : aEdges)
2498 if (rEdge.nIndex == 0)
2500 aTableRows.put("left", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2502 else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
2504 aTableRows.put("right", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2506 else
2508 boost::property_tree::ptree aEntry;
2509 aEntry.put("position", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2510 aEntry.put("min", o3tl::toTwips(rEdge.nPosition + rEdge.nMin, o3tl::Length::mm100));
2511 aEntry.put("max", o3tl::toTwips(rEdge.nPosition + rEdge.nMax, o3tl::Length::mm100));
2512 aEntry.put("hidden", false);
2513 aEntries.push_back(std::make_pair("", aEntry));
2516 aTableRows.push_back(std::make_pair("entries", aEntries));
2518 rJsonRoot.add_child("rows", aTableRows);
2519 return true;
2524 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */