Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / table / svdotable.cxx
blob53e6133ac6dee7588c4f6da804dcb1492323a989
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 <cppuhelper/implbase.hxx>
54 #include <libxml/xmlwriter.h>
55 #include <rtl/ustrbuf.hxx>
56 #include <tools/diagnose_ex.h>
57 #include <tools/UnitConversion.hxx>
59 #include <boost/property_tree/ptree.hpp>
61 using ::com::sun::star::uno::Any;
62 using ::com::sun::star::uno::Reference;
63 using ::com::sun::star::uno::UNO_QUERY;
64 using ::com::sun::star::uno::UNO_QUERY_THROW;
65 using ::com::sun::star::uno::Exception;
66 using ::com::sun::star::container::XIndexAccess;
67 using ::com::sun::star::style::XStyle;
68 using ::com::sun::star::table::XTableRows;
69 using ::com::sun::star::table::XTableColumns;
70 using ::com::sun::star::table::XTable;
71 using ::com::sun::star::beans::XPropertySet;
72 using ::com::sun::star::util::XModifyBroadcaster;
73 using sdr::properties::TextProperties;
74 using sdr::properties::BaseProperties;
75 using namespace ::com::sun::star;
76 using namespace ::com::sun::star::text;
77 using namespace ::com::sun::star::container;
78 using namespace ::com::sun::star::style;
80 namespace sdr::table {
82 namespace {
84 class TableProperties : public TextProperties
86 protected:
87 // create a new itemset
88 std::unique_ptr<SfxItemSet> CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
90 public:
91 // basic constructor
92 explicit TableProperties(SdrObject& rObj );
94 // constructor for copying, but using new object
95 TableProperties(const TableProperties& rProps, SdrObject& rObj );
97 // Clone() operator, normally just calls the local copy constructor
98 std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
100 virtual void ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem = nullptr) override;
105 TableProperties::TableProperties(SdrObject& rObj)
106 : TextProperties(rObj)
110 TableProperties::TableProperties(const TableProperties& rProps, SdrObject& rObj)
111 : TextProperties(rProps, rObj)
115 std::unique_ptr<BaseProperties> TableProperties::Clone(SdrObject& rObj) const
117 return std::unique_ptr<BaseProperties>(new TableProperties(*this, rObj));
120 void TableProperties::ItemChange(const sal_uInt16 nWhich, const SfxPoolItem* pNewItem)
122 if( nWhich == SDRATTR_TEXTDIRECTION )
123 AttributeProperties::ItemChange( nWhich, pNewItem );
124 else
125 TextProperties::ItemChange( nWhich, pNewItem );
128 // create a new itemset
129 std::unique_ptr<SfxItemSet> TableProperties::CreateObjectSpecificItemSet(SfxItemPool& rPool)
131 return std::make_unique<SfxItemSet>(rPool,
133 // range from SdrAttrObj
134 svl::Items<SDRATTR_START, SDRATTR_SHADOW_LAST,
135 SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST,
136 SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION,
138 // range for SdrTableObj
139 SDRATTR_TABLE_FIRST, SDRATTR_TABLE_LAST,
141 // range from SdrTextObj
142 EE_ITEMS_START, EE_ITEMS_END>{});
145 namespace {
147 class TableObjectGeoData : public SdrTextObjGeoData
149 public:
150 tools::Rectangle maLogicRect;
155 TableStyleSettings::TableStyleSettings()
156 : mbUseFirstRow(true)
157 , mbUseLastRow(false)
158 , mbUseFirstColumn(false)
159 , mbUseLastColumn(false)
160 , mbUseRowBanding(true)
161 , mbUseColumnBanding(false)
165 TableStyleSettings::TableStyleSettings( const TableStyleSettings& rStyle )
167 (*this) = rStyle;
170 TableStyleSettings& TableStyleSettings::operator=(const TableStyleSettings& rStyle)
172 mbUseFirstRow = rStyle.mbUseFirstRow;
173 mbUseLastRow = rStyle.mbUseLastRow;
174 mbUseFirstColumn = rStyle.mbUseFirstColumn;
175 mbUseLastColumn = rStyle.mbUseLastColumn;
176 mbUseRowBanding = rStyle.mbUseRowBanding;
177 mbUseColumnBanding = rStyle.mbUseColumnBanding;
178 return *this;
181 bool TableStyleSettings::operator==( const TableStyleSettings& rStyle ) const
183 return
184 (mbUseFirstRow == rStyle.mbUseFirstRow) &&
185 (mbUseLastRow == rStyle.mbUseLastRow) &&
186 (mbUseFirstColumn == rStyle.mbUseFirstColumn) &&
187 (mbUseLastColumn == rStyle.mbUseLastColumn) &&
188 (mbUseRowBanding == rStyle.mbUseRowBanding) &&
189 (mbUseColumnBanding == rStyle.mbUseColumnBanding);
193 class SdrTableObjImpl : public TableDesignUser, public ::cppu::WeakImplHelper< css::util::XModifyListener >
195 public:
196 CellRef mxActiveCell;
197 TableModelRef mxTable;
198 SdrTableObj* mpTableObj;
199 std::unique_ptr<TableLayouter> mpLayouter;
200 CellPos maEditPos;
201 TableStyleSettings maTableStyle;
202 Reference< XIndexAccess > mxTableStyle;
203 std::vector<std::unique_ptr<SdrUndoAction>> maUndos;
204 bool mbSkipChangeLayout;
206 void CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd);
208 CellRef getCell( const CellPos& rPos ) const;
209 void LayoutTable( tools::Rectangle& rArea, bool bFitWidth, bool bFitHeight );
211 void ApplyCellStyles();
212 void UpdateCells( tools::Rectangle const & rArea );
214 SdrTableObjImpl();
215 virtual ~SdrTableObjImpl() override;
217 void init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows );
218 void dispose();
220 sal_Int32 getColumnCount() const;
221 /// Get widths of the columns in the table.
222 std::vector<sal_Int32> getColumnWidths() const;
223 sal_Int32 getRowCount() const;
225 void DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset );
227 SdrTableObjImpl& operator=( const SdrTableObjImpl& rSource );
229 // XModifyListener
230 virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
232 // XEventListener
233 virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
235 void update();
237 void connectTableStyle();
238 void disconnectTableStyle();
239 virtual bool isInUse() override;
240 void dumpAsXml(xmlTextWriterPtr pWriter) const;
241 private:
242 static SdrTableObjImpl* lastLayoutTable;
243 static tools::Rectangle lastLayoutInputRectangle;
244 static tools::Rectangle lastLayoutResultRectangle;
245 static bool lastLayoutFitWidth;
246 static bool lastLayoutFitHeight;
247 static WritingMode lastLayoutMode;
248 static sal_Int32 lastRowCount;
249 static sal_Int32 lastColCount;
250 static std::vector<sal_Int32> lastColWidths;
253 SdrTableObjImpl* SdrTableObjImpl::lastLayoutTable = nullptr;
254 tools::Rectangle SdrTableObjImpl::lastLayoutInputRectangle;
255 tools::Rectangle SdrTableObjImpl::lastLayoutResultRectangle;
256 bool SdrTableObjImpl::lastLayoutFitWidth;
257 bool SdrTableObjImpl::lastLayoutFitHeight;
258 WritingMode SdrTableObjImpl::lastLayoutMode;
259 sal_Int32 SdrTableObjImpl::lastRowCount;
260 sal_Int32 SdrTableObjImpl::lastColCount;
261 std::vector<sal_Int32> SdrTableObjImpl::lastColWidths;
263 SdrTableObjImpl::SdrTableObjImpl()
264 : mpTableObj( nullptr )
265 , mbSkipChangeLayout(false)
270 SdrTableObjImpl::~SdrTableObjImpl()
272 if( lastLayoutTable == this )
273 lastLayoutTable = nullptr;
277 void SdrTableObjImpl::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
279 if(!mxTable.is())
281 return;
284 const sal_Int32 nColumns(rEnd.mnCol - rStart.mnCol + 1);
285 const sal_Int32 nRows(rEnd.mnRow - rStart.mnRow + 1);
287 if(nColumns < 1 || nRows < 1 || nColumns > getColumnCount() || nRows > getRowCount())
289 return;
292 // tdf#116977 First thought was to create the new TableModel, copy data to it and then exchange
293 // mxTable and dispose old one. This does *not* work, even when all stuff looks nicely referenced
294 // and safe *because* Cell::create gets handed over the current SdrTableObj, hands it to
295 // ::Cell and there the local mxTable is initialized using rTableObj.getTable() (!). Due to This,
296 // the new created Cells in a new created TableModel based on given mpTableObj *will be disposed*
297 // when the old mxTable gets disposed - ARGH!
298 // To avoid, change strategy: Remember old TableModel, reset mxTable immediately - this is the
299 // SdrTableObjImpl of the current SdrTableObj anyways. Luckily, this works as intended...
301 // remember old TableModel
302 TableModelRef xOldTable(mxTable);
304 // immediately create new one and initialize. This creates ::Cell's which then will use
305 // the correct TableModel (accessed through SdrTableObj, but using local mxTable)
306 mxTable = new TableModel(mpTableObj);
307 mxTable->init(nColumns, nRows);
309 // copy cells
310 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
312 for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol ) try
314 CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
315 if( xTargetCell.is() )
316 xTargetCell->cloneFrom( dynamic_cast< Cell* >( xOldTable->getCellByPosition( rStart.mnCol + nCol, rStart.mnRow + nRow ).get() ) );
318 catch( Exception& )
320 TOOLS_WARN_EXCEPTION("svx.table", "");
324 // copy row heights
325 Reference< XTableRows > xNewRows(mxTable->getRows(), css::uno::UNO_SET_THROW );
326 const OUString sHeight( "Height" );
327 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
329 Reference< XPropertySet > xNewSet( xNewRows->getByIndex( nRow ), UNO_QUERY_THROW );
330 xNewSet->setPropertyValue( sHeight, Any( mpLayouter->getRowHeight( rStart.mnRow + nRow ) ) );
333 // copy column widths
334 Reference< XTableColumns > xNewColumns( mxTable->getColumns(), css::uno::UNO_SET_THROW );
335 const OUString sWidth( "Width" );
336 for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol )
338 Reference< XPropertySet > xNewSet( xNewColumns->getByIndex( nCol ), UNO_QUERY_THROW );
339 xNewSet->setPropertyValue( sWidth, Any( mpLayouter->getColumnWidth( rStart.mnCol + nCol ) ) );
342 // reset layouter which still holds a copy to old TableModel
343 mpLayouter.reset();
345 // cleanup old TableModel
347 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
348 xOldTable->removeModifyListener( xListener );
349 xOldTable->dispose();
350 xOldTable.clear();
353 // create and hand over to new TableLayouter
354 mpLayouter.reset(new TableLayouter( mxTable ));
356 // add needed listener to react on changes
357 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
358 mxTable->addModifyListener( xListener );
360 // Apply Style to Cells
361 ApplyCellStyles();
363 // layout cropped table
364 LayoutTable( mpTableObj->maRect, false, false );
367 void SdrTableObjImpl::init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows )
369 mpTableObj = pTable;
370 mxTable = new TableModel( pTable );
371 mxTable->init( nColumns, nRows );
372 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
373 mxTable->addModifyListener( xListener );
374 mpLayouter.reset(new TableLayouter( mxTable ));
375 LayoutTable( mpTableObj->maRect, true, true );
376 mpTableObj->maLogicRect = mpTableObj->maRect;
380 SdrTableObjImpl& SdrTableObjImpl::operator=( const SdrTableObjImpl& rSource )
382 if(this == &rSource)
384 return *this;
387 if(nullptr == mpTableObj || nullptr == rSource.mpTableObj)
389 // error: need both SdrObjects to successfully copy data
390 return *this;
393 // remove evtl. listeners from local
394 disconnectTableStyle();
396 // reset layouter which holds a copy
397 mpLayouter.reset();
399 // cleanup local mxTable if used
400 if( mxTable.is() )
402 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
403 mxTable->removeModifyListener( xListener );
404 mxTable->dispose();
405 mxTable.clear();
408 // tdf#127481: reset active cell reference
409 mxActiveCell.clear();
411 // copy TableStyle (short internal data)
412 maTableStyle = rSource.maTableStyle;
414 // create/copy new mxTable. This will copy all needed cells, too
415 mxTable = new TableModel( mpTableObj, rSource.mxTable );
417 // create and hand over to new TableLayouter
418 mpLayouter.reset(new TableLayouter( mxTable ));
420 // add needed listener to react on changes
421 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
422 mxTable->addModifyListener( xListener );
424 // handle TableStyle
425 Reference< XIndexAccess > xNewTableStyle;
426 SdrModel& rSourceSdrModel(rSource.mpTableObj->getSdrModelFromSdrObject());
427 SdrModel& rTargetSdrModel(mpTableObj->getSdrModelFromSdrObject());
429 if(rSource.mxTableStyle.is() && &rSourceSdrModel == &rTargetSdrModel)
431 // source and target model the same -> keep current TableStyle
432 xNewTableStyle = rSource.mxTableStyle;
435 if(!xNewTableStyle.is() && rSource.mxTableStyle.is()) try
437 // search in target SdrModel for that TableStyle
438 const OUString sStyleName( Reference< XNamed >( rSource.mxTableStyle, UNO_QUERY_THROW )->getName() );
439 Reference< XStyleFamiliesSupplier > xSFS(rTargetSdrModel.getUnoModel(), UNO_QUERY_THROW );
440 Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), css::uno::UNO_SET_THROW );
441 Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( "table" ), UNO_QUERY_THROW );
443 if( xTableFamilyAccess->hasByName( sStyleName ) )
445 // found table style with the same name
446 xTableFamilyAccess->getByName( sStyleName ) >>= xNewTableStyle;
448 else
450 // copy or? Not found, use 1st existing TableStyle (or none)
451 Reference< XIndexAccess > xIndexAccess( xTableFamilyAccess, UNO_QUERY_THROW );
452 xIndexAccess->getByIndex( 0 ) >>= xNewTableStyle;
455 catch( Exception& )
457 TOOLS_WARN_EXCEPTION("svx.table", "");
460 // set that TableStyle
461 mxTableStyle = xNewTableStyle;
463 // Apply Style to Cells
464 ApplyCellStyles();
466 // copy geometry
467 mpTableObj->maRect = mpTableObj->maLogicRect;
469 // layout cloned table
470 LayoutTable( mpTableObj->maRect, false, false );
472 // re-connect to styles (evtl. in new SdrModel)
473 connectTableStyle();
475 return *this;
478 void SdrTableObjImpl::ApplyCellStyles()
480 if( !mxTable.is() || !mxTableStyle.is() )
481 return;
483 const sal_Int32 nColCount = getColumnCount();
484 const sal_Int32 nRowCount = getRowCount();
486 const TableStyleSettings& rStyle = maTableStyle;
488 CellPos aPos;
489 for( aPos.mnRow = 0; aPos.mnRow < nRowCount; ++aPos.mnRow )
491 const bool bFirstRow = (aPos.mnRow == 0) && rStyle.mbUseFirstRow;
492 const bool bLastRow = (aPos.mnRow == nRowCount-1) && rStyle.mbUseLastRow;
494 for( aPos.mnCol = 0; aPos.mnCol < nColCount; ++aPos.mnCol )
496 Reference< XStyle > xStyle;
498 // first and last row win first, if used and available
499 if( bFirstRow )
501 mxTableStyle->getByIndex(first_row_style) >>= xStyle;
503 else if( bLastRow )
505 mxTableStyle->getByIndex(last_row_style) >>= xStyle;
508 if( !xStyle.is() )
510 // next come first and last column, if used and available
511 if( rStyle.mbUseFirstColumn && (aPos.mnCol == 0) )
513 mxTableStyle->getByIndex(first_column_style) >>= xStyle;
515 else if( rStyle.mbUseLastColumn && (aPos.mnCol == nColCount-1) )
517 mxTableStyle->getByIndex(last_column_style) >>= xStyle;
521 if( !xStyle.is() && rStyle.mbUseRowBanding )
523 if( (aPos.mnRow & 1) == 0 )
525 mxTableStyle->getByIndex(even_rows_style) >>= xStyle;
527 else
529 mxTableStyle->getByIndex(odd_rows_style) >>= xStyle;
533 if( !xStyle.is() && rStyle.mbUseColumnBanding )
535 if( (aPos.mnCol & 1) == 0 )
537 mxTableStyle->getByIndex(even_columns_style) >>= xStyle;
539 else
541 mxTableStyle->getByIndex(odd_columns_style) >>= xStyle;
545 if( !xStyle.is() )
547 // use default cell style if non found yet
548 mxTableStyle->getByIndex(body_style) >>= xStyle;
552 if( xStyle.is() )
554 SfxUnoStyleSheet* pStyle = SfxUnoStyleSheet::getUnoStyleSheet(xStyle);
556 if( pStyle )
558 CellRef xCell( getCell( aPos ) );
559 if( xCell.is() && ( xCell->GetStyleSheet() != pStyle ) )
561 xCell->SetStyleSheet( pStyle, true );
570 void SdrTableObjImpl::dispose()
572 disconnectTableStyle();
573 mxTableStyle.clear();
575 mpLayouter.reset();
577 if( mxTable.is() )
579 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
580 mxTable->removeModifyListener( xListener );
581 mxTable->dispose();
582 mxTable.clear();
587 void SdrTableObjImpl::DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset )
589 if( !((nEdge >= 0) && mxTable.is()))
590 return;
594 const OUString sSize( "Size" );
595 if( mbHorizontal )
597 if (nEdge <= getRowCount())
599 sal_Int32 nHeight = mpLayouter->getRowHeight( (!nEdge)?nEdge:(nEdge-1) );
600 if(nEdge==0)
601 nHeight -= nOffset;
602 else
603 nHeight += nOffset;
604 Reference< XIndexAccess > xRows( mxTable->getRows(), UNO_QUERY_THROW );
605 Reference< XPropertySet > xRowSet( xRows->getByIndex( (!nEdge)?nEdge:(nEdge-1) ), UNO_QUERY_THROW );
606 xRowSet->setPropertyValue( sSize, Any( nHeight ) );
609 else
612 fixes fdo#59889 and resizing of table in edge dragging
613 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
614 In LTR table vertical edge responsible for dragging of column x(x=0 to N-1) is, Edge x+1
615 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
616 In LTR table dragging of edge 0(for RTL table edge N) does nothing.
618 //Todo: Implement Dragging functionality for leftmost edge of table.
619 if (nEdge <= getColumnCount())
621 const bool bRTL = mpTableObj != nullptr && (mpTableObj->GetWritingMode() == WritingMode_RL_TB);
622 sal_Int32 nWidth;
623 if(bRTL)
625 nWidth = mpLayouter->getColumnWidth( nEdge );
627 else
629 nWidth = mpLayouter->getColumnWidth( (!nEdge)?nEdge:(nEdge-1) );
631 Reference< XIndexAccess > xCols( mxTable->getColumns(), UNO_QUERY_THROW );
632 nWidth += nOffset;
633 if(bRTL && nEdge<getColumnCount())
635 Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge ), UNO_QUERY_THROW );
636 xColSet->setPropertyValue( sSize, Any( nWidth ) );
638 else if(!bRTL && nEdge>0)
640 Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge-1 ), UNO_QUERY_THROW );
641 xColSet->setPropertyValue( sSize, Any( nWidth ) );
643 /* To prevent the table resizing on edge dragging */
644 if( nEdge > 0 && nEdge < mxTable->getColumnCount() )
646 if( bRTL )
647 nEdge--;
649 nWidth = mpLayouter->getColumnWidth(nEdge);
650 nWidth = std::max(static_cast<sal_Int32>(nWidth - nOffset), sal_Int32(0));
652 Reference<XPropertySet> xColSet(xCols->getByIndex(nEdge), UNO_QUERY_THROW);
653 xColSet->setPropertyValue(sSize, Any(nWidth));
658 catch( Exception& )
660 TOOLS_WARN_EXCEPTION("svx.table", "");
665 // XModifyListener
668 void SAL_CALL SdrTableObjImpl::modified( const css::lang::EventObject& /*aEvent*/ )
670 update();
673 void SdrTableObjImpl::update()
675 // source can be the table model itself or the assigned table template
676 TableModelNotifyGuard aGuard( mxTable.get() );
677 if( !mpTableObj )
678 return;
680 if( (maEditPos.mnRow >= getRowCount()) || (maEditPos.mnCol >= getColumnCount()) || (getCell( maEditPos ) != mxActiveCell) )
682 if(maEditPos.mnRow >= getRowCount())
683 maEditPos.mnRow = getRowCount()-1;
685 if(maEditPos.mnCol >= getColumnCount())
686 maEditPos.mnCol = getColumnCount()-1;
688 mpTableObj->setActiveCell( maEditPos );
691 ApplyCellStyles();
693 mpTableObj->maRect = mpTableObj->maLogicRect;
694 LayoutTable( mpTableObj->maRect, false, false );
696 mpTableObj->SetRectsDirty();
697 mpTableObj->ActionChanged();
698 mpTableObj->BroadcastObjectChange();
702 void SdrTableObjImpl::connectTableStyle()
704 if( mxTableStyle.is() )
706 Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
707 if( xBroadcaster.is() )
709 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
710 xBroadcaster->addModifyListener( xListener );
716 void SdrTableObjImpl::disconnectTableStyle()
718 if( mxTableStyle.is() )
720 Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
721 if( xBroadcaster.is() )
723 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
724 xBroadcaster->removeModifyListener( xListener );
730 bool SdrTableObjImpl::isInUse()
732 return mpTableObj && mpTableObj->IsInserted();
735 void SdrTableObjImpl::dumpAsXml(xmlTextWriterPtr pWriter) const
737 xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObjImpl"));
738 if (mpLayouter)
739 mpLayouter->dumpAsXml(pWriter);
740 mxTable->dumpAsXml(pWriter);
741 xmlTextWriterEndElement(pWriter);
745 // XEventListener
748 void SAL_CALL SdrTableObjImpl::disposing( const css::lang::EventObject& /*Source*/ )
750 mxActiveCell.clear();
751 mxTable.clear();
752 mpLayouter.reset();
753 mpTableObj = nullptr;
757 CellRef SdrTableObjImpl::getCell( const CellPos& rPos ) const
759 CellRef xCell;
760 if( mxTable.is() ) try
762 xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
764 catch( Exception& )
766 TOOLS_WARN_EXCEPTION("svx.table", "");
768 return xCell;
772 sal_Int32 SdrTableObjImpl::getColumnCount() const
774 return mxTable.is() ? mxTable->getColumnCount() : 0;
777 std::vector<sal_Int32> SdrTableObjImpl::getColumnWidths() const
779 std::vector<sal_Int32> aRet;
781 if (mxTable.is())
782 aRet = mxTable->getColumnWidths();
784 return aRet;
787 sal_Int32 SdrTableObjImpl::getRowCount() const
789 return mxTable.is() ? mxTable->getRowCount() : 0;
792 void SdrTableObjImpl::LayoutTable( tools::Rectangle& rArea, bool bFitWidth, bool bFitHeight )
794 if (utl::ConfigManager::IsFuzzing())
795 return;
796 if(!mpLayouter)
797 return;
799 // Optimization: SdrTableObj::SetChanged() can call this very often, repeatedly
800 // with the same settings, noticeably increasing load time. Skip if already done.
801 bool bInteractiveMightGrowBecauseTextChanged =
802 mpTableObj->IsReallyEdited() && (mpTableObj->IsAutoGrowHeight() || mpTableObj->IsAutoGrowWidth());
803 WritingMode writingMode = mpTableObj->GetWritingMode();
804 if( bInteractiveMightGrowBecauseTextChanged
805 || lastLayoutTable != this || lastLayoutInputRectangle != rArea
806 || lastLayoutFitWidth != bFitWidth || lastLayoutFitHeight != bFitHeight
807 || lastLayoutMode != writingMode
808 || lastRowCount != getRowCount()
809 || lastColCount != getColumnCount()
810 || lastColWidths != getColumnWidths() )
812 lastLayoutTable = this;
813 lastLayoutInputRectangle = rArea;
814 lastLayoutFitWidth = bFitWidth;
815 lastLayoutFitHeight = bFitHeight;
816 lastLayoutMode = writingMode;
817 lastRowCount = getRowCount();
818 lastColCount = getColumnCount();
819 // Column resize, when the total width and column count of the
820 // table is unchanged, but re-layout is still needed.
821 lastColWidths = getColumnWidths();
822 TableModelNotifyGuard aGuard( mxTable.get() );
823 mpLayouter->LayoutTable( rArea, bFitWidth, bFitHeight );
824 lastLayoutResultRectangle = rArea;
826 else
828 rArea = lastLayoutResultRectangle;
829 mpLayouter->UpdateBorderLayout();
833 void SdrTableObjImpl::UpdateCells( tools::Rectangle const & rArea )
835 if( mpLayouter && mxTable.is() )
837 TableModelNotifyGuard aGuard( mxTable.get() );
838 mpLayouter->updateCells( rArea );
839 mxTable->setModified(true);
844 // BaseProperties section
847 std::unique_ptr<sdr::properties::BaseProperties> SdrTableObj::CreateObjectSpecificProperties()
849 return std::make_unique<TableProperties>(*this);
853 // DrawContact section
856 std::unique_ptr<sdr::contact::ViewContact> SdrTableObj::CreateObjectSpecificViewContact()
858 return std::make_unique<sdr::contact::ViewContactOfTableObj>(*this);
861 SdrTableObj::SdrTableObj(SdrModel& rSdrModel)
862 : SdrTextObj(rSdrModel)
864 init( 1, 1 );
867 SdrTableObj::SdrTableObj(
868 SdrModel& rSdrModel,
869 const ::tools::Rectangle& rNewRect,
870 sal_Int32 nColumns,
871 sal_Int32 nRows)
872 : SdrTextObj(rSdrModel, rNewRect)
873 ,maLogicRect(rNewRect)
875 if( nColumns <= 0 )
876 nColumns = 1;
878 if( nRows <= 0 )
879 nRows = 1;
881 init( nColumns, nRows );
885 void SdrTableObj::init( sal_Int32 nColumns, sal_Int32 nRows )
887 bClosedObj = true;
889 mpImpl = new SdrTableObjImpl;
890 mpImpl->init( this, nColumns, nRows );
892 // Stuff done from old SetModel:
893 if( !maLogicRect.IsEmpty() )
895 maRect = maLogicRect;
896 mpImpl->LayoutTable( maRect, false, false );
901 SdrTableObj::~SdrTableObj()
903 mpImpl->dispose();
907 // table stuff
910 Reference< XTable > SdrTableObj::getTable() const
912 return Reference< XTable >( mpImpl->mxTable.get() );
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.get(), 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() - maRect.Left();
1172 sal_Int32 nY = rPos.Y() - maRect.Top();
1174 if( (nX < 0) || (nX > maRect.GetWidth()) || (nY < 0) || (nY > maRect.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.get(), 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 dynamic_cast< SdrText* >( 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 dynamic_cast< SdrText* >( 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 pEdtOutl;
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 pEdtOutl && 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( maRect );
1420 maRect = maLogicRect;
1421 mpImpl->LayoutTable( maRect, false, false );
1422 SetRectsDirty();
1423 ActionChanged();
1424 BroadcastObjectChange();
1425 if (aRect0 != maRect)
1426 SendUserCall(SdrUserCallType::Resize,aRect0);
1431 void SdrTableObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
1433 rInfo.bResizeFreeAllowed=true;
1434 rInfo.bResizePropAllowed=true;
1435 rInfo.bRotateFreeAllowed=false;
1436 rInfo.bRotate90Allowed =false;
1437 rInfo.bMirrorFreeAllowed=false;
1438 rInfo.bMirror45Allowed =false;
1439 rInfo.bMirror90Allowed =false;
1441 // allow transparence
1442 rInfo.bTransparenceAllowed = true;
1444 rInfo.bShearAllowed =false;
1445 rInfo.bEdgeRadiusAllowed=false;
1446 rInfo.bCanConvToPath =false;
1447 rInfo.bCanConvToPoly =false;
1448 rInfo.bCanConvToPathLineToArea=false;
1449 rInfo.bCanConvToPolyLineToArea=false;
1450 rInfo.bCanConvToContour = false;
1453 SdrObjKind SdrTableObj::GetObjIdentifier() const
1455 return OBJ_TABLE;
1458 void SdrTableObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect, bool /*bLineWidth*/ ) const
1460 if( mpImpl.is() )
1461 TakeTextRect( mpImpl->maEditPos, rOutliner, rTextRect, bNoEditText, pAnchorRect );
1465 void SdrTableObj::TakeTextRect( const CellPos& rPos, SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect ) const
1467 if( !mpImpl.is())
1468 return;
1470 CellRef xCell( mpImpl->getCell( rPos ) );
1471 if( !xCell.is() )
1472 return;
1474 tools::Rectangle aAnkRect;
1475 TakeTextAnchorRect( rPos, aAnkRect );
1477 SdrTextVertAdjust eVAdj=xCell->GetTextVerticalAdjust();
1479 EEControlBits nStat0=rOutliner.GetControlWord();
1480 nStat0 |= EEControlBits::AUTOPAGESIZE;
1481 rOutliner.SetControlWord(nStat0);
1482 rOutliner.SetMinAutoPaperSize(Size());
1483 rOutliner.SetMaxAutoPaperSize(aAnkRect.GetSize());
1484 rOutliner.SetPaperSize(aAnkRect.GetSize());
1486 // #103516# New try with _BLOCK for hor and ver after completely
1487 // supporting full width for vertical text.
1488 // if( SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
1489 // {
1490 rOutliner.SetMinAutoPaperSize(Size(aAnkRect.GetWidth(), 0));
1491 // }
1492 // else if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
1493 // {
1494 // rOutliner.SetMinAutoPaperSize(Size(0, aAnkRect.GetHeight()));
1495 // }
1498 // set text at outliner, maybe from edit outliner
1499 OutlinerParaObject* pPara= xCell->GetOutlinerParaObject();
1500 if (pEdtOutl && !bNoEditText && mpImpl->mxActiveCell == xCell )
1501 pPara=pEdtOutl->CreateParaObject().release();
1503 if (pPara)
1505 const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
1506 const SdrTextObj* pTestObj(rOutliner.GetTextObj());
1508 if( !pTestObj || !bHitTest || (pTestObj != this) || (pTestObj->GetOutlinerParaObject() != xCell->GetOutlinerParaObject()) )
1510 if( bHitTest ) // #i33696# take back fix #i27510#
1511 rOutliner.SetTextObj( this );
1513 rOutliner.SetUpdateMode(true);
1514 rOutliner.SetText(*pPara);
1517 else
1519 rOutliner.SetTextObj( nullptr );
1522 if (pEdtOutl && !bNoEditText && pPara && mpImpl->mxActiveCell == xCell )
1523 delete pPara;
1525 rOutliner.SetUpdateMode(true);
1526 rOutliner.SetControlWord(nStat0);
1528 Point aTextPos(aAnkRect.TopLeft());
1529 Size aTextSiz(rOutliner.GetPaperSize());
1530 if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1532 tools::Long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
1533 if (eVAdj==SDRTEXTVERTADJUST_CENTER)
1534 aTextPos.AdjustY(nFreeHgt/2 );
1535 if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1536 aTextPos.AdjustY(nFreeHgt );
1539 if (pAnchorRect)
1540 *pAnchorRect=aAnkRect;
1542 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.get(), 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(maRect);
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 OUStringBuffer sName(SvxResId(STR_ObjNameSingulTable));
1739 OUString aName(GetName());
1740 if (!aName.isEmpty())
1742 sName.append(' ');
1743 sName.append('\'');
1744 sName.append(aName);
1745 sName.append('\'');
1748 return sName.makeStringAndClear();
1752 OUString SdrTableObj::TakeObjNamePlural() const
1754 return SvxResId(STR_ObjNamePluralTable);
1758 SdrTableObj* SdrTableObj::CloneSdrObject(SdrModel& rTargetModel) const
1760 return CloneHelper< SdrTableObj >(rTargetModel);
1763 SdrTableObj& SdrTableObj::operator=(const SdrTableObj& rObj)
1765 if( this == &rObj )
1767 return *this;
1770 // call parent
1771 // before SdrObject::operator= was called which is wrong from
1772 // the derivation hierarchy and may leave quite some entries
1773 // uninitialized. Changed to SdrTextObj::operator=, but had to adapt
1774 // usage of pNewOutlinerParaObject/mpText there due to nullptr access
1775 SdrTextObj::operator=(rObj);
1777 TableModelNotifyGuard aGuard( mpImpl.is() ? mpImpl->mxTable.get() : nullptr );
1779 maLogicRect = rObj.maLogicRect;
1780 maRect = rObj.maRect;
1781 aGeo = rObj.aGeo;
1782 eTextKind = rObj.eTextKind;
1783 bTextFrame = rObj.bTextFrame;
1784 aTextSize = rObj.aTextSize;
1785 bTextSizeDirty = rObj.bTextSizeDirty;
1786 bNoShear = rObj.bNoShear;
1787 bDisableAutoWidthOnDragging = rObj.bDisableAutoWidthOnDragging;
1789 // use SdrTableObjImpl::operator= now to
1790 // copy model data and other stuff (see there)
1791 *mpImpl = *rObj.mpImpl;
1793 return *this;
1797 const tools::Rectangle& SdrTableObj::GetSnapRect() const
1799 return maRect;
1803 void SdrTableObj::NbcSetSnapRect(const tools::Rectangle& rRect)
1805 NbcSetLogicRect( rRect );
1809 const tools::Rectangle& SdrTableObj::GetLogicRect() const
1811 return maLogicRect;
1815 void SdrTableObj::RecalcSnapRect()
1820 bool SdrTableObj::BegTextEdit(SdrOutliner& rOutl)
1822 if( pEdtOutl != nullptr )
1823 return false;
1825 pEdtOutl=&rOutl;
1827 mbInEditMode = true;
1829 rOutl.Init( OutlinerMode::TextObject );
1830 rOutl.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());
1832 bool bUpdateMode=rOutl.GetUpdateMode();
1833 if (bUpdateMode) rOutl.SetUpdateMode(false);
1834 Size aPaperMin;
1835 Size aPaperMax;
1836 tools::Rectangle aEditArea;
1837 TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,nullptr);
1839 rOutl.SetMinAutoPaperSize(aPaperMin);
1840 rOutl.SetMaxAutoPaperSize(aPaperMax);
1841 rOutl.SetPaperSize(aPaperMax);
1843 if (bUpdateMode) rOutl.SetUpdateMode(true);
1845 EEControlBits nStat=rOutl.GetControlWord();
1846 nStat |= EEControlBits::AUTOPAGESIZE;
1847 nStat &=~EEControlBits::STRETCHING;
1848 rOutl.SetControlWord(nStat);
1850 OutlinerParaObject* pPara = GetOutlinerParaObject();
1851 if(pPara)
1852 rOutl.SetText(*pPara);
1854 rOutl.UpdateFields();
1855 rOutl.ClearModifyFlag();
1857 return true;
1861 void SdrTableObj::EndTextEdit(SdrOutliner& rOutl)
1864 if (getSdrModelFromSdrObject().IsUndoEnabled() && !mpImpl->maUndos.empty())
1866 // These actions should be on the undo stack after text edit.
1867 for (std::unique_ptr<SdrUndoAction>& pAction : mpImpl->maUndos)
1868 getSdrModelFromSdrObject().AddUndo( std::move(pAction));
1869 mpImpl->maUndos.clear();
1871 getSdrModelFromSdrObject().AddUndo(getSdrModelFromSdrObject().GetSdrUndoFactory().CreateUndoGeoObject(*this));
1874 if(rOutl.IsModified())
1876 std::unique_ptr<OutlinerParaObject> pNewText;
1877 Paragraph* p1stPara = rOutl.GetParagraph( 0 );
1878 sal_Int32 nParaCnt = rOutl.GetParagraphCount();
1880 if(p1stPara)
1882 // to remove the grey field background
1883 rOutl.UpdateFields();
1885 // create new text object
1886 pNewText = rOutl.CreateParaObject( 0, nParaCnt );
1888 SetOutlinerParaObject(std::move(pNewText));
1891 pEdtOutl = nullptr;
1892 rOutl.Clear();
1893 EEControlBits nStat = rOutl.GetControlWord();
1894 nStat &= ~EEControlBits::AUTOPAGESIZE;
1895 rOutl.SetControlWord(nStat);
1897 mbInEditMode = false;
1901 OutlinerParaObject* SdrTableObj::GetOutlinerParaObject() const
1903 CellRef xCell( getActiveCell() );
1904 if( xCell.is() )
1905 return xCell->GetOutlinerParaObject();
1906 else
1907 return nullptr;
1911 void SdrTableObj::NbcSetOutlinerParaObject( std::unique_ptr<OutlinerParaObject> pTextObject)
1913 CellRef xCell( getActiveCell() );
1914 if( !xCell.is() )
1915 return;
1917 // Update HitTestOutliner
1918 const SdrTextObj* pTestObj(getSdrModelFromSdrObject().GetHitTestOutliner().GetTextObj());
1920 if(pTestObj && pTestObj->GetOutlinerParaObject() == xCell->GetOutlinerParaObject())
1922 getSdrModelFromSdrObject().GetHitTestOutliner().SetTextObj(nullptr);
1925 xCell->SetOutlinerParaObject( std::move(pTextObject) );
1926 SetTextSizeDirty();
1927 NbcAdjustTextFrameWidthAndHeight();
1931 void SdrTableObj::NbcSetLogicRect(const tools::Rectangle& rRect)
1933 maLogicRect=rRect;
1934 ImpJustifyRect(maLogicRect);
1935 const bool bWidth = maLogicRect.getWidth() != maRect.getWidth();
1936 const bool bHeight = maLogicRect.getHeight() != maRect.getHeight();
1937 maRect = maLogicRect;
1938 if (mpImpl->mbSkipChangeLayout)
1939 // Avoid distributing newly available space between existing cells.
1940 NbcAdjustTextFrameWidthAndHeight();
1941 else
1942 NbcAdjustTextFrameWidthAndHeight(!bHeight, !bWidth);
1943 SetRectsDirty();
1947 void SdrTableObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
1949 tools::Rectangle aAdjustRect( rMaxRect );
1950 aAdjustRect.setHeight( GetLogicRect().getHeight() );
1951 SetLogicRect( aAdjustRect );
1955 void SdrTableObj::NbcMove(const Size& rSiz)
1957 maLogicRect.Move(rSiz);
1958 SdrTextObj::NbcMove( rSiz );
1959 if( mpImpl.is() )
1960 mpImpl->UpdateCells( maRect );
1964 void SdrTableObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1966 tools::Rectangle aOldRect( maLogicRect );
1967 ResizeRect(maLogicRect,rRef,xFact,yFact);
1969 maRect = maLogicRect;
1970 NbcAdjustTextFrameWidthAndHeight( maLogicRect.GetHeight() == aOldRect.GetHeight(), maLogicRect.GetWidth() == aOldRect.GetWidth() );
1971 SetRectsDirty();
1975 bool SdrTableObj::AdjustTextFrameWidthAndHeight()
1977 tools::Rectangle aNewRect(maLogicRect);
1978 bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
1979 if (bRet)
1981 tools::Rectangle aBoundRect0;
1982 if (pUserCall!=nullptr)
1983 aBoundRect0=GetLastBoundRect();
1984 maRect = aNewRect;
1985 SetRectsDirty();
1986 SetChanged();
1987 BroadcastObjectChange();
1988 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1990 return bRet;
1994 bool SdrTableObj::AdjustTextFrameWidthAndHeight(tools::Rectangle& rR, bool bHeight, bool bWidth) const
1996 if(rR.IsEmpty() || !mpImpl.is() || !mpImpl->mxTable.is())
1997 return false;
1999 tools::Rectangle aRectangle( rR );
2000 mpImpl->LayoutTable( aRectangle, !bWidth, !bHeight );
2002 if( aRectangle != rR )
2004 rR = aRectangle;
2005 return true;
2007 else
2009 return false;
2014 void SdrTableObj::NbcReformatText()
2016 NbcAdjustTextFrameWidthAndHeight();
2020 bool SdrTableObj::IsVerticalWriting() const
2022 const SvxWritingModeItem& rModeItem = GetObjectItem( SDRATTR_TEXTDIRECTION );
2023 return rModeItem.GetValue() == css::text::WritingMode_TB_RL;
2027 void SdrTableObj::SetVerticalWriting(bool bVertical)
2029 if(bVertical != IsVerticalWriting() )
2031 SvxWritingModeItem aModeItem( css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION );
2032 SetObjectItem( aModeItem );
2037 WritingMode SdrTableObj::GetWritingMode() const
2039 SfxStyleSheet* pStyle = GetStyleSheet();
2040 if ( !pStyle )
2041 return WritingMode_LR_TB;
2043 WritingMode eWritingMode = WritingMode_LR_TB;
2044 const SfxItemSet &rSet = pStyle->GetItemSet();
2045 const SfxPoolItem *pItem;
2047 if ( rSet.GetItemState( SDRATTR_TEXTDIRECTION, false, &pItem ) == SfxItemState::SET )
2048 eWritingMode = static_cast< const SvxWritingModeItem * >( pItem )->GetValue();
2050 if ( ( eWritingMode != WritingMode_TB_RL ) &&
2051 ( rSet.GetItemState( EE_PARA_WRITINGDIR, false, &pItem ) == SfxItemState::SET ) )
2053 if ( static_cast< const SvxFrameDirectionItem * >( pItem )->GetValue() == SvxFrameDirection::Horizontal_LR_TB )
2054 eWritingMode = WritingMode_LR_TB;
2055 else
2056 eWritingMode = WritingMode_RL_TB;
2059 return eWritingMode;
2062 void SdrTableObj::AddUndo(SdrUndoAction* pUndo)
2064 mpImpl->maUndos.push_back(std::unique_ptr<SdrUndoAction>(pUndo));
2067 void SdrTableObj::SetSkipChangeLayout(bool bSkipChangeLayout)
2069 mpImpl->mbSkipChangeLayout = bSkipChangeLayout;
2072 bool SdrTableObj::IsReallyEdited() const
2074 return pEdtOutl && pEdtOutl->IsModified();
2077 bool SdrTableObj::IsFontwork() const
2079 return false;
2082 sal_uInt32 SdrTableObj::GetHdlCount() const
2084 sal_uInt32 nCount = SdrTextObj::GetHdlCount();
2085 const sal_Int32 nRowCount = mpImpl->getRowCount();
2086 const sal_Int32 nColCount = mpImpl->getColumnCount();
2088 if( nRowCount && nColCount )
2089 nCount += nRowCount + nColCount + 2 + 1;
2091 return nCount;
2094 void SdrTableObj::AddToHdlList(SdrHdlList& rHdlList) const
2096 const sal_Int32 nRowCount = mpImpl->getRowCount();
2097 const sal_Int32 nColCount = mpImpl->getColumnCount();
2099 // first add row handles
2100 std::vector<TableEdgeHdl*> aRowEdges(nRowCount + 1);
2101 for (auto const & rEdge : mpImpl->mpLayouter->getHorizontalEdges())
2103 Point aPoint(maRect.TopLeft());
2104 aPoint.AdjustY(rEdge.nPosition);
2106 std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, true, rEdge.nMin, rEdge.nMax, nColCount + 1));
2107 pHdl->SetPointNum(rEdge.nIndex);
2108 aRowEdges[rEdge.nIndex] = pHdl.get();
2109 rHdlList.AddHdl(std::move(pHdl));
2112 // second add column handles
2113 std::vector<TableEdgeHdl*> aColEdges(nColCount + 1);
2114 for (auto const & rEdge : mpImpl->mpLayouter->getVerticalEdges())
2116 Point aPoint(maRect.TopLeft());
2117 aPoint.AdjustX(rEdge.nPosition);
2119 std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, false, rEdge.nMin, rEdge.nMax, nRowCount + 1));
2120 pHdl->SetPointNum(rEdge.nIndex);
2121 aColEdges[rEdge.nIndex] = pHdl.get();
2122 rHdlList.AddHdl(std::move(pHdl));
2125 // now add visible edges to row and column handles
2126 if( mpImpl->mpLayouter )
2128 TableLayouter& rLayouter = *mpImpl->mpLayouter;
2130 sal_Int32 nY = 0;
2132 for( sal_Int32 nRow = 0; nRow <= nRowCount; ++nRow )
2134 const sal_Int32 nRowHeight = (nRow == nRowCount) ? 0 : rLayouter.getRowHeight(nRow);
2135 sal_Int32 nX = 0;
2137 for( sal_Int32 nCol = 0; nCol <= nColCount; ++nCol )
2139 const sal_Int32 nColWidth = (nCol == nColCount) ? 0 : rLayouter.getColumnWidth(nCol);
2141 if( nRowHeight > 0 )
2143 if( rLayouter.isEdgeVisible( nCol, nRow, false ) )
2144 aColEdges[nCol]->SetEdge( nRow, nY, nY + nRowHeight, (rLayouter.getBorderLine( nCol, nRow, false ) == nullptr) ? Visible : Invisible);
2147 if( nColWidth > 0 )
2149 if( rLayouter.isEdgeVisible( nCol, nRow, true ) )
2150 aRowEdges[nRow]->SetEdge( nCol, nX, nX + nColWidth, (rLayouter.getBorderLine( nCol, nRow, true ) == nullptr) ? Visible : Invisible);
2153 nX += nColWidth;
2156 nY += nRowHeight;
2160 // add remaining handles
2161 SdrHdlList tempList(nullptr);
2162 tempList.AddHdl( std::make_unique<TableBorderHdl>( maRect, !IsTextEditActive() ) );
2163 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopLeft(),SdrHdlKind::UpperLeft) );
2164 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopCenter(),SdrHdlKind::Upper) );
2165 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopRight(),SdrHdlKind::UpperRight) );
2166 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.LeftCenter(),SdrHdlKind::Left) );
2167 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.RightCenter(),SdrHdlKind::Right) );
2168 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomLeft(),SdrHdlKind::LowerLeft) );
2169 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomCenter(),SdrHdlKind::Lower) );
2170 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomRight(),SdrHdlKind::LowerRight) );
2171 for( size_t nHdl = 0; nHdl < tempList.GetHdlCount(); ++nHdl )
2172 tempList.GetHdl(nHdl)->SetMoveOutside(true);
2173 tempList.MoveTo(rHdlList);
2175 const size_t nHdlCount = rHdlList.GetHdlCount();
2176 for( size_t nHdl = 0; nHdl < nHdlCount; ++nHdl )
2177 rHdlList.GetHdl(nHdl)->SetObj(const_cast<SdrTableObj*>(this));
2180 // Dragging
2182 bool SdrTableObj::hasSpecialDrag() const
2184 return true;
2187 bool SdrTableObj::beginSpecialDrag(SdrDragStat& rDrag) const
2189 const SdrHdl* pHdl = rDrag.GetHdl();
2190 const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2192 switch( eHdl )
2194 case SdrHdlKind::UpperLeft:
2195 case SdrHdlKind::Upper:
2196 case SdrHdlKind::UpperRight:
2197 case SdrHdlKind::Left:
2198 case SdrHdlKind::Right:
2199 case SdrHdlKind::LowerLeft:
2200 case SdrHdlKind::Lower:
2201 case SdrHdlKind::LowerRight:
2202 case SdrHdlKind::Move:
2204 break;
2207 case SdrHdlKind::User:
2209 rDrag.SetEndDragChangesAttributes(false);
2210 rDrag.SetNoSnap();
2211 break;
2214 default:
2216 return false;
2220 return true;
2223 bool SdrTableObj::applySpecialDrag(SdrDragStat& rDrag)
2225 bool bRet(true);
2226 const SdrHdl* pHdl = rDrag.GetHdl();
2227 const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2229 switch( eHdl )
2231 case SdrHdlKind::UpperLeft:
2232 case SdrHdlKind::Upper:
2233 case SdrHdlKind::UpperRight:
2234 case SdrHdlKind::Left:
2235 case SdrHdlKind::Right:
2236 case SdrHdlKind::LowerLeft:
2237 case SdrHdlKind::Lower:
2238 case SdrHdlKind::LowerRight:
2240 const tools::Rectangle aNewRectangle(ImpDragCalcRect(rDrag));
2242 if (aNewRectangle != maRect)
2244 NbcSetLogicRect(aNewRectangle);
2247 break;
2250 case SdrHdlKind::Move:
2252 NbcMove( Size( rDrag.GetDX(), rDrag.GetDY() ) );
2253 break;
2256 case SdrHdlKind::User:
2258 rDrag.SetEndDragChangesAttributes(false);
2259 rDrag.SetNoSnap();
2260 const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
2262 if( pEdgeHdl )
2264 if( IsInserted() )
2266 rDrag.SetEndDragChangesAttributes(true);
2267 rDrag.SetEndDragChangesLayout(true);
2270 mpImpl->DragEdge( pEdgeHdl->IsHorizontalEdge(), pEdgeHdl->GetPointNum(), pEdgeHdl->GetValidDragOffset( rDrag ) );
2272 break;
2275 default:
2277 bRet = false;
2281 return bRet;
2284 basegfx::B2DPolyPolygon SdrTableObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
2286 basegfx::B2DPolyPolygon aRetval;
2287 const SdrHdl* pHdl = rDrag.GetHdl();
2289 if( pHdl && (SdrHdlKind::User == pHdl->GetKind()) )
2291 const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
2293 if( pEdgeHdl )
2295 aRetval = pEdgeHdl->getSpecialDragPoly( rDrag );
2299 return aRetval;
2303 // Create
2306 bool SdrTableObj::BegCreate(SdrDragStat& rStat)
2308 rStat.SetOrtho4Possible();
2309 tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
2310 aRect1.Justify();
2311 rStat.SetActionRect(aRect1);
2312 maRect = aRect1;
2313 return true;
2317 bool SdrTableObj::MovCreate(SdrDragStat& rStat)
2319 tools::Rectangle aRect1;
2320 rStat.TakeCreateRect(aRect1);
2321 ImpJustifyRect(aRect1);
2322 rStat.SetActionRect(aRect1);
2323 maRect = aRect1; // for ObjName
2324 SetBoundRectDirty();
2325 bSnapRectDirty=true;
2326 return true;
2330 bool SdrTableObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
2332 rStat.TakeCreateRect(maRect);
2333 ImpJustifyRect(maRect);
2334 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
2337 void SdrTableObj::BrkCreate(SdrDragStat& /*rStat*/)
2342 bool SdrTableObj::BckCreate(SdrDragStat& /*rStat*/)
2344 return true;
2348 basegfx::B2DPolyPolygon SdrTableObj::TakeCreatePoly(const SdrDragStat& rDrag) const
2350 tools::Rectangle aRect1;
2351 rDrag.TakeCreateRect(aRect1);
2352 aRect1.Justify();
2354 basegfx::B2DPolyPolygon aRetval;
2355 const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aRect1);
2356 aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
2357 return aRetval;
2361 PointerStyle SdrTableObj::GetCreatePointer() const
2363 return PointerStyle::Cross;
2367 void SdrTableObj::createCell( CellRef& xNewCell )
2369 xNewCell = Cell::create( *this );
2373 SdrObjGeoData *SdrTableObj::NewGeoData() const
2375 return new TableObjectGeoData;
2379 void SdrTableObj::SaveGeoData(SdrObjGeoData& rGeo) const
2381 DBG_ASSERT( dynamic_cast< TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" );
2382 SdrTextObj::SaveGeoData (rGeo);
2384 static_cast<TableObjectGeoData &>(rGeo).maLogicRect = maLogicRect;
2388 void SdrTableObj::RestGeoData(const SdrObjGeoData& rGeo)
2390 DBG_ASSERT( dynamic_cast< const TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" );
2392 maLogicRect = static_cast<const TableObjectGeoData &>(rGeo).maLogicRect;
2394 SdrTextObj::RestGeoData (rGeo);
2396 if( mpImpl.is() )
2397 mpImpl->LayoutTable(maRect, false, false);
2398 ActionChanged();
2401 void SdrTableObj::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
2403 if(!mpImpl.is())
2405 return;
2408 mpImpl->CropTableModelToSelection(rStart, rEnd);
2411 void SdrTableObj::DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn, const bool bOptimize, const bool bMinimize )
2413 if( mpImpl.is() && mpImpl->mpLayouter )
2415 TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
2416 mpImpl->mpLayouter->DistributeColumns( maRect, nFirstColumn, nLastColumn, bOptimize, bMinimize );
2421 void SdrTableObj::DistributeRows( sal_Int32 nFirstRow, sal_Int32 nLastRow, const bool bOptimize, const bool bMinimize )
2423 if( mpImpl.is() && mpImpl->mpLayouter )
2425 TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
2426 mpImpl->mpLayouter->DistributeRows( maRect, nFirstRow, nLastRow, bOptimize, bMinimize );
2431 void SdrTableObj::SetChanged()
2433 if( mpImpl.is() )
2435 mpImpl->LayoutTable( maRect, false, false );
2438 ::SdrTextObj::SetChanged();
2442 void SdrTableObj::uno_lock()
2444 if( mpImpl.is() && mpImpl->mxTable.is() )
2445 mpImpl->mxTable->lockBroadcasts();
2449 void SdrTableObj::uno_unlock()
2451 if( mpImpl.is() && mpImpl->mxTable.is() )
2452 mpImpl->mxTable->unlockBroadcasts();
2455 void SdrTableObj::dumpAsXml(xmlTextWriterPtr pWriter) const
2457 xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObj"));
2458 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
2460 SdrObject::dumpAsXml(pWriter);
2462 mpImpl->dumpAsXml(pWriter);
2464 xmlTextWriterEndElement(pWriter);
2467 bool SdrTableObj::createTableEdgesJson(boost::property_tree::ptree & rJsonRoot)
2469 if (!mpImpl.is() || !mpImpl->mxTable.is())
2470 return false;
2472 tools::Rectangle aRect = GetCurrentBoundRect();
2473 boost::property_tree::ptree aTableColumns;
2475 aTableColumns.put("tableOffset", convertMm100ToTwip(aRect.Left()));
2477 boost::property_tree::ptree aEntries;
2478 auto const & aEdges = mpImpl->mpLayouter->getVerticalEdges();
2479 for (auto & rEdge : aEdges)
2481 if (rEdge.nIndex == 0)
2483 aTableColumns.put("left", convertMm100ToTwip(rEdge.nPosition));
2485 else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
2487 aTableColumns.put("right", convertMm100ToTwip(rEdge.nPosition));
2489 else
2491 boost::property_tree::ptree aEntry;
2492 aEntry.put("position", convertMm100ToTwip(rEdge.nPosition));
2493 aEntry.put("min", convertMm100ToTwip(rEdge.nPosition + rEdge.nMin));
2494 aEntry.put("max", convertMm100ToTwip(rEdge.nPosition + rEdge.nMax));
2495 aEntry.put("hidden", false);
2496 aEntries.push_back(std::make_pair("", aEntry));
2499 aTableColumns.push_back(std::make_pair("entries", aEntries));
2501 rJsonRoot.add_child("columns", aTableColumns);
2503 boost::property_tree::ptree aTableRows;
2505 aTableRows.put("tableOffset", convertMm100ToTwip(aRect.Top()));
2507 boost::property_tree::ptree aEntries;
2508 auto const & aEdges = mpImpl->mpLayouter->getHorizontalEdges();
2509 for (auto & rEdge : aEdges)
2511 if (rEdge.nIndex == 0)
2513 aTableRows.put("left", convertMm100ToTwip(rEdge.nPosition));
2515 else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
2517 aTableRows.put("right", convertMm100ToTwip(rEdge.nPosition));
2519 else
2521 boost::property_tree::ptree aEntry;
2522 aEntry.put("position", convertMm100ToTwip(rEdge.nPosition));
2523 aEntry.put("min", convertMm100ToTwip(rEdge.nPosition + rEdge.nMin));
2524 aEntry.put("max", convertMm100ToTwip(rEdge.nPosition + rEdge.nMax));
2525 aEntry.put("hidden", false);
2526 aEntries.push_back(std::make_pair("", aEntry));
2529 aTableRows.push_back(std::make_pair("entries", aEntries));
2531 rJsonRoot.add_child("rows", aTableRows);
2532 return true;
2537 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */