xref: /AOO41X/main/svx/source/table/tablemodel.cxx (revision 04f4019c437c8e2792962dc7c04252117eb65c03)
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 avalaible
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->replaceContentAndFormating( 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 avalaible
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->replaceContentAndFormating( 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 completly 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