xref: /aoo41x/main/svx/source/table/tablemodel.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 
31 #include <com/sun/star/table/XMergeableCell.hpp>
32 
33 #include <algorithm>
34 #include <boost/bind.hpp>
35 
36 #include <vcl/svapp.hxx>
37 #include <vos/mutex.hxx>
38 
39 #include "cell.hxx"
40 #include "cellcursor.hxx"
41 #include "tablemodel.hxx"
42 #include "tablerow.hxx"
43 #include "tablerows.hxx"
44 #include "tablecolumn.hxx"
45 #include "tablecolumns.hxx"
46 #include "tableundo.hxx"
47 #include "svx/svdotable.hxx"
48 #include "svx/svdmodel.hxx"
49 #include "svx/svdstr.hrc"
50 #include "svx/svdglob.hxx"
51 
52 //#define PLEASE_DEBUG_THE_TABLES 1
53 
54 using ::rtl::OUString;
55 using namespace ::osl;
56 using namespace ::vos;
57 using namespace ::com::sun::star::uno;
58 using namespace ::com::sun::star::table;
59 using namespace ::com::sun::star::lang;
60 using namespace ::com::sun::star::container;
61 using namespace ::com::sun::star::beans;
62 using namespace ::com::sun::star::util;
63 
64 // -----------------------------------------------------------------------------
65 
66 namespace sdr { namespace table {
67 
68 // -----------------------------------------------------------------------------
69 
70 // removes the given range from a vector
71 template< class Vec, class Iter > void remove_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
72 {
73 	const sal_Int32 nSize = static_cast<sal_Int32>(rVector.size());
74 	if( nCount && (nIndex >= 0) && (nIndex < nSize) )
75 	{
76 		if( (nIndex + nCount) >= nSize )
77 		{
78 			// remove at end
79 			rVector.resize( nIndex );
80 		}
81 		else
82 		{
83 			Iter aBegin( rVector.begin() );
84 			while( nIndex-- )
85 				aBegin++;
86 			if( nCount == 1 )
87 			{
88 				rVector.erase( aBegin );
89 			}
90 			else
91 			{
92 				Iter aEnd( aBegin );
93 
94 				while( nCount-- )
95 					aEnd++;
96 				rVector.erase( aBegin, aEnd );
97 			}
98 		}
99 	}
100 }
101 
102 // -----------------------------------------------------------------------------
103 
104 /** inserts a range into a vector */
105 template< class Vec, class Iter, class Entry > sal_Int32 insert_range( Vec& rVector, sal_Int32 nIndex, sal_Int32 nCount )
106 {
107 	if( nCount )
108 	{
109 		if( nIndex >= static_cast< sal_Int32 >( rVector.size() ) )
110 		{
111 			// append at end
112 			nIndex = static_cast< sal_Int32 >( rVector.size() ); // cap to end
113 			rVector.resize( nIndex + nCount );
114 		}
115 		else
116 		{
117 			// insert
118 			sal_Int32 nFind = nIndex;
119 			Iter aIter( rVector.begin() );
120 			while( nFind-- )
121 				aIter++;
122 
123 			Entry aEmpty;
124 			rVector.insert( aIter, nCount, aEmpty );
125 		}
126 	}
127 	return nIndex;
128 }
129 
130 // -----------------------------------------------------------------------------
131 
132 TableModel::TableModel( SdrTableObj* pTableObj )
133 : TableModelBase( m_aMutex  )
134 , mpTableObj( pTableObj )
135 , mbModified( sal_False )
136 , mbNotifyPending( false )
137 , mnNotifyLock( 0 )
138 {
139 }
140 
141 TableModel::TableModel( SdrTableObj* pTableObj, const TableModelRef& xSourceTable )
142 : TableModelBase( m_aMutex  )
143 , mpTableObj( pTableObj )
144 , mbModified( sal_False )
145 , mbNotifyPending( false )
146 , mnNotifyLock( 0 )
147 {
148 	if( xSourceTable.is() )
149 	{
150 		const sal_Int32 nColCount = xSourceTable->getColumnCountImpl();
151 		const sal_Int32 nRowCount = xSourceTable->getRowCountImpl();
152 
153 		init( nColCount, nRowCount );
154 
155 		sal_Int32 nRows = nRowCount;
156 		while( nRows-- )
157 			(*maRows[nRows]) = (*xSourceTable->maRows[nRows]);
158 
159 		sal_Int32 nColumns = nColCount;
160 		while( nColumns-- )
161 			(*maColumns[nColumns]) = (*xSourceTable->maColumns[nColumns]);
162 
163 		// copy cells
164 		for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
165 		{
166 			for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
167 			{
168 				CellRef xTargetCell( getCell( nCol, nRow ) );
169 				if( xTargetCell.is() )
170 					xTargetCell->cloneFrom( xSourceTable->getCell( nCol, nRow ) );
171 			}
172 		}
173 	}
174 }
175 
176 // -----------------------------------------------------------------------------
177 
178 TableModel::~TableModel()
179 {
180 }
181 
182 // -----------------------------------------------------------------------------
183 
184 void TableModel::init( sal_Int32 nColumns, sal_Int32 nRows )
185 {
186 	if( nRows < 20 )
187 		maRows.reserve( 20 );
188 
189 	if( nColumns < 20 )
190 		maColumns.reserve( 20 );
191 
192 	if( nRows && nColumns )
193 	{
194 		maColumns.resize( nColumns );
195 		maRows.resize( nRows );
196 
197 		while( nRows-- )
198 			maRows[nRows].set( new TableRow( this, nRows, nColumns ) );
199 
200 		while( nColumns-- )
201 			maColumns[nColumns].set( new TableColumn( this, nColumns ) );
202 	}
203 }
204 
205 // -----------------------------------------------------------------------------
206 // ICellRange
207 // -----------------------------------------------------------------------------
208 
209 sal_Int32 TableModel::getLeft()
210 {
211 	return 0;
212 }
213 
214 // -----------------------------------------------------------------------------
215 
216 sal_Int32 TableModel::getTop()
217 {
218 	return 0;
219 }
220 
221 // -----------------------------------------------------------------------------
222 
223 sal_Int32 TableModel::getRight()
224 {
225 	return getColumnCount();
226 }
227 
228 // -----------------------------------------------------------------------------
229 
230 sal_Int32 TableModel::getBottom()
231 {
232 	return getRowCount();
233 }
234 
235 // -----------------------------------------------------------------------------
236 
237 Reference< XTable > TableModel::getTable()
238 {
239 	return this;
240 }
241 
242 // -----------------------------------------------------------------------------
243 
244 void TableModel::UndoInsertRows( sal_Int32 nIndex, sal_Int32 nCount )
245 {
246 	TableModelNotifyGuard aGuard( this );
247 
248 	// remove the rows
249 	remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
250     updateRows();
251 	setModified(sal_True);
252 }
253 
254 // -----------------------------------------------------------------------------
255 
256 void TableModel::UndoRemoveRows( sal_Int32 nIndex, RowVector& aRows )
257 {
258 	TableModelNotifyGuard aGuard( this );
259 
260 	const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aRows.size() );
261 
262 	nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
263 
264 	for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
265 		maRows[nIndex+nOffset] = aRows[nOffset];
266 
267     updateRows();
268 	setModified(sal_True);
269 }
270 
271 // -----------------------------------------------------------------------------
272 
273 void TableModel::UndoInsertColumns( sal_Int32 nIndex, sal_Int32 nCount )
274 {
275 	TableModelNotifyGuard aGuard( this );
276 
277 	// now remove the columns
278 	remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
279 	sal_Int32 nRows = getRowCountImpl();
280 	while( nRows-- )
281 		maRows[nRows]->removeColumns( nIndex, nCount );
282 
283     updateColumns();
284 	setModified(sal_True);
285 }
286 
287 // -----------------------------------------------------------------------------
288 
289 void TableModel::UndoRemoveColumns( sal_Int32 nIndex, ColumnVector& aCols, CellVector& aCells )
290 {
291 	TableModelNotifyGuard aGuard( this );
292 
293 	const sal_Int32 nCount = sal::static_int_cast< sal_Int32 >( aCols.size() );
294 
295 	// assert if there are not enough cells saved
296 	DBG_ASSERT( (aCols.size() * maRows.size()) == aCells.size(), "sdr::table::TableModel::UndoRemoveColumns(), invalid undo data!" );
297 
298 	nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
299 	for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
300 		maColumns[nIndex+nOffset] = aCols[nOffset];
301 
302 	CellVector::iterator aIter( aCells.begin() );
303 
304 	sal_Int32 nRows = getRowCountImpl();
305 	for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
306 		maRows[nRow]->insertColumns( nIndex, nCount, &aIter );
307 
308     updateColumns();
309 	setModified(sal_True);
310 }
311 
312 // -----------------------------------------------------------------------------
313 // XTable
314 // -----------------------------------------------------------------------------
315 
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 
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 
338 sal_Int32 SAL_CALL TableModel::getRowCount() throw (RuntimeException)
339 {
340 	OGuard aGuard( Application::GetSolarMutex() );
341 	return getRowCountImpl();
342 }
343 
344 // -----------------------------------------------------------------------------
345 
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 
356 void TableModel::dispose() throw (RuntimeException)
357 {
358 	OGuard aGuard( Application::GetSolarMutex() );
359 	TableModelBase::dispose();
360 }
361 
362 // -----------------------------------------------------------------------------
363 
364 void SAL_CALL TableModel::addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
365 {
366 	TableModelBase::addEventListener( xListener );
367 }
368 
369 // -----------------------------------------------------------------------------
370 
371 void SAL_CALL TableModel::removeEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
372 {
373 	TableModelBase::removeEventListener( xListener );
374 }
375 
376 // -----------------------------------------------------------------------------
377 // XModifiable
378 // -----------------------------------------------------------------------------
379 
380 sal_Bool SAL_CALL TableModel::isModified(  ) throw (RuntimeException)
381 {
382 	OGuard aGuard( Application::GetSolarMutex() );
383 	return mbModified;
384 }
385 
386 // -----------------------------------------------------------------------------
387 
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 
402 void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
403 {
404 	rBHelper.addListener( XModifyListener::static_type() , xListener );
405 }
406 
407 // -----------------------------------------------------------------------------
408 
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 
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 
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 
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 
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 
470 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException)
471 {
472 	return Reference< XCellRange >();
473 }
474 
475 // -----------------------------------------------------------------------------
476 // XPropertySet
477 // -----------------------------------------------------------------------------
478 
479 Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo(  ) throw (RuntimeException)
480 {
481 	Reference< XPropertySetInfo > xInfo;
482 	return xInfo;
483 }
484 
485 // -----------------------------------------------------------------------------
486 
487 void SAL_CALL TableModel::setPropertyValue( const ::rtl::OUString& /*aPropertyName*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
488 {
489 }
490 
491 // -----------------------------------------------------------------------------
492 
493 Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
494 {
495 	return Any();
496 }
497 
498 // -----------------------------------------------------------------------------
499 
500 void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
501 {
502 }
503 
504 // -----------------------------------------------------------------------------
505 
506 void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
507 {
508 }
509 
510 // -----------------------------------------------------------------------------
511 
512 void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
513 {
514 }
515 
516 // -----------------------------------------------------------------------------
517 
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 
526 void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
527 {
528 }
529 
530 // -----------------------------------------------------------------------------
531 
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 
542 sal_Int32 TableModel::getRowCountImpl() const
543 {
544 	return static_cast< sal_Int32 >( maRows.size() );
545 }
546 
547 // -----------------------------------------------------------------------------
548 
549 sal_Int32 TableModel::getColumnCountImpl() const
550 {
551 	return static_cast< sal_Int32 >( maColumns.size() );
552 }
553 
554 // -----------------------------------------------------------------------------
555 
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 
593 void TableModel::lockBroadcasts() throw (RuntimeException)
594 {
595 	OGuard aGuard( Application::GetSolarMutex() );
596 	++mnNotifyLock;
597 }
598 // -----------------------------------------------------------------------------
599 
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 
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 
684 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 
719 CellRef TableModel::createCell()
720 {
721 	CellRef xCell;
722 	if( mpTableObj )
723 		mpTableObj->createCell( xCell );
724 	return xCell;
725 }
726 
727 // -----------------------------------------------------------------------------
728 
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 
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 
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 
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 
1079 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 
1089 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! */
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 
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 
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 
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