xref: /aoo42x/main/svx/source/table/tablemodel.cxx (revision f6e50924)
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
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 */
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 
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 
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 
174 TableModel::~TableModel()
175 {
176 }
177 
178 // -----------------------------------------------------------------------------
179 
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 
205 sal_Int32 TableModel::getLeft()
206 {
207 	return 0;
208 }
209 
210 // -----------------------------------------------------------------------------
211 
212 sal_Int32 TableModel::getTop()
213 {
214 	return 0;
215 }
216 
217 // -----------------------------------------------------------------------------
218 
219 sal_Int32 TableModel::getRight()
220 {
221 	return getColumnCount();
222 }
223 
224 // -----------------------------------------------------------------------------
225 
226 sal_Int32 TableModel::getBottom()
227 {
228 	return getRowCount();
229 }
230 
231 // -----------------------------------------------------------------------------
232 
233 Reference< XTable > TableModel::getTable()
234 {
235 	return this;
236 }
237 
238 // -----------------------------------------------------------------------------
239 
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 
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 
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 
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 		maRows[nRow]->insertColumns( nIndex, nCount, &aIter );
303 
304     updateColumns();
305 	setModified(sal_True);
306 }
307 
308 // -----------------------------------------------------------------------------
309 // XTable
310 // -----------------------------------------------------------------------------
311 
312 Reference< XCellCursor > SAL_CALL TableModel::createCursor() throw (RuntimeException)
313 {
314 	OGuard aGuard( Application::GetSolarMutex() );
315 	return createCursorByRange( Reference< XCellRange >( this ) );
316 }
317 
318 // -----------------------------------------------------------------------------
319 
320 Reference< XCellCursor > SAL_CALL TableModel::createCursorByRange( const Reference< XCellRange >& Range ) throw (IllegalArgumentException, RuntimeException)
321 {
322 	OGuard aGuard( Application::GetSolarMutex() );
323 
324 	ICellRange* pRange = dynamic_cast< ICellRange* >( Range.get() );
325 	if( (pRange == 0) || (pRange->getTable().get() != this) )
326 		throw IllegalArgumentException();
327 
328 	TableModelRef xModel( this );
329 	return new CellCursor( xModel, pRange->getLeft(), pRange->getTop(), pRange->getRight(), pRange->getBottom() );
330 }
331 
332 // -----------------------------------------------------------------------------
333 
334 sal_Int32 SAL_CALL TableModel::getRowCount() throw (RuntimeException)
335 {
336 	OGuard aGuard( Application::GetSolarMutex() );
337 	return getRowCountImpl();
338 }
339 
340 // -----------------------------------------------------------------------------
341 
342 sal_Int32 SAL_CALL TableModel::getColumnCount() throw (RuntimeException)
343 {
344 	OGuard aGuard( Application::GetSolarMutex() );
345 	return getColumnCountImpl();
346 }
347 
348 // -----------------------------------------------------------------------------
349 // XComponent
350 // -----------------------------------------------------------------------------
351 
352 void TableModel::dispose() throw (RuntimeException)
353 {
354 	OGuard aGuard( Application::GetSolarMutex() );
355 	TableModelBase::dispose();
356 }
357 
358 // -----------------------------------------------------------------------------
359 
360 void SAL_CALL TableModel::addEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
361 {
362 	TableModelBase::addEventListener( xListener );
363 }
364 
365 // -----------------------------------------------------------------------------
366 
367 void SAL_CALL TableModel::removeEventListener( const Reference< XEventListener >& xListener ) throw (RuntimeException)
368 {
369 	TableModelBase::removeEventListener( xListener );
370 }
371 
372 // -----------------------------------------------------------------------------
373 // XModifiable
374 // -----------------------------------------------------------------------------
375 
376 sal_Bool SAL_CALL TableModel::isModified(  ) throw (RuntimeException)
377 {
378 	OGuard aGuard( Application::GetSolarMutex() );
379 	return mbModified;
380 }
381 
382 // -----------------------------------------------------------------------------
383 
384 void SAL_CALL TableModel::setModified( sal_Bool bModified ) throw (PropertyVetoException, RuntimeException)
385 {
386 	{
387 		OGuard aGuard( Application::GetSolarMutex() );
388 		mbModified = bModified;
389 	}
390 	if( bModified )
391 		notifyModification();
392 }
393 
394 // -----------------------------------------------------------------------------
395 // XModifyBroadcaster
396 // -----------------------------------------------------------------------------
397 
398 void SAL_CALL TableModel::addModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
399 {
400 	rBHelper.addListener( XModifyListener::static_type() , xListener );
401 }
402 
403 // -----------------------------------------------------------------------------
404 
405 void SAL_CALL TableModel::removeModifyListener( const Reference< XModifyListener >& xListener ) throw (RuntimeException)
406 {
407 	rBHelper.removeListener( XModifyListener::static_type() , xListener );
408 }
409 
410 // -----------------------------------------------------------------------------
411 // XColumnRowRange
412 // -----------------------------------------------------------------------------
413 
414 Reference< XTableColumns > SAL_CALL TableModel::getColumns() throw (RuntimeException)
415 {
416 	OGuard aGuard( Application::GetSolarMutex() );
417 
418 	if( !mxTableColumns.is() )
419 		mxTableColumns.set( new TableColumns( this ) );
420 	return mxTableColumns.get();
421 }
422 
423 // -----------------------------------------------------------------------------
424 
425 Reference< XTableRows > SAL_CALL TableModel::getRows() throw (RuntimeException)
426 {
427 	OGuard aGuard( Application::GetSolarMutex() );
428 
429 	if( !mxTableRows.is() )
430 		mxTableRows.set( new TableRows( this ) );
431 	return mxTableRows.get();
432 }
433 
434 // -----------------------------------------------------------------------------
435 // XCellRange
436 // -----------------------------------------------------------------------------
437 
438 Reference< XCell > SAL_CALL TableModel::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw ( IndexOutOfBoundsException, RuntimeException)
439 {
440 	OGuard aGuard( Application::GetSolarMutex() );
441 
442 	CellRef xCell( getCell( nColumn, nRow ) );
443 	if( xCell.is() )
444 		return xCell.get();
445 
446 	throw IndexOutOfBoundsException();
447 }
448 
449 // -----------------------------------------------------------------------------
450 
451 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) throw (IndexOutOfBoundsException, RuntimeException)
452 {
453 	OGuard aGuard( Application::GetSolarMutex() );
454 
455 	if( (nLeft >= 0) && (nTop >= 0) && (nRight >= nLeft) && (nBottom >= nTop) && (nRight < getColumnCountImpl()) && (nBottom < getRowCountImpl() ) )
456 	{
457 		TableModelRef xModel( this );
458 		return new CellRange( xModel, nLeft, nTop, nRight, nBottom );
459 	}
460 
461 	throw IndexOutOfBoundsException();
462 }
463 
464 // -----------------------------------------------------------------------------
465 
466 Reference< XCellRange > SAL_CALL TableModel::getCellRangeByName( const OUString& /*aRange*/ ) throw (RuntimeException)
467 {
468 	return Reference< XCellRange >();
469 }
470 
471 // -----------------------------------------------------------------------------
472 // XPropertySet
473 // -----------------------------------------------------------------------------
474 
475 Reference< XPropertySetInfo > SAL_CALL TableModel::getPropertySetInfo(  ) throw (RuntimeException)
476 {
477 	Reference< XPropertySetInfo > xInfo;
478 	return xInfo;
479 }
480 
481 // -----------------------------------------------------------------------------
482 
483 void SAL_CALL TableModel::setPropertyValue( const ::rtl::OUString& /*aPropertyName*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
484 {
485 }
486 
487 // -----------------------------------------------------------------------------
488 
489 Any SAL_CALL TableModel::getPropertyValue( const OUString& /*PropertyName*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
490 {
491 	return Any();
492 }
493 
494 // -----------------------------------------------------------------------------
495 
496 void SAL_CALL TableModel::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
497 {
498 }
499 
500 // -----------------------------------------------------------------------------
501 
502 void SAL_CALL TableModel::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
503 {
504 }
505 
506 // -----------------------------------------------------------------------------
507 
508 void SAL_CALL TableModel::addVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
509 {
510 }
511 
512 // -----------------------------------------------------------------------------
513 
514 void SAL_CALL TableModel::removeVetoableChangeListener( const OUString& /*aPropertyName*/, const Reference< XVetoableChangeListener >& /*xListener*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
515 {
516 }
517 
518 // -----------------------------------------------------------------------------
519 // XFastPropertySet
520 // -----------------------------------------------------------------------------
521 
522 void SAL_CALL TableModel::setFastPropertyValue( ::sal_Int32 /*nHandle*/, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
523 {
524 }
525 
526 // -----------------------------------------------------------------------------
527 
528 Any SAL_CALL TableModel::getFastPropertyValue( ::sal_Int32 /*nHandle*/ ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
529 {
530 	Any aAny;
531 	return aAny;
532 }
533 
534 // -----------------------------------------------------------------------------
535 // internals
536 // -----------------------------------------------------------------------------
537 
538 sal_Int32 TableModel::getRowCountImpl() const
539 {
540 	return static_cast< sal_Int32 >( maRows.size() );
541 }
542 
543 // -----------------------------------------------------------------------------
544 
545 sal_Int32 TableModel::getColumnCountImpl() const
546 {
547 	return static_cast< sal_Int32 >( maColumns.size() );
548 }
549 
550 // -----------------------------------------------------------------------------
551 
552 void TableModel::disposing()
553 {
554 	if( !maRows.empty() )
555 	{
556 		RowVector::iterator aIter( maRows.begin() );
557 		while( aIter != maRows.end() )
558 			(*aIter++)->dispose();
559 		RowVector().swap(maRows);
560 	}
561 
562 	if( !maColumns.empty() )
563 	{
564 		ColumnVector::iterator aIter( maColumns.begin() );
565 		while( aIter != maColumns.end() )
566 			(*aIter++)->dispose();
567 		ColumnVector().swap(maColumns);
568 	}
569 
570 	if( mxTableColumns.is() )
571 	{
572 		mxTableColumns->dispose();
573 		mxTableColumns.clear();
574 	}
575 
576 	if( mxTableRows.is() )
577 	{
578 		mxTableRows->dispose();
579 		mxTableRows.clear();
580 	}
581 
582 	mpTableObj = 0;
583 }
584 
585 // -----------------------------------------------------------------------------
586 // XBroadcaster
587 // -----------------------------------------------------------------------------
588 
589 void TableModel::lockBroadcasts() throw (RuntimeException)
590 {
591 	OGuard aGuard( Application::GetSolarMutex() );
592 	++mnNotifyLock;
593 }
594 // -----------------------------------------------------------------------------
595 
596 void TableModel::unlockBroadcasts() throw (RuntimeException)
597 {
598 	OGuard aGuard( Application::GetSolarMutex() );
599 	--mnNotifyLock;
600 	if( mnNotifyLock <= 0 )
601 	{
602 		mnNotifyLock = 0;
603 		if( mbNotifyPending )
604 			notifyModification();
605 	}
606 }
607 
608 // -----------------------------------------------------------------------------
609 #ifdef PLEASE_DEBUG_THE_TABLES
610 #include <stdio.h>
611 #endif
612 
613 void TableModel::notifyModification()
614 {
615 	::osl::MutexGuard guard( m_aMutex );
616 	if( (mnNotifyLock == 0) && mpTableObj && mpTableObj->GetModel() )
617 	{
618 		mbNotifyPending = false;
619 
620 		::cppu::OInterfaceContainerHelper * pModifyListeners = rBHelper.getContainer( XModifyListener::static_type() );
621 		if( pModifyListeners )
622 		{
623 			EventObject aSource;
624 			aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
625 			pModifyListeners->notifyEach( &XModifyListener::modified, aSource);
626 		}
627 	}
628 	else
629 	{
630 		mbNotifyPending = true;
631 	}
632 
633 #ifdef PLEASE_DEBUG_THE_TABLES
634 		FILE* file = fopen( "c:\\table.xml","w" );
635 
636 		const sal_Int32 nColCount = getColumnCountImpl();
637 		const sal_Int32 nRowCount = getRowCountImpl();
638 
639         fprintf( file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\r" );
640         fprintf( file, "<table columns=\"%ld\" rows=\"%ld\" updated=\"%s\">\n\r", nColCount, nRowCount, mbNotifyPending ? "false" : "true");
641 
642 		for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
643 		{
644 			fprintf( file, "<column this=\"%lx\"/>\n\r", maColumns[nCol].get() );
645 		}
646 
647 		// first check merged cells before and inside the removed rows
648 		for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
649 		{
650 			fprintf( file, "<row this=\"%lx\">\n\r", maRows[nRow].get() );
651 			for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
652 			{
653 				CellRef xCell( getCell( nCol, nRow ) );
654 				fprintf( file, "<cell this=\"%lx\"", xCell.get() );
655 
656 				sal_Int32 nRowSpan = xCell->getRowSpan();
657 				sal_Int32 nColSpan = xCell->getColumnSpan();
658 				sal_Bool bMerged = xCell->isMerged();
659 
660 				if( nColSpan != 1 )
661 					fprintf( file, " column-span=\"%ld\"", nColSpan );
662 				if( nRowSpan != 1 )
663 					fprintf( file, " row-span=\"%ld\"", nRowSpan );
664 
665 				if( bMerged )
666 					fprintf( file, " merged=\"true\"" );
667 
668 				fprintf( file, "/>" );
669 			}
670 			fprintf( file, "\n\r</row>\n\r" );
671 		}
672 
673 		fprintf( file, "</table>\n\r" );
674 		fclose( file );
675 #endif
676 }
677 
678 // -----------------------------------------------------------------------------
679 
680 CellRef TableModel::getCell( sal_Int32 nCol, sal_Int32 nRow ) const
681 {
682 	if( ((nRow >= 0) && (nRow < getRowCountImpl())) && (nCol >= 0) && (nCol < getColumnCountImpl()) )
683 	{
684 		return maRows[nRow]->maCells[nCol];
685 	}
686 	else
687 	{
688 		CellRef xRet;
689 		return xRet;
690 	}
691 }
692 
693 // -----------------------------------------------------------------------------
694 /*
695 bool TableModel::getCellPos( const CellRef& xCell, ::sal_Int32& rnCol, ::sal_Int32& rnRow ) const
696 {
697 	const sal_Int32 nRowCount = getRowCount();
698 	const sal_Int32 nColCount = getColumnCount();
699 	for( rnRow = 0; rnRow < nRowCount; rnRow++ )
700 	{
701 		for( rnCol = 0; rnCol < nColCount; rnCol++ )
702 		{
703 			if( maRows[rnRow]->maCells[rnCol] == xCell )
704 			{
705 				return true;
706 			}
707 		}
708 	}
709 	return false;
710 }
711 */
712 
713 // -----------------------------------------------------------------------------
714 
715 CellRef TableModel::createCell()
716 {
717 	CellRef xCell;
718 	if( mpTableObj )
719 		mpTableObj->createCell( xCell );
720 	return xCell;
721 }
722 
723 // -----------------------------------------------------------------------------
724 
725 void TableModel::insertColumns( sal_Int32 nIndex, sal_Int32 nCount )
726 {
727 	if( nCount && mpTableObj )
728 	{
729 		try
730 		{
731 			SdrModel* pModel = mpTableObj->GetModel();
732 
733 			TableModelNotifyGuard aGuard( this );
734 			nIndex = insert_range<ColumnVector,ColumnVector::iterator,TableColumnRef>( maColumns, nIndex, nCount );
735 
736 			sal_Int32 nRows = getRowCountImpl();
737 			while( nRows-- )
738 				maRows[nRows]->insertColumns( nIndex, nCount );
739 
740 			ColumnVector aNewColumns(nCount);
741 			for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
742 			{
743 				TableColumnRef xNewCol( new TableColumn( this, nIndex+nOffset ) );
744 				maColumns[nIndex+nOffset] = xNewCol;
745 				aNewColumns[nOffset] = xNewCol;
746 			}
747 
748 			const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
749 			if( bUndo )
750 			{
751 				pModel->BegUndo( ImpGetResStr(STR_TABLE_INSCOL) );
752 				pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
753 
754 				TableModelRef xThis( this );
755 
756 				nRows = getRowCountImpl();
757 				CellVector aNewCells( nCount * nRows );
758 				CellVector::iterator aCellIter( aNewCells.begin() );
759 
760 				nRows = getRowCountImpl();
761 				for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
762 				{
763 					for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
764 						(*aCellIter++) = getCell( nIndex + nOffset, nRow );
765 				}
766 
767 				pModel->AddUndo( new InsertColUndo( xThis, nIndex, aNewColumns, aNewCells ) );
768 			}
769 
770 			const sal_Int32 nRowCount = getRowCountImpl();
771 			// check if cells merge over new columns
772 			for( sal_Int32 nCol = 0; nCol < nIndex; ++nCol )
773 			{
774 				for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
775 				{
776 					CellRef xCell( getCell( nCol, nRow ) );
777 					sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
778 					if( (nColSpan != 1) && ((nColSpan + nCol ) > nIndex) )
779 					{
780 						// cell merges over newly created columns, so add the new columns to the merged cell
781 						const sal_Int32 nRowSpan = xCell->getRowSpan();
782 						nColSpan += nCount;
783                         merge( nCol, nRow, nColSpan, nRowSpan );
784 					}
785 				}
786 			}
787 
788 			if( bUndo )
789 				pModel->EndUndo();
790 
791 			if( pModel )
792 			    pModel->SetChanged();
793 
794 		}
795 		catch( Exception& )
796 		{
797 			DBG_ERROR("sdr::table::TableModel::insertColumns(), exception caught!");
798 		}
799         updateColumns();
800 		setModified(sal_True);
801 	}
802 }
803 
804 // -----------------------------------------------------------------------------
805 
806 void TableModel::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
807 {
808 	sal_Int32 nColCount = getColumnCountImpl();
809 
810 	if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nColCount) )
811 	{
812 		try
813 		{
814 			TableModelNotifyGuard aGuard( this );
815 
816 			// clip removed columns to columns actually avalaible
817 			if( (nIndex + nCount) > nColCount )
818 				nCount = nColCount - nIndex;
819 
820 			sal_Int32 nRows = getRowCountImpl();
821 
822 			SdrModel* pModel = mpTableObj->GetModel();
823 
824 			const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
825 			if( bUndo  )
826 			{
827 				pModel->BegUndo( ImpGetResStr(STR_UNDO_COL_DELETE) );
828 				pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
829 
830 				TableModelRef xThis( this );
831 				ColumnVector aRemovedCols( nCount );
832 				sal_Int32 nOffset;
833 				for( nOffset = 0; nOffset < nCount; ++nOffset )
834 				{
835 					aRemovedCols[nOffset] = maColumns[nIndex+nOffset];
836 				}
837 
838 				CellVector aRemovedCells( nCount * nRows );
839 				CellVector::iterator aCellIter( aRemovedCells.begin() );
840 				for( sal_Int32 nRow = 0; nRow < nRows; ++nRow )
841 				{
842 					for( nOffset = 0; nOffset < nCount; ++nOffset )
843 						(*aCellIter++) = getCell( nIndex + nOffset, nRow );
844 				}
845 
846 				pModel->AddUndo( new RemoveColUndo( xThis, nIndex, aRemovedCols, aRemovedCells ) );
847 			}
848 
849 			// only rows before and inside the removed rows are considered
850 			nColCount = nIndex + nCount + 1;
851 
852 			const sal_Int32 nRowCount = getRowCountImpl();
853 
854 			// first check merged cells before and inside the removed rows
855 			for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
856 			{
857 				for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
858 				{
859 					CellRef xCell( getCell( nCol, nRow ) );
860 					sal_Int32 nColSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getColumnSpan() : 1;
861 					if( nColSpan <= 1 )
862 						continue;
863 
864 					if( nCol >= nIndex )
865 					{
866 						// current cell is inside the removed columns
867 						if( (nCol + nColSpan) > ( nIndex + nCount ) )
868 						{
869 							// current cells merges with columns after the removed columns
870 							const sal_Int32 nRemove = nCount - nCol + nIndex;
871 
872 							CellRef xTargetCell( getCell( nIndex + nCount, nRow ) );
873 							if( xTargetCell.is() )
874 							{
875 								if( bUndo )
876 									xTargetCell->AddUndo();
877 								xTargetCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
878 								xTargetCell->replaceContentAndFormating( xCell );
879 							}
880 						}
881 					}
882 					else if( nColSpan > (nIndex - nCol) )
883 					{
884 						// current cells spans inside the removed columns, so adjust
885 						const sal_Int32 nRemove = ::std::min( nCount, nCol + nColSpan - nIndex );
886 						if( bUndo )
887 							xCell->AddUndo();
888 						xCell->merge( nColSpan - nRemove, xCell->getRowSpan() );
889 					}
890 				}
891 			}
892 
893 			// now remove the columns
894 			remove_range<ColumnVector,ColumnVector::iterator>( maColumns, nIndex, nCount );
895 			while( nRows-- )
896 				maRows[nRows]->removeColumns( nIndex, nCount );
897 
898 			if( bUndo )
899 				pModel->EndUndo();
900 
901 			if( pModel )
902                 pModel->SetChanged();
903 		}
904 		catch( Exception& )
905 		{
906 			DBG_ERROR("sdr::table::TableModel::removeColumns(), exception caught!");
907 		}
908 
909         updateColumns();
910 		setModified(sal_True);
911 	}
912 }
913 
914 // -----------------------------------------------------------------------------
915 
916 void TableModel::insertRows( sal_Int32 nIndex, sal_Int32 nCount )
917 {
918 	if( nCount && mpTableObj )
919 	{
920     	SdrModel* pModel = mpTableObj->GetModel();
921 		const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
922 		try
923 		{
924 			TableModelNotifyGuard aGuard( this );
925 
926 			nIndex = insert_range<RowVector,RowVector::iterator,TableRowRef>( maRows, nIndex, nCount );
927 
928 			RowVector aNewRows(nCount);
929 			const sal_Int32 nColCount = getColumnCountImpl();
930 			for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
931 			{
932 				TableRowRef xNewRow( new TableRow( this, nIndex+nOffset, nColCount ) );
933 				maRows[nIndex+nOffset] = xNewRow;
934 				aNewRows[nOffset] = xNewRow;
935 			}
936 
937 			if( bUndo )
938 			{
939 				pModel->BegUndo( ImpGetResStr(STR_TABLE_INSROW) );
940 				pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
941 				TableModelRef xThis( this );
942 				pModel->AddUndo( new InsertRowUndo( xThis, nIndex, aNewRows ) );
943 			}
944 
945 			// check if cells merge over new columns
946 			for( sal_Int32 nRow = 0; nRow < nIndex; ++nRow )
947 			{
948 				for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
949 				{
950 					CellRef xCell( getCell( nCol, nRow ) );
951 					sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
952 					if( (nRowSpan > 1) && ((nRowSpan + nRow) > nIndex) )
953 					{
954 						// cell merges over newly created columns, so add the new columns to the merged cell
955 						const sal_Int32 nColSpan = xCell->getColumnSpan();
956 						nRowSpan += nCount;
957                         merge( nCol, nRow, nColSpan, nRowSpan );
958 					}
959 				}
960 			}
961 		}
962 		catch( Exception& )
963 		{
964 			DBG_ERROR("sdr::table::TableModel::insertRows(), exception caught!");
965 		}
966 		if( bUndo )
967 			pModel->EndUndo();
968 
969 		if( pModel )
970 			pModel->SetChanged();
971 
972         updateRows();
973 		setModified(sal_True);
974 	}
975 }
976 
977 // -----------------------------------------------------------------------------
978 
979 void TableModel::removeRows( sal_Int32 nIndex, sal_Int32 nCount )
980 {
981 	sal_Int32 nRowCount = getRowCountImpl();
982 
983 	if( mpTableObj && nCount && (nIndex >= 0) && (nIndex < nRowCount) )
984 	{
985 		SdrModel* pModel = mpTableObj->GetModel();
986 		const bool bUndo = pModel && mpTableObj->IsInserted()&& pModel->IsUndoEnabled();
987 
988 		try
989 		{
990 			TableModelNotifyGuard aGuard( this );
991 
992 			// clip removed rows to rows actually avalaible
993 			if( (nIndex + nCount) > nRowCount )
994 				nCount = nRowCount - nIndex;
995 
996 			if( bUndo )
997 			{
998 				pModel->BegUndo( ImpGetResStr(STR_UNDO_ROW_DELETE) );
999 				pModel->AddUndo( pModel->GetSdrUndoFactory().CreateUndoGeoObject(*mpTableObj) );
1000 
1001 				TableModelRef xThis( this );
1002 
1003 				RowVector aRemovedRows( nCount );
1004 				for( sal_Int32 nOffset = 0; nOffset < nCount; ++nOffset )
1005 					aRemovedRows[nOffset] = maRows[nIndex+nOffset];
1006 
1007 				pModel->AddUndo( new RemoveRowUndo( xThis, nIndex, aRemovedRows ) );
1008 			}
1009 
1010 			// only rows before and inside the removed rows are considered
1011 			nRowCount = nIndex + nCount + 1;
1012 
1013 			const sal_Int32 nColCount = getColumnCountImpl();
1014 
1015 			// first check merged cells before and inside the removed rows
1016 			for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow )
1017 			{
1018 				for( sal_Int32 nCol = 0; nCol < nColCount; ++nCol )
1019 				{
1020 					CellRef xCell( getCell( nCol, nRow ) );
1021 					sal_Int32 nRowSpan = (xCell.is() && !xCell->isMerged()) ? xCell->getRowSpan() : 1;
1022 					if( nRowSpan <= 1 )
1023 						continue;
1024 
1025 					if( nRow >= nIndex )
1026 					{
1027 						// current cell is inside the removed rows
1028 						if( (nRow + nRowSpan) > (nIndex + nCount) )
1029 						{
1030 							// current cells merges with rows after the removed rows
1031 							const sal_Int32 nRemove = nCount - nRow + nIndex;
1032 
1033 							CellRef xTargetCell( getCell( nCol, nIndex + nCount ) );
1034 							if( xTargetCell.is() )
1035 							{
1036 								if( bUndo )
1037 									xTargetCell->AddUndo();
1038 								xTargetCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
1039 								xTargetCell->replaceContentAndFormating( xCell );
1040 							}
1041 						}
1042 					}
1043 					else if( nRowSpan > (nIndex - nRow) )
1044 					{
1045 						// current cells spans inside the removed rows, so adjust
1046 						const sal_Int32 nRemove = ::std::min( nCount, nRow + nRowSpan - nIndex );
1047 						if( bUndo )
1048 							xCell->AddUndo();
1049 						xCell->merge( xCell->getColumnSpan(), nRowSpan - nRemove );
1050 					}
1051 				}
1052 			}
1053 
1054 			// now remove the rows
1055 			remove_range<RowVector,RowVector::iterator>( maRows, nIndex, nCount );
1056 
1057 			if( bUndo )
1058 				pModel->EndUndo();
1059 
1060 			if( pModel )
1061                 pModel->SetChanged();
1062 		}
1063 		catch( Exception& )
1064 		{
1065 			DBG_ERROR("sdr::table::TableModel::removeRows(), exception caught!");
1066 		}
1067 
1068         updateRows();
1069 		setModified(sal_True);
1070 	}
1071 }
1072 
1073 // -----------------------------------------------------------------------------
1074 
1075 TableRowRef TableModel::getRow( sal_Int32 nRow ) const throw (IndexOutOfBoundsException)
1076 {
1077 	if( (nRow >= 0) && (nRow < getRowCountImpl()) )
1078 		return maRows[nRow];
1079 
1080 	throw IndexOutOfBoundsException();
1081 }
1082 
1083 // -----------------------------------------------------------------------------
1084 
1085 TableColumnRef TableModel::getColumn( sal_Int32 nColumn ) const throw (IndexOutOfBoundsException)
1086 {
1087 	if( (nColumn >= 0) && (nColumn < getColumnCountImpl()) )
1088 		return maColumns[nColumn];
1089 
1090 	throw IndexOutOfBoundsException();
1091 }
1092 
1093 // -----------------------------------------------------------------------------
1094 
1095 /** deletes rows and columns that are completly merged. Must be called between BegUndo/EndUndo! */
1096 void TableModel::optimize()
1097 {
1098 	TableModelNotifyGuard aGuard( this );
1099 
1100 	bool bWasModified = false;
1101 
1102 	if( !maRows.empty() && !maColumns.empty() )
1103 	{
1104 		sal_Int32 nCol = getColumnCountImpl() - 1;
1105 		while( nCol > 0 )
1106 		{
1107 			bool bEmpty = true;
1108 			for( sal_Int32 nRow = 0; (nRow < getRowCountImpl()) && bEmpty; nRow++ )
1109 			{
1110 				Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1111 				if( xCell.is() && !xCell->isMerged() )
1112 					bEmpty = false;
1113 			}
1114 
1115 			if( bEmpty )
1116 			{
1117 				if( nCol > 0 ) try
1118 				{
1119 					const OUString sWidth( RTL_CONSTASCII_USTRINGPARAM("Width") );
1120 					sal_Int32 nWidth1 = 0, nWidth2 = 0;
1121 					Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maColumns[nCol].get() ), UNO_QUERY_THROW );
1122 					Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maColumns[nCol-1].get() ), UNO_QUERY_THROW );
1123 					xSet1->getPropertyValue( sWidth ) >>= nWidth1;
1124 					xSet2->getPropertyValue( sWidth ) >>= nWidth2;
1125 					nWidth1 += nWidth2;
1126 					xSet2->setPropertyValue( sWidth, Any( nWidth1 ) );
1127 				}
1128 				catch( Exception& e )
1129 				{
1130 					(void)e;
1131 					DBG_ERROR("svx::TableModel::optimize(), exception caught!");
1132 				}
1133 
1134 				removeColumns( nCol, 1 );
1135 				bWasModified = true;
1136 			}
1137 
1138 			nCol--;
1139 		}
1140 
1141 		sal_Int32 nRow = getRowCountImpl() - 1;
1142 		while( nRow > 0 )
1143 		{
1144 			bool bEmpty = true;
1145 			for( nCol = 0; (nCol < getColumnCountImpl()) && bEmpty; nCol++ )
1146 			{
1147 				Reference< XMergeableCell > xCell( getCellByPosition( nCol, nRow ), UNO_QUERY );
1148 				if( xCell.is() && !xCell->isMerged() )
1149 					bEmpty = false;
1150 			}
1151 
1152 			if( bEmpty )
1153 			{
1154 				if( nRow > 0 ) try
1155 				{
1156 					const OUString sHeight( RTL_CONSTASCII_USTRINGPARAM("Height") );
1157 					sal_Int32 nHeight1 = 0, nHeight2 = 0;
1158 					Reference< XPropertySet > xSet1( static_cast< XCellRange* >( maRows[nRow].get() ), UNO_QUERY_THROW );
1159 					Reference< XPropertySet > xSet2( static_cast< XCellRange* >( maRows[nRow-1].get() ), UNO_QUERY_THROW );
1160 					xSet1->getPropertyValue( sHeight ) >>= nHeight1;
1161 					xSet2->getPropertyValue( sHeight ) >>= nHeight2;
1162 					nHeight1 += nHeight2;
1163 					xSet2->setPropertyValue( sHeight, Any( nHeight1 ) );
1164 				}
1165 				catch( Exception& e )
1166 				{
1167 					(void)e;
1168 					DBG_ERROR("svx::TableModel::optimize(), exception caught!");
1169 				}
1170 
1171 				removeRows( nRow, 1 );
1172 				bWasModified = true;
1173 			}
1174 
1175 			nRow--;
1176 		}
1177 	}
1178 	if( bWasModified )
1179 		setModified(sal_True);
1180 }
1181 
1182 // -----------------------------------------------------------------------------
1183 
1184 void TableModel::merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan )
1185 {
1186 	SdrModel* pModel = mpTableObj->GetModel();
1187 
1188     const bool bUndo = pModel && mpTableObj->IsInserted() && pModel->IsUndoEnabled();
1189 
1190 	const sal_Int32 nLastRow = nRow + nRowSpan;
1191 	const sal_Int32 nLastCol = nCol + nColSpan;
1192 
1193     if( (nLastRow > getRowCount()) || (nLastCol > getRowCount() ) )
1194     {
1195         DBG_ERROR("TableModel::merge(), merge beyound the table!");
1196     }
1197 
1198 	// merge first cell
1199 	CellRef xOriginCell( dynamic_cast< Cell* >( getCellByPosition( nCol, nRow ).get() ) );
1200 	if( xOriginCell.is() )
1201 	{
1202 	    if( bUndo )
1203 		    xOriginCell->AddUndo();
1204 		xOriginCell->merge( nColSpan, nRowSpan );
1205 	}
1206 
1207 	sal_Int32 nTempCol = nCol + 1;
1208 
1209 	// merge remaining cells
1210 	for( ; nRow < nLastRow; nRow++ )
1211 	{
1212 		for( ; nTempCol < nLastCol; nTempCol++ )
1213 		{
1214 			CellRef xCell( dynamic_cast< Cell* >( getCellByPosition( nTempCol, nRow ).get() ) );
1215 			if( xCell.is() && !xCell->isMerged() )
1216 			{
1217 			    if( bUndo )
1218 				    xCell->AddUndo();
1219 				xCell->setMerged();
1220 				xOriginCell->mergeContent( xCell );
1221 			}
1222 		}
1223 		nTempCol = nCol;
1224 	}
1225 }
1226 
1227 
1228 // -----------------------------------------------------------------------------
1229 
1230 void TableModel::updateRows()
1231 {
1232     sal_Int32 nRow = 0;
1233     RowVector::iterator iter = maRows.begin();
1234     while( iter != maRows.end() )
1235     {
1236         (*iter++)->mnRow = nRow++;
1237     }
1238 }
1239 
1240 // -----------------------------------------------------------------------------
1241 
1242 void TableModel::updateColumns()
1243 {
1244     sal_Int32 nColumn = 0;
1245     ColumnVector::iterator iter = maColumns.begin();
1246     while( iter != maColumns.end() )
1247     {
1248         (*iter++)->mnColumn = nColumn++;
1249     }
1250 }
1251 
1252 // -----------------------------------------------------------------------------
1253 
1254 } }
1255