Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / table / svdotable.cxx
blob25ab8715d30738dfed3bda1f81a30ae0b1ee011b
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 <unotools/configmgr.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( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
255 if( xTargetCell.is() )
256 xTargetCell->cloneFrom( dynamic_cast< Cell* >( xOldTable->getCellByPosition( rStart.mnCol + nCol, rStart.mnRow + nRow ).get() ) );
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 const 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 const 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( "table" ), 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 = 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 const OUStringLiteral sSize( u"Size" );
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("table"), UNO_QUERY_THROW);
710 xDefaultStyle.set(xTableFamily->getByName("default"), 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.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
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 (utl::ConfigManager::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;
916 bool SdrTableObj::isValid( const CellPos& rPos ) const
918 return (rPos.mnCol >= 0) && (rPos.mnCol < mpImpl->getColumnCount()) && (rPos.mnRow >= 0) && (rPos.mnRow < mpImpl->getRowCount());
922 CellPos SdrTableObj::getFirstCell()
924 return CellPos( 0,0 );
928 CellPos SdrTableObj::getLastCell() const
930 CellPos aPos;
931 if( mpImpl->mxTable.is() )
933 aPos.mnCol = mpImpl->getColumnCount()-1;
934 aPos.mnRow = mpImpl->getRowCount()-1;
936 return aPos;
940 CellPos SdrTableObj::getLeftCell( const CellPos& rPos, bool bEdgeTravel ) const
942 switch( GetWritingMode() )
944 default:
945 case WritingMode_LR_TB:
946 return getPreviousCell( rPos, bEdgeTravel );
947 case WritingMode_RL_TB:
948 return getNextCell( rPos, bEdgeTravel );
949 case WritingMode_TB_RL:
950 return getPreviousRow( rPos, bEdgeTravel );
955 CellPos SdrTableObj::getRightCell( const CellPos& rPos, bool bEdgeTravel ) const
957 switch( GetWritingMode() )
959 default:
960 case WritingMode_LR_TB:
961 return getNextCell( rPos, bEdgeTravel );
962 case WritingMode_RL_TB:
963 return getPreviousCell( rPos, bEdgeTravel );
964 case WritingMode_TB_RL:
965 return getNextRow( rPos, bEdgeTravel );
970 CellPos SdrTableObj::getUpCell( const CellPos& rPos, bool bEdgeTravel ) const
972 switch( GetWritingMode() )
974 default:
975 case WritingMode_LR_TB:
976 case WritingMode_RL_TB:
977 return getPreviousRow( rPos, bEdgeTravel );
978 case WritingMode_TB_RL:
979 return getPreviousCell( rPos, bEdgeTravel );
984 CellPos SdrTableObj::getDownCell( const CellPos& rPos, bool bEdgeTravel ) const
986 switch( GetWritingMode() )
988 default:
989 case WritingMode_LR_TB:
990 case WritingMode_RL_TB:
991 return getNextRow( rPos, bEdgeTravel );
992 case WritingMode_TB_RL:
993 return getNextCell( rPos, bEdgeTravel );
998 CellPos SdrTableObj::getPreviousCell( const CellPos& rPos, bool bEdgeTravel ) const
1000 CellPos aPos( rPos );
1001 if( mpImpl.is() )
1003 CellRef xCell( mpImpl->getCell( aPos ) );
1004 if( xCell.is() && xCell->isMerged() )
1006 sal_Int32 nTemp = 0;
1007 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, nTemp );
1010 if( aPos.mnCol > 0 )
1012 --aPos.mnCol;
1015 else if( bEdgeTravel && (aPos.mnRow > 0) )
1017 aPos.mnCol = mpImpl->mxTable->getColumnCount()-1;
1018 --aPos.mnRow;
1021 return aPos;
1025 CellPos SdrTableObj::getNextCell( const CellPos& rPos, bool bEdgeTravel ) const
1027 CellPos aPos( rPos );
1028 if( mpImpl.is() )
1030 CellRef xCell( mpImpl->getCell( aPos ) );
1031 if( xCell.is() )
1033 if( xCell->isMerged() )
1035 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
1037 xCell = mpImpl->getCell(aPos);
1039 if( xCell.is() )
1041 aPos.mnCol += xCell->getColumnSpan();
1042 aPos.mnRow = rPos.mnRow;
1045 else
1047 aPos.mnCol += xCell->getColumnSpan();
1050 if( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
1051 return aPos;
1053 if( bEdgeTravel && ((aPos.mnRow + 1) < mpImpl->getRowCount()) )
1055 aPos.mnCol = 0;
1056 aPos.mnRow += 1;
1057 return aPos;
1062 // last cell reached, no traveling possible
1063 return rPos;
1067 CellPos SdrTableObj::getPreviousRow( const CellPos& rPos, bool bEdgeTravel ) const
1069 CellPos aPos( rPos );
1070 if( mpImpl.is() )
1072 CellRef xCell( mpImpl->getCell( aPos ) );
1073 if( xCell.is() && xCell->isMerged() )
1075 sal_Int32 nTemp = 0;
1076 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, nTemp, aPos.mnRow );
1079 if( aPos.mnRow > 0 )
1081 --aPos.mnRow;
1083 else if( bEdgeTravel && (aPos.mnCol > 0) )
1085 aPos.mnRow = mpImpl->mxTable->getRowCount()-1;
1086 --aPos.mnCol;
1089 return aPos;
1093 CellPos SdrTableObj::getNextRow( const CellPos& rPos, bool bEdgeTravel ) const
1095 CellPos aPos( rPos );
1097 if( mpImpl.is() )
1099 CellRef xCell( mpImpl->getCell( rPos ) );
1100 if( xCell.is() )
1102 if( xCell->isMerged() )
1104 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
1105 xCell = mpImpl->getCell(aPos);
1106 aPos.mnCol = rPos.mnCol;
1109 if( xCell.is() )
1110 aPos.mnRow += xCell->getRowSpan();
1112 if( aPos.mnRow < mpImpl->mxTable->getRowCount() )
1113 return aPos;
1115 if( bEdgeTravel && (aPos.mnCol + 1) < mpImpl->mxTable->getColumnCount() )
1117 aPos.mnRow = 0;
1118 aPos.mnCol += 1;
1120 while( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
1122 xCell = mpImpl->getCell( aPos );
1123 if( xCell.is() && !xCell->isMerged() )
1124 return aPos;
1125 aPos.mnCol += 1;
1131 // last position reached, no more traveling possible
1132 return rPos;
1136 const TableStyleSettings& SdrTableObj::getTableStyleSettings() const
1138 if( mpImpl.is())
1140 return mpImpl->maTableStyle;
1142 else
1144 static TableStyleSettings aTmp;
1145 return aTmp;
1150 void SdrTableObj::setTableStyleSettings( const TableStyleSettings& rStyle )
1152 if( mpImpl.is() )
1154 mpImpl->maTableStyle = rStyle;
1155 mpImpl->update();
1160 TableHitKind SdrTableObj::CheckTableHit( const Point& rPos, sal_Int32& rnX, sal_Int32& rnY, const sal_uInt16 aTol ) const
1162 if( !mpImpl.is() || !mpImpl->mxTable.is() )
1163 return TableHitKind::NONE;
1165 rnX = 0;
1166 rnY = 0;
1168 const sal_Int32 nColCount = mpImpl->getColumnCount();
1169 const sal_Int32 nRowCount = mpImpl->getRowCount();
1171 sal_Int32 nX = rPos.X() - getRectangle().Left();
1172 sal_Int32 nY = rPos.Y() - getRectangle().Top();
1174 if( (nX < 0) || (nX > getRectangle().GetWidth()) || (nY < 0) || (nY > getRectangle().GetHeight() ) )
1175 return TableHitKind::NONE;
1177 // get vertical edge number and check for a hit
1178 const bool bRTL = (GetWritingMode() == WritingMode_RL_TB);
1179 bool bVrtHit = false;
1180 if( !bRTL )
1182 while( rnX <= nColCount )
1184 if( nX - aTol <= 0 )
1186 bVrtHit = true;
1187 break;
1190 if( rnX == nColCount )
1191 break;
1193 nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
1194 if( nX < 0 )
1195 break;
1196 rnX++;
1199 else
1201 rnX = nColCount;
1202 while( rnX >= 0 )
1204 if( nX - aTol <= 0 )
1206 bVrtHit = true;
1207 break;
1210 if( rnX == 0 )
1211 break;
1213 rnX--;
1214 nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
1215 if( nX < 0 )
1216 break;
1220 // rnX is now the edge number left to the pointer, if it was hit bHrzHit is also true
1222 // get vertical edge number and check for a hit
1223 bool bHrzHit = false;
1224 while( rnY <= nRowCount )
1226 if( nY - aTol <= 0 )
1228 bHrzHit = true;
1229 break;
1232 if( rnY == nRowCount )
1233 break;
1235 nY -= mpImpl->mpLayouter->getRowHeight(rnY);
1236 if( nY < 0 )
1237 break;
1238 rnY++;
1241 // rnY is now the edge number above the pointer, if it was hit bVrtHit is also true
1243 if( bVrtHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, false ) )
1244 return TableHitKind::VerticallBorder;
1246 if( bHrzHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, true ) )
1247 return TableHitKind::HorizontalBorder;
1249 CellRef xCell( mpImpl->getCell( CellPos( rnX, rnY ) ) );
1250 if( xCell.is() && xCell->isMerged() )
1251 findMergeOrigin( mpImpl->mxTable, rnX, rnY, rnX, rnY );
1253 if( xCell.is() )
1255 nX += mpImpl->mpLayouter->getColumnWidth( rnX );
1256 //Fix for fdo#62673 : non-editable cell in table on cell merge
1257 sal_Int32 i=0;
1258 while(xCell.is() && xCell->isMerged())
1260 nX += mpImpl->mpLayouter->getColumnWidth( rnX+i );
1261 i++;
1262 if(rnX+i < nColCount)
1263 xCell=mpImpl->getCell( CellPos( rnX+i, rnY) );
1264 else
1265 break;
1268 if( nX < xCell->GetTextLeftDistance() )
1269 return TableHitKind::Cell;
1272 return TableHitKind::CellTextArea;
1275 const SfxItemSet& SdrTableObj::GetActiveCellItemSet() const
1277 return getActiveCell()->GetItemSet();
1280 void SdrTableObj::setTableStyle( const Reference< XIndexAccess >& xTableStyle )
1282 if( mpImpl.is() && (mpImpl->mxTableStyle != xTableStyle) )
1284 mpImpl->disconnectTableStyle();
1285 mpImpl->mxTableStyle = xTableStyle;
1286 mpImpl->connectTableStyle();
1287 mpImpl->update();
1292 const Reference< XIndexAccess >& SdrTableObj::getTableStyle() const
1294 if( mpImpl.is() )
1296 return mpImpl->mxTableStyle;
1298 else
1300 static Reference< XIndexAccess > aTmp;
1301 return aTmp;
1306 // text stuff
1309 /** returns the currently active text. */
1310 SdrText* SdrTableObj::getActiveText() const
1312 return getActiveCell().get();
1316 /** returns the nth available text. */
1317 SdrText* SdrTableObj::getText( sal_Int32 nIndex ) const
1319 if( mpImpl->mxTable.is() )
1321 const sal_Int32 nColCount = mpImpl->getColumnCount();
1322 if( nColCount )
1324 CellPos aPos( nIndex % nColCount, nIndex / nColCount );
1326 CellRef xCell( mpImpl->getCell( aPos ) );
1327 return xCell.get();
1330 return nullptr;
1334 /** returns the number of texts available for this object. */
1335 sal_Int32 SdrTableObj::getTextCount() const
1337 if( mpImpl->mxTable.is() )
1339 const sal_Int32 nColCount = mpImpl->getColumnCount();
1340 const sal_Int32 nRowCount = mpImpl->getRowCount();
1342 return nColCount * nRowCount;
1344 else
1346 return 0;
1351 /** changes the current active text */
1352 void SdrTableObj::setActiveText( sal_Int32 nIndex )
1354 if( mpImpl.is() && mpImpl->mxTable.is() )
1356 const sal_Int32 nColCount = mpImpl->mxTable->getColumnCount();
1357 if( nColCount )
1359 CellPos aPos( nIndex % nColCount, nIndex / nColCount );
1360 if( isValid( aPos ) )
1361 setActiveCell( aPos );
1367 /** returns the index of the text that contains the given point or -1 */
1368 sal_Int32 SdrTableObj::CheckTextHit(const Point& rPnt) const
1370 if( mpImpl.is() && mpImpl->mxTable.is() )
1372 CellPos aPos;
1373 if( CheckTableHit( rPnt, aPos.mnCol, aPos.mnRow ) == TableHitKind::CellTextArea )
1374 return aPos.mnRow * mpImpl->mxTable->getColumnCount() + aPos.mnCol;
1377 return 0;
1380 SdrOutliner* SdrTableObj::GetCellTextEditOutliner( const Cell& rCell ) const
1382 if( mpImpl.is() && (mpImpl->getCell( mpImpl->maEditPos ).get() == &rCell) )
1383 return mpEditingOutliner;
1384 else
1385 return nullptr;
1388 const TableLayouter& SdrTableObj::getTableLayouter() const
1390 assert(mpImpl.is() && mpImpl->mpLayouter && "getTableLayouter() error: no mpImpl or mpLayouter (!)");
1391 return *(mpImpl->mpLayouter);
1394 bool SdrTableObj::IsAutoGrowHeight() const
1396 return true;
1399 bool SdrTableObj::IsAutoGrowWidth() const
1401 return true;
1404 bool SdrTableObj::HasText() const
1406 return true;
1409 bool SdrTableObj::IsTextEditActive( const CellPos& rPos )
1411 return mpEditingOutliner && mpImpl.is() && (rPos == mpImpl->maEditPos);
1415 void SdrTableObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus )
1417 if( (pEditStatus->GetStatusWord() & EditStatusFlags::TextHeightChanged) && mpImpl.is() && mpImpl->mpLayouter )
1419 tools::Rectangle aRect0(getRectangle());
1420 setRectangle(maLogicRect);
1421 auto aRectangle = getRectangle();
1422 mpImpl->LayoutTable(aRectangle, false, false);
1423 setRectangle(aRectangle);
1424 SetBoundAndSnapRectsDirty();
1425 ActionChanged();
1426 BroadcastObjectChange();
1427 if (aRect0 != getRectangle())
1428 SendUserCall(SdrUserCallType::Resize,aRect0);
1433 void SdrTableObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
1435 rInfo.bResizeFreeAllowed=true;
1436 rInfo.bResizePropAllowed=true;
1437 rInfo.bRotateFreeAllowed=false;
1438 rInfo.bRotate90Allowed =false;
1439 rInfo.bMirrorFreeAllowed=false;
1440 rInfo.bMirror45Allowed =false;
1441 rInfo.bMirror90Allowed =false;
1443 // allow transparence
1444 rInfo.bTransparenceAllowed = true;
1446 rInfo.bShearAllowed =false;
1447 rInfo.bEdgeRadiusAllowed=false;
1448 rInfo.bCanConvToPath =false;
1449 rInfo.bCanConvToPoly =false;
1450 rInfo.bCanConvToPathLineToArea=false;
1451 rInfo.bCanConvToPolyLineToArea=false;
1452 rInfo.bCanConvToContour = false;
1455 SdrObjKind SdrTableObj::GetObjIdentifier() const
1457 return SdrObjKind::Table;
1460 void SdrTableObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect, bool /*bLineWidth*/ ) const
1462 if( mpImpl.is() )
1463 TakeTextRect( mpImpl->maEditPos, rOutliner, rTextRect, bNoEditText, pAnchorRect );
1467 void SdrTableObj::TakeTextRect( const CellPos& rPos, SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect ) const
1469 if( !mpImpl.is())
1470 return;
1472 CellRef xCell( mpImpl->getCell( rPos ) );
1473 if( !xCell.is() )
1474 return;
1476 tools::Rectangle aAnkRect;
1477 TakeTextAnchorRect( rPos, aAnkRect );
1479 SdrTextVertAdjust eVAdj=xCell->GetTextVerticalAdjust();
1481 EEControlBits nStat0=rOutliner.GetControlWord();
1482 nStat0 |= EEControlBits::AUTOPAGESIZE;
1483 rOutliner.SetControlWord(nStat0);
1484 rOutliner.SetMinAutoPaperSize(Size());
1485 rOutliner.SetMaxAutoPaperSize(aAnkRect.GetSize());
1486 rOutliner.SetPaperSize(aAnkRect.GetSize());
1488 // #103516# New try with _BLOCK for hor and ver after completely
1489 // supporting full width for vertical text.
1490 // if( SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
1491 // {
1492 rOutliner.SetMinAutoPaperSize(Size(aAnkRect.GetWidth(), 0));
1493 // }
1494 // else if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
1495 // {
1496 // rOutliner.SetMinAutoPaperSize(Size(0, aAnkRect.GetHeight()));
1497 // }
1500 // set text at outliner, maybe from edit outliner
1501 std::optional<OutlinerParaObject> pPara;
1502 if (xCell->GetOutlinerParaObject())
1503 pPara = *xCell->GetOutlinerParaObject();
1504 if (mpEditingOutliner && !bNoEditText && mpImpl->mxActiveCell == xCell )
1505 pPara = mpEditingOutliner->CreateParaObject();
1507 if (pPara)
1509 const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
1510 const SdrTextObj* pTestObj(rOutliner.GetTextObj());
1512 if( !pTestObj || !bHitTest || (pTestObj != this) || (pTestObj->GetOutlinerParaObject() != xCell->GetOutlinerParaObject()) )
1514 if( bHitTest ) // #i33696# take back fix #i27510#
1515 rOutliner.SetTextObj( this );
1517 rOutliner.SetUpdateLayout(true);
1518 rOutliner.SetText(*pPara);
1521 else
1523 rOutliner.SetTextObj( nullptr );
1526 rOutliner.SetUpdateLayout(true);
1527 rOutliner.SetControlWord(nStat0);
1529 Point aTextPos(aAnkRect.TopLeft());
1530 Size aTextSiz(rOutliner.GetPaperSize());
1531 if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1533 tools::Long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
1534 if (eVAdj==SDRTEXTVERTADJUST_CENTER)
1535 aTextPos.AdjustY(nFreeHgt/2 );
1536 if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1537 aTextPos.AdjustY(nFreeHgt );
1540 if (pAnchorRect)
1541 *pAnchorRect=aAnkRect;
1543 rTextRect=tools::Rectangle(aTextPos,aTextSiz);
1546 const CellRef& SdrTableObj::getActiveCell() const
1548 if( mpImpl.is() )
1550 if( !mpImpl->mxActiveCell.is() )
1552 CellPos aPos;
1553 const_cast< SdrTableObj* >(this)->setActiveCell( aPos );
1555 return mpImpl->mxActiveCell;
1557 else
1559 static CellRef xCell;
1560 return xCell;
1565 sal_Int32 SdrTableObj::getColumnCount() const
1567 return mpImpl.is() ? mpImpl->getColumnCount() : 0;
1570 sal_Int32 SdrTableObj::getRowCount() const
1572 return mpImpl.is() ? mpImpl->getRowCount() : 0;
1575 void SdrTableObj::changeEdge(bool bHorizontal, int nEdge, sal_Int32 nOffset)
1577 if (mpImpl.is())
1578 mpImpl->DragEdge(bHorizontal, nEdge, nOffset);
1581 void SdrTableObj::setActiveCell( const CellPos& rPos )
1583 if( !(mpImpl.is() && mpImpl->mxTable.is()) )
1584 return;
1588 mpImpl->mxActiveCell.set( dynamic_cast< Cell* >( mpImpl->mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
1589 if( mpImpl->mxActiveCell.is() && mpImpl->mxActiveCell->isMerged() )
1591 CellPos aOrigin;
1592 findMergeOrigin( mpImpl->mxTable, rPos.mnCol, rPos.mnRow, aOrigin.mnCol, aOrigin.mnRow );
1593 mpImpl->mxActiveCell.set( dynamic_cast< Cell* >( mpImpl->mxTable->getCellByPosition( aOrigin.mnCol, aOrigin.mnRow ).get() ) );
1594 mpImpl->maEditPos = aOrigin;
1596 else
1598 mpImpl->maEditPos = rPos;
1601 catch( Exception& )
1603 TOOLS_WARN_EXCEPTION("svx.table", "");
1608 void SdrTableObj::getActiveCellPos( CellPos& rPos ) const
1610 rPos = mpImpl->maEditPos;
1614 void SdrTableObj::getCellBounds( const CellPos& rPos, ::tools::Rectangle& rCellRect )
1616 if( mpImpl.is() )
1618 CellRef xCell( mpImpl->getCell( rPos ) );
1619 if( xCell.is() )
1620 rCellRect = xCell->getCellRect();
1625 void SdrTableObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
1627 if( mpImpl.is() )
1628 TakeTextAnchorRect( mpImpl->maEditPos, rAnchorRect );
1632 void SdrTableObj::TakeTextAnchorRect( const CellPos& rPos, tools::Rectangle& rAnchorRect ) const
1634 tools::Rectangle aAnkRect(getRectangle());
1636 if( mpImpl.is() )
1638 CellRef xCell( mpImpl->getCell( rPos ) );
1639 if( xCell.is() )
1640 xCell->TakeTextAnchorRect( aAnkRect );
1643 ImpJustifyRect(aAnkRect);
1644 rAnchorRect=aAnkRect;
1648 void SdrTableObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
1650 if( mpImpl.is() )
1651 TakeTextEditArea( mpImpl->maEditPos, pPaperMin, pPaperMax, pViewInit, pViewMin );
1655 void SdrTableObj::TakeTextEditArea( const CellPos& rPos, Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin ) const
1657 Size aPaperMin,aPaperMax;
1658 tools::Rectangle aViewInit;
1659 TakeTextAnchorRect( rPos, aViewInit );
1661 Size aAnkSiz(aViewInit.GetSize());
1662 aAnkSiz.AdjustWidth( -1 ); aAnkSiz.AdjustHeight( -1 ); // because GetSize() increments by one
1664 Size aMaxSiz(aAnkSiz.Width(),1000000);
1665 Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
1666 if (aTmpSiz.Height()!=0)
1667 aMaxSiz.setHeight(aTmpSiz.Height() );
1669 CellRef xCell( mpImpl->getCell( rPos ) );
1670 SdrTextVertAdjust eVAdj = xCell.is() ? xCell->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_TOP;
1672 aPaperMax=aMaxSiz;
1674 aPaperMin.setWidth( aAnkSiz.Width() );
1676 if (pViewMin!=nullptr)
1678 *pViewMin=aViewInit;
1679 tools::Long nYFree=aAnkSiz.Height()-aPaperMin.Height();
1681 if (eVAdj==SDRTEXTVERTADJUST_TOP)
1683 pViewMin->AdjustBottom( -nYFree );
1685 else if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1687 pViewMin->AdjustTop(nYFree );
1689 else
1691 pViewMin->AdjustTop(nYFree/2 );
1692 pViewMin->SetBottom(pViewMin->Top()+aPaperMin.Height() );
1697 if(IsVerticalWriting())
1698 aPaperMin.setWidth( 0 );
1699 else
1700 aPaperMin.setHeight( 0 );
1702 if (pPaperMin!=nullptr) *pPaperMin=aPaperMin;
1703 if (pPaperMax!=nullptr) *pPaperMax=aPaperMax;
1704 if (pViewInit!=nullptr) *pViewInit=aViewInit;
1708 EEAnchorMode SdrTableObj::GetOutlinerViewAnchorMode() const
1710 EEAnchorMode eRet=EEAnchorMode::TopLeft;
1711 CellRef xCell( getActiveCell() );
1712 if( xCell.is() )
1714 SdrTextVertAdjust eV=xCell->GetTextVerticalAdjust();
1717 if (eV==SDRTEXTVERTADJUST_TOP)
1719 eRet=EEAnchorMode::TopLeft;
1721 else if (eV==SDRTEXTVERTADJUST_BOTTOM)
1723 eRet=EEAnchorMode::BottomLeft;
1725 else
1727 eRet=EEAnchorMode::VCenterLeft;
1731 return eRet;
1735 OUString SdrTableObj::TakeObjNameSingul() const
1737 OUString sName(SvxResId(STR_ObjNameSingulTable));
1739 OUString aName(GetName());
1740 if (!aName.isEmpty())
1741 sName += " '" + aName + "'";
1743 return sName;
1747 OUString SdrTableObj::TakeObjNamePlural() const
1749 return SvxResId(STR_ObjNamePluralTable);
1753 rtl::Reference<SdrObject> SdrTableObj::CloneSdrObject(SdrModel& rTargetModel) const
1755 return new SdrTableObj(rTargetModel, *this);
1759 const tools::Rectangle& SdrTableObj::GetSnapRect() const
1761 return getRectangle();
1765 void SdrTableObj::NbcSetSnapRect(const tools::Rectangle& rRect)
1767 NbcSetLogicRect( rRect );
1771 const tools::Rectangle& SdrTableObj::GetLogicRect() const
1773 return maLogicRect;
1777 void SdrTableObj::RecalcSnapRect()
1782 bool SdrTableObj::BegTextEdit(SdrOutliner& rOutl)
1784 if( mpEditingOutliner != nullptr )
1785 return false;
1787 mpEditingOutliner=&rOutl;
1789 mbInEditMode = true;
1791 rOutl.Init( OutlinerMode::TextObject );
1792 rOutl.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());
1794 bool bUpdateMode = rOutl.SetUpdateLayout(false);
1795 Size aPaperMin;
1796 Size aPaperMax;
1797 tools::Rectangle aEditArea;
1798 TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,nullptr);
1800 rOutl.SetMinAutoPaperSize(aPaperMin);
1801 rOutl.SetMaxAutoPaperSize(aPaperMax);
1802 rOutl.SetPaperSize(aPaperMax);
1804 if (bUpdateMode) rOutl.SetUpdateLayout(true);
1806 EEControlBits nStat=rOutl.GetControlWord();
1807 nStat |= EEControlBits::AUTOPAGESIZE;
1808 nStat &=~EEControlBits::STRETCHING;
1809 rOutl.SetControlWord(nStat);
1811 OutlinerParaObject* pPara = GetOutlinerParaObject();
1812 if(pPara)
1813 rOutl.SetText(*pPara);
1815 rOutl.UpdateFields();
1816 rOutl.ClearModifyFlag();
1818 return true;
1822 void SdrTableObj::EndTextEdit(SdrOutliner& rOutl)
1825 if (getSdrModelFromSdrObject().IsUndoEnabled() && !mpImpl->maUndos.empty())
1827 // These actions should be on the undo stack after text edit.
1828 for (std::unique_ptr<SdrUndoAction>& pAction : mpImpl->maUndos)
1829 getSdrModelFromSdrObject().AddUndo( std::move(pAction));
1830 mpImpl->maUndos.clear();
1832 getSdrModelFromSdrObject().AddUndo(getSdrModelFromSdrObject().GetSdrUndoFactory().CreateUndoGeoObject(*this));
1835 if(rOutl.IsModified())
1837 std::optional<OutlinerParaObject> pNewText;
1838 Paragraph* p1stPara = rOutl.GetParagraph( 0 );
1839 sal_Int32 nParaCnt = rOutl.GetParagraphCount();
1841 if(p1stPara)
1843 // to remove the grey field background
1844 rOutl.UpdateFields();
1846 // create new text object
1847 pNewText = rOutl.CreateParaObject( 0, nParaCnt );
1849 SetOutlinerParaObject(std::move(pNewText));
1852 mpEditingOutliner = nullptr;
1853 rOutl.Clear();
1854 EEControlBits nStat = rOutl.GetControlWord();
1855 nStat &= ~EEControlBits::AUTOPAGESIZE;
1856 rOutl.SetControlWord(nStat);
1858 mbInEditMode = false;
1862 OutlinerParaObject* SdrTableObj::GetOutlinerParaObject() const
1864 CellRef xCell( getActiveCell() );
1865 if( xCell.is() )
1866 return xCell->GetOutlinerParaObject();
1867 else
1868 return nullptr;
1872 void SdrTableObj::NbcSetOutlinerParaObject( std::optional<OutlinerParaObject> pTextObject)
1874 CellRef xCell( getActiveCell() );
1875 if( !xCell.is() )
1876 return;
1878 // Update HitTestOutliner
1879 const SdrTextObj* pTestObj(getSdrModelFromSdrObject().GetHitTestOutliner().GetTextObj());
1881 if(pTestObj && pTestObj->GetOutlinerParaObject() == xCell->GetOutlinerParaObject())
1883 getSdrModelFromSdrObject().GetHitTestOutliner().SetTextObj(nullptr);
1886 xCell->SetOutlinerParaObject( std::move(pTextObject) );
1887 SetTextSizeDirty();
1888 NbcAdjustTextFrameWidthAndHeight();
1892 void SdrTableObj::NbcSetLogicRect(const tools::Rectangle& rRect)
1894 maLogicRect=rRect;
1895 ImpJustifyRect(maLogicRect);
1896 const bool bWidth = maLogicRect.getOpenWidth() != getRectangle().getOpenWidth();
1897 const bool bHeight = maLogicRect.getOpenHeight() != getRectangle().getOpenHeight();
1898 setRectangle(maLogicRect);
1899 if (mpImpl->mbSkipChangeLayout)
1900 // Avoid distributing newly available space between existing cells.
1901 NbcAdjustTextFrameWidthAndHeight();
1902 else
1903 NbcAdjustTextFrameWidthAndHeight(!bHeight, !bWidth);
1904 SetBoundAndSnapRectsDirty();
1908 void SdrTableObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
1910 tools::Rectangle aAdjustRect( rMaxRect );
1911 aAdjustRect.setHeight( GetLogicRect().getOpenHeight() );
1912 SetLogicRect( aAdjustRect );
1916 void SdrTableObj::NbcMove(const Size& rSiz)
1918 maLogicRect.Move(rSiz);
1919 SdrTextObj::NbcMove( rSiz );
1920 if( mpImpl.is() )
1921 mpImpl->UpdateCells(getRectangle());
1925 void SdrTableObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1927 tools::Rectangle aOldRect( maLogicRect );
1928 ResizeRect(maLogicRect,rRef,xFact,yFact);
1930 setRectangle(maLogicRect);
1931 NbcAdjustTextFrameWidthAndHeight( maLogicRect.GetHeight() == aOldRect.GetHeight(), maLogicRect.GetWidth() == aOldRect.GetWidth() );
1932 SetBoundAndSnapRectsDirty();
1936 bool SdrTableObj::AdjustTextFrameWidthAndHeight()
1938 tools::Rectangle aNewRect(maLogicRect);
1939 bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
1940 if (bRet)
1942 tools::Rectangle aBoundRect0;
1943 if (m_pUserCall!=nullptr)
1944 aBoundRect0=GetLastBoundRect();
1945 setRectangle(aNewRect);
1946 SetBoundAndSnapRectsDirty();
1947 SetChanged();
1948 BroadcastObjectChange();
1949 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1951 return bRet;
1955 bool SdrTableObj::AdjustTextFrameWidthAndHeight(tools::Rectangle& rR, bool bHeight, bool bWidth) const
1957 if(rR.IsEmpty() || !mpImpl.is() || !mpImpl->mxTable.is())
1958 return false;
1960 tools::Rectangle aRectangle( rR );
1961 mpImpl->LayoutTable( aRectangle, !bWidth, !bHeight );
1963 if( aRectangle != rR )
1965 rR = aRectangle;
1966 return true;
1968 else
1970 return false;
1975 void SdrTableObj::NbcReformatText()
1977 NbcAdjustTextFrameWidthAndHeight();
1981 bool SdrTableObj::IsVerticalWriting() const
1983 const SvxWritingModeItem& rModeItem = GetObjectItem( SDRATTR_TEXTDIRECTION );
1984 return rModeItem.GetValue() == css::text::WritingMode_TB_RL;
1988 void SdrTableObj::SetVerticalWriting(bool bVertical)
1990 if(bVertical != IsVerticalWriting() )
1992 SvxWritingModeItem aModeItem( css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION );
1993 SetObjectItem( aModeItem );
1998 WritingMode SdrTableObj::GetWritingMode() const
2000 SfxStyleSheet* pStyle = GetStyleSheet();
2001 if ( !pStyle )
2002 return WritingMode_LR_TB;
2004 WritingMode eWritingMode = WritingMode_LR_TB;
2005 const SfxItemSet &rSet = pStyle->GetItemSet();
2007 if ( const SvxWritingModeItem *pItem = rSet.GetItemIfSet( SDRATTR_TEXTDIRECTION ))
2008 eWritingMode = pItem->GetValue();
2010 if ( const SvxFrameDirectionItem *pItem;
2011 ( eWritingMode != WritingMode_TB_RL ) &&
2012 ( pItem = rSet.GetItemIfSet( EE_PARA_WRITINGDIR, false ) ) )
2014 if ( pItem->GetValue() == SvxFrameDirection::Horizontal_LR_TB )
2015 eWritingMode = WritingMode_LR_TB;
2016 else
2017 eWritingMode = WritingMode_RL_TB;
2020 return eWritingMode;
2023 void SdrTableObj::AddUndo(SdrUndoAction* pUndo)
2025 mpImpl->maUndos.push_back(std::unique_ptr<SdrUndoAction>(pUndo));
2028 void SdrTableObj::SetSkipChangeLayout(bool bSkipChangeLayout)
2030 mpImpl->mbSkipChangeLayout = bSkipChangeLayout;
2033 bool SdrTableObj::IsReallyEdited() const
2035 return mpEditingOutliner && mpEditingOutliner->IsModified();
2038 bool SdrTableObj::IsFontwork() const
2040 return false;
2043 sal_uInt32 SdrTableObj::GetHdlCount() const
2045 sal_uInt32 nCount = SdrTextObj::GetHdlCount();
2046 const sal_Int32 nRowCount = mpImpl->getRowCount();
2047 const sal_Int32 nColCount = mpImpl->getColumnCount();
2049 if( nRowCount && nColCount )
2050 nCount += nRowCount + nColCount + 2 + 1;
2052 return nCount;
2055 void SdrTableObj::AddToHdlList(SdrHdlList& rHdlList) const
2057 const sal_Int32 nRowCount = mpImpl->getRowCount();
2058 const sal_Int32 nColCount = mpImpl->getColumnCount();
2060 // first add row handles
2061 std::vector<TableEdgeHdl*> aRowEdges(nRowCount + 1);
2062 for (auto const & rEdge : mpImpl->mpLayouter->getHorizontalEdges())
2064 Point aPoint(getRectangle().TopLeft());
2065 aPoint.AdjustY(rEdge.nPosition);
2067 std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, true, rEdge.nMin, rEdge.nMax, nColCount + 1));
2068 pHdl->SetPointNum(rEdge.nIndex);
2069 aRowEdges[rEdge.nIndex] = pHdl.get();
2070 rHdlList.AddHdl(std::move(pHdl));
2073 // second add column handles
2074 std::vector<TableEdgeHdl*> aColEdges(nColCount + 1);
2075 for (auto const & rEdge : mpImpl->mpLayouter->getVerticalEdges())
2077 Point aPoint(getRectangle().TopLeft());
2078 aPoint.AdjustX(rEdge.nPosition);
2080 std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, false, rEdge.nMin, rEdge.nMax, nRowCount + 1));
2081 pHdl->SetPointNum(rEdge.nIndex);
2082 aColEdges[rEdge.nIndex] = pHdl.get();
2083 rHdlList.AddHdl(std::move(pHdl));
2086 // now add visible edges to row and column handles
2087 if( mpImpl->mpLayouter )
2089 TableLayouter& rLayouter = *mpImpl->mpLayouter;
2091 sal_Int32 nY = 0;
2093 for( sal_Int32 nRow = 0; nRow <= nRowCount; ++nRow )
2095 const sal_Int32 nRowHeight = (nRow == nRowCount) ? 0 : rLayouter.getRowHeight(nRow);
2096 sal_Int32 nX = 0;
2098 for( sal_Int32 nCol = 0; nCol <= nColCount; ++nCol )
2100 const sal_Int32 nColWidth = (nCol == nColCount) ? 0 : rLayouter.getColumnWidth(nCol);
2102 if( nRowHeight > 0 )
2104 if( rLayouter.isEdgeVisible( nCol, nRow, false ) )
2105 aColEdges[nCol]->SetEdge( nRow, nY, nY + nRowHeight, (rLayouter.getBorderLine( nCol, nRow, false ) == nullptr) ? Visible : Invisible);
2108 if( nColWidth > 0 )
2110 if( rLayouter.isEdgeVisible( nCol, nRow, true ) )
2111 aRowEdges[nRow]->SetEdge( nCol, nX, nX + nColWidth, (rLayouter.getBorderLine( nCol, nRow, true ) == nullptr) ? Visible : Invisible);
2114 nX += nColWidth;
2117 nY += nRowHeight;
2121 // add remaining handles
2122 SdrHdlList tempList(nullptr);
2123 auto aRectangle = getRectangle();
2124 tempList.AddHdl( std::make_unique<TableBorderHdl>(aRectangle, !IsTextEditActive() ) );
2125 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopLeft(),SdrHdlKind::UpperLeft) );
2126 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopCenter(),SdrHdlKind::Upper) );
2127 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.TopRight(),SdrHdlKind::UpperRight) );
2128 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.LeftCenter(),SdrHdlKind::Left) );
2129 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.RightCenter(),SdrHdlKind::Right) );
2130 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomLeft(),SdrHdlKind::LowerLeft) );
2131 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomCenter(),SdrHdlKind::Lower) );
2132 tempList.AddHdl( std::make_unique<SdrHdl>(aRectangle.BottomRight(),SdrHdlKind::LowerRight) );
2133 for( size_t nHdl = 0; nHdl < tempList.GetHdlCount(); ++nHdl )
2134 tempList.GetHdl(nHdl)->SetMoveOutside(true);
2135 tempList.MoveTo(rHdlList);
2137 const size_t nHdlCount = rHdlList.GetHdlCount();
2138 for( size_t nHdl = 0; nHdl < nHdlCount; ++nHdl )
2139 rHdlList.GetHdl(nHdl)->SetObj(const_cast<SdrTableObj*>(this));
2142 // Dragging
2144 bool SdrTableObj::hasSpecialDrag() const
2146 return true;
2149 bool SdrTableObj::beginSpecialDrag(SdrDragStat& rDrag) const
2151 const SdrHdl* pHdl = rDrag.GetHdl();
2152 const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2154 switch( eHdl )
2156 case SdrHdlKind::UpperLeft:
2157 case SdrHdlKind::Upper:
2158 case SdrHdlKind::UpperRight:
2159 case SdrHdlKind::Left:
2160 case SdrHdlKind::Right:
2161 case SdrHdlKind::LowerLeft:
2162 case SdrHdlKind::Lower:
2163 case SdrHdlKind::LowerRight:
2164 case SdrHdlKind::Move:
2166 break;
2169 case SdrHdlKind::User:
2171 rDrag.SetEndDragChangesAttributes(false);
2172 rDrag.SetNoSnap();
2173 break;
2176 default:
2178 return false;
2182 return true;
2185 bool SdrTableObj::applySpecialDrag(SdrDragStat& rDrag)
2187 bool bRet(true);
2188 const SdrHdl* pHdl = rDrag.GetHdl();
2189 const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2191 switch( eHdl )
2193 case SdrHdlKind::UpperLeft:
2194 case SdrHdlKind::Upper:
2195 case SdrHdlKind::UpperRight:
2196 case SdrHdlKind::Left:
2197 case SdrHdlKind::Right:
2198 case SdrHdlKind::LowerLeft:
2199 case SdrHdlKind::Lower:
2200 case SdrHdlKind::LowerRight:
2202 const tools::Rectangle aNewRectangle(ImpDragCalcRect(rDrag));
2204 if (aNewRectangle != getRectangle())
2206 NbcSetLogicRect(aNewRectangle);
2209 break;
2212 case SdrHdlKind::Move:
2214 NbcMove( Size( rDrag.GetDX(), rDrag.GetDY() ) );
2215 break;
2218 case SdrHdlKind::User:
2220 rDrag.SetEndDragChangesAttributes(false);
2221 rDrag.SetNoSnap();
2222 const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
2224 if( pEdgeHdl )
2226 if( IsInserted() )
2228 rDrag.SetEndDragChangesAttributes(true);
2229 rDrag.SetEndDragChangesLayout(true);
2232 mpImpl->DragEdge( pEdgeHdl->IsHorizontalEdge(), pEdgeHdl->GetPointNum(), pEdgeHdl->GetValidDragOffset( rDrag ) );
2234 break;
2237 default:
2239 bRet = false;
2243 return bRet;
2246 basegfx::B2DPolyPolygon SdrTableObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
2248 basegfx::B2DPolyPolygon aRetval;
2249 const SdrHdl* pHdl = rDrag.GetHdl();
2251 if( pHdl && (SdrHdlKind::User == pHdl->GetKind()) )
2253 const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
2255 if( pEdgeHdl )
2257 aRetval = pEdgeHdl->getSpecialDragPoly( rDrag );
2261 return aRetval;
2265 // Create
2268 bool SdrTableObj::BegCreate(SdrDragStat& rStat)
2270 rStat.SetOrtho4Possible();
2271 tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
2272 aRect1.Normalize();
2273 rStat.SetActionRect(aRect1);
2274 setRectangle(aRect1);
2275 return true;
2279 bool SdrTableObj::MovCreate(SdrDragStat& rStat)
2281 tools::Rectangle aRect1;
2282 rStat.TakeCreateRect(aRect1);
2283 ImpJustifyRect(aRect1);
2284 rStat.SetActionRect(aRect1);
2285 setRectangle(aRect1); // for ObjName
2286 SetBoundRectDirty();
2287 m_bSnapRectDirty=true;
2288 return true;
2292 bool SdrTableObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
2294 auto aRectangle = getRectangle();
2295 rStat.TakeCreateRect(aRectangle);
2296 ImpJustifyRect(aRectangle);
2297 setRectangle(aRectangle);
2298 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
2301 void SdrTableObj::BrkCreate(SdrDragStat& /*rStat*/)
2306 bool SdrTableObj::BckCreate(SdrDragStat& /*rStat*/)
2308 return true;
2312 basegfx::B2DPolyPolygon SdrTableObj::TakeCreatePoly(const SdrDragStat& rDrag) const
2314 tools::Rectangle aRect1;
2315 rDrag.TakeCreateRect(aRect1);
2316 aRect1.Normalize();
2318 basegfx::B2DPolyPolygon aRetval;
2319 const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aRect1);
2320 aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
2321 return aRetval;
2325 PointerStyle SdrTableObj::GetCreatePointer() const
2327 return PointerStyle::Cross;
2331 void SdrTableObj::createCell( CellRef& xNewCell )
2333 xNewCell = Cell::create( *this );
2337 std::unique_ptr<SdrObjGeoData> SdrTableObj::NewGeoData() const
2339 return std::make_unique<TableObjectGeoData>();
2343 void SdrTableObj::SaveGeoData(SdrObjGeoData& rGeo) const
2345 DBG_ASSERT( dynamic_cast< TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" );
2346 SdrTextObj::SaveGeoData (rGeo);
2348 static_cast<TableObjectGeoData &>(rGeo).maLogicRect = maLogicRect;
2352 void SdrTableObj::RestoreGeoData(const SdrObjGeoData& rGeo)
2354 DBG_ASSERT( dynamic_cast< const TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::RestoreGeoData(), illegal geo data!" );
2356 maLogicRect = static_cast<const TableObjectGeoData &>(rGeo).maLogicRect;
2358 SdrTextObj::RestoreGeoData (rGeo);
2360 if( mpImpl.is() )
2362 auto aRectangle = getRectangle();
2363 mpImpl->LayoutTable(aRectangle, false, false);
2364 setRectangle(aRectangle);
2366 ActionChanged();
2369 void SdrTableObj::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
2371 if(!mpImpl.is())
2373 return;
2376 mpImpl->CropTableModelToSelection(rStart, rEnd);
2379 void SdrTableObj::LayoutTableHeight(tools::Rectangle& rArea, bool bFit)
2381 if( mpImpl.is() && mpImpl->mpLayouter)
2383 mpImpl->mpLayouter->LayoutTableHeight(rArea, bFit);
2387 void SdrTableObj::DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn, const bool bOptimize, const bool bMinimize )
2389 if( mpImpl.is() && mpImpl->mpLayouter )
2391 TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
2392 auto aRectangle = getRectangle();
2393 mpImpl->mpLayouter->DistributeColumns(aRectangle, nFirstColumn, nLastColumn, bOptimize, bMinimize);
2394 setRectangle(aRectangle);
2399 void SdrTableObj::DistributeRows( sal_Int32 nFirstRow, sal_Int32 nLastRow, const bool bOptimize, const bool bMinimize )
2401 if( mpImpl.is() && mpImpl->mpLayouter )
2403 TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
2404 auto aRectangle = getRectangle();
2405 mpImpl->mpLayouter->DistributeRows(aRectangle, nFirstRow, nLastRow, bOptimize, bMinimize);
2406 setRectangle(aRectangle);
2411 void SdrTableObj::SetChanged()
2413 if( mpImpl.is() )
2415 auto aRectangle = getRectangle();
2416 mpImpl->LayoutTable(aRectangle, false, false);
2417 setRectangle(aRectangle);
2420 ::SdrTextObj::SetChanged();
2424 void SdrTableObj::uno_lock()
2426 if( mpImpl.is() && mpImpl->mxTable.is() )
2427 mpImpl->mxTable->lockBroadcasts();
2431 void SdrTableObj::uno_unlock()
2433 if( mpImpl.is() && mpImpl->mxTable.is() )
2434 mpImpl->mxTable->unlockBroadcasts();
2437 void SdrTableObj::dumpAsXml(xmlTextWriterPtr pWriter) const
2439 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObj"));
2440 (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
2442 SdrObject::dumpAsXml(pWriter);
2444 mpImpl->dumpAsXml(pWriter);
2446 (void)xmlTextWriterEndElement(pWriter);
2449 bool SdrTableObj::createTableEdgesJson(boost::property_tree::ptree & rJsonRoot)
2451 if (!mpImpl.is() || !mpImpl->mxTable.is())
2452 return false;
2454 tools::Rectangle aRect = GetCurrentBoundRect();
2455 boost::property_tree::ptree aTableColumns;
2457 aTableColumns.put("tableOffset", o3tl::toTwips(aRect.Left(), o3tl::Length::mm100));
2459 boost::property_tree::ptree aEntries;
2460 auto const & aEdges = mpImpl->mpLayouter->getVerticalEdges();
2461 for (auto & rEdge : aEdges)
2463 if (rEdge.nIndex == 0)
2465 aTableColumns.put("left", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2467 else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
2469 aTableColumns.put("right", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2471 else
2473 boost::property_tree::ptree aEntry;
2474 aEntry.put("position", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2475 aEntry.put("min", o3tl::toTwips(rEdge.nPosition + rEdge.nMin, o3tl::Length::mm100));
2476 aEntry.put("max", o3tl::toTwips(rEdge.nPosition + rEdge.nMax, o3tl::Length::mm100));
2477 aEntry.put("hidden", false);
2478 aEntries.push_back(std::make_pair("", aEntry));
2481 aTableColumns.push_back(std::make_pair("entries", aEntries));
2483 rJsonRoot.add_child("columns", aTableColumns);
2485 boost::property_tree::ptree aTableRows;
2487 aTableRows.put("tableOffset", o3tl::toTwips(aRect.Top(), o3tl::Length::mm100));
2489 boost::property_tree::ptree aEntries;
2490 auto const & aEdges = mpImpl->mpLayouter->getHorizontalEdges();
2491 for (auto & rEdge : aEdges)
2493 if (rEdge.nIndex == 0)
2495 aTableRows.put("left", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2497 else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
2499 aTableRows.put("right", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2501 else
2503 boost::property_tree::ptree aEntry;
2504 aEntry.put("position", o3tl::toTwips(rEdge.nPosition, o3tl::Length::mm100));
2505 aEntry.put("min", o3tl::toTwips(rEdge.nPosition + rEdge.nMin, o3tl::Length::mm100));
2506 aEntry.put("max", o3tl::toTwips(rEdge.nPosition + rEdge.nMax, o3tl::Length::mm100));
2507 aEntry.put("hidden", false);
2508 aEntries.push_back(std::make_pair("", aEntry));
2511 aTableRows.push_back(std::make_pair("entries", aEntries));
2513 rJsonRoot.add_child("rows", aTableRows);
2514 return true;
2519 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */