1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26
27 #include <com/sun/star/table/XMergeableCell.hpp>
28
29 #include <algorithm>
30 #include <boost/bind.hpp>
31
32 #include <vcl/svapp.hxx>
33 #include <vos/mutex.hxx>
34
35 #include "cell.hxx"
36 #include "cellcursor.hxx"
37 #include "tablemodel.hxx"
38 #include "tablerow.hxx"
39 #include "tablerows.hxx"
40 #include "tablecolumn.hxx"
41 #include "tablecolumns.hxx"
42 #include "tableundo.hxx"
43 #include "svx/svdotable.hxx"
44 #include "svx/svdmodel.hxx"
45 #include "svx/svdstr.hrc"
46 #include "svx/svdglob.hxx"
47
48 //#define PLEASE_DEBUG_THE_TABLES 1
49
50 using ::rtl::OUString;
51 using namespace ::osl;
52 using namespace ::vos;
53 using namespace ::com::sun::star::uno;
54 using namespace ::com::sun::star::table;
55 using namespace ::com::sun::star::lang;
56 using namespace ::com::sun::star::container;
57 using namespace ::com::sun::star::beans;
58 using namespace ::com::sun::star::util;
59
60 // -----------------------------------------------------------------------------
61
62 namespace sdr { namespace table {
63
64 // -----------------------------------------------------------------------------
65
66 // removes the given range from a vector
remove_range(Vec & rVector,sal_Int32 nIndex,sal_Int32 nCount)67 template< class Vec, class Iter > void remove_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
68 {
69 const sal_Int32 nSize = static_cast<sal_Int32>(rVector.size());
70 if( nCount && (nIndex >= 0) && (nIndex < nSize) )
71 {
72 if( (nIndex + nCount) >= nSize )
73 {
74 // remove at end
75 rVector.resize( nIndex );
76 }
77 else
78 {
79 Iter aBegin( rVector.begin() );
80 while( nIndex-- )
81 aBegin++;
82 if( nCount == 1 )
83 {
84 rVector.erase( aBegin );
85 }
86 else
87 {
88 Iter aEnd( aBegin );
89
90 while( nCount-- )
91 aEnd++;
92 rVector.erase( aBegin, aEnd );
93 }
94 }
95 }
96 }
97
98 // -----------------------------------------------------------------------------
99
100 /** inserts a range into a vector */
insert_range(Vec & rVector,sal_Int32 nIndex,sal_Int32 nCount)101 template< class Vec, class Iter, class Entry > sal_Int32 insert_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
102 {
103 if( nCount )
104 {
105 if( nIndex >= static_cast< sal_Int32 >( rVector.size() ) )
106 {
107 // append at end
108 nIndex = static_cast< sal_Int32 >( rVector.size() ); // cap to end
109 rVector.resize( nIndex + nCount );
110 }
111 else
112 {
113 // insert
114 sal_Int32 nFind = nIndex;
115 Iter aIter( rVector.begin() );
116 while( nFind-- )
117 aIter++;
118
119 Entry aEmpty;
120 rVector.insert( aIter, nCount, aEmpty );
121 }
122 }
123 return nIndex;
124 }
125
126 // -----------------------------------------------------------------------------
127
TableModel(SdrTableObj * pTableObj)128 TableModel::TableModel( SdrTableObj* pTableObj )
129 : TableModelBase( m_aMutex )
130 , mpTableObj( pTableObj )
131 , mbModified( sal_False )
132 , mbNotifyPending( false )
133 , mnNotifyLock( 0 )
134 {
135 }
136
TableModel(SdrTableObj * pTableObj,const TableModelRef & xSourceTable)137 TableModel::TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable )
138 : TableModelBase( m_aMutex )
139 , mpTableObj( pTableObj )
140 , mbModified( sal_False )
141 , mbNotifyPending( false )
142 , mnNotifyLock( 0 )
143 {
144 if( xSourceTable.is() )
145 {
146 const sal_Int32 nColCount = xSourceTable->getColumnCountImpl();
147 const sal_Int32 nRowCount = xSourceTable->getRowCountImpl();
148
149 init( nColCount, nRowCount );
150
151 sal_Int32 nRows = nRowCount;
152 while( nRows-- )
153 (*maRows[nRows]) = (*xSourceTable->maRows[nRows]);
154
155 sal_Int32 nColumns = nColCount;
156 while( nColumns-- )
157 (*maColumns[nColumns]) = (*xSourceTable->maColumns[nColumns]);
158
159 // copy cells
160 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
161 {
162 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
163 {
164 CellRef xTargetCell( getCell( nCol, nRow ) );
165 if( xTargetCell.is() )
166 xTargetCell->cloneFrom( xSourceTable->getCell( nCol, nRow ) );
167 }
168 }
169 }
170 }
171
172 // -----------------------------------------------------------------------------
173
~TableModel()174 TableModel::~TableModel()
175 {
176 }
177
178 // -----------------------------------------------------------------------------
179
init(sal_Int32 nColumns,sal_Int32 nRows)180 void TableModel::init( sal_Int32 nColumns, sal_Int32 nRows )
181 {
182 if( nRows < 20 )
183 maRows.reserve( 20 );
184
185 if( nColumns < 20 )
186 maColumns.reserve( 20 );
187
188 if( nRows && nColumns )
189 {
190 maColumns.resize( nColumns );
191 maRows.resize( nRows );
192
193 while( nRows-- )
194 maRows[nRows].set( new TableRow( this, nRows, nColumns ) );
195
196 while( nColumns-- )
197 maColumns[nColumns].set( new TableColumn( this, nColumns ) );
198 }
199 }
200
201 // -----------------------------------------------------------------------------
202 // ICellRange
203 // -----------------------------------------------------------------------------
204
getLeft()205 sal_Int32 TableModel::getLeft()
206 {
207 return 0;
208 }
209
210 // -----------------------------------------------------------------------------
211
getTop()212 sal_Int32 TableModel::getTop()
213 {
214 return 0;
215 }
216
217 // -----------------------------------------------------------------------------
218
getRight()219 sal_Int32 TableModel::getRight()
220 {
221 return getColumnCount();
222 }
223
224 // -----------------------------------------------------------------------------
225
getBottom()226 sal_Int32 TableModel::getBottom()
227 {
228 return getRowCount();
229 }
230
231 // -----------------------------------------------------------------------------
232
getTable()233 Reference< XTable > TableModel::getTable()
234 {
235 return this;
236 }
237
238 // -----------------------------------------------------------------------------
239
UndoInsertRows(sal_Int32 nIndex,sal_Int32 nCount)240 void TableModel::UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount )
241 {
242 TableModelNotifyGuard aGuard( this );
243
244 // remove the rows
245 remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
246 updateRows();
247 setModified(sal_True);
248 }
249
250 // -----------------------------------------------------------------------------
251
UndoRemoveRows(sal_Int32 nIndex,RowVector & aRows)252 void TableModel::UndoRemoveRows( sal_Int32 nIndex, RowVector& aRows )
253 {
254 TableModelNotifyGuard aGuard( this );
255
256 const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aRows.size() );
257
258 nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
259
260 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
261 maRows[nIndex+nOffset] = aRows[nOffset];
262
263 updateRows();
264 setModified(sal_True);
265 }
266
267 // -----------------------------------------------------------------------------
268
UndoInsertColumns(sal_Int32 nIndex,sal_Int32 nCount)269 void TableModel::UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount )
270 {
271 TableModelNotifyGuard aGuard( this );
272
273 // now remove the columns
274 remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
275 sal_Int32 nRows = getRowCountImpl();
276 while( nRows-- )
277 maRows[nRows]->removeColumns( nIndex, nCount );
278
279 updateColumns();
280 setModified(sal_True);
281 }
282
283 // -----------------------------------------------------------------------------
284
UndoRemoveColumns(sal_Int32 nIndex,ColumnVector & aCols,CellVector & aCells)285 void TableModel::UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aCols, CellVector& aCells )
286 {
287 TableModelNotifyGuard aGuard( this );
288
289 const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aCols.size() );
290
291 // assert if there are not enough cells saved
292 DBG_ASSERT( (aCols.size() * maRows.size()) == aCells.size(), "sdr::table::TableModel::UndoRemoveColumns(), invalid undo data!" );
293
294 nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
295 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
296 maColumns[nIndex+nOffset] = aCols[nOffset];
297
298 CellVector::iterator aIter( aCells.begin() );
299
300 sal_Int32 nRows = getRowCountImpl();
301 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
302 {
303 CellVector::iterator aIter2 = aIter + nRow * nCount;
304 DBG_ASSERT(aIter2 < aCells.end(), "sdr::table::TableModel::UndoRemoveColumns(), invalid iterator!");
305 maRows[nRow]->insertColumns( nIndex, nCount, &aIter2 );
306 }
307
308 updateColumns();
309 setModified(sal_True);
310 }
311
312 // -----------------------------------------------------------------------------
313 // XTable
314 // -----------------------------------------------------------------------------
315
createCursor()316 Reference< XCellCursor > SAL_CALL TableModel::createCursor() throw (RuntimeException)
317 {
318 OGuard aGuard( Application::GetSolarMutex() );
319 return createCursorByRange( Reference< XCellRange >( this ) );
320 }
321
322 // -----------------------------------------------------------------------------
323
createCursorByRange(const Reference<XCellRange> & Range)324 Reference< XCellCursor > SAL_CALL TableModel::createCursorByRange( const Reference< XCellRange >& Range ) throw (IllegalArgumentException, RuntimeException)
325 {
326 OGuard aGuard( Application::GetSolarMutex() );
327
328 ICellRange* pRange = dynamic_cast< ICellRange* >( Range.get() );
329 if( (pRange == 0) || (pRange->getTable().get() != this) )
330 throw IllegalArgumentException();
331
332 TableModelRef xModel( this );
333 return new CellCursor( xModel, pRange->getLeft(), pRange->getTop(), pRange->getRight(), pRange->getBottom() );
334 }
335
336 // -----------------------------------------------------------------------------
337
getRowCount()338 sal_Int32 SAL_CALL TableModel::getRowCount() throw (RuntimeException)
339 {
340 OGuard aGuard( Application::GetSolarMutex() );
341 return getRowCountImpl();
342 }
343
344 // -----------------------------------------------------------------------------
345
getColumnCount()346 sal_Int32 SAL_CALL TableModel::getColumnCount() throw (RuntimeException)
347 {
348 OGuard aGuard( Application::GetSolarMutex() );
349 return getColumnCountImpl();
350 }
351
352 // -----------------------------------------------------------------------------
353 // XComponent
354 // -----------------------------------------------------------------------------
355
dispose()356 void TableModel::dispose() throw (RuntimeException)
357 {
358 OGuard aGuard( Application::GetSolarMutex() );
359 TableModelBase::dispose();
360 }
361
362 // -----------------------------------------------------------------------------
363
addEventListener(const Reference<XEventListener> & xListener)364 void SAL_CALL TableModel::addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
365 {
366 TableModelBase::addEventListener( xListener );
367 }
368
369 // -----------------------------------------------------------------------------
370
removeEventListener(const Reference<XEventListener> & xListener)371 void SAL_CALL TableModel::removeEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
372 {
373 TableModelBase::removeEventListener( xListener );
374 }
375
376 // -----------------------------------------------------------------------------
377 // XModifiable
378 // -----------------------------------------------------------------------------
379
isModified()380 sal_Bool SAL_CALL TableModel::isModified( ) throw (RuntimeException)
381 {
382 OGuard aGuard( Application::GetSolarMutex() );
383 return mbModified;
384 }
385
386 // -----------------------------------------------------------------------------
387
setModified(sal_Bool bModified)388 void SAL_CALL TableModel::setModified( sal_Bool bModified ) throw (PropertyVetoException, RuntimeException)
389 {
390 {
391 OGuard aGuard( Application::GetSolarMutex() );
392 mbModified = bModified;
393 }
394 if( bModified )
395 notifyModification();
396 }
397
398 // -----------------------------------------------------------------------------
399 // XModifyBroadcaster
400 // -----------------------------------------------------------------------------
401
addModifyListener(const Reference<XModifyListener> & xListener)402 void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
403 {
404 rBHelper.addListener( XModifyListener::static_type() , xListener );
405 }
406
407 // -----------------------------------------------------------------------------
408
removeModifyListener(const Reference<XModifyListener> & xListener)409 void SAL_CALL TableModel::removeModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
410 {
411 rBHelper.removeListener( XModifyListener::static_type() , xListener );
412 }
413
414 // -----------------------------------------------------------------------------
415 // XColumnRowRange
416 // -----------------------------------------------------------------------------
417
getColumns()418 Reference< XTableColumns > SAL_CALL TableModel::getColumns() throw (RuntimeException)
419 {
420 OGuard aGuard( Application::GetSolarMutex() );
421
422 if( !mxTableColumns.is() )
423 mxTableColumns.set( new TableColumns( this ) );
424 return mxTableColumns.get();
425 }
426
427 // -----------------------------------------------------------------------------
428
getRows()429 Reference< XTableRows > SAL_CALL TableModel::getRows() throw (RuntimeException)
430 {
431 OGuard aGuard( Application::GetSolarMutex() );
432
433 if( !mxTableRows.is() )
434 mxTableRows.set( new TableRows( this ) );
435 return mxTableRows.get();
436 }
437
438 // -----------------------------------------------------------------------------
439 // XCellRange
440 // -----------------------------------------------------------------------------
441
getCellByPosition(sal_Int32 nColumn,sal_Int32 nRow)442 Reference< XCell > SAL_CALL TableModel::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw ( IndexOutOfBoundsException, RuntimeException)
443 {
444 OGuard aGuard( Application::GetSolarMutex() );
445
446 CellRef xCell( getCell( nColumn, nRow ) );
447 if( xCell.is() )
448 return xCell.get();
449
450 throw IndexOutOfBoundsException();
451 }
452
453 // -----------------------------------------------------------------------------
454
getCellRangeByPosition(sal_Int32 nLeft,sal_Int32 nTop,sal_Int32 nRight,sal_Int32 nBottom)455 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException)
456 {
457 OGuard aGuard( Application::GetSolarMutex() );
458
459 if( (nLeft >= 0) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) && (nRight < getColumnCountImpl()) && (nBottom < getRowCountImpl() ) )
460 {
461 TableModelRef xModel( this );
462 return new CellRange( xModel, nLeft, nTop, nRight, nBottom );
463 }
464
465 throw IndexOutOfBoundsException();
466 }
467
468 // -----------------------------------------------------------------------------
469
getCellRangeByName(const OUString &)470 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException)
471 {
472 return Reference< XCellRange >();
473 }
474
475 // -----------------------------------------------------------------------------
476 // XPropertySet
477 // -----------------------------------------------------------------------------
478
getPropertySetInfo()479 Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo( ) throw (RuntimeException)
480 {
481 Reference< XPropertySetInfo > xInfo;
482 return xInfo;
483 }
484
485 // -----------------------------------------------------------------------------
486
setPropertyValue(const::rtl::OUString &,const Any &)487 void SAL_CALL TableModel::setPropertyValue( const ::rtl::OUString& /*aPropertyName*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
488 {
489 }
490
491 // -----------------------------------------------------------------------------
492
getPropertyValue(const OUString &)493 Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
494 {
495 return Any();
496 }
497
498 // -----------------------------------------------------------------------------
499
addPropertyChangeListener(const OUString &,const Reference<XPropertyChangeListener> &)500 void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
501 {
502 }
503
504 // -----------------------------------------------------------------------------
505
removePropertyChangeListener(const OUString &,const Reference<XPropertyChangeListener> &)506 void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
507 {
508 }
509
510 // -----------------------------------------------------------------------------
511
addVetoableChangeListener(const OUString &,const Reference<XVetoableChangeListener> &)512 void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
513 {
514 }
515
516 // -----------------------------------------------------------------------------
517
removeVetoableChangeListener(const OUString &,const Reference<XVetoableChangeListener> &)518 void SAL_CALL TableModel::removeVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
519 {
520 }
521
522 // -----------------------------------------------------------------------------
523 // XFastPropertySet
524 // -----------------------------------------------------------------------------
525
setFastPropertyValue(::sal_Int32,const Any &)526 void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
527 {
528 }
529
530 // -----------------------------------------------------------------------------
531
getFastPropertyValue(::sal_Int32)532 Any SAL_CALL TableModel::getFastPropertyValue( ::sal_Int32 /*nHandle*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
533 {
534 Any aAny;
535 return aAny;
536 }
537
538 // -----------------------------------------------------------------------------
539 // internals
540 // -----------------------------------------------------------------------------
541
getRowCountImpl() const542 sal_Int32 TableModel::getRowCountImpl() const
543 {
544 return static_cast< sal_Int32 >( maRows.size() );
545 }
546
547 // -----------------------------------------------------------------------------
548
getColumnCountImpl() const549 sal_Int32 TableModel::getColumnCountImpl() const
550 {
551 return static_cast< sal_Int32 >( maColumns.size() );
552 }
553
554 // -----------------------------------------------------------------------------
555
disposing()556 void TableModel::disposing()
557 {
558 if( !maRows.empty() )
559 {
560 RowVector::iterator aIter( maRows.begin() );
561 while( aIter != maRows.end() )
562 (*aIter++)->dispose();
563 RowVector().swap(maRows);
564 }
565
566 if( !maColumns.empty() )
567 {
568 ColumnVector::iterator aIter( maColumns.begin() );
569 while( aIter != maColumns.end() )
570 (*aIter++)->dispose();
571 ColumnVector().swap(maColumns);
572 }
573
574 if( mxTableColumns.is() )
575 {
576 mxTableColumns->dispose();
577 mxTableColumns.clear();
578 }
579
580 if( mxTableRows.is() )
581 {
582 mxTableRows->dispose();
583 mxTableRows.clear();
584 }
585
586 mpTableObj = 0;
587 }
588
589 // -----------------------------------------------------------------------------
590 // XBroadcaster
591 // -----------------------------------------------------------------------------
592
lockBroadcasts()593 void TableModel::lockBroadcasts() throw (RuntimeException)
594 {
595 OGuard aGuard( Application::GetSolarMutex() );
596 ++mnNotifyLock;
597 }
598 // -----------------------------------------------------------------------------
599
unlockBroadcasts()600 void TableModel::unlockBroadcasts() throw (RuntimeException)
601 {
602 OGuard aGuard( Application::GetSolarMutex() );
603 --mnNotifyLock;
604 if( mnNotifyLock <= 0 )
605 {
606 mnNotifyLock = 0;
607 if( mbNotifyPending )
608 notifyModification();
609 }
610 }
611
612 // -----------------------------------------------------------------------------
613 #ifdef PLEASE_DEBUG_THE_TABLES
614 #include <stdio.h>
615 #endif
616
notifyModification()617 void TableModel::notifyModification()
618 {
619 ::osl::MutexGuard guard( m_aMutex );
620 if( (mnNotifyLock == 0) && mpTableObj && mpTableObj->GetModel() )
621 {
622 mbNotifyPending = false;
623
624 ::cppu::OInterfaceContainerHelper * pModifyListeners = rBHelper.getContainer( XModifyListener::static_type() );
625 if( pModifyListeners )
626 {
627 EventObject aSource;
628 aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
629 pModifyListeners->notifyEach( &XModifyListener::modified, aSource);
630 }
631 }
632 else
633 {
634 mbNotifyPending = true;
635 }
636
637 #ifdef PLEASE_DEBUG_THE_TABLES
638 FILE* file = fopen( "c:\\table.xml","w" );
639
640 const sal_Int32 nColCount = getColumnCountImpl();
641 const sal_Int32 nRowCount = getRowCountImpl();
642
643 fprintf( file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\r" );
644 fprintf( file, "<table columns=\"%ld\" rows=\"%ld\" updated=\"%s\">\n\r", nColCount, nRowCount, mbNotifyPending ? "false" : "true");
645
646 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
647 {
648 fprintf( file, "<column this=\"%lx\"/>\n\r", maColumns[nCol].get() );
649 }
650
651 // first check merged cells before and inside the removed rows
652 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
653 {
654 fprintf( file, "<row this=\"%lx\">\n\r", maRows[nRow].get() );
655 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
656 {
657 CellRef xCell( getCell( nCol, nRow ) );
658 fprintf( file, "<cell this=\"%lx\"", xCell.get() );
659
660 sal_Int32 nRowSpan = xCell->getRowSpan();
661 sal_Int32 nColSpan = xCell->getColumnSpan();
662 sal_Bool bMerged = xCell->isMerged();
663
664 if( nColSpan != 1 )
665 fprintf( file, " column-span=\"%ld\"", nColSpan );
666 if( nRowSpan != 1 )
667 fprintf( file, " row-span=\"%ld\"", nRowSpan );
668
669 if( bMerged )
670 fprintf( file, " merged=\"true\"" );
671
672 fprintf( file, "/>" );
673 }
674 fprintf( file, "\n\r</row>\n\r" );
675 }
676
677 fprintf( file, "</table>\n\r" );
678 fclose( file );
679 #endif
680 }
681
682 // -----------------------------------------------------------------------------
683
getCell(sal_Int32 nCol,sal_Int32 nRow) const684 CellRef TableModel::getCell( sal_Int32 nCol, sal_Int32 nRow ) const
685 {
686 if( ((nRow >= 0) && (nRow < getRowCountImpl())) && (nCol >= 0) && (nCol < getColumnCountImpl()) )
687 {
688 return maRows[nRow]->maCells[nCol];
689 }
690 else
691 {
692 CellRef xRet;
693 return xRet;
694 }
695 }
696
697 // -----------------------------------------------------------------------------
698 /*
699 bool TableModel::getCellPos( const CellRef& xCell, ::sal_Int32& rnCol, ::sal_Int32& rnRow ) const
700 {
701 const sal_Int32 nRowCount = getRowCount();
702 const sal_Int32 nColCount = getColumnCount();
703 for( rnRow = 0; rnRow < nRowCount; rnRow++ )
704 {
705 for( rnCol = 0; rnCol < nColCount; rnCol++ )
706 {
707 if( maRows[rnRow]->maCells[rnCol] == xCell )
708 {
709 return true;
710 }
711 }
712 }
713 return false;
714 }
715 */
716
717 // -----------------------------------------------------------------------------
718
createCell()719 CellRef TableModel::createCell()
720 {
721 CellRef xCell;
722 if( mpTableObj )
723 mpTableObj->createCell( xCell );
724 return xCell;
725 }
726
727 // -----------------------------------------------------------------------------
728
insertColumns(sal_Int32 nIndex,sal_Int32 nCount)729 void TableModel::insertColumns( sal_Int32 nIndex, sal_Int32 nCount )
730 {
731 if( nCount && mpTableObj )
732 {
733 try
734 {
735 SdrModel* pModel = mpTableObj->GetModel();
736
737 TableModelNotifyGuard aGuard( this );
738 nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
739
740 sal_Int32 nRows = getRowCountImpl();
741 while( nRows-- )
742 maRows[nRows]->insertColumns( nIndex, nCount );
743
744 ColumnVector aNewColumns(nCount);
745 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
746 {
747 TableColumnRef xNewCol( new TableColumn( this, nIndex+nOffset ) );
748 maColumns[nIndex+nOffset] = xNewCol;
749 aNewColumns[nOffset] = xNewCol;
750 }
751
752 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
753 if( bUndo )
754 {
755 pModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) );
756 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
757
758 TableModelRef xThis( this );
759
760 nRows = getRowCountImpl();
761 CellVector aNewCells( nCount * nRows );
762 CellVector::iterator aCellIter( aNewCells.begin() );
763
764 nRows = getRowCountImpl();
765 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
766 {
767 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
768 (*aCellIter++) = getCell( nIndex + nOffset, nRow );
769 }
770
771 pModel->AddUndo( new InsertColUndo( xThis, nIndex, aNewColumns, aNewCells ) );
772 }
773
774 const sal_Int32 nRowCount = getRowCountImpl();
775 // check if cells merge over new columns
776 for( sal_Int32 nCol = 0; nCol < nIndex; ++nCol )
777 {
778 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
779 {
780 CellRef xCell( getCell( nCol, nRow ) );
781 sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
782 if( (nColSpan != 1) && ((nColSpan + nCol ) > nIndex) )
783 {
784 // cell merges over newly created columns, so add the new columns to the merged cell
785 const sal_Int32 nRowSpan = xCell->getRowSpan();
786 nColSpan += nCount;
787 merge( nCol, nRow, nColSpan, nRowSpan );
788 }
789 }
790 }
791
792 if( bUndo )
793 pModel->EndUndo();
794
795 if( pModel )
796 pModel->SetChanged();
797
798 }
799 catch( Exception& )
800 {
801 DBG_ERROR("sdr::table::TableModel::insertColumns(), exception caught!");
802 }
803 updateColumns();
804 setModified(sal_True);
805 }
806 }
807
808 // -----------------------------------------------------------------------------
809
removeColumns(sal_Int32 nIndex,sal_Int32 nCount)810 void TableModel::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
811 {
812 sal_Int32 nColCount = getColumnCountImpl();
813
814 if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nColCount) )
815 {
816 try
817 {
818 TableModelNotifyGuard aGuard( this );
819
820 // clip removed columns to columns actually available
821 if( (nIndex + nCount) > nColCount )
822 nCount = nColCount - nIndex;
823
824 sal_Int32 nRows = getRowCountImpl();
825
826 SdrModel* pModel = mpTableObj->GetModel();
827
828 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
829 if( bUndo )
830 {
831 pModel->BegUndo( ImpGetResStr(STR_UNDO_COL_DELETE) );
832 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
833
834 TableModelRef xThis( this );
835 ColumnVector aRemovedCols( nCount );
836 sal_Int32 nOffset;
837 for( nOffset = 0; nOffset < nCount; ++nOffset )
838 {
839 aRemovedCols[nOffset] = maColumns[nIndex+nOffset];
840 }
841
842 CellVector aRemovedCells( nCount * nRows );
843 CellVector::iterator aCellIter( aRemovedCells.begin() );
844 for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
845 {
846 for( nOffset = 0; nOffset < nCount; ++nOffset )
847 (*aCellIter++) = getCell( nIndex + nOffset, nRow );
848 }
849
850 pModel->AddUndo( new RemoveColUndo( xThis, nIndex, aRemovedCols, aRemovedCells ) );
851 }
852
853 // only rows before and inside the removed rows are considered
854 nColCount = nIndex + nCount + 1;
855
856 const sal_Int32 nRowCount = getRowCountImpl();
857
858 // first check merged cells before and inside the removed rows
859 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
860 {
861 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
862 {
863 CellRef xCell( getCell( nCol, nRow ) );
864 sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
865 if( nColSpan <= 1 )
866 continue;
867
868 if( nCol >= nIndex )
869 {
870 // current cell is inside the removed columns
871 if( (nCol + nColSpan) > ( nIndex + nCount ) )
872 {
873 // current cells merges with columns after the removed columns
874 const sal_Int32 nRemove = nCount - nCol + nIndex;
875
876 CellRef xTargetCell( getCell( nIndex + nCount, nRow ) );
877 if( xTargetCell.is() )
878 {
879 if( bUndo )
880 xTargetCell->AddUndo();
881 xTargetCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
882 xTargetCell->replaceContentAndFormatting( xCell );
883 }
884 }
885 }
886 else if( nColSpan > (nIndex - nCol) )
887 {
888 // current cells spans inside the removed columns, so adjust
889 const sal_Int32 nRemove = ::std::min( nCount, nCol + nColSpan - nIndex );
890 if( bUndo )
891 xCell->AddUndo();
892 xCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
893 }
894 }
895 }
896
897 // now remove the columns
898 remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
899 while( nRows-- )
900 maRows[nRows]->removeColumns( nIndex, nCount );
901
902 if( bUndo )
903 pModel->EndUndo();
904
905 if( pModel )
906 pModel->SetChanged();
907 }
908 catch( Exception& )
909 {
910 DBG_ERROR("sdr::table::TableModel::removeColumns(), exception caught!");
911 }
912
913 updateColumns();
914 setModified(sal_True);
915 }
916 }
917
918 // -----------------------------------------------------------------------------
919
insertRows(sal_Int32 nIndex,sal_Int32 nCount)920 void TableModel::insertRows( sal_Int32 nIndex, sal_Int32 nCount )
921 {
922 if( nCount && mpTableObj )
923 {
924 SdrModel* pModel = mpTableObj->GetModel();
925 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
926 try
927 {
928 TableModelNotifyGuard aGuard( this );
929
930 nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
931
932 RowVector aNewRows(nCount);
933 const sal_Int32 nColCount = getColumnCountImpl();
934 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
935 {
936 TableRowRef xNewRow( new TableRow( this, nIndex+nOffset, nColCount ) );
937 maRows[nIndex+nOffset] = xNewRow;
938 aNewRows[nOffset] = xNewRow;
939 }
940
941 if( bUndo )
942 {
943 pModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW) );
944 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
945 TableModelRef xThis( this );
946 pModel->AddUndo( new InsertRowUndo( xThis, nIndex, aNewRows ) );
947 }
948
949 // check if cells merge over new columns
950 for( sal_Int32 nRow = 0; nRow < nIndex; ++nRow )
951 {
952 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
953 {
954 CellRef xCell( getCell( nCol, nRow ) );
955 sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
956 if( (nRowSpan > 1) && ((nRowSpan + nRow) > nIndex) )
957 {
958 // cell merges over newly created columns, so add the new columns to the merged cell
959 const sal_Int32 nColSpan = xCell->getColumnSpan();
960 nRowSpan += nCount;
961 merge( nCol, nRow, nColSpan, nRowSpan );
962 }
963 }
964 }
965 }
966 catch( Exception& )
967 {
968 DBG_ERROR("sdr::table::TableModel::insertRows(), exception caught!");
969 }
970 if( bUndo )
971 pModel->EndUndo();
972
973 if( pModel )
974 pModel->SetChanged();
975
976 updateRows();
977 setModified(sal_True);
978 }
979 }
980
981 // -----------------------------------------------------------------------------
982
removeRows(sal_Int32 nIndex,sal_Int32 nCount)983 void TableModel::removeRows( sal_Int32 nIndex, sal_Int32 nCount )
984 {
985 sal_Int32 nRowCount = getRowCountImpl();
986
987 if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nRowCount) )
988 {
989 SdrModel* pModel = mpTableObj->GetModel();
990 const bool bUndo = pModel && mpTableObj->IsInserted()&& pModel->IsUndoEnabled();
991
992 try
993 {
994 TableModelNotifyGuard aGuard( this );
995
996 // clip removed rows to rows actually available
997 if( (nIndex + nCount) > nRowCount )
998 nCount = nRowCount - nIndex;
999
1000 if( bUndo )
1001 {
1002 pModel->BegUndo( ImpGetResStr(STR_UNDO_ROW_DELETE) );
1003 pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
1004
1005 TableModelRef xThis( this );
1006
1007 RowVector aRemovedRows( nCount );
1008 for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
1009 aRemovedRows[nOffset] = maRows[nIndex+nOffset];
1010
1011 pModel->AddUndo( new RemoveRowUndo( xThis, nIndex, aRemovedRows ) );
1012 }
1013
1014 // only rows before and inside the removed rows are considered
1015 nRowCount = nIndex + nCount + 1;
1016
1017 const sal_Int32 nColCount = getColumnCountImpl();
1018
1019 // first check merged cells before and inside the removed rows
1020 for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
1021 {
1022 for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
1023 {
1024 CellRef xCell( getCell( nCol, nRow ) );
1025 sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
1026 if( nRowSpan <= 1 )
1027 continue;
1028
1029 if( nRow >= nIndex )
1030 {
1031 // current cell is inside the removed rows
1032 if( (nRow + nRowSpan) > (nIndex + nCount) )
1033 {
1034 // current cells merges with rows after the removed rows
1035 const sal_Int32 nRemove = nCount - nRow + nIndex;
1036
1037 CellRef xTargetCell( getCell( nCol, nIndex + nCount ) );
1038 if( xTargetCell.is() )
1039 {
1040 if( bUndo )
1041 xTargetCell->AddUndo();
1042 xTargetCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
1043 xTargetCell->replaceContentAndFormatting( xCell );
1044 }
1045 }
1046 }
1047 else if( nRowSpan > (nIndex - nRow) )
1048 {
1049 // current cells spans inside the removed rows, so adjust
1050 const sal_Int32 nRemove = ::std::min( nCount, nRow + nRowSpan - nIndex );
1051 if( bUndo )
1052 xCell->AddUndo();
1053 xCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
1054 }
1055 }
1056 }
1057
1058 // now remove the rows
1059 remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
1060
1061 if( bUndo )
1062 pModel->EndUndo();
1063
1064 if( pModel )
1065 pModel->SetChanged();
1066 }
1067 catch( Exception& )
1068 {
1069 DBG_ERROR("sdr::table::TableModel::removeRows(), exception caught!");
1070 }
1071
1072 updateRows();
1073 setModified(sal_True);
1074 }
1075 }
1076
1077 // -----------------------------------------------------------------------------
1078
getRow(sal_Int32 nRow) const1079 TableRowRef TableModel::getRow( sal_Int32 nRow ) const throw (IndexOutOfBoundsException)
1080 {
1081 if( (nRow >= 0) && (nRow < getRowCountImpl()) )
1082 return maRows[nRow];
1083
1084 throw IndexOutOfBoundsException();
1085 }
1086
1087 // -----------------------------------------------------------------------------
1088
getColumn(sal_Int32 nColumn) const1089 TableColumnRef TableModel::getColumn( sal_Int32 nColumn ) const throw (IndexOutOfBoundsException)
1090 {
1091 if( (nColumn >= 0) && (nColumn < getColumnCountImpl()) )
1092 return maColumns[nColumn];
1093
1094 throw IndexOutOfBoundsException();
1095 }
1096
1097 // -----------------------------------------------------------------------------
1098
1099 /** deletes rows and columns that are completely merged. Must be called between BegUndo/EndUndo! */
optimize()1100 void TableModel::optimize()
1101 {
1102 TableModelNotifyGuard aGuard( this );
1103
1104 bool bWasModified = false;
1105
1106 if( !maRows.empty() && !maColumns.empty() )
1107 {
1108 sal_Int32 nCol = getColumnCountImpl() - 1;
1109 while( nCol > 0 )
1110 {
1111 bool bEmpty = true;
1112 for( sal_Int32 nRow = 0; (nRow < getRowCountImpl()) && bEmpty; nRow++ )
1113 {
1114 Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1115 if( xCell.is() && !xCell->isMerged() )
1116 bEmpty = false;
1117 }
1118
1119 if( bEmpty )
1120 {
1121 if( nCol > 0 ) try
1122 {
1123 const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM("Width") );
1124 sal_Int32 nWidth1 = 0, nWidth2 = 0;
1125 Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maColumns[nCol].get() ), UNO_QUERY_THROW );
1126 Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maColumns[nCol-1].get() ), UNO_QUERY_THROW );
1127 xSet1->getPropertyValue( sWidth ) >>= nWidth1;
1128 xSet2->getPropertyValue( sWidth ) >>= nWidth2;
1129 nWidth1 += nWidth2;
1130 xSet2->setPropertyValue( sWidth, Any( nWidth1 ) );
1131 }
1132 catch( Exception& e )
1133 {
1134 (void)e;
1135 DBG_ERROR("svx::TableModel::optimize(), exception caught!");
1136 }
1137
1138 removeColumns( nCol, 1 );
1139 bWasModified = true;
1140 }
1141
1142 nCol--;
1143 }
1144
1145 sal_Int32 nRow = getRowCountImpl() - 1;
1146 while( nRow > 0 )
1147 {
1148 bool bEmpty = true;
1149 for( nCol = 0; (nCol < getColumnCountImpl()) && bEmpty; nCol++ )
1150 {
1151 Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1152 if( xCell.is() && !xCell->isMerged() )
1153 bEmpty = false;
1154 }
1155
1156 if( bEmpty )
1157 {
1158 if( nRow > 0 ) try
1159 {
1160 const OUString sHeight( RTL_CONSTASCII_USTRINGPARAM("Height") );
1161 sal_Int32 nHeight1 = 0, nHeight2 = 0;
1162 Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maRows[nRow].get() ), UNO_QUERY_THROW );
1163 Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maRows[nRow-1].get() ), UNO_QUERY_THROW );
1164 xSet1->getPropertyValue( sHeight ) >>= nHeight1;
1165 xSet2->getPropertyValue( sHeight ) >>= nHeight2;
1166 nHeight1 += nHeight2;
1167 xSet2->setPropertyValue( sHeight, Any( nHeight1 ) );
1168 }
1169 catch( Exception& e )
1170 {
1171 (void)e;
1172 DBG_ERROR("svx::TableModel::optimize(), exception caught!");
1173 }
1174
1175 removeRows( nRow, 1 );
1176 bWasModified = true;
1177 }
1178
1179 nRow--;
1180 }
1181 }
1182 if( bWasModified )
1183 setModified(sal_True);
1184 }
1185
1186 // -----------------------------------------------------------------------------
1187
merge(sal_Int32 nCol,sal_Int32 nRow,sal_Int32 nColSpan,sal_Int32 nRowSpan)1188 void TableModel::merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan )
1189 {
1190 SdrModel* pModel = mpTableObj->GetModel();
1191
1192 const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
1193
1194 const sal_Int32 nLastRow = nRow + nRowSpan;
1195 const sal_Int32 nLastCol = nCol + nColSpan;
1196
1197 if( (nLastRow > getRowCount()) || (nLastCol > getRowCount() ) )
1198 {
1199 DBG_ERROR("TableModel::merge(), merge beyound the table!");
1200 }
1201
1202 // merge first cell
1203 CellRef xOriginCell( dynamic_cast< Cell* >( getCellByPosition( nCol, nRow ).get() ) );
1204 if( xOriginCell.is() )
1205 {
1206 if( bUndo )
1207 xOriginCell->AddUndo();
1208 xOriginCell->merge( nColSpan, nRowSpan );
1209 }
1210
1211 sal_Int32 nTempCol = nCol + 1;
1212
1213 // merge remaining cells
1214 for( ; nRow < nLastRow; nRow++ )
1215 {
1216 for( ; nTempCol < nLastCol; nTempCol++ )
1217 {
1218 CellRef xCell( dynamic_cast< Cell* >( getCellByPosition( nTempCol, nRow ).get() ) );
1219 if( xCell.is() && !xCell->isMerged() )
1220 {
1221 if( bUndo )
1222 xCell->AddUndo();
1223 xCell->setMerged();
1224 xOriginCell->mergeContent( xCell );
1225 }
1226 }
1227 nTempCol = nCol;
1228 }
1229 }
1230
1231
1232 // -----------------------------------------------------------------------------
1233
updateRows()1234 void TableModel::updateRows()
1235 {
1236 sal_Int32 nRow = 0;
1237 RowVector::iterator iter = maRows.begin();
1238 while( iter != maRows.end() )
1239 {
1240 (*iter++)->mnRow = nRow++;
1241 }
1242 }
1243
1244 // -----------------------------------------------------------------------------
1245
updateColumns()1246 void TableModel::updateColumns()
1247 {
1248 sal_Int32 nColumn = 0;
1249 ColumnVector::iterator iter = maColumns.begin();
1250 while( iter != maColumns.end() )
1251 {
1252 (*iter++)->mnColumn = nColumn++;
1253 }
1254 }
1255
1256 // -----------------------------------------------------------------------------
1257
1258 } }
1259