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