Bump version to 6.4-15
[LibreOffice.git] / svx / source / table / svdotable.cxx
blob47e079a3f7c2c86ef8e811a75331ae6b49024781
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 <vcl/canvastools.hxx>
26 #include <vcl/ptrstyle.hxx>
27 #include <com/sun/star/style/XStyle.hpp>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <basegfx/polygon/b2dpolygontools.hxx>
30 #include <basegfx/polygon/b2dpolypolygon.hxx>
31 #include <basegfx/polygon/b2dpolygon.hxx>
32 #include <svl/style.hxx>
33 #include <editeng/editstat.hxx>
34 #include <editeng/outlobj.hxx>
35 #include <svx/svdview.hxx>
36 #include <sdr/properties/textproperties.hxx>
37 #include <svx/svdotable.hxx>
38 #include <svx/svdhdl.hxx>
39 #include "viewcontactoftableobj.hxx"
40 #include <svx/svdoutl.hxx>
41 #include <svx/svddrag.hxx>
42 #include <svx/svdpagv.hxx>
43 #include <tablemodel.hxx>
44 #include <cell.hxx>
45 #include <svx/xflclit.hxx>
46 #include "tablelayouter.hxx"
47 #include <svx/svdetc.hxx>
48 #include "tablehandles.hxx"
49 #include <editeng/boxitem.hxx>
50 #include <svx/framelink.hxx>
51 #include <svx/sdr/table/tabledesign.hxx>
52 #include <svx/svdundo.hxx>
53 #include <svx/strings.hrc>
54 #include <svx/dialmgr.hxx>
55 #include <editeng/writingmodeitem.hxx>
56 #include <editeng/frmdiritem.hxx>
57 #include <svx/xflhtit.hxx>
58 #include <svx/xflftrit.hxx>
59 #include <svx/xfltrit.hxx>
60 #include <cppuhelper/implbase.hxx>
61 #include <libxml/xmlwriter.h>
63 #include <boost/property_tree/json_parser.hpp>
65 using ::com::sun::star::uno::Any;
66 using ::com::sun::star::uno::Reference;
67 using ::com::sun::star::uno::UNO_QUERY;
68 using ::com::sun::star::uno::UNO_QUERY_THROW;
69 using ::com::sun::star::uno::Exception;
70 using ::com::sun::star::container::XIndexAccess;
71 using ::com::sun::star::style::XStyle;
72 using ::com::sun::star::table::XTableRows;
73 using ::com::sun::star::table::XTableColumns;
74 using ::com::sun::star::table::XTable;
75 using ::com::sun::star::beans::XPropertySet;
76 using ::com::sun::star::util::XModifyBroadcaster;
77 using sdr::properties::TextProperties;
78 using sdr::properties::BaseProperties;
79 using namespace ::com::sun::star;
80 using namespace ::com::sun::star::text;
81 using namespace ::com::sun::star::container;
82 using namespace ::com::sun::star::style;
84 namespace sdr { namespace table {
86 class TableProperties : public TextProperties
88 protected:
89 // create a new itemset
90 std::unique_ptr<SfxItemSet> CreateObjectSpecificItemSet(SfxItemPool& rPool) override;
92 public:
93 // basic constructor
94 explicit TableProperties(SdrObject& rObj );
96 // constructor for copying, but using new object
97 TableProperties(const TableProperties& rProps, SdrObject& rObj );
99 // Clone() operator, normally just calls the local copy constructor
100 std::unique_ptr<BaseProperties> Clone(SdrObject& rObj) const override;
102 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 class TableObjectGeoData : public SdrTextObjGeoData
147 public:
148 tools::Rectangle maLogicRect;
151 TableStyleSettings::TableStyleSettings()
152 : mbUseFirstRow(true)
153 , mbUseLastRow(false)
154 , mbUseFirstColumn(false)
155 , mbUseLastColumn(false)
156 , mbUseRowBanding(true)
157 , mbUseColumnBanding(false)
161 TableStyleSettings::TableStyleSettings( const TableStyleSettings& rStyle )
163 (*this) = rStyle;
166 TableStyleSettings& TableStyleSettings::operator=(const TableStyleSettings& rStyle)
168 mbUseFirstRow = rStyle.mbUseFirstRow;
169 mbUseLastRow = rStyle.mbUseLastRow;
170 mbUseFirstColumn = rStyle.mbUseFirstColumn;
171 mbUseLastColumn = rStyle.mbUseLastColumn;
172 mbUseRowBanding = rStyle.mbUseRowBanding;
173 mbUseColumnBanding = rStyle.mbUseColumnBanding;
174 return *this;
177 bool TableStyleSettings::operator==( const TableStyleSettings& rStyle ) const
179 return
180 (mbUseFirstRow == rStyle.mbUseFirstRow) &&
181 (mbUseLastRow == rStyle.mbUseLastRow) &&
182 (mbUseFirstColumn == rStyle.mbUseFirstColumn) &&
183 (mbUseLastColumn == rStyle.mbUseLastColumn) &&
184 (mbUseRowBanding == rStyle.mbUseRowBanding) &&
185 (mbUseColumnBanding == rStyle.mbUseColumnBanding);
189 class SdrTableObjImpl : public TableDesignUser, public ::cppu::WeakImplHelper< css::util::XModifyListener >
191 public:
192 CellRef mxActiveCell;
193 TableModelRef mxTable;
194 SdrTableObj* mpTableObj;
195 std::unique_ptr<TableLayouter> mpLayouter;
196 CellPos maEditPos;
197 TableStyleSettings maTableStyle;
198 Reference< XIndexAccess > mxTableStyle;
199 std::vector<std::unique_ptr<SdrUndoAction>> maUndos;
200 bool mbSkipChangeLayout;
202 void CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd);
204 CellRef getCell( const CellPos& rPos ) const;
205 void LayoutTable( tools::Rectangle& rArea, bool bFitWidth, bool bFitHeight );
207 void ApplyCellStyles();
208 void UpdateCells( tools::Rectangle const & rArea );
210 SdrTableObjImpl();
211 virtual ~SdrTableObjImpl() override;
213 void init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows );
214 void dispose();
216 sal_Int32 getColumnCount() const;
217 /// Get widths of the columns in the table.
218 std::vector<sal_Int32> getColumnWidths() const;
219 sal_Int32 getRowCount() const;
221 void DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset );
223 SdrTableObjImpl& operator=( const SdrTableObjImpl& rSource );
225 // XModifyListener
226 virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
228 // XEventListener
229 virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
231 void update();
233 void connectTableStyle();
234 void disconnectTableStyle();
235 virtual bool isInUse() override;
236 void dumpAsXml(xmlTextWriterPtr pWriter) const;
237 private:
238 static SdrTableObjImpl* lastLayoutTable;
239 static tools::Rectangle lastLayoutInputRectangle;
240 static tools::Rectangle lastLayoutResultRectangle;
241 static bool lastLayoutFitWidth;
242 static bool lastLayoutFitHeight;
243 static WritingMode lastLayoutMode;
244 static sal_Int32 lastRowCount;
245 static sal_Int32 lastColCount;
246 static std::vector<sal_Int32> lastColWidths;
249 SdrTableObjImpl* SdrTableObjImpl::lastLayoutTable = nullptr;
250 tools::Rectangle SdrTableObjImpl::lastLayoutInputRectangle;
251 tools::Rectangle SdrTableObjImpl::lastLayoutResultRectangle;
252 bool SdrTableObjImpl::lastLayoutFitWidth;
253 bool SdrTableObjImpl::lastLayoutFitHeight;
254 WritingMode SdrTableObjImpl::lastLayoutMode;
255 sal_Int32 SdrTableObjImpl::lastRowCount;
256 sal_Int32 SdrTableObjImpl::lastColCount;
257 std::vector<sal_Int32> SdrTableObjImpl::lastColWidths;
259 SdrTableObjImpl::SdrTableObjImpl()
260 : mpTableObj( nullptr )
261 , mbSkipChangeLayout(false)
266 SdrTableObjImpl::~SdrTableObjImpl()
268 if( lastLayoutTable == this )
269 lastLayoutTable = nullptr;
273 void SdrTableObjImpl::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
275 if(!mxTable.is())
277 return;
280 const sal_Int32 nColumns(rEnd.mnCol - rStart.mnCol + 1);
281 const sal_Int32 nRows(rEnd.mnRow - rStart.mnRow + 1);
283 if(nColumns < 1 || nRows < 1 || nColumns > getColumnCount() || nRows > getRowCount())
285 return;
288 // tdf#116977 First thought was to create the new TableModel, copy data to it and then exchange
289 // mxTable and dispose old one. This does *not* work, even when all stuff looks nicely referenced
290 // and safe *because* Cell::create gets handed over the current SdrTableObj, hands it to
291 // ::Cell and there the local mxTable is initialized using rTableObj.getTable() (!). Due to This,
292 // the new created Cells in a new created TableModel based on given mpTableObj *will be disposed*
293 // when the old mxTable gets disposed - ARGH!
294 // To avoid, change strategy: Remember old TableModel, reset mxTable immediately - this is the
295 // SdrTableObjImpl of the current SdrTableObj anyways. Luckily, this works as intended...
297 // remember old TableModel
298 TableModelRef xOldTable(mxTable);
300 // immediately create new one and initialize. This creates ::Cell's which then will use
301 // the correct TableModel (accessed through SdrTableObj, but using local mxTable)
302 mxTable = new TableModel(mpTableObj);
303 mxTable->init(nColumns, nRows);
305 // copy cells
306 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
308 for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol ) try
310 CellRef xTargetCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
311 if( xTargetCell.is() )
312 xTargetCell->cloneFrom( dynamic_cast< Cell* >( xOldTable->getCellByPosition( rStart.mnCol + nCol, rStart.mnRow + nRow ).get() ) );
314 catch( Exception& )
316 OSL_FAIL( "SdrTableObj::CropTableModelToSelection(), exception caught!" );
320 // copy row heights
321 Reference< XTableRows > xNewRows(mxTable->getRows(), css::uno::UNO_SET_THROW );
322 const OUString sHeight( "Height" );
323 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
325 Reference< XPropertySet > xNewSet( xNewRows->getByIndex( nRow ), UNO_QUERY_THROW );
326 xNewSet->setPropertyValue( sHeight, Any( mpLayouter->getRowHeight( rStart.mnRow + nRow ) ) );
329 // copy column widths
330 Reference< XTableColumns > xNewColumns( mxTable->getColumns(), css::uno::UNO_SET_THROW );
331 const OUString sWidth( "Width" );
332 for( sal_Int32 nCol = 0; nCol < nColumns; ++nCol )
334 Reference< XPropertySet > xNewSet( xNewColumns->getByIndex( nCol ), UNO_QUERY_THROW );
335 xNewSet->setPropertyValue( sWidth, Any( mpLayouter->getColumnWidth( rStart.mnCol + nCol ) ) );
338 // reset layouter which still holds a copy to old TableModel
339 mpLayouter.reset();
341 // cleanup old TableModel
343 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
344 xOldTable->removeModifyListener( xListener );
345 xOldTable->dispose();
346 xOldTable.clear();
349 // create and hand over to new TableLayouter
350 mpLayouter.reset(new TableLayouter( mxTable ));
352 // add needed listener to react on changes
353 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
354 mxTable->addModifyListener( xListener );
356 // Apply Style to Cells
357 ApplyCellStyles();
359 // layout cropped table
360 LayoutTable( mpTableObj->maRect, false, false );
363 void SdrTableObjImpl::init( SdrTableObj* pTable, sal_Int32 nColumns, sal_Int32 nRows )
365 mpTableObj = pTable;
366 mxTable = new TableModel( pTable );
367 mxTable->init( nColumns, nRows );
368 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
369 mxTable->addModifyListener( xListener );
370 mpLayouter.reset(new TableLayouter( mxTable ));
371 LayoutTable( mpTableObj->maRect, true, true );
372 mpTableObj->maLogicRect = mpTableObj->maRect;
376 SdrTableObjImpl& SdrTableObjImpl::operator=( const SdrTableObjImpl& rSource )
378 if(this == &rSource)
380 return *this;
383 if(nullptr == mpTableObj || nullptr == rSource.mpTableObj)
385 // error: need both SdrObjects to successfully copy data
386 return *this;
389 // remove evtl. listeners from local
390 disconnectTableStyle();
392 // reset layouter which holds a copy
393 mpLayouter.reset();
395 // cleanup local mxTable if used
396 if( mxTable.is() )
398 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
399 mxTable->removeModifyListener( xListener );
400 mxTable->dispose();
401 mxTable.clear();
404 // tdf#127481: reset active cell reference
405 mxActiveCell.clear();
407 // copy TableStyle (short internal data)
408 maTableStyle = rSource.maTableStyle;
410 // create/copy new mxTable. This will copy all needed cells, too
411 mxTable = new TableModel( mpTableObj, rSource.mxTable );
413 // create and hand over to new TableLayouter
414 mpLayouter.reset(new TableLayouter( mxTable ));
416 // add needed listener to react on changes
417 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
418 mxTable->addModifyListener( xListener );
420 // handle TableStyle
421 Reference< XIndexAccess > xNewTableStyle;
422 SdrModel& rSourceSdrModel(rSource.mpTableObj->getSdrModelFromSdrObject());
423 SdrModel& rTargetSdrModel(mpTableObj->getSdrModelFromSdrObject());
425 if(rSource.mxTableStyle.is() && &rSourceSdrModel == &rTargetSdrModel)
427 // source and target model the same -> keep current TableStyle
428 xNewTableStyle = rSource.mxTableStyle;
431 if(!xNewTableStyle.is() && rSource.mxTableStyle.is()) try
433 // search in traget SdrModel for that TableStyle
434 const OUString sStyleName( Reference< XNamed >( rSource.mxTableStyle, UNO_QUERY_THROW )->getName() );
435 Reference< XStyleFamiliesSupplier > xSFS(rTargetSdrModel.getUnoModel(), UNO_QUERY_THROW );
436 Reference< XNameAccess > xFamilyNameAccess( xSFS->getStyleFamilies(), css::uno::UNO_SET_THROW );
437 const OUString sFamilyName( "table" );
438 Reference< XNameAccess > xTableFamilyAccess( xFamilyNameAccess->getByName( sFamilyName ), UNO_QUERY_THROW );
440 if( xTableFamilyAccess->hasByName( sStyleName ) )
442 // found table style with the same name
443 xTableFamilyAccess->getByName( sStyleName ) >>= xNewTableStyle;
445 else
447 // copy or? Not found, use 1st existing TableStyle (or none)
448 Reference< XIndexAccess > xIndexAccess( xTableFamilyAccess, UNO_QUERY_THROW );
449 xIndexAccess->getByIndex( 0 ) >>= xNewTableStyle;
452 catch( Exception& )
454 OSL_FAIL("svx::SdrTableObjImpl::operator=(), exception caught!");
457 // set that TableStyle
458 mxTableStyle = xNewTableStyle;
460 // Apply Style to Cells
461 ApplyCellStyles();
463 // copy geometry
464 mpTableObj->maRect = mpTableObj->maLogicRect;
466 // layout cloned table
467 LayoutTable( mpTableObj->maRect, false, false );
469 // re-connect to styles (evtl. in new SdrModel)
470 connectTableStyle();
472 return *this;
475 void SdrTableObjImpl::ApplyCellStyles()
477 if( !mxTable.is() || !mxTableStyle.is() )
478 return;
480 const sal_Int32 nColCount = getColumnCount();
481 const sal_Int32 nRowCount = getRowCount();
483 const TableStyleSettings& rStyle = maTableStyle;
485 CellPos aPos;
486 for( aPos.mnRow = 0; aPos.mnRow < nRowCount; ++aPos.mnRow )
488 const bool bFirstRow = (aPos.mnRow == 0) && rStyle.mbUseFirstRow;
489 const bool bLastRow = (aPos.mnRow == nRowCount-1) && rStyle.mbUseLastRow;
491 for( aPos.mnCol = 0; aPos.mnCol < nColCount; ++aPos.mnCol )
493 Reference< XStyle > xStyle;
495 // first and last row win first, if used and available
496 if( bFirstRow )
498 mxTableStyle->getByIndex(first_row_style) >>= xStyle;
500 else if( bLastRow )
502 mxTableStyle->getByIndex(last_row_style) >>= xStyle;
505 if( !xStyle.is() )
507 // next come first and last column, if used and available
508 if( rStyle.mbUseFirstColumn && (aPos.mnCol == 0) )
510 mxTableStyle->getByIndex(first_column_style) >>= xStyle;
512 else if( rStyle.mbUseLastColumn && (aPos.mnCol == nColCount-1) )
514 mxTableStyle->getByIndex(last_column_style) >>= xStyle;
518 if( !xStyle.is() && rStyle.mbUseRowBanding )
520 if( (aPos.mnRow & 1) == 0 )
522 mxTableStyle->getByIndex(even_rows_style) >>= xStyle;
524 else
526 mxTableStyle->getByIndex(odd_rows_style) >>= xStyle;
530 if( !xStyle.is() && rStyle.mbUseColumnBanding )
532 if( (aPos.mnCol & 1) == 0 )
534 mxTableStyle->getByIndex(even_columns_style) >>= xStyle;
536 else
538 mxTableStyle->getByIndex(odd_columns_style) >>= xStyle;
542 if( !xStyle.is() )
544 // use default cell style if non found yet
545 mxTableStyle->getByIndex(body_style) >>= xStyle;
549 if( xStyle.is() )
551 SfxUnoStyleSheet* pStyle = SfxUnoStyleSheet::getUnoStyleSheet(xStyle);
553 if( pStyle )
555 CellRef xCell( getCell( aPos ) );
556 if( xCell.is() && ( xCell->GetStyleSheet() != pStyle ) )
558 xCell->SetStyleSheet( pStyle, true );
567 void SdrTableObjImpl::dispose()
569 disconnectTableStyle();
570 mxTableStyle.clear();
572 mpLayouter.reset();
574 if( mxTable.is() )
576 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
577 mxTable->removeModifyListener( xListener );
578 mxTable->dispose();
579 mxTable.clear();
584 void SdrTableObjImpl::DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset )
586 if( (nEdge >= 0) && mxTable.is()) try
588 const OUString sSize( "Size" );
589 if( mbHorizontal )
591 if (nEdge <= getRowCount())
593 sal_Int32 nHeight = mpLayouter->getRowHeight( (!nEdge)?nEdge:(nEdge-1) );
594 if(nEdge==0)
595 nHeight -= nOffset;
596 else
597 nHeight += nOffset;
598 Reference< XIndexAccess > xRows( mxTable->getRows(), UNO_QUERY_THROW );
599 Reference< XPropertySet > xRowSet( xRows->getByIndex( (!nEdge)?nEdge:(nEdge-1) ), UNO_QUERY_THROW );
600 xRowSet->setPropertyValue( sSize, Any( nHeight ) );
603 else
606 fixes fdo#59889 and resizing of table in edge dragging
607 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
608 In LTR table vertical edge responsible for dragging of column x(x=0 to N-1) is, Edge x+1
609 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
610 In LTR table dragging of edge 0(for RTL table edge N) does nothing.
612 //Todo: Implement Dragging functionality for leftmost edge of table.
613 if (nEdge <= getColumnCount())
615 const bool bRTL = mpTableObj != nullptr && (mpTableObj->GetWritingMode() == WritingMode_RL_TB);
616 sal_Int32 nWidth;
617 if(bRTL)
619 nWidth = mpLayouter->getColumnWidth( nEdge );
621 else
623 nWidth = mpLayouter->getColumnWidth( (!nEdge)?nEdge:(nEdge-1) );
625 Reference< XIndexAccess > xCols( mxTable->getColumns(), UNO_QUERY_THROW );
626 nWidth += nOffset;
627 if(bRTL && nEdge<getColumnCount())
629 Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge ), UNO_QUERY_THROW );
630 xColSet->setPropertyValue( sSize, Any( nWidth ) );
632 else if(!bRTL && nEdge>0)
634 Reference< XPropertySet > xColSet( xCols->getByIndex( nEdge-1 ), UNO_QUERY_THROW );
635 xColSet->setPropertyValue( sSize, Any( nWidth ) );
637 /* To prevent the table resizing on edge dragging */
638 if( nEdge > 0 && nEdge < mxTable->getColumnCount() )
640 if( bRTL )
641 nEdge--;
643 nWidth = mpLayouter->getColumnWidth(nEdge);
644 nWidth = std::max(static_cast<sal_Int32>(nWidth - nOffset), sal_Int32(0));
646 Reference<XPropertySet> xColSet(xCols->getByIndex(nEdge), UNO_QUERY_THROW);
647 xColSet->setPropertyValue(sSize, Any(nWidth));
652 catch( Exception& )
654 OSL_FAIL( "svx::SdrTableObjImpl::DragEdge(), exception caught!" );
659 // XModifyListener
662 void SAL_CALL SdrTableObjImpl::modified( const css::lang::EventObject& /*aEvent*/ )
664 update();
667 void SdrTableObjImpl::update()
669 // source can be the table model itself or the assigned table template
670 TableModelNotifyGuard aGuard( mxTable.get() );
671 if( mpTableObj )
673 if( (maEditPos.mnRow >= getRowCount()) || (maEditPos.mnCol >= getColumnCount()) || (getCell( maEditPos ) != mxActiveCell) )
675 if(maEditPos.mnRow >= getRowCount())
676 maEditPos.mnRow = getRowCount()-1;
678 if(maEditPos.mnCol >= getColumnCount())
679 maEditPos.mnCol = getColumnCount()-1;
681 mpTableObj->setActiveCell( maEditPos );
684 ApplyCellStyles();
686 mpTableObj->maRect = mpTableObj->maLogicRect;
687 LayoutTable( mpTableObj->maRect, false, false );
689 mpTableObj->SetRectsDirty();
690 mpTableObj->ActionChanged();
691 mpTableObj->BroadcastObjectChange();
696 void SdrTableObjImpl::connectTableStyle()
698 if( mxTableStyle.is() )
700 Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
701 if( xBroadcaster.is() )
703 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
704 xBroadcaster->addModifyListener( xListener );
710 void SdrTableObjImpl::disconnectTableStyle()
712 if( mxTableStyle.is() )
714 Reference< XModifyBroadcaster > xBroadcaster( mxTableStyle, UNO_QUERY );
715 if( xBroadcaster.is() )
717 Reference< XModifyListener > xListener( static_cast< css::util::XModifyListener* >(this) );
718 xBroadcaster->removeModifyListener( xListener );
724 bool SdrTableObjImpl::isInUse()
726 return mpTableObj && mpTableObj->IsInserted();
729 void SdrTableObjImpl::dumpAsXml(xmlTextWriterPtr pWriter) const
731 xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObjImpl"));
732 if (mpLayouter)
733 mpLayouter->dumpAsXml(pWriter);
734 mxTable->dumpAsXml(pWriter);
735 xmlTextWriterEndElement(pWriter);
739 // XEventListener
742 void SAL_CALL SdrTableObjImpl::disposing( const css::lang::EventObject& /*Source*/ )
744 mxActiveCell.clear();
745 mxTable.clear();
746 mpLayouter.reset();
747 mpTableObj = nullptr;
751 CellRef SdrTableObjImpl::getCell( const CellPos& rPos ) const
753 CellRef xCell;
754 if( mxTable.is() ) try
756 xCell.set( dynamic_cast< Cell* >( mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
758 catch( Exception& )
760 OSL_FAIL( "svx::SdrTableObjImpl::getCell(), exception caught!" );
762 return xCell;
766 sal_Int32 SdrTableObjImpl::getColumnCount() const
768 return mxTable.is() ? mxTable->getColumnCount() : 0;
771 std::vector<sal_Int32> SdrTableObjImpl::getColumnWidths() const
773 std::vector<sal_Int32> aRet;
775 if (mxTable.is())
776 aRet = mxTable->getColumnWidths();
778 return aRet;
781 sal_Int32 SdrTableObjImpl::getRowCount() const
783 return mxTable.is() ? mxTable->getRowCount() : 0;
786 void SdrTableObjImpl::LayoutTable( tools::Rectangle& rArea, bool bFitWidth, bool bFitHeight )
788 if(mpLayouter)
790 // Optimization: SdrTableObj::SetChanged() can call this very often, repeatedly
791 // with the same settings, noticeably increasing load time. Skip if already done.
792 bool bInteractiveMightGrowBecauseTextChanged =
793 mpTableObj->IsReallyEdited() && (mpTableObj->IsAutoGrowHeight() || mpTableObj->IsAutoGrowWidth());
794 WritingMode writingMode = mpTableObj->GetWritingMode();
795 if( bInteractiveMightGrowBecauseTextChanged
796 || lastLayoutTable != this || lastLayoutInputRectangle != rArea
797 || lastLayoutFitWidth != bFitWidth || lastLayoutFitHeight != bFitHeight
798 || lastLayoutMode != writingMode
799 || lastRowCount != getRowCount()
800 || lastColCount != getColumnCount()
801 || lastColWidths != getColumnWidths() )
803 lastLayoutTable = this;
804 lastLayoutInputRectangle = rArea;
805 lastLayoutFitWidth = bFitWidth;
806 lastLayoutFitHeight = bFitHeight;
807 lastLayoutMode = writingMode;
808 lastRowCount = getRowCount();
809 lastColCount = getColumnCount();
810 // Column resize, when the total width and column count of the
811 // table is unchanged, but re-layout is still needed.
812 lastColWidths = getColumnWidths();
813 TableModelNotifyGuard aGuard( mxTable.get() );
814 mpLayouter->LayoutTable( rArea, bFitWidth, bFitHeight );
815 lastLayoutResultRectangle = rArea;
817 else
819 rArea = lastLayoutResultRectangle;
820 mpLayouter->UpdateBorderLayout();
825 void SdrTableObjImpl::UpdateCells( tools::Rectangle const & rArea )
827 if( mpLayouter && mxTable.is() )
829 TableModelNotifyGuard aGuard( mxTable.get() );
830 mpLayouter->updateCells( rArea );
831 mxTable->setModified(true);
836 // BaseProperties section
839 std::unique_ptr<sdr::properties::BaseProperties> SdrTableObj::CreateObjectSpecificProperties()
841 return std::make_unique<TableProperties>(*this);
845 // DrawContact section
848 std::unique_ptr<sdr::contact::ViewContact> SdrTableObj::CreateObjectSpecificViewContact()
850 return std::make_unique<sdr::contact::ViewContactOfTableObj>(*this);
853 SdrTableObj::SdrTableObj(SdrModel& rSdrModel)
854 : SdrTextObj(rSdrModel)
856 init( 1, 1 );
859 SdrTableObj::SdrTableObj(
860 SdrModel& rSdrModel,
861 const ::tools::Rectangle& rNewRect,
862 sal_Int32 nColumns,
863 sal_Int32 nRows)
864 : SdrTextObj(rSdrModel, rNewRect)
865 ,maLogicRect(rNewRect)
867 if( nColumns <= 0 )
868 nColumns = 1;
870 if( nRows <= 0 )
871 nRows = 1;
873 init( nColumns, nRows );
877 void SdrTableObj::init( sal_Int32 nColumns, sal_Int32 nRows )
879 bClosedObj = true;
881 mpImpl = new SdrTableObjImpl;
882 mpImpl->init( this, nColumns, nRows );
884 // Stuff done from old SetModel:
885 if( !maLogicRect.IsEmpty() )
887 maRect = maLogicRect;
888 mpImpl->LayoutTable( maRect, false, false );
893 SdrTableObj::~SdrTableObj()
895 mpImpl->dispose();
899 // table stuff
902 Reference< XTable > SdrTableObj::getTable() const
904 return Reference< XTable >( mpImpl->mxTable.get() );
908 bool SdrTableObj::isValid( const CellPos& rPos ) const
910 return (rPos.mnCol >= 0) && (rPos.mnCol < mpImpl->getColumnCount()) && (rPos.mnRow >= 0) && (rPos.mnRow < mpImpl->getRowCount());
914 CellPos SdrTableObj::getFirstCell()
916 return CellPos( 0,0 );
920 CellPos SdrTableObj::getLastCell() const
922 CellPos aPos;
923 if( mpImpl->mxTable.is() )
925 aPos.mnCol = mpImpl->getColumnCount()-1;
926 aPos.mnRow = mpImpl->getRowCount()-1;
928 return aPos;
932 CellPos SdrTableObj::getLeftCell( const CellPos& rPos, bool bEdgeTravel ) const
934 switch( GetWritingMode() )
936 default:
937 case WritingMode_LR_TB:
938 return getPreviousCell( rPos, bEdgeTravel );
939 case WritingMode_RL_TB:
940 return getNextCell( rPos, bEdgeTravel );
941 case WritingMode_TB_RL:
942 return getPreviousRow( rPos, bEdgeTravel );
947 CellPos SdrTableObj::getRightCell( const CellPos& rPos, bool bEdgeTravel ) const
949 switch( GetWritingMode() )
951 default:
952 case WritingMode_LR_TB:
953 return getNextCell( rPos, bEdgeTravel );
954 case WritingMode_RL_TB:
955 return getPreviousCell( rPos, bEdgeTravel );
956 case WritingMode_TB_RL:
957 return getNextRow( rPos, bEdgeTravel );
962 CellPos SdrTableObj::getUpCell( const CellPos& rPos, bool bEdgeTravel ) const
964 switch( GetWritingMode() )
966 default:
967 case WritingMode_LR_TB:
968 case WritingMode_RL_TB:
969 return getPreviousRow( rPos, bEdgeTravel );
970 case WritingMode_TB_RL:
971 return getPreviousCell( rPos, bEdgeTravel );
976 CellPos SdrTableObj::getDownCell( const CellPos& rPos, bool bEdgeTravel ) const
978 switch( GetWritingMode() )
980 default:
981 case WritingMode_LR_TB:
982 case WritingMode_RL_TB:
983 return getNextRow( rPos, bEdgeTravel );
984 case WritingMode_TB_RL:
985 return getNextCell( rPos, bEdgeTravel );
990 CellPos SdrTableObj::getPreviousCell( const CellPos& rPos, bool bEdgeTravel ) const
992 CellPos aPos( rPos );
993 if( mpImpl.is() )
995 CellRef xCell( mpImpl->getCell( aPos ) );
996 if( xCell.is() && xCell->isMerged() )
998 sal_Int32 nTemp = 0;
999 findMergeOrigin( mpImpl->mxTable.get(), aPos.mnCol, aPos.mnRow, aPos.mnCol, nTemp );
1002 if( aPos.mnCol > 0 )
1004 --aPos.mnCol;
1007 else if( bEdgeTravel && (aPos.mnRow > 0) )
1009 aPos.mnCol = mpImpl->mxTable->getColumnCount()-1;
1010 --aPos.mnRow;
1013 return aPos;
1017 CellPos SdrTableObj::getNextCell( const CellPos& rPos, bool bEdgeTravel ) const
1019 CellPos aPos( rPos );
1020 if( mpImpl.is() )
1022 CellRef xCell( mpImpl->getCell( aPos ) );
1023 if( xCell.is() )
1025 if( xCell->isMerged() )
1027 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
1029 xCell = mpImpl->getCell(aPos);
1031 if( xCell.is() )
1033 aPos.mnCol += xCell->getColumnSpan();
1034 aPos.mnRow = rPos.mnRow;
1037 else
1039 aPos.mnCol += xCell->getColumnSpan();
1042 if( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
1043 return aPos;
1045 if( bEdgeTravel && ((aPos.mnRow + 1) < mpImpl->getRowCount()) )
1047 aPos.mnCol = 0;
1048 aPos.mnRow += 1;
1049 return aPos;
1054 // last cell reached, no traveling possible
1055 return rPos;
1059 CellPos SdrTableObj::getPreviousRow( const CellPos& rPos, bool bEdgeTravel ) const
1061 CellPos aPos( rPos );
1062 if( mpImpl.is() )
1064 CellRef xCell( mpImpl->getCell( aPos ) );
1065 if( xCell.is() && xCell->isMerged() )
1067 sal_Int32 nTemp = 0;
1068 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, nTemp, aPos.mnRow );
1071 if( aPos.mnRow > 0 )
1073 --aPos.mnRow;
1075 else if( bEdgeTravel && (aPos.mnCol > 0) )
1077 aPos.mnRow = mpImpl->mxTable->getRowCount()-1;
1078 --aPos.mnCol;
1081 return aPos;
1085 CellPos SdrTableObj::getNextRow( const CellPos& rPos, bool bEdgeTravel ) const
1087 CellPos aPos( rPos );
1089 if( mpImpl.is() )
1091 CellRef xCell( mpImpl->getCell( rPos ) );
1092 if( xCell.is() )
1094 if( xCell->isMerged() )
1096 findMergeOrigin( mpImpl->mxTable, aPos.mnCol, aPos.mnRow, aPos.mnCol, aPos.mnRow );
1097 xCell = mpImpl->getCell(aPos);
1098 aPos.mnCol = rPos.mnCol;
1101 if( xCell.is() )
1102 aPos.mnRow += xCell->getRowSpan();
1104 if( aPos.mnRow < mpImpl->mxTable->getRowCount() )
1105 return aPos;
1107 if( bEdgeTravel && (aPos.mnCol + 1) < mpImpl->mxTable->getColumnCount() )
1109 aPos.mnRow = 0;
1110 aPos.mnCol += 1;
1112 while( aPos.mnCol < mpImpl->mxTable->getColumnCount() )
1114 xCell = mpImpl->getCell( aPos );
1115 if( xCell.is() && !xCell->isMerged() )
1116 return aPos;
1117 aPos.mnCol += 1;
1123 // last position reached, no more traveling possible
1124 return rPos;
1128 const TableStyleSettings& SdrTableObj::getTableStyleSettings() const
1130 if( mpImpl.is())
1132 return mpImpl->maTableStyle;
1134 else
1136 static TableStyleSettings aTmp;
1137 return aTmp;
1142 void SdrTableObj::setTableStyleSettings( const TableStyleSettings& rStyle )
1144 if( mpImpl.is() )
1146 mpImpl->maTableStyle = rStyle;
1147 mpImpl->update();
1152 TableHitKind SdrTableObj::CheckTableHit( const Point& rPos, sal_Int32& rnX, sal_Int32& rnY, const sal_uInt16 aTol ) const
1154 if( !mpImpl.is() || !mpImpl->mxTable.is() )
1155 return TableHitKind::NONE;
1157 rnX = 0;
1158 rnY = 0;
1160 const sal_Int32 nColCount = mpImpl->getColumnCount();
1161 const sal_Int32 nRowCount = mpImpl->getRowCount();
1163 sal_Int32 nX = rPos.X() - maRect.Left();
1164 sal_Int32 nY = rPos.Y() - maRect.Top();
1166 if( (nX < 0) || (nX > maRect.GetWidth()) || (nY < 0) || (nY > maRect.GetHeight() ) )
1167 return TableHitKind::NONE;
1169 // get vertical edge number and check for a hit
1170 const bool bRTL = (GetWritingMode() == WritingMode_RL_TB);
1171 bool bVrtHit = false;
1172 if( !bRTL )
1174 while( rnX <= nColCount )
1176 if( nX - aTol <= 0 )
1178 bVrtHit = true;
1179 break;
1182 if( rnX == nColCount )
1183 break;
1185 nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
1186 if( nX < 0 )
1187 break;
1188 rnX++;
1191 else
1193 rnX = nColCount;
1194 while( rnX >= 0 )
1196 if( nX - aTol <= 0 )
1198 bVrtHit = true;
1199 break;
1202 if( rnX == 0 )
1203 break;
1205 rnX--;
1206 nX -= mpImpl->mpLayouter->getColumnWidth( rnX );
1207 if( nX < 0 )
1208 break;
1212 // rnX is now the edge number left to the pointer, if it was hit bHrzHit is also true
1214 // get vertical edge number and check for a hit
1215 bool bHrzHit = false;
1216 while( rnY <= nRowCount )
1218 if( nY - aTol <= 0 )
1220 bHrzHit = true;
1221 break;
1224 if( rnY == nRowCount )
1225 break;
1227 nY -= mpImpl->mpLayouter->getRowHeight(rnY);
1228 if( nY < 0 )
1229 break;
1230 rnY++;
1233 // rnY is now the edge number above the pointer, if it was hit bVrtHit is also true
1235 if( bVrtHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, false ) )
1236 return TableHitKind::VerticallBorder;
1238 if( bHrzHit && mpImpl->mpLayouter->isEdgeVisible( rnX, rnY, true ) )
1239 return TableHitKind::HorizontalBorder;
1241 CellRef xCell( mpImpl->getCell( CellPos( rnX, rnY ) ) );
1242 if( xCell.is() && xCell->isMerged() )
1243 findMergeOrigin( mpImpl->mxTable.get(), rnX, rnY, rnX, rnY );
1245 if( xCell.is() )
1247 nX += mpImpl->mpLayouter->getColumnWidth( rnX );
1248 //Fix for fdo#62673 : non-editable cell in table on cell merge
1249 sal_Int32 i=0;
1250 while(xCell.is() && xCell->isMerged())
1252 nX += mpImpl->mpLayouter->getColumnWidth( rnX+i );
1253 i++;
1254 if(rnX+i < nColCount)
1255 xCell=mpImpl->getCell( CellPos( rnX+i, rnY) );
1256 else
1257 break;
1260 if( nX < xCell->GetTextLeftDistance() )
1261 return TableHitKind::Cell;
1264 return TableHitKind::CellTextArea;
1267 const SfxItemSet& SdrTableObj::GetActiveCellItemSet() const
1269 return getActiveCell()->GetItemSet();
1272 void SdrTableObj::setTableStyle( const Reference< XIndexAccess >& xTableStyle )
1274 if( mpImpl.is() && (mpImpl->mxTableStyle != xTableStyle) )
1276 mpImpl->disconnectTableStyle();
1277 mpImpl->mxTableStyle = xTableStyle;
1278 mpImpl->connectTableStyle();
1279 mpImpl->update();
1284 const Reference< XIndexAccess >& SdrTableObj::getTableStyle() const
1286 if( mpImpl.is() )
1288 return mpImpl->mxTableStyle;
1290 else
1292 static Reference< XIndexAccess > aTmp;
1293 return aTmp;
1298 // text stuff
1301 /** returns the currently active text. */
1302 SdrText* SdrTableObj::getActiveText() const
1304 return dynamic_cast< SdrText* >( getActiveCell().get() );
1308 /** returns the nth available text. */
1309 SdrText* SdrTableObj::getText( sal_Int32 nIndex ) const
1311 if( mpImpl->mxTable.is() )
1313 const sal_Int32 nColCount = mpImpl->getColumnCount();
1314 if( nColCount )
1316 CellPos aPos( nIndex % nColCount, nIndex / nColCount );
1318 CellRef xCell( mpImpl->getCell( aPos ) );
1319 return dynamic_cast< SdrText* >( xCell.get() );
1322 return nullptr;
1326 /** returns the number of texts available for this object. */
1327 sal_Int32 SdrTableObj::getTextCount() const
1329 if( mpImpl->mxTable.is() )
1331 const sal_Int32 nColCount = mpImpl->getColumnCount();
1332 const sal_Int32 nRowCount = mpImpl->getRowCount();
1334 return nColCount * nRowCount;
1336 else
1338 return 0;
1343 /** changes the current active text */
1344 void SdrTableObj::setActiveText( sal_Int32 nIndex )
1346 if( mpImpl.is() && mpImpl->mxTable.is() )
1348 const sal_Int32 nColCount = mpImpl->mxTable->getColumnCount();
1349 if( nColCount )
1351 CellPos aPos( nIndex % nColCount, nIndex / nColCount );
1352 if( isValid( aPos ) )
1353 setActiveCell( aPos );
1359 /** returns the index of the text that contains the given point or -1 */
1360 sal_Int32 SdrTableObj::CheckTextHit(const Point& rPnt) const
1362 if( mpImpl.is() && mpImpl->mxTable.is() )
1364 CellPos aPos;
1365 if( CheckTableHit( rPnt, aPos.mnCol, aPos.mnRow ) == TableHitKind::CellTextArea )
1366 return aPos.mnRow * mpImpl->mxTable->getColumnCount() + aPos.mnCol;
1369 return 0;
1372 SdrOutliner* SdrTableObj::GetCellTextEditOutliner( const Cell& rCell ) const
1374 if( mpImpl.is() && (mpImpl->getCell( mpImpl->maEditPos ).get() == &rCell) )
1375 return pEdtOutl;
1376 else
1377 return nullptr;
1380 const TableLayouter& SdrTableObj::getTableLayouter() const
1382 assert(mpImpl.is() && mpImpl->mpLayouter && "getTableLayouter() error: no mpImpl or mpLayouter (!)");
1383 return *(mpImpl->mpLayouter);
1386 bool SdrTableObj::IsAutoGrowHeight() const
1388 return true;
1391 bool SdrTableObj::IsAutoGrowWidth() const
1393 return true;
1396 bool SdrTableObj::HasText() const
1398 return true;
1401 bool SdrTableObj::IsTextEditActive( const CellPos& rPos )
1403 return pEdtOutl && mpImpl.is() && (rPos == mpImpl->maEditPos);
1407 void SdrTableObj::onEditOutlinerStatusEvent( EditStatus* pEditStatus )
1409 if( (pEditStatus->GetStatusWord() & EditStatusFlags::TextHeightChanged) && mpImpl.is() && mpImpl->mpLayouter )
1411 tools::Rectangle aRect0( maRect );
1412 maRect = maLogicRect;
1413 mpImpl->LayoutTable( maRect, false, false );
1414 SetRectsDirty();
1415 ActionChanged();
1416 BroadcastObjectChange();
1417 if (aRect0 != maRect)
1418 SendUserCall(SdrUserCallType::Resize,aRect0);
1423 void SdrTableObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
1425 rInfo.bResizeFreeAllowed=true;
1426 rInfo.bResizePropAllowed=true;
1427 rInfo.bRotateFreeAllowed=false;
1428 rInfo.bRotate90Allowed =false;
1429 rInfo.bMirrorFreeAllowed=false;
1430 rInfo.bMirror45Allowed =false;
1431 rInfo.bMirror90Allowed =false;
1433 // allow transparence
1434 rInfo.bTransparenceAllowed = true;
1436 rInfo.bShearAllowed =false;
1437 rInfo.bEdgeRadiusAllowed=false;
1438 rInfo.bCanConvToPath =false;
1439 rInfo.bCanConvToPoly =false;
1440 rInfo.bCanConvToPathLineToArea=false;
1441 rInfo.bCanConvToPolyLineToArea=false;
1442 rInfo.bCanConvToContour = false;
1446 sal_uInt16 SdrTableObj::GetObjIdentifier() const
1448 return static_cast<sal_uInt16>(OBJ_TABLE);
1451 void SdrTableObj::TakeTextRect( SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect, bool /*bLineWidth*/ ) const
1453 if( mpImpl.is() )
1454 TakeTextRect( mpImpl->maEditPos, rOutliner, rTextRect, bNoEditText, pAnchorRect );
1458 void SdrTableObj::TakeTextRect( const CellPos& rPos, SdrOutliner& rOutliner, tools::Rectangle& rTextRect, bool bNoEditText, tools::Rectangle* pAnchorRect ) const
1460 if( !mpImpl.is())
1461 return;
1463 CellRef xCell( mpImpl->getCell( rPos ) );
1464 if( !xCell.is() )
1465 return;
1467 tools::Rectangle aAnkRect;
1468 TakeTextAnchorRect( rPos, aAnkRect );
1470 SdrTextVertAdjust eVAdj=xCell->GetTextVerticalAdjust();
1472 EEControlBits nStat0=rOutliner.GetControlWord();
1473 nStat0 |= EEControlBits::AUTOPAGESIZE;
1474 rOutliner.SetControlWord(nStat0);
1475 rOutliner.SetMinAutoPaperSize(Size());
1476 rOutliner.SetMaxAutoPaperSize(aAnkRect.GetSize());
1477 rOutliner.SetPaperSize(aAnkRect.GetSize());
1479 // #103516# New try with _BLOCK for hor and ver after completely
1480 // supporting full width for vertical text.
1481 // if( SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
1482 // {
1483 rOutliner.SetMinAutoPaperSize(Size(aAnkRect.GetWidth(), 0));
1484 // }
1485 // else if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
1486 // {
1487 // rOutliner.SetMinAutoPaperSize(Size(0, aAnkRect.GetHeight()));
1488 // }
1491 // set text at outliner, maybe from edit outliner
1492 OutlinerParaObject* pPara= xCell->GetOutlinerParaObject();
1493 if (pEdtOutl && !bNoEditText && mpImpl->mxActiveCell == xCell )
1494 pPara=pEdtOutl->CreateParaObject().release();
1496 if (pPara)
1498 const bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner);
1499 const SdrTextObj* pTestObj(rOutliner.GetTextObj());
1501 if( !pTestObj || !bHitTest || (pTestObj != this) || (pTestObj->GetOutlinerParaObject() != xCell->GetOutlinerParaObject()) )
1503 if( bHitTest ) // #i33696# take back fix #i27510#
1504 rOutliner.SetTextObj( this );
1506 rOutliner.SetUpdateMode(true);
1507 rOutliner.SetText(*pPara);
1510 else
1512 rOutliner.SetTextObj( nullptr );
1515 if (pEdtOutl && !bNoEditText && pPara && mpImpl->mxActiveCell == xCell )
1516 delete pPara;
1518 rOutliner.SetUpdateMode(true);
1519 rOutliner.SetControlWord(nStat0);
1521 Point aTextPos(aAnkRect.TopLeft());
1522 Size aTextSiz(rOutliner.GetPaperSize());
1523 if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1525 long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
1526 if (eVAdj==SDRTEXTVERTADJUST_CENTER)
1527 aTextPos.AdjustY(nFreeHgt/2 );
1528 if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1529 aTextPos.AdjustY(nFreeHgt );
1532 if (pAnchorRect)
1533 *pAnchorRect=aAnkRect;
1535 rTextRect=tools::Rectangle(aTextPos,aTextSiz);
1539 const CellRef& SdrTableObj::getActiveCell() const
1541 if( mpImpl.is() )
1543 if( !mpImpl->mxActiveCell.is() )
1545 CellPos aPos;
1546 const_cast< SdrTableObj* >(this)->setActiveCell( aPos );
1548 return mpImpl->mxActiveCell;
1550 else
1552 static CellRef xCell;
1553 return xCell;
1558 sal_Int32 SdrTableObj::getColumnCount() const
1560 return mpImpl.is() ? mpImpl->getColumnCount() : 0;
1563 sal_Int32 SdrTableObj::getRowCount() const
1565 return mpImpl.is() ? mpImpl->getRowCount() : 0;
1568 void SdrTableObj::changeEdge(bool bHorizontal, int nEdge, sal_Int32 nOffset)
1570 if (mpImpl.is())
1571 mpImpl->DragEdge(bHorizontal, nEdge, nOffset);
1574 void SdrTableObj::setActiveCell( const CellPos& rPos )
1576 if( mpImpl.is() && mpImpl->mxTable.is() ) try
1578 mpImpl->mxActiveCell.set( dynamic_cast< Cell* >( mpImpl->mxTable->getCellByPosition( rPos.mnCol, rPos.mnRow ).get() ) );
1579 if( mpImpl->mxActiveCell.is() && mpImpl->mxActiveCell->isMerged() )
1581 CellPos aOrigin;
1582 findMergeOrigin( mpImpl->mxTable.get(), rPos.mnCol, rPos.mnRow, aOrigin.mnCol, aOrigin.mnRow );
1583 mpImpl->mxActiveCell.set( dynamic_cast< Cell* >( mpImpl->mxTable->getCellByPosition( aOrigin.mnCol, aOrigin.mnRow ).get() ) );
1584 mpImpl->maEditPos = aOrigin;
1586 else
1588 mpImpl->maEditPos = rPos;
1591 catch( Exception& )
1593 OSL_FAIL("SdrTableObj::setActiveCell(), exception caught!");
1598 void SdrTableObj::getActiveCellPos( CellPos& rPos ) const
1600 rPos = mpImpl->maEditPos;
1604 void SdrTableObj::getCellBounds( const CellPos& rPos, ::tools::Rectangle& rCellRect )
1606 if( mpImpl.is() )
1608 CellRef xCell( mpImpl->getCell( rPos ) );
1609 if( xCell.is() )
1610 rCellRect = xCell->getCellRect();
1615 void SdrTableObj::TakeTextAnchorRect(tools::Rectangle& rAnchorRect) const
1617 if( mpImpl.is() )
1618 TakeTextAnchorRect( mpImpl->maEditPos, rAnchorRect );
1622 void SdrTableObj::TakeTextAnchorRect( const CellPos& rPos, tools::Rectangle& rAnchorRect ) const
1624 tools::Rectangle aAnkRect(maRect);
1626 if( mpImpl.is() )
1628 CellRef xCell( mpImpl->getCell( rPos ) );
1629 if( xCell.is() )
1630 xCell->TakeTextAnchorRect( aAnkRect );
1633 ImpJustifyRect(aAnkRect);
1634 rAnchorRect=aAnkRect;
1638 void SdrTableObj::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin) const
1640 if( mpImpl.is() )
1641 TakeTextEditArea( mpImpl->maEditPos, pPaperMin, pPaperMax, pViewInit, pViewMin );
1645 void SdrTableObj::TakeTextEditArea( const CellPos& rPos, Size* pPaperMin, Size* pPaperMax, tools::Rectangle* pViewInit, tools::Rectangle* pViewMin ) const
1647 Size aPaperMin,aPaperMax;
1648 tools::Rectangle aViewInit;
1649 TakeTextAnchorRect( rPos, aViewInit );
1651 Size aAnkSiz(aViewInit.GetSize());
1652 aAnkSiz.AdjustWidth( -1 ); aAnkSiz.AdjustHeight( -1 ); // because GetSize() increments by one
1654 Size aMaxSiz(aAnkSiz.Width(),1000000);
1655 Size aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
1656 if (aTmpSiz.Height()!=0)
1657 aMaxSiz.setHeight(aTmpSiz.Height() );
1659 CellRef xCell( mpImpl->getCell( rPos ) );
1660 SdrTextVertAdjust eVAdj = xCell.is() ? xCell->GetTextVerticalAdjust() : SDRTEXTVERTADJUST_TOP;
1662 aPaperMax=aMaxSiz;
1664 aPaperMin.setWidth( aAnkSiz.Width() );
1666 if (pViewMin!=nullptr)
1668 *pViewMin=aViewInit;
1669 long nYFree=aAnkSiz.Height()-aPaperMin.Height();
1671 if (eVAdj==SDRTEXTVERTADJUST_TOP)
1673 pViewMin->AdjustBottom( -nYFree );
1675 else if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
1677 pViewMin->AdjustTop(nYFree );
1679 else
1681 pViewMin->AdjustTop(nYFree/2 );
1682 pViewMin->SetBottom(pViewMin->Top()+aPaperMin.Height() );
1687 if(IsVerticalWriting())
1688 aPaperMin.setWidth( 0 );
1689 else
1690 aPaperMin.setHeight( 0 );
1692 if (pPaperMin!=nullptr) *pPaperMin=aPaperMin;
1693 if (pPaperMax!=nullptr) *pPaperMax=aPaperMax;
1694 if (pViewInit!=nullptr) *pViewInit=aViewInit;
1698 EEAnchorMode SdrTableObj::GetOutlinerViewAnchorMode() const
1700 EEAnchorMode eRet=EEAnchorMode::TopLeft;
1701 CellRef xCell( getActiveCell() );
1702 if( xCell.is() )
1704 SdrTextVertAdjust eV=xCell->GetTextVerticalAdjust();
1707 if (eV==SDRTEXTVERTADJUST_TOP)
1709 eRet=EEAnchorMode::TopLeft;
1711 else if (eV==SDRTEXTVERTADJUST_BOTTOM)
1713 eRet=EEAnchorMode::BottomLeft;
1715 else
1717 eRet=EEAnchorMode::VCenterLeft;
1721 return eRet;
1725 OUString SdrTableObj::TakeObjNameSingul() const
1727 OUStringBuffer sName(SvxResId(STR_ObjNameSingulTable));
1729 OUString aName(GetName());
1730 if (!aName.isEmpty())
1732 sName.append(' ');
1733 sName.append('\'');
1734 sName.append(aName);
1735 sName.append('\'');
1738 return sName.makeStringAndClear();
1742 OUString SdrTableObj::TakeObjNamePlural() const
1744 return SvxResId(STR_ObjNamePluralTable);
1748 SdrTableObj* SdrTableObj::CloneSdrObject(SdrModel& rTargetModel) const
1750 return CloneHelper< SdrTableObj >(rTargetModel);
1753 SdrTableObj& SdrTableObj::operator=(const SdrTableObj& rObj)
1755 if( this == &rObj )
1757 return *this;
1760 // call parent
1761 // before SdrObject::operator= was called which is wrong from
1762 // the derivation hierarchy and may leave quite some entries
1763 // uninitialized. Changed to SdrTextObj::operator=, but had to adapt
1764 // usage of pNewOutlinerParaObject/mpText there due to nullptr access
1765 SdrTextObj::operator=(rObj);
1767 TableModelNotifyGuard aGuard( mpImpl.is() ? mpImpl->mxTable.get() : nullptr );
1769 maLogicRect = rObj.maLogicRect;
1770 maRect = rObj.maRect;
1771 aGeo = rObj.aGeo;
1772 eTextKind = rObj.eTextKind;
1773 bTextFrame = rObj.bTextFrame;
1774 aTextSize = rObj.aTextSize;
1775 bTextSizeDirty = rObj.bTextSizeDirty;
1776 bNoShear = rObj.bNoShear;
1777 bDisableAutoWidthOnDragging = rObj.bDisableAutoWidthOnDragging;
1779 // use SdrTableObjImpl::operator= now to
1780 // copy model data and other stuff (see there)
1781 *mpImpl = *rObj.mpImpl;
1783 return *this;
1787 const tools::Rectangle& SdrTableObj::GetSnapRect() const
1789 return maRect;
1793 void SdrTableObj::NbcSetSnapRect(const tools::Rectangle& rRect)
1795 NbcSetLogicRect( rRect );
1799 const tools::Rectangle& SdrTableObj::GetLogicRect() const
1801 return maLogicRect;
1805 void SdrTableObj::RecalcSnapRect()
1810 bool SdrTableObj::BegTextEdit(SdrOutliner& rOutl)
1812 if( pEdtOutl != nullptr )
1813 return false;
1815 pEdtOutl=&rOutl;
1817 mbInEditMode = true;
1819 rOutl.Init( OutlinerMode::TextObject );
1820 rOutl.SetRefDevice(getSdrModelFromSdrObject().GetRefDevice());
1822 bool bUpdateMode=rOutl.GetUpdateMode();
1823 if (bUpdateMode) rOutl.SetUpdateMode(false);
1824 Size aPaperMin;
1825 Size aPaperMax;
1826 tools::Rectangle aEditArea;
1827 TakeTextEditArea(&aPaperMin,&aPaperMax,&aEditArea,nullptr);
1829 rOutl.SetMinAutoPaperSize(aPaperMin);
1830 rOutl.SetMaxAutoPaperSize(aPaperMax);
1831 rOutl.SetPaperSize(aPaperMax);
1833 if (bUpdateMode) rOutl.SetUpdateMode(true);
1835 EEControlBits nStat=rOutl.GetControlWord();
1836 nStat |= EEControlBits::AUTOPAGESIZE;
1837 nStat &=~EEControlBits::STRETCHING;
1838 rOutl.SetControlWord(nStat);
1840 OutlinerParaObject* pPara = GetOutlinerParaObject();
1841 if(pPara)
1842 rOutl.SetText(*pPara);
1844 rOutl.UpdateFields();
1845 rOutl.ClearModifyFlag();
1847 return true;
1851 void SdrTableObj::EndTextEdit(SdrOutliner& rOutl)
1854 if (getSdrModelFromSdrObject().IsUndoEnabled() && !mpImpl->maUndos.empty())
1856 // These actions should be on the undo stack after text edit.
1857 for (std::unique_ptr<SdrUndoAction>& pAction : mpImpl->maUndos)
1858 getSdrModelFromSdrObject().AddUndo( std::move(pAction));
1859 mpImpl->maUndos.clear();
1861 getSdrModelFromSdrObject().AddUndo(getSdrModelFromSdrObject().GetSdrUndoFactory().CreateUndoGeoObject(*this));
1864 if(rOutl.IsModified())
1866 std::unique_ptr<OutlinerParaObject> pNewText;
1867 Paragraph* p1stPara = rOutl.GetParagraph( 0 );
1868 sal_Int32 nParaCnt = rOutl.GetParagraphCount();
1870 if(p1stPara)
1872 // to remove the grey field background
1873 rOutl.UpdateFields();
1875 // create new text object
1876 pNewText = rOutl.CreateParaObject( 0, nParaCnt );
1878 SetOutlinerParaObject(std::move(pNewText));
1881 pEdtOutl = nullptr;
1882 rOutl.Clear();
1883 EEControlBits nStat = rOutl.GetControlWord();
1884 nStat &= ~EEControlBits::AUTOPAGESIZE;
1885 rOutl.SetControlWord(nStat);
1887 mbInEditMode = false;
1891 OutlinerParaObject* SdrTableObj::GetOutlinerParaObject() const
1893 CellRef xCell( getActiveCell() );
1894 if( xCell.is() )
1895 return xCell->GetOutlinerParaObject();
1896 else
1897 return nullptr;
1901 void SdrTableObj::NbcSetOutlinerParaObject( std::unique_ptr<OutlinerParaObject> pTextObject)
1903 CellRef xCell( getActiveCell() );
1904 if( xCell.is() )
1906 // Update HitTestOutliner
1907 const SdrTextObj* pTestObj(getSdrModelFromSdrObject().GetHitTestOutliner().GetTextObj());
1909 if(pTestObj && pTestObj->GetOutlinerParaObject() == xCell->GetOutlinerParaObject())
1911 getSdrModelFromSdrObject().GetHitTestOutliner().SetTextObj(nullptr);
1914 xCell->SetOutlinerParaObject( std::move(pTextObject) );
1915 SetTextSizeDirty();
1916 NbcAdjustTextFrameWidthAndHeight();
1921 void SdrTableObj::NbcSetLogicRect(const tools::Rectangle& rRect)
1923 maLogicRect=rRect;
1924 ImpJustifyRect(maLogicRect);
1925 const bool bWidth = maLogicRect.getWidth() != maRect.getWidth();
1926 const bool bHeight = maLogicRect.getHeight() != maRect.getHeight();
1927 maRect = maLogicRect;
1928 if (mpImpl->mbSkipChangeLayout)
1929 // Avoid distributing newly available space between existing cells.
1930 NbcAdjustTextFrameWidthAndHeight();
1931 else
1932 NbcAdjustTextFrameWidthAndHeight(!bHeight, !bWidth);
1933 SetRectsDirty();
1937 void SdrTableObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool /* bShrinkOnly = false */ )
1939 tools::Rectangle aAdjustRect( rMaxRect );
1940 aAdjustRect.setHeight( GetLogicRect().getHeight() );
1941 SetLogicRect( aAdjustRect );
1945 void SdrTableObj::NbcMove(const Size& rSiz)
1947 maLogicRect.Move(rSiz);
1948 SdrTextObj::NbcMove( rSiz );
1949 if( mpImpl.is() )
1950 mpImpl->UpdateCells( maRect );
1954 void SdrTableObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
1956 tools::Rectangle aOldRect( maLogicRect );
1957 ResizeRect(maLogicRect,rRef,xFact,yFact);
1959 maRect = maLogicRect;
1960 NbcAdjustTextFrameWidthAndHeight( maLogicRect.GetHeight() == aOldRect.GetHeight(), maLogicRect.GetWidth() == aOldRect.GetWidth() );
1961 SetRectsDirty();
1965 bool SdrTableObj::AdjustTextFrameWidthAndHeight()
1967 tools::Rectangle aNewRect(maLogicRect);
1968 bool bRet=AdjustTextFrameWidthAndHeight(aNewRect);
1969 if (bRet)
1971 tools::Rectangle aBoundRect0;
1972 if (pUserCall!=nullptr)
1973 aBoundRect0=GetLastBoundRect();
1974 maRect = aNewRect;
1975 SetRectsDirty();
1976 SetChanged();
1977 BroadcastObjectChange();
1978 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
1980 return bRet;
1984 bool SdrTableObj::AdjustTextFrameWidthAndHeight(tools::Rectangle& rR, bool bHeight, bool bWidth) const
1986 if(rR.IsEmpty() || !mpImpl.is() || !mpImpl->mxTable.is())
1987 return false;
1989 tools::Rectangle aRectangle( rR );
1990 mpImpl->LayoutTable( aRectangle, !bWidth, !bHeight );
1992 if( aRectangle != rR )
1994 rR = aRectangle;
1995 return true;
1997 else
1999 return false;
2004 void SdrTableObj::NbcReformatText()
2006 NbcAdjustTextFrameWidthAndHeight();
2010 bool SdrTableObj::IsVerticalWriting() const
2012 const SvxWritingModeItem& rModeItem = GetObjectItem( SDRATTR_TEXTDIRECTION );
2013 return rModeItem.GetValue() == css::text::WritingMode_TB_RL;
2017 void SdrTableObj::SetVerticalWriting(bool bVertical)
2019 if(bVertical != IsVerticalWriting() )
2021 SvxWritingModeItem aModeItem( css::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION );
2022 SetObjectItem( aModeItem );
2027 WritingMode SdrTableObj::GetWritingMode() const
2029 SfxStyleSheet* pStyle = GetStyleSheet();
2030 if ( !pStyle )
2031 return WritingMode_LR_TB;
2033 WritingMode eWritingMode = WritingMode_LR_TB;
2034 const SfxItemSet &rSet = pStyle->GetItemSet();
2035 const SfxPoolItem *pItem;
2037 if ( rSet.GetItemState( SDRATTR_TEXTDIRECTION, false, &pItem ) == SfxItemState::SET )
2038 eWritingMode = static_cast< const SvxWritingModeItem * >( pItem )->GetValue();
2040 if ( ( eWritingMode != WritingMode_TB_RL ) &&
2041 ( rSet.GetItemState( EE_PARA_WRITINGDIR, false, &pItem ) == SfxItemState::SET ) )
2043 if ( static_cast< const SvxFrameDirectionItem * >( pItem )->GetValue() == SvxFrameDirection::Horizontal_LR_TB )
2044 eWritingMode = WritingMode_LR_TB;
2045 else
2046 eWritingMode = WritingMode_RL_TB;
2049 return eWritingMode;
2052 void SdrTableObj::AddUndo(SdrUndoAction* pUndo)
2054 mpImpl->maUndos.push_back(std::unique_ptr<SdrUndoAction>(pUndo));
2057 void SdrTableObj::SetSkipChangeLayout(bool bSkipChangeLayout)
2059 mpImpl->mbSkipChangeLayout = bSkipChangeLayout;
2062 bool SdrTableObj::IsReallyEdited() const
2064 return pEdtOutl && pEdtOutl->IsModified();
2067 bool SdrTableObj::IsFontwork() const
2069 return false;
2072 sal_uInt32 SdrTableObj::GetHdlCount() const
2074 sal_uInt32 nCount = SdrTextObj::GetHdlCount();
2075 const sal_Int32 nRowCount = mpImpl->getRowCount();
2076 const sal_Int32 nColCount = mpImpl->getColumnCount();
2078 if( nRowCount && nColCount )
2079 nCount += nRowCount + nColCount + 2 + 1;
2081 return nCount;
2084 void SdrTableObj::AddToHdlList(SdrHdlList& rHdlList) const
2086 const sal_Int32 nRowCount = mpImpl->getRowCount();
2087 const sal_Int32 nColCount = mpImpl->getColumnCount();
2089 // first add row handles
2090 std::vector<TableEdgeHdl*> aRowEdges(nRowCount + 1);
2091 for (auto const & rEdge : mpImpl->mpLayouter->getHorizontalEdges())
2093 Point aPoint(maRect.TopLeft());
2094 aPoint.AdjustY(rEdge.nPosition);
2096 std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, true, rEdge.nMin, rEdge.nMax, nColCount + 1));
2097 pHdl->SetPointNum(rEdge.nIndex);
2098 aRowEdges[rEdge.nIndex] = pHdl.get();
2099 rHdlList.AddHdl(std::move(pHdl));
2102 // second add column handles
2103 std::vector<TableEdgeHdl*> aColEdges(nColCount + 1);
2104 for (auto const & rEdge : mpImpl->mpLayouter->getVerticalEdges())
2106 Point aPoint(maRect.TopLeft());
2107 aPoint.AdjustX(rEdge.nPosition);
2109 std::unique_ptr<TableEdgeHdl> pHdl(new TableEdgeHdl(aPoint, false, rEdge.nMin, rEdge.nMax, nRowCount + 1));
2110 pHdl->SetPointNum(rEdge.nIndex);
2111 aColEdges[rEdge.nIndex] = pHdl.get();
2112 rHdlList.AddHdl(std::move(pHdl));
2115 // now add visible edges to row and column handles
2116 if( mpImpl->mpLayouter )
2118 TableLayouter& rLayouter = *mpImpl->mpLayouter;
2120 sal_Int32 nY = 0;
2122 for( sal_Int32 nRow = 0; nRow <= nRowCount; ++nRow )
2124 const sal_Int32 nRowHeight = (nRow == nRowCount) ? 0 : rLayouter.getRowHeight(nRow);
2125 sal_Int32 nX = 0;
2127 for( sal_Int32 nCol = 0; nCol <= nColCount; ++nCol )
2129 const sal_Int32 nColWidth = (nCol == nColCount) ? 0 : rLayouter.getColumnWidth(nCol);
2131 if( nRowHeight > 0 )
2133 if( rLayouter.isEdgeVisible( nCol, nRow, false ) )
2134 aColEdges[nCol]->SetEdge( nRow, nY, nY + nRowHeight, (rLayouter.getBorderLine( nCol, nRow, false ) == nullptr) ? Visible : Invisible);
2137 if( nColWidth > 0 )
2139 if( rLayouter.isEdgeVisible( nCol, nRow, true ) )
2140 aRowEdges[nRow]->SetEdge( nCol, nX, nX + nColWidth, (rLayouter.getBorderLine( nCol, nRow, true ) == nullptr) ? Visible : Invisible);
2143 nX += nColWidth;
2146 nY += nRowHeight;
2150 // add remaining handles
2151 SdrHdlList tempList(nullptr);
2152 tempList.AddHdl( std::make_unique<TableBorderHdl>( maRect, !IsTextEditActive() ) );
2153 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopLeft(),SdrHdlKind::UpperLeft) );
2154 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopCenter(),SdrHdlKind::Upper) );
2155 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.TopRight(),SdrHdlKind::UpperRight) );
2156 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.LeftCenter(),SdrHdlKind::Left) );
2157 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.RightCenter(),SdrHdlKind::Right) );
2158 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomLeft(),SdrHdlKind::LowerLeft) );
2159 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomCenter(),SdrHdlKind::Lower) );
2160 tempList.AddHdl( std::make_unique<SdrHdl>(maRect.BottomRight(),SdrHdlKind::LowerRight) );
2161 for( size_t nHdl = 0; nHdl < tempList.GetHdlCount(); ++nHdl )
2162 tempList.GetHdl(nHdl)->SetMoveOutside(true);
2163 tempList.MoveTo(rHdlList);
2165 const size_t nHdlCount = rHdlList.GetHdlCount();
2166 for( size_t nHdl = 0; nHdl < nHdlCount; ++nHdl )
2167 rHdlList.GetHdl(nHdl)->SetObj(const_cast<SdrTableObj*>(this));
2170 // Dragging
2172 bool SdrTableObj::hasSpecialDrag() const
2174 return true;
2177 bool SdrTableObj::beginSpecialDrag(SdrDragStat& rDrag) const
2179 const SdrHdl* pHdl = rDrag.GetHdl();
2180 const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2182 switch( eHdl )
2184 case SdrHdlKind::UpperLeft:
2185 case SdrHdlKind::Upper:
2186 case SdrHdlKind::UpperRight:
2187 case SdrHdlKind::Left:
2188 case SdrHdlKind::Right:
2189 case SdrHdlKind::LowerLeft:
2190 case SdrHdlKind::Lower:
2191 case SdrHdlKind::LowerRight:
2192 case SdrHdlKind::Move:
2194 break;
2197 case SdrHdlKind::User:
2199 rDrag.SetEndDragChangesAttributes(false);
2200 rDrag.SetNoSnap();
2201 break;
2204 default:
2206 return false;
2210 return true;
2213 bool SdrTableObj::applySpecialDrag(SdrDragStat& rDrag)
2215 bool bRet(true);
2216 const SdrHdl* pHdl = rDrag.GetHdl();
2217 const SdrHdlKind eHdl((pHdl == nullptr) ? SdrHdlKind::Move : pHdl->GetKind());
2219 switch( eHdl )
2221 case SdrHdlKind::UpperLeft:
2222 case SdrHdlKind::Upper:
2223 case SdrHdlKind::UpperRight:
2224 case SdrHdlKind::Left:
2225 case SdrHdlKind::Right:
2226 case SdrHdlKind::LowerLeft:
2227 case SdrHdlKind::Lower:
2228 case SdrHdlKind::LowerRight:
2230 const tools::Rectangle aNewRectangle(ImpDragCalcRect(rDrag));
2232 if (aNewRectangle != maRect)
2234 NbcSetLogicRect(aNewRectangle);
2237 break;
2240 case SdrHdlKind::Move:
2242 NbcMove( Size( rDrag.GetDX(), rDrag.GetDY() ) );
2243 break;
2246 case SdrHdlKind::User:
2248 rDrag.SetEndDragChangesAttributes(false);
2249 rDrag.SetNoSnap();
2250 const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
2252 if( pEdgeHdl )
2254 if( IsInserted() )
2256 rDrag.SetEndDragChangesAttributes(true);
2257 rDrag.SetEndDragChangesLayout(true);
2260 mpImpl->DragEdge( pEdgeHdl->IsHorizontalEdge(), pEdgeHdl->GetPointNum(), pEdgeHdl->GetValidDragOffset( rDrag ) );
2262 break;
2265 default:
2267 bRet = false;
2271 return bRet;
2274 basegfx::B2DPolyPolygon SdrTableObj::getSpecialDragPoly(const SdrDragStat& rDrag) const
2276 basegfx::B2DPolyPolygon aRetval;
2277 const SdrHdl* pHdl = rDrag.GetHdl();
2279 if( pHdl && (SdrHdlKind::User == pHdl->GetKind()) )
2281 const TableEdgeHdl* pEdgeHdl = dynamic_cast< const TableEdgeHdl* >( pHdl );
2283 if( pEdgeHdl )
2285 aRetval = pEdgeHdl->getSpecialDragPoly( rDrag );
2289 return aRetval;
2293 // Create
2296 bool SdrTableObj::BegCreate(SdrDragStat& rStat)
2298 rStat.SetOrtho4Possible();
2299 tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
2300 aRect1.Justify();
2301 rStat.SetActionRect(aRect1);
2302 maRect = aRect1;
2303 return true;
2307 bool SdrTableObj::MovCreate(SdrDragStat& rStat)
2309 tools::Rectangle aRect1;
2310 rStat.TakeCreateRect(aRect1);
2311 ImpJustifyRect(aRect1);
2312 rStat.SetActionRect(aRect1);
2313 maRect = aRect1; // for ObjName
2314 SetBoundRectDirty();
2315 bSnapRectDirty=true;
2316 return true;
2320 bool SdrTableObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
2322 rStat.TakeCreateRect(maRect);
2323 ImpJustifyRect(maRect);
2324 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
2327 void SdrTableObj::BrkCreate(SdrDragStat& /*rStat*/)
2332 bool SdrTableObj::BckCreate(SdrDragStat& /*rStat*/)
2334 return true;
2338 basegfx::B2DPolyPolygon SdrTableObj::TakeCreatePoly(const SdrDragStat& rDrag) const
2340 tools::Rectangle aRect1;
2341 rDrag.TakeCreateRect(aRect1);
2342 aRect1.Justify();
2344 basegfx::B2DPolyPolygon aRetval;
2345 const basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aRect1);
2346 aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
2347 return aRetval;
2351 PointerStyle SdrTableObj::GetCreatePointer() const
2353 return PointerStyle::Cross;
2357 void SdrTableObj::createCell( CellRef& xNewCell )
2359 xNewCell = Cell::create( *this );
2363 SdrObjGeoData *SdrTableObj::NewGeoData() const
2365 return new TableObjectGeoData;
2369 void SdrTableObj::SaveGeoData(SdrObjGeoData& rGeo) const
2371 DBG_ASSERT( dynamic_cast< TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" );
2372 SdrTextObj::SaveGeoData (rGeo);
2374 static_cast<TableObjectGeoData &>(rGeo).maLogicRect = maLogicRect;
2378 void SdrTableObj::RestGeoData(const SdrObjGeoData& rGeo)
2380 DBG_ASSERT( dynamic_cast< const TableObjectGeoData* >( &rGeo ), "svx::SdrTableObj::SaveGeoData(), illegal geo data!" );
2382 maLogicRect = static_cast<const TableObjectGeoData &>(rGeo).maLogicRect;
2384 SdrTextObj::RestGeoData (rGeo);
2386 if( mpImpl.is() )
2387 mpImpl->LayoutTable(maRect, false, false);
2388 ActionChanged();
2391 void SdrTableObj::CropTableModelToSelection(const CellPos& rStart, const CellPos& rEnd)
2393 if(!mpImpl.is())
2395 return;
2398 mpImpl->CropTableModelToSelection(rStart, rEnd);
2401 void SdrTableObj::DistributeColumns( sal_Int32 nFirstColumn, sal_Int32 nLastColumn, const bool bOptimize, const bool bMinimize )
2403 if( mpImpl.is() && mpImpl->mpLayouter )
2405 TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
2406 mpImpl->mpLayouter->DistributeColumns( maRect, nFirstColumn, nLastColumn, bOptimize, bMinimize );
2411 void SdrTableObj::DistributeRows( sal_Int32 nFirstRow, sal_Int32 nLastRow, const bool bOptimize, const bool bMinimize )
2413 if( mpImpl.is() && mpImpl->mpLayouter )
2415 TableModelNotifyGuard aGuard( mpImpl->mxTable.get() );
2416 mpImpl->mpLayouter->DistributeRows( maRect, nFirstRow, nLastRow, bOptimize, bMinimize );
2421 void SdrTableObj::SetChanged()
2423 if( mpImpl.is() )
2425 mpImpl->LayoutTable( maRect, false, false );
2428 ::SdrTextObj::SetChanged();
2432 void SdrTableObj::uno_lock()
2434 if( mpImpl.is() && mpImpl->mxTable.is() )
2435 mpImpl->mxTable->lockBroadcasts();
2439 void SdrTableObj::uno_unlock()
2441 if( mpImpl.is() && mpImpl->mxTable.is() )
2442 mpImpl->mxTable->unlockBroadcasts();
2445 void SdrTableObj::dumpAsXml(xmlTextWriterPtr pWriter) const
2447 xmlTextWriterStartElement(pWriter, BAD_CAST("SdrTableObj"));
2448 xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
2450 SdrObject::dumpAsXml(pWriter);
2452 mpImpl->dumpAsXml(pWriter);
2454 xmlTextWriterEndElement(pWriter);
2457 bool SdrTableObj::createTableEdgesJson(boost::property_tree::ptree & rJsonRoot)
2459 if (!mpImpl.is() || !mpImpl->mxTable.is())
2460 return false;
2462 tools::Rectangle aRect = GetCurrentBoundRect();
2463 boost::property_tree::ptree aTableColumns;
2465 aTableColumns.put("tableOffset", convertMm100ToTwip(aRect.Left()));
2467 boost::property_tree::ptree aEntries;
2468 auto const & aEdges = mpImpl->mpLayouter->getVerticalEdges();
2469 for (auto & rEdge : aEdges)
2471 if (rEdge.nIndex == 0)
2473 aTableColumns.put("left", convertMm100ToTwip(rEdge.nPosition));
2475 else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
2477 aTableColumns.put("right", convertMm100ToTwip(rEdge.nPosition));
2479 else
2481 boost::property_tree::ptree aEntry;
2482 aEntry.put("position", convertMm100ToTwip(rEdge.nPosition));
2483 aEntry.put("min", convertMm100ToTwip(rEdge.nPosition + rEdge.nMin));
2484 aEntry.put("max", convertMm100ToTwip(rEdge.nPosition + rEdge.nMax));
2485 aEntry.put("hidden", false);
2486 aEntries.push_back(std::make_pair("", aEntry));
2489 aTableColumns.push_back(std::make_pair("entries", aEntries));
2491 rJsonRoot.add_child("columns", aTableColumns);
2493 boost::property_tree::ptree aTableRows;
2495 aTableRows.put("tableOffset", convertMm100ToTwip(aRect.Top()));
2497 boost::property_tree::ptree aEntries;
2498 auto const & aEdges = mpImpl->mpLayouter->getHorizontalEdges();
2499 for (auto & rEdge : aEdges)
2501 if (rEdge.nIndex == 0)
2503 aTableRows.put("left", convertMm100ToTwip(rEdge.nPosition));
2505 else if (rEdge.nIndex == sal_Int32(aEdges.size() - 1))
2507 aTableRows.put("right", convertMm100ToTwip(rEdge.nPosition));
2509 else
2511 boost::property_tree::ptree aEntry;
2512 aEntry.put("position", convertMm100ToTwip(rEdge.nPosition));
2513 aEntry.put("min", convertMm100ToTwip(rEdge.nPosition + rEdge.nMin));
2514 aEntry.put("max", convertMm100ToTwip(rEdge.nPosition + rEdge.nMax));
2515 aEntry.put("hidden", false);
2516 aEntries.push_back(std::make_pair("", aEntry));
2519 aTableRows.push_back(std::make_pair("entries", aEntries));
2521 rJsonRoot.add_child("rows", aTableRows);
2522 return true;
2527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */