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