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