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