LibreOffice Module svx (master)  1
tablemodel.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
23 #include <com/sun/star/table/XMergeableCell.hpp>
24 
25 #include <algorithm>
26 
27 #include <vcl/svapp.hxx>
28 #include <osl/mutex.hxx>
29 #include <libxml/xmlwriter.h>
30 #include <tools/debug.hxx>
31 
32 #include <cell.hxx>
33 #include "cellcursor.hxx"
34 #include <tablemodel.hxx>
35 #include "tablerow.hxx"
36 #include "tablerows.hxx"
37 #include "tablecolumn.hxx"
38 #include "tablecolumns.hxx"
39 #include "tableundo.hxx"
40 #include <o3tl/safeint.hxx>
41 #include <svx/svdotable.hxx>
42 #include <svx/svdmodel.hxx>
43 #include <svx/strings.hrc>
44 #include <svx/dialmgr.hxx>
45 
46 using namespace ::osl;
47 using namespace ::com::sun::star::uno;
48 using namespace ::com::sun::star::table;
49 using namespace ::com::sun::star::lang;
50 using namespace ::com::sun::star::container;
51 using namespace ::com::sun::star::beans;
52 using namespace ::com::sun::star::util;
53 
54 
55 namespace sdr { namespace table {
56 
57 
58 // removes the given range from a vector
59 template< class Vec, class Iter > static void remove_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
60 {
61  const sal_Int32 nSize = static_cast<sal_Int32>(rVector.size());
62  if( nCount && (nIndex >= 0) && (nIndex < nSize) )
63  {
64  if( (nIndex + nCount) >= nSize )
65  {
66  // remove at end
67  rVector.resize( nIndex );
68  }
69  else
70  {
71  rVector.erase(rVector.begin() + nIndex, rVector.begin() + nIndex + nCount);
72  }
73  }
74 }
75 
76 
78 template< class Vec, class Iter, class Entry > static sal_Int32 insert_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
79 {
80  if( nCount )
81  {
82  if( nIndex >= static_cast< sal_Int32 >( rVector.size() ) )
83  {
84  // append at end
85  nIndex = static_cast< sal_Int32 >( rVector.size() ); // cap to end
86  rVector.resize( nIndex + nCount );
87  }
88  else
89  {
90  // insert
91  Iter aIter( rVector.begin() );
92  std::advance( aIter, nIndex );
93 
94  Entry aEmpty;
95  rVector.insert( aIter, nCount, aEmpty );
96  }
97  }
98  return nIndex;
99 }
100 
101 
104 , mpTableObj( pTableObj )
105 , mbModified( false )
106 , mbNotifyPending( false )
107 , mnNotifyLock( 0 )
108 {
109 }
110 
111 TableModel::TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable )
113 , mpTableObj( pTableObj )
114 , mbModified( false )
115 , mbNotifyPending( false )
116 , mnNotifyLock( 0 )
117 {
118  if( xSourceTable.is() )
119  {
120  const sal_Int32 nColCount = xSourceTable->getColumnCountImpl();
121  const sal_Int32 nRowCount = xSourceTable->getRowCountImpl();
122 
123  init( nColCount, nRowCount );
124 
125  sal_Int32 nRows = nRowCount;
126  while( nRows-- )
127  (*maRows[nRows]) = *xSourceTable->maRows[nRows];
128 
129  sal_Int32 nColumns = nColCount;
130  while( nColumns-- )
131  (*maColumns[nColumns]) = *xSourceTable->maColumns[nColumns];
132 
133  // copy cells
134  for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
135  {
136  for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
137  {
138  CellRef xTargetCell( getCell( nCol, nRow ) );
139  if( xTargetCell.is() )
140  xTargetCell->cloneFrom( xSourceTable->getCell( nCol, nRow ) );
141  }
142  }
143  }
144 }
145 
146 
148 {
149 }
150 
151 
152 void TableModel::init( sal_Int32 nColumns, sal_Int32 nRows )
153 {
154  if( nRows < 20 )
155  maRows.reserve( 20 );
156 
157  if( nColumns < 20 )
158  maColumns.reserve( 20 );
159 
160  if( nRows && nColumns )
161  {
162  maColumns.resize( nColumns );
163  maRows.resize( nRows );
164 
165  while( nRows-- )
166  maRows[nRows].set( new TableRow( this, nRows, nColumns ) );
167 
168  while( nColumns-- )
169  maColumns[nColumns].set( new TableColumn( this, nColumns ) );
170  }
171 }
172 
173 
174 // ICellRange
175 
176 
178 {
179  return 0;
180 }
181 
182 
184 {
185  return 0;
186 }
187 
188 
190 {
191  return getColumnCount();
192 }
193 
194 
196 {
197  return getRowCount();
198 }
199 
200 
201 Reference< XTable > TableModel::getTable()
202 {
203  return this;
204 }
205 
206 
207 void TableModel::UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount )
208 {
209  TableModelNotifyGuard aGuard( this );
210 
211  // remove the rows
212  remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
213  updateRows();
214  setModified(true);
215 }
216 
217 
218 void TableModel::UndoRemoveRows( sal_Int32 nIndex, RowVector& aRows )
219 {
220  TableModelNotifyGuard aGuard( this );
221 
222  const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aRows.size() );
223 
224  nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
225 
226  for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
227  maRows[nIndex+nOffset] = aRows[nOffset];
228 
229  updateRows();
230  setModified(true);
231 }
232 
233 
234 void TableModel::UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount )
235 {
236  TableModelNotifyGuard aGuard( this );
237 
238  // now remove the columns
239  remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
240  sal_Int32 nRows = getRowCountImpl();
241  while( nRows-- )
242  maRows[nRows]->removeColumns( nIndex, nCount );
243 
244  updateColumns();
245  setModified(true);
246 }
247 
248 
249 void TableModel::UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aCols, CellVector& aCells )
250 {
251  TableModelNotifyGuard aGuard( this );
252 
253  const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aCols.size() );
254 
255  // assert if there are not enough cells saved
256  DBG_ASSERT( (aCols.size() * maRows.size()) == aCells.size(), "sdr::table::TableModel::UndoRemoveColumns(), invalid undo data!" );
257 
258  nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
259  for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
260  maColumns[nIndex+nOffset] = aCols[nOffset];
261 
262  CellVector::iterator aIter( aCells.begin() );
263 
264  sal_Int32 nRows = getRowCountImpl();
265  for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
266  {
267  CellVector::iterator aIter2 = aIter + nRow * nCount;
268  OSL_ENSURE(aIter2 < aCells.end(), "invalid iterator!");
269  maRows[nRow]->insertColumns( nIndex, nCount, &aIter2 );
270  }
271 
272  updateColumns();
273  setModified(true);
274 }
275 
276 
277 // XTable
278 
279 
280 Reference< XCellCursor > SAL_CALL TableModel::createCursor()
281 {
282  ::SolarMutexGuard aGuard;
283  return createCursorByRange( Reference< XCellRange >( this ) );
284 }
285 
286 
287 Reference< XCellCursor > SAL_CALL TableModel::createCursorByRange( const Reference< XCellRange >& rRange )
288 {
289  ::SolarMutexGuard aGuard;
290 
291  ICellRange* pRange = dynamic_cast< ICellRange* >( rRange.get() );
292  if( (pRange == nullptr) || (pRange->getTable().get() != this) )
293  throw IllegalArgumentException();
294 
295  TableModelRef xModel( this );
296  return new CellCursor( xModel, pRange->getLeft(), pRange->getTop(), pRange->getRight(), pRange->getBottom() );
297 }
298 
299 
300 sal_Int32 SAL_CALL TableModel::getRowCount()
301 {
302  ::SolarMutexGuard aGuard;
303  return getRowCountImpl();
304 }
305 
306 sal_Int32 SAL_CALL TableModel::getColumnCount()
307 {
308  ::SolarMutexGuard aGuard;
309  return getColumnCountImpl();
310 }
311 
312 std::vector<sal_Int32> TableModel::getColumnWidths()
313 {
314  std::vector<sal_Int32> aRet;
315  for (const TableColumnRef& xColumn : maColumns)
316  aRet.push_back(xColumn->getWidth());
317  return aRet;
318 }
319 
320 // XComponent
321 
322 
324 {
325  ::SolarMutexGuard aGuard;
326  TableModelBase::dispose();
327 }
328 
329 
330 // XModifiable
331 
332 
334 {
335  ::SolarMutexGuard aGuard;
336  return mbModified;
337 }
338 
339 
340 void SAL_CALL TableModel::setModified( sal_Bool bModified )
341 {
342  {
343  ::SolarMutexGuard aGuard;
344  mbModified = bModified;
345  }
346  if( bModified )
348 }
349 
350 
351 // XModifyBroadcaster
352 
353 
354 void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener )
355 {
356  rBHelper.addListener( cppu::UnoType<XModifyListener>::get() , xListener );
357 }
358 
359 
360 void SAL_CALL TableModel::removeModifyListener( const Reference< XModifyListener >& xListener )
361 {
362  rBHelper.removeListener( cppu::UnoType<XModifyListener>::get() , xListener );
363 }
364 
365 
366 // XColumnRowRange
367 
368 
369 Reference< XTableColumns > SAL_CALL TableModel::getColumns()
370 {
371  ::SolarMutexGuard aGuard;
372 
373  if( !mxTableColumns.is() )
374  mxTableColumns.set( new TableColumns( this ) );
375  return mxTableColumns.get();
376 }
377 
378 
379 Reference< XTableRows > SAL_CALL TableModel::getRows()
380 {
381  ::SolarMutexGuard aGuard;
382 
383  if( !mxTableRows.is() )
384  mxTableRows.set( new TableRows( this ) );
385  return mxTableRows.get();
386 }
387 
388 
389 // XCellRange
390 
391 
392 Reference< XCell > SAL_CALL TableModel::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow )
393 {
394  ::SolarMutexGuard aGuard;
395 
396  CellRef xCell( getCell( nColumn, nRow ) );
397  if( xCell.is() )
398  return xCell.get();
399 
400  throw IndexOutOfBoundsException();
401 }
402 
403 
404 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
405 {
406  ::SolarMutexGuard aGuard;
407 
408  if( (nLeft >= 0) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) && (nRight < getColumnCountImpl()) && (nBottom < getRowCountImpl() ) )
409  {
410  TableModelRef xModel( this );
411  return new CellRange( xModel, nLeft, nTop, nRight, nBottom );
412  }
413 
414  throw IndexOutOfBoundsException();
415 }
416 
417 
418 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ )
419 {
420  return Reference< XCellRange >();
421 }
422 
423 
424 // XPropertySet
425 
426 
427 Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo( )
428 {
429  Reference< XPropertySetInfo > xInfo;
430  return xInfo;
431 }
432 
433 
434 void SAL_CALL TableModel::setPropertyValue( const OUString& /*aPropertyName*/, const Any& /*aValue*/ )
435 {
436 }
437 
438 
439 Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ )
440 {
441  return Any();
442 }
443 
444 
445 void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ )
446 {
447 }
448 
449 
450 void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ )
451 {
452 }
453 
454 
455 void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ )
456 {
457 }
458 
459 
460 void SAL_CALL TableModel::removeVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ )
461 {
462 }
463 
464 
465 // XFastPropertySet
466 
467 
468 void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ )
469 {
470 }
471 
472 
473 Any SAL_CALL TableModel::getFastPropertyValue( ::sal_Int32 /*nHandle*/ )
474 {
475  Any aAny;
476  return aAny;
477 }
478 
479 
480 // internals
481 
482 
484 {
485  return static_cast< sal_Int32 >( maRows.size() );
486 }
487 
488 
490 {
491  return static_cast< sal_Int32 >( maColumns.size() );
492 }
493 
494 
496 {
497  if( !maRows.empty() )
498  {
499  for( auto& rpRow : maRows )
500  rpRow->dispose();
501  RowVector().swap(maRows);
502  }
503 
504  if( !maColumns.empty() )
505  {
506  for( auto& rpCol : maColumns )
507  rpCol->dispose();
508  ColumnVector().swap(maColumns);
509  }
510 
511  if( mxTableColumns.is() )
512  {
513  mxTableColumns->dispose();
514  mxTableColumns.clear();
515  }
516 
517  if( mxTableRows.is() )
518  {
519  mxTableRows->dispose();
520  mxTableRows.clear();
521  }
522 
523  mpTableObj = nullptr;
524 }
525 
526 
527 // XBroadcaster
528 
529 
531 {
532  ::SolarMutexGuard aGuard;
533  ++mnNotifyLock;
534 }
535 
536 
538 {
539  ::SolarMutexGuard aGuard;
540  --mnNotifyLock;
541  if( mnNotifyLock <= 0 )
542  {
543  mnNotifyLock = 0;
544  if( mbNotifyPending )
546  }
547 }
548 
549 
551 {
552  ::osl::MutexGuard guard( m_aMutex );
553  if( (mnNotifyLock == 0) && mpTableObj )
554  {
555  mbNotifyPending = false;
556 
557  ::cppu::OInterfaceContainerHelper * pModifyListeners = rBHelper.getContainer( cppu::UnoType<XModifyListener>::get() );
558  if( pModifyListeners )
559  {
560  EventObject aSource;
561  aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
562  pModifyListeners->notifyEach( &XModifyListener::modified, aSource);
563  }
564  }
565  else
566  {
567  mbNotifyPending = true;
568  }
569 }
570 
571 
572 CellRef TableModel::getCell( sal_Int32 nCol, sal_Int32 nRow ) const
573 {
574  if( ((nRow >= 0) && (nRow < getRowCountImpl())) && (nCol >= 0) && (nCol < getColumnCountImpl()) )
575  {
576  return maRows[nRow]->maCells[nCol];
577  }
578  else
579  {
580  CellRef xRet;
581  return xRet;
582  }
583 }
584 
585 
587 {
588  CellRef xCell;
589  if( mpTableObj )
590  mpTableObj->createCell( xCell );
591  return xCell;
592 }
593 
594 
595 void TableModel::insertColumns( sal_Int32 nIndex, sal_Int32 nCount )
596 {
597  if( nCount && mpTableObj )
598  {
599  try
600  {
602  TableModelNotifyGuard aGuard( this );
603  nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
604 
605  sal_Int32 nRows = getRowCountImpl();
606  while( nRows-- )
607  maRows[nRows]->insertColumns( nIndex, nCount, nullptr );
608 
609  ColumnVector aNewColumns(nCount);
610  for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
611  {
612  TableColumnRef xNewCol( new TableColumn( this, nIndex+nOffset ) );
613  maColumns[nIndex+nOffset] = xNewCol;
614  aNewColumns[nOffset] = xNewCol;
615  }
616 
617  const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
618 
619  if( bUndo )
620  {
621  rModel.BegUndo( SvxResId(STR_TABLE_INSCOL) );
622  rModel.AddUndo( rModel.GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
623 
624  TableModelRef xThis( this );
625 
626  nRows = getRowCountImpl();
627  CellVector aNewCells( nCount * nRows );
628  CellVector::iterator aCellIter( aNewCells.begin() );
629 
630  nRows = getRowCountImpl();
631  for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
632  {
633  for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
634  (*aCellIter++) = getCell( nIndex + nOffset, nRow );
635  }
636 
637  rModel.AddUndo( std::make_unique<InsertColUndo>( xThis, nIndex, aNewColumns, aNewCells ) );
638  }
639 
640  const sal_Int32 nRowCount = getRowCountImpl();
641  // check if cells merge over new columns
642  for( sal_Int32 nCol = 0; nCol < nIndex; ++nCol )
643  {
644  for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
645  {
646  CellRef xCell( getCell( nCol, nRow ) );
647  sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
648  if( (nColSpan != 1) && ((nColSpan + nCol ) > nIndex) )
649  {
650  // cell merges over newly created columns, so add the new columns to the merged cell
651  const sal_Int32 nRowSpan = xCell->getRowSpan();
652  nColSpan += nCount;
653  merge( nCol, nRow, nColSpan, nRowSpan );
654  }
655  }
656  }
657 
658  if( bUndo )
659  rModel.EndUndo();
660 
661  rModel.SetChanged();
662  }
663  catch( Exception& )
664  {
665  OSL_FAIL("sdr::table::TableModel::insertColumns(), exception caught!");
666  }
667  updateColumns();
668  setModified(true);
669  }
670 }
671 
672 
673 void TableModel::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
674 {
675  sal_Int32 nColCount = getColumnCountImpl();
676 
677  if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nColCount) )
678  {
679  try
680  {
681  TableModelNotifyGuard aGuard( this );
682 
683  // clip removed columns to columns actually available
684  if( (nIndex + nCount) > nColCount )
685  nCount = nColCount - nIndex;
686 
687  sal_Int32 nRows = getRowCountImpl();
689  const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
690 
691  if( bUndo )
692  {
693  rModel.BegUndo( SvxResId(STR_UNDO_COL_DELETE) );
694  rModel.AddUndo( rModel.GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
695 
696  TableModelRef xThis( this );
697  ColumnVector aRemovedCols( nCount );
698  sal_Int32 nOffset;
699  for( nOffset = 0; nOffset < nCount; ++nOffset )
700  {
701  aRemovedCols[nOffset] = maColumns[nIndex+nOffset];
702  }
703 
704  CellVector aRemovedCells( nCount * nRows );
705  CellVector::iterator aCellIter( aRemovedCells.begin() );
706  for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
707  {
708  for( nOffset = 0; nOffset < nCount; ++nOffset )
709  (*aCellIter++) = getCell( nIndex + nOffset, nRow );
710  }
711 
712  rModel.AddUndo( std::make_unique<RemoveColUndo>( xThis, nIndex, aRemovedCols, aRemovedCells ) );
713  }
714 
715  // only rows before and inside the removed rows are considered
716  nColCount = nIndex + nCount + 1;
717 
718  const sal_Int32 nRowCount = getRowCountImpl();
719 
720  // first check merged cells before and inside the removed rows
721  for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
722  {
723  for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
724  {
725  CellRef xCell( getCell( nCol, nRow ) );
726  sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
727  if( nColSpan <= 1 )
728  continue;
729 
730  if( nCol >= nIndex )
731  {
732  // current cell is inside the removed columns
733  if( (nCol + nColSpan) > ( nIndex + nCount ) )
734  {
735  // current cells merges with columns after the removed columns
736  const sal_Int32 nRemove = nCount - nCol + nIndex;
737 
738  CellRef xTargetCell( getCell( nIndex + nCount, nRow ) );
739  if( xTargetCell.is() )
740  {
741  if( bUndo )
742  xTargetCell->AddUndo();
743  xTargetCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
744  xTargetCell->replaceContentAndFormating( xCell );
745  }
746  }
747  }
748  else if( nColSpan > (nIndex - nCol) )
749  {
750  // current cells spans inside the removed columns, so adjust
751  const sal_Int32 nRemove = ::std::min( nCount, nCol + nColSpan - nIndex );
752  if( bUndo )
753  xCell->AddUndo();
754  xCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
755  }
756  }
757  }
758 
759  // now remove the columns
760  remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
761  while( nRows-- )
762  maRows[nRows]->removeColumns( nIndex, nCount );
763 
764  if( bUndo )
765  rModel.EndUndo();
766 
767  rModel.SetChanged();
768  }
769  catch( Exception& )
770  {
771  OSL_FAIL("sdr::table::TableModel::removeColumns(), exception caught!");
772  }
773 
774  updateColumns();
775  setModified(true);
776  }
777 }
778 
779 
780 void TableModel::insertRows( sal_Int32 nIndex, sal_Int32 nCount )
781 {
782  if( nCount && mpTableObj )
783  {
785  const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
786 
787  try
788  {
789  TableModelNotifyGuard aGuard( this );
790 
791  nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
792 
793  RowVector aNewRows(nCount);
794  const sal_Int32 nColCount = getColumnCountImpl();
795  for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
796  {
797  TableRowRef xNewRow( new TableRow( this, nIndex+nOffset, nColCount ) );
798  maRows[nIndex+nOffset] = xNewRow;
799  aNewRows[nOffset] = xNewRow;
800  }
801 
802  if( bUndo )
803  {
804  rModel.BegUndo( SvxResId(STR_TABLE_INSROW) );
805  rModel.AddUndo( rModel.GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
806  TableModelRef xThis( this );
807  rModel.AddUndo( std::make_unique<InsertRowUndo>( xThis, nIndex, aNewRows ) );
808  }
809 
810  // check if cells merge over new columns
811  for( sal_Int32 nRow = 0; nRow < nIndex; ++nRow )
812  {
813  for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
814  {
815  CellRef xCell( getCell( nCol, nRow ) );
816  sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
817  if( (nRowSpan > 1) && ((nRowSpan + nRow) > nIndex) )
818  {
819  // cell merges over newly created columns, so add the new columns to the merged cell
820  const sal_Int32 nColSpan = xCell->getColumnSpan();
821  nRowSpan += nCount;
822  merge( nCol, nRow, nColSpan, nRowSpan );
823  }
824  }
825  }
826  }
827  catch( Exception& )
828  {
829  OSL_FAIL("sdr::table::TableModel::insertRows(), exception caught!");
830  }
831  if( bUndo )
832  rModel.EndUndo();
833 
834  rModel.SetChanged();
835 
836  updateRows();
837  setModified(true);
838  }
839 }
840 
841 
842 void TableModel::removeRows( sal_Int32 nIndex, sal_Int32 nCount )
843 {
844  sal_Int32 nRowCount = getRowCountImpl();
845 
846  if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nRowCount) )
847  {
849  const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
850 
851  try
852  {
853  TableModelNotifyGuard aGuard( this );
854 
855  // clip removed rows to rows actually available
856  if( (nIndex + nCount) > nRowCount )
857  nCount = nRowCount - nIndex;
858 
859  if( bUndo )
860  {
861  rModel.BegUndo( SvxResId(STR_UNDO_ROW_DELETE) );
862  rModel.AddUndo( rModel.GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
863 
864  TableModelRef xThis( this );
865 
866  RowVector aRemovedRows( nCount );
867  for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
868  aRemovedRows[nOffset] = maRows[nIndex+nOffset];
869 
870  rModel.AddUndo( std::make_unique<RemoveRowUndo>( xThis, nIndex, aRemovedRows ) );
871  }
872 
873  // only rows before and inside the removed rows are considered
874  nRowCount = nIndex + nCount + 1;
875 
876  const sal_Int32 nColCount = getColumnCountImpl();
877 
878  // first check merged cells before and inside the removed rows
879  for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
880  {
881  for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
882  {
883  CellRef xCell( getCell( nCol, nRow ) );
884  sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
885  if( nRowSpan <= 1 )
886  continue;
887 
888  if( nRow >= nIndex )
889  {
890  // current cell is inside the removed rows
891  if( (nRow + nRowSpan) > (nIndex + nCount) )
892  {
893  // current cells merges with rows after the removed rows
894  const sal_Int32 nRemove = nCount - nRow + nIndex;
895 
896  CellRef xTargetCell( getCell( nCol, nIndex + nCount ) );
897  if( xTargetCell.is() )
898  {
899  if( bUndo )
900  xTargetCell->AddUndo();
901  xTargetCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
902  xTargetCell->replaceContentAndFormating( xCell );
903  }
904  }
905  }
906  else if( nRowSpan > (nIndex - nRow) )
907  {
908  // current cells spans inside the removed rows, so adjust
909  const sal_Int32 nRemove = ::std::min( nCount, nRow + nRowSpan - nIndex );
910  if( bUndo )
911  xCell->AddUndo();
912  xCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
913  }
914  }
915  }
916 
917  // now remove the rows
918  remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
919 
920  if( bUndo )
921  rModel.EndUndo();
922 
923  rModel.SetChanged();
924  }
925  catch( Exception& )
926  {
927  OSL_FAIL("sdr::table::TableModel::removeRows(), exception caught!");
928  }
929 
930  updateRows();
931  setModified(true);
932  }
933 }
934 
935 
936 TableRowRef const & TableModel::getRow( sal_Int32 nRow ) const
937 {
938  if( (nRow >= 0) && (nRow < getRowCountImpl()) )
939  return maRows[nRow];
940 
941  throw IndexOutOfBoundsException();
942 }
943 
944 
945 TableColumnRef const & TableModel::getColumn( sal_Int32 nColumn ) const
946 {
947  if( (nColumn >= 0) && (nColumn < getColumnCountImpl()) )
948  return maColumns[nColumn];
949 
950  throw IndexOutOfBoundsException();
951 }
952 
953 
956 {
957  TableModelNotifyGuard aGuard( this );
958 
959  bool bWasModified = false;
960 
961  if( !maRows.empty() && !maColumns.empty() )
962  {
963  sal_Int32 nCol = getColumnCountImpl() - 1;
964  sal_Int32 nRows = getRowCountImpl();
965  while( nCol > 0 )
966  {
967  bool bEmpty = true;
968  for( sal_Int32 nRow = 0; (nRow < nRows) && bEmpty; nRow++ )
969  {
970  Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
971  if( xCell.is() && !xCell->isMerged() )
972  bEmpty = false;
973  }
974 
975  if( bEmpty )
976  {
977  try
978  {
979  const OUString sWidth("Width");
980  sal_Int32 nWidth1 = 0, nWidth2 = 0;
981  Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maColumns[nCol].get() ), UNO_QUERY_THROW );
982  Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maColumns[nCol-1].get() ), UNO_QUERY_THROW );
983  xSet1->getPropertyValue( sWidth ) >>= nWidth1;
984  xSet2->getPropertyValue( sWidth ) >>= nWidth2;
985  nWidth1 = o3tl::saturating_add(nWidth1, nWidth2);
986  xSet2->setPropertyValue( sWidth, Any( nWidth1 ) );
987  }
988  catch( Exception& )
989  {
990  OSL_FAIL("svx::TableModel::optimize(), exception caught!");
991  }
992 
993  removeColumns( nCol, 1 );
994  bWasModified = true;
995  }
996 
997  nCol--;
998  }
999 
1000  sal_Int32 nRow = getRowCountImpl() - 1;
1001  sal_Int32 nCols = getColumnCountImpl();
1002  while( nRow > 0 )
1003  {
1004  bool bEmpty = true;
1005  for( nCol = 0; (nCol < nCols) && bEmpty; nCol++ )
1006  {
1007  Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1008  if( xCell.is() && !xCell->isMerged() )
1009  bEmpty = false;
1010  }
1011 
1012  if( bEmpty )
1013  {
1014  try
1015  {
1016  const OUString sHeight("Height");
1017  sal_Int32 nHeight1 = 0, nHeight2 = 0;
1018  Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maRows[nRow].get() ), UNO_QUERY_THROW );
1019  Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maRows[nRow-1].get() ), UNO_QUERY_THROW );
1020  xSet1->getPropertyValue( sHeight ) >>= nHeight1;
1021  xSet2->getPropertyValue( sHeight ) >>= nHeight2;
1022  nHeight1 = o3tl::saturating_add(nHeight1, nHeight2);
1023  xSet2->setPropertyValue( sHeight, Any( nHeight1 ) );
1024  }
1025  catch( Exception& )
1026  {
1027  OSL_FAIL("svx::TableModel::optimize(), exception caught!");
1028  }
1029 
1030  removeRows( nRow, 1 );
1031  bWasModified = true;
1032  }
1033 
1034  nRow--;
1035  }
1036  }
1037  if( bWasModified )
1038  setModified(true);
1039 }
1040 
1041 
1042 void TableModel::merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan )
1043 {
1044  if(nullptr == mpTableObj)
1045  return;
1046 
1048  const bool bUndo(mpTableObj->IsInserted() && rModel.IsUndoEnabled());
1049  const sal_Int32 nLastRow = nRow + nRowSpan;
1050  const sal_Int32 nLastCol = nCol + nColSpan;
1051 
1052  if( (nLastRow > getRowCount()) || (nLastCol > getColumnCount() ) )
1053  {
1054  OSL_FAIL("TableModel::merge(), merge beyond the table!");
1055  }
1056 
1057  // merge first cell
1058  CellRef xOriginCell( dynamic_cast< Cell* >( getCellByPosition( nCol, nRow ).get() ) );
1059  if(!xOriginCell.is())
1060  return;
1061 
1062  if( bUndo )
1063  xOriginCell->AddUndo();
1064  xOriginCell->merge( nColSpan, nRowSpan );
1065 
1066  sal_Int32 nTempCol = nCol + 1;
1067 
1068  // merge remaining cells
1069  for( ; nRow < nLastRow; nRow++ )
1070  {
1071  for( ; nTempCol < nLastCol; nTempCol++ )
1072  {
1073  CellRef xCell( dynamic_cast< Cell* >( getCellByPosition( nTempCol, nRow ).get() ) );
1074  if( xCell.is() && !xCell->isMerged() )
1075  {
1076  if( bUndo )
1077  xCell->AddUndo();
1078  xCell->setMerged();
1079  xOriginCell->mergeContent( xCell );
1080  }
1081  }
1082  nTempCol = nCol;
1083  }
1084 }
1085 
1087 {
1088  sal_Int32 nRow = 0;
1089  for( auto& rpRow : maRows )
1090  {
1091  rpRow->mnRow = nRow++;
1092  }
1093 }
1094 
1096 {
1097  sal_Int32 nColumn = 0;
1098  for( auto& rpCol : maColumns )
1099  {
1100  rpCol->mnColumn = nColumn++;
1101  }
1102 }
1103 
1105 {
1106  xmlTextWriterStartElement(pWriter, BAD_CAST("TableModel"));
1107  for (sal_Int32 nRow = 0; nRow < getRowCountImpl(); ++nRow)
1108  for (sal_Int32 nCol = 0; nCol < getColumnCountImpl(); ++nCol)
1109  {
1110  maRows[nRow]->maCells[nCol]->dumpAsXml(pWriter, nRow, nCol);
1111  }
1112  xmlTextWriterEndElement(pWriter);
1113 }
1114 
1115 } }
1116 
1117 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const int nColCount
std::vector< TableRowRef > RowVector
Definition: celltypes.hxx:39
osl::Mutex m_aMutex
void removeRows(sal_Int32 nIndex, sal_Int32 nCount)
Definition: tablemodel.cxx:842
void createCell(sdr::table::CellRef &xCell)
Definition: svdotable.cxx:2365
bool IsInserted() const
Definition: svdobj.hxx:792
void UndoRemoveRows(sal_Int32 nIndex, RowVector &aNewRows)
Definition: tablemodel.cxx:218
mutable::osl::Mutex m_aMutex
void UndoInsertColumns(sal_Int32 nIndex, sal_Int32 nCount)
Definition: tablemodel.cxx:234
void optimize()
deletes rows and columns that are completely merged.
Definition: tablemodel.cxx:955
virtual css::uno::Reference< css::table::XCellCursor > SAL_CALL createCursorByRange(const css::uno::Reference< css::table::XCellRange > &rRange) override
Definition: tablemodel.cxx:287
virtual void SAL_CALL setPropertyValue(const OUString &aPropertyName, const css::uno::Any &aValue) override
Definition: tablemodel.cxx:434
struct _xmlTextWriter * xmlTextWriterPtr
void UndoRemoveColumns(sal_Int32 nIndex, ColumnVector &aNewCols, CellVector &aCells)
Definition: tablemodel.cxx:249
void BegUndo()
Definition: svdmodel.cxx:425
void merge(sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan)
merges the cell at the given position with the given span
OUString SvxResId(const char *pId)
Definition: dialmgr.cxx:28
virtual css::uno::Reference< css::table::XTable > getTable()=0
virtual ::sal_Int32 SAL_CALL getColumnCount() override
Definition: tablemodel.cxx:306
virtual ~TableModel() override
Definition: tablemodel.cxx:147
int nCount
virtual sal_Int32 getTop() override
Definition: tablemodel.cxx:183
virtual sal_Bool SAL_CALL isModified() override
Definition: tablemodel.cxx:333
sal_Int32 getColumnCountImpl() const
Definition: tablemodel.cxx:489
virtual void SAL_CALL setModified(sal_Bool bModified) override
Definition: tablemodel.cxx:340
virtual void SAL_CALL unlockBroadcasts() override
Definition: tablemodel.cxx:537
virtual css::uno::Any SAL_CALL getPropertyValue(const OUString &PropertyName) override
Definition: tablemodel.cxx:439
void removeColumns(sal_Int32 nIndex, sal_Int32 nCount)
Definition: tablemodel.cxx:673
std::vector< TableColumnRef > ColumnVector
Definition: celltypes.hxx:40
virtual css::uno::Reference< css::table::XTableColumns > SAL_CALL getColumns() override
Definition: tablemodel.cxx:369
static void remove_range(Vec &rVector, sal_Int32 nIndex, sal_Int32 nCount)
Definition: tablemodel.cxx:59
sal_Int32 getRowCountImpl() const
Definition: tablemodel.cxx:483
virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByPosition(::sal_Int32 nLeft,::sal_Int32 nTop,::sal_Int32 nRight,::sal_Int32 nBottom) override
Definition: tablemodel.cxx:404
std::vector< sal_Int32 > getColumnWidths()
Get the width of all columns in this table.
Definition: tablemodel.cxx:312
#define DBG_ASSERT(sCon, aError)
CellRef getCell(::sal_Int32 nCol,::sal_Int32 nRow) const
Definition: tablemodel.cxx:572
void UndoInsertRows(sal_Int32 nIndex, sal_Int32 nCount)
Definition: tablemodel.cxx:207
rtl::Reference< TableColumns > mxTableColumns
Definition: tablemodel.hxx:176
TableColumnRef const & getColumn(sal_Int32 nColumn) const
Definition: tablemodel.cxx:945
std::enable_if< std::is_signed< T >::value, T >::type saturating_add(T a, T b)
std::vector< CellRef > CellVector
Definition: celltypes.hxx:38
unsigned char sal_Bool
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:299
virtual sal_Int32 getLeft() override
Definition: tablemodel.cxx:177
TableRowRef const & getRow(sal_Int32 nRow) const
Definition: tablemodel.cxx:936
virtual void SAL_CALL addVetoableChangeListener(const OUString &PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &aListener) override
Definition: tablemodel.cxx:455
TableModel(SdrTableObj *pTableObj)
Definition: tablemodel.cxx:102
rtl::Reference< TableRows > mxTableRows
Definition: tablemodel.hxx:177
void init(sal_Int32 nColumns, sal_Int32 nRows)
Definition: tablemodel.cxx:152
void insertColumns(sal_Int32 nIndex, sal_Int32 nCount)
Definition: tablemodel.cxx:595
virtual sal_Int32 getRight()=0
virtual sal_Int32 getRight() override
Definition: tablemodel.cxx:189
virtual css::uno::Any SAL_CALL getFastPropertyValue(::sal_Int32 nHandle) override
Definition: tablemodel.cxx:473
virtual sal_Int32 getBottom() override
Definition: tablemodel.cxx:195
virtual void SAL_CALL dispose() override
Definition: tablemodel.cxx:323
ColumnVector maColumns
Definition: tablemodel.hxx:174
virtual ::sal_Int32 SAL_CALL getRowCount() override
Definition: tablemodel.cxx:300
friend class TableRow
Definition: tablemodel.hxx:66
friend class TableColumn
Definition: tablemodel.hxx:65
void insertRows(sal_Int32 nIndex, sal_Int32 nCount)
Definition: tablemodel.cxx:780
virtual void SAL_CALL lockBroadcasts() override
Definition: tablemodel.cxx:530
virtual void SAL_CALL removePropertyChangeListener(const OUString &aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &aListener) override
Definition: tablemodel.cxx:450
virtual void SAL_CALL removeModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: tablemodel.cxx:360
virtual void SAL_CALL addModifyListener(const css::uno::Reference< css::util::XModifyListener > &aListener) override
Definition: tablemodel.cxx:354
virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override
Definition: tablemodel.cxx:427
static sal_Int32 insert_range(Vec &rVector, sal_Int32 nIndex, sal_Int32 nCount)
inserts a range into a vector
Definition: tablemodel.cxx:78
virtual css::uno::Reference< css::table::XTableRows > SAL_CALL getRows() override
Definition: tablemodel.cxx:379
Reference< XColumn > xColumn
virtual css::uno::Reference< css::table::XTable > getTable() override
Definition: tablemodel.cxx:201
::cppu::WeakComponentImplHelper< css::table::XTable, css::util::XBroadcaster > TableModelBase
Definition: tablemodel.hxx:53
Reference< XModel > xModel
virtual void SAL_CALL removeVetoableChangeListener(const OUString &PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > &aListener) override
Definition: tablemodel.cxx:460
void notifyEach(void(SAL_CALL ListenerT::*NotificationMethod)(const EventT &), const EventT &Event)
virtual css::uno::Reference< css::table::XCellRange > SAL_CALL getCellRangeByName(const OUString &aRange) override
Definition: tablemodel.cxx:418
virtual sal_Int32 getLeft()=0
virtual void SAL_CALL disposing() override
this function is called upon disposing the component
Definition: tablemodel.cxx:495
virtual sal_Int32 getBottom()=0
SdrTableObj * mpTableObj
Definition: tablemodel.hxx:179
virtual void SAL_CALL setFastPropertyValue(::sal_Int32 nHandle, const css::uno::Any &aValue) override
Definition: tablemodel.cxx:468
virtual css::uno::Reference< css::table::XCellCursor > SAL_CALL createCursor() override
Definition: tablemodel.cxx:280
virtual void SAL_CALL addPropertyChangeListener(const OUString &aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > &xListener) override
Definition: tablemodel.cxx:445
base class for each object implementing an XCellRange
Definition: tablemodel.hxx:40
virtual sal_Int32 getTop()=0
void dumpAsXml(xmlTextWriterPtr pWriter) const
virtual css::uno::Reference< css::table::XCell > SAL_CALL getCellByPosition(::sal_Int32 nColumn,::sal_Int32 nRow) override
Definition: tablemodel.cxx:392