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_sc.hxx" 30 31 32 33 #include "scitems.hxx" 34 #include <svl/intitem.hxx> 35 #include <svl/zforlist.hxx> 36 #include <rtl/uuid.h> 37 38 #include "cursuno.hxx" 39 #include "cellsuno.hxx" 40 #include "docsh.hxx" 41 #include "hints.hxx" 42 #include "markdata.hxx" 43 #include "dociter.hxx" 44 #include "unoguard.hxx" 45 #include "miscuno.hxx" 46 47 using namespace com::sun::star; 48 49 //------------------------------------------------------------------------ 50 51 #define SCSHEETCELLCURSOR_SERVICE "com.sun.star.sheet.SheetCellCursor" 52 #define SCCELLCURSOR_SERVICE "com.sun.star.table.CellCursor" 53 54 //------------------------------------------------------------------------ 55 56 ScCellCursorObj::ScCellCursorObj(ScDocShell* pDocSh, const ScRange& rR) : 57 ScCellRangeObj( pDocSh, rR ) 58 { 59 } 60 61 ScCellCursorObj::~ScCellCursorObj() 62 { 63 } 64 65 uno::Any SAL_CALL ScCellCursorObj::queryInterface( const uno::Type& rType ) throw(uno::RuntimeException) 66 { 67 SC_QUERYINTERFACE( sheet::XSheetCellCursor ) 68 SC_QUERYINTERFACE( sheet::XUsedAreaCursor ) 69 SC_QUERYINTERFACE( table::XCellCursor ) 70 71 return ScCellRangeObj::queryInterface( rType ); 72 } 73 74 void SAL_CALL ScCellCursorObj::acquire() throw() 75 { 76 ScCellRangeObj::acquire(); 77 } 78 79 void SAL_CALL ScCellCursorObj::release() throw() 80 { 81 ScCellRangeObj::release(); 82 } 83 84 uno::Sequence<uno::Type> SAL_CALL ScCellCursorObj::getTypes() throw(uno::RuntimeException) 85 { 86 static uno::Sequence<uno::Type> aTypes; 87 if ( aTypes.getLength() == 0 ) 88 { 89 uno::Sequence<uno::Type> aParentTypes(ScCellRangeObj::getTypes()); 90 long nParentLen = aParentTypes.getLength(); 91 const uno::Type* pParentPtr = aParentTypes.getConstArray(); 92 93 aTypes.realloc( nParentLen + 3 ); 94 uno::Type* pPtr = aTypes.getArray(); 95 pPtr[nParentLen + 0] = getCppuType((const uno::Reference<sheet::XSheetCellCursor>*)0); 96 pPtr[nParentLen + 1] = getCppuType((const uno::Reference<sheet::XUsedAreaCursor>*)0); 97 pPtr[nParentLen + 2] = getCppuType((const uno::Reference<table::XCellCursor>*)0); 98 99 for (long i=0; i<nParentLen; i++) 100 pPtr[i] = pParentPtr[i]; // parent types first 101 } 102 return aTypes; 103 } 104 105 uno::Sequence<sal_Int8> SAL_CALL ScCellCursorObj::getImplementationId() throw(uno::RuntimeException) 106 { 107 static uno::Sequence< sal_Int8 > aId; 108 if( aId.getLength() == 0 ) 109 { 110 aId.realloc( 16 ); 111 rtl_createUuid( (sal_uInt8 *)aId.getArray(), 0, sal_True ); 112 } 113 return aId; 114 } 115 116 // XSheetCellCursor 117 118 void SAL_CALL ScCellCursorObj::collapseToCurrentRegion() throw(uno::RuntimeException) 119 { 120 ScUnoGuard aGuard; 121 const ScRangeList& rRanges = GetRangeList(); 122 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 123 ScRange aOneRange(*rRanges.GetObject(0)); 124 125 aOneRange.Justify(); 126 ScDocShell* pDocSh = GetDocShell(); 127 if ( pDocSh ) 128 { 129 SCCOL nStartCol = aOneRange.aStart.Col(); 130 SCROW nStartRow = aOneRange.aStart.Row(); 131 SCCOL nEndCol = aOneRange.aEnd.Col(); 132 SCROW nEndRow = aOneRange.aEnd.Row(); 133 SCTAB nTab = aOneRange.aStart.Tab(); 134 135 pDocSh->GetDocument()->GetDataArea( 136 nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_True, false ); 137 138 ScRange aNew( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab ); 139 SetNewRange( aNew ); 140 } 141 } 142 143 void SAL_CALL ScCellCursorObj::collapseToCurrentArray() throw(uno::RuntimeException) 144 { 145 ScUnoGuard aGuard; 146 const ScRangeList& rRanges = GetRangeList(); 147 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 148 ScRange aOneRange(*rRanges.GetObject(0)); 149 150 aOneRange.Justify(); 151 ScAddress aCursor(aOneRange.aStart); // use the start address of the range 152 153 ScDocShell* pDocSh = GetDocShell(); 154 if ( pDocSh ) 155 { 156 ScDocument* pDoc = pDocSh->GetDocument(); 157 ScRange aMatrix; 158 159 // finding the matrix range is now in GetMatrixFormulaRange in the document 160 if ( pDoc->GetMatrixFormulaRange( aCursor, aMatrix ) ) 161 { 162 SetNewRange( aMatrix ); 163 } 164 } 165 // thats a Bug, that this assertion comes; the API Reference says, that 166 // if there is no Matrix, the Range is left unchanged; they says nothing 167 // about a exception 168 /*if (!bFound) 169 { 170 DBG_ERROR("keine Matrix"); 171 //! Exception, oder was? 172 }*/ 173 } 174 175 void SAL_CALL ScCellCursorObj::collapseToMergedArea() throw(uno::RuntimeException) 176 { 177 ScUnoGuard aGuard; 178 ScDocShell* pDocSh = GetDocShell(); 179 if ( pDocSh ) 180 { 181 const ScRangeList& rRanges = GetRangeList(); 182 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 183 ScRange aNewRange(*rRanges.GetObject(0)); 184 185 ScDocument* pDoc = pDocSh->GetDocument(); 186 pDoc->ExtendOverlapped( aNewRange ); 187 pDoc->ExtendMerge( aNewRange ); // after ExtendOverlapped! 188 189 SetNewRange( aNewRange ); 190 } 191 } 192 193 void SAL_CALL ScCellCursorObj::expandToEntireColumns() throw(uno::RuntimeException) 194 { 195 ScUnoGuard aGuard; 196 const ScRangeList& rRanges = GetRangeList(); 197 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 198 ScRange aNewRange(*rRanges.GetObject(0)); 199 200 aNewRange.aStart.SetRow( 0 ); 201 aNewRange.aEnd.SetRow( MAXROW ); 202 203 SetNewRange( aNewRange ); 204 } 205 206 void SAL_CALL ScCellCursorObj::expandToEntireRows() throw(uno::RuntimeException) 207 { 208 ScUnoGuard aGuard; 209 const ScRangeList& rRanges = GetRangeList(); 210 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 211 ScRange aNewRange(*rRanges.GetObject(0)); 212 213 aNewRange.aStart.SetCol( 0 ); 214 aNewRange.aEnd.SetCol( MAXCOL ); 215 216 SetNewRange( aNewRange ); 217 } 218 219 void SAL_CALL ScCellCursorObj::collapseToSize( sal_Int32 nColumns, sal_Int32 nRows ) 220 throw(uno::RuntimeException) 221 { 222 ScUnoGuard aGuard; 223 if ( nColumns <= 0 || nRows <= 0 ) 224 { 225 DBG_ERROR("leerer Range geht nicht"); 226 //! und dann? 227 } 228 else 229 { 230 const ScRangeList& rRanges = GetRangeList(); 231 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 232 ScRange aNewRange(*rRanges.GetObject(0)); 233 234 aNewRange.Justify(); //! wirklich? 235 236 long nEndX = aNewRange.aStart.Col() + nColumns - 1; 237 long nEndY = aNewRange.aStart.Row() + nRows - 1; 238 if ( nEndX < 0 ) nEndX = 0; 239 if ( nEndX > MAXCOL ) nEndX = MAXCOL; 240 if ( nEndY < 0 ) nEndY = 0; 241 if ( nEndY > MAXROW ) nEndY = MAXROW; 242 //! Fehler/Exception oder so, wenn zu gross/zu klein? 243 244 aNewRange.aEnd.SetCol((SCCOL)nEndX); 245 aNewRange.aEnd.SetRow((SCROW)nEndY); 246 247 aNewRange.Justify(); //! wirklich? 248 249 SetNewRange( aNewRange ); 250 } 251 } 252 253 // XUsedAreaCursor 254 255 void SAL_CALL ScCellCursorObj::gotoStartOfUsedArea( sal_Bool bExpand ) 256 throw(uno::RuntimeException) 257 { 258 ScUnoGuard aGuard; 259 ScDocShell* pDocSh = GetDocShell(); 260 if ( pDocSh ) 261 { 262 const ScRangeList& rRanges = GetRangeList(); 263 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 264 ScRange aNewRange(*rRanges.GetObject(0)); 265 SCTAB nTab = aNewRange.aStart.Tab(); 266 267 SCCOL nUsedX = 0; // Anfang holen 268 SCROW nUsedY = 0; 269 if (!pDocSh->GetDocument()->GetDataStart( nTab, nUsedX, nUsedY )) 270 { 271 nUsedX = 0; 272 nUsedY = 0; 273 } 274 275 aNewRange.aStart.SetCol( nUsedX ); 276 aNewRange.aStart.SetRow( nUsedY ); 277 if (!bExpand) 278 aNewRange.aEnd = aNewRange.aStart; 279 SetNewRange( aNewRange ); 280 } 281 } 282 283 void SAL_CALL ScCellCursorObj::gotoEndOfUsedArea( sal_Bool bExpand ) 284 throw(uno::RuntimeException) 285 { 286 ScUnoGuard aGuard; 287 ScDocShell* pDocSh = GetDocShell(); 288 if ( pDocSh ) 289 { 290 const ScRangeList& rRanges = GetRangeList(); 291 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 292 ScRange aNewRange(*rRanges.GetObject(0)); 293 SCTAB nTab = aNewRange.aStart.Tab(); 294 295 SCCOL nUsedX = 0; // Ende holen 296 SCROW nUsedY = 0; 297 if (!pDocSh->GetDocument()->GetTableArea( nTab, nUsedX, nUsedY )) 298 { 299 nUsedX = 0; 300 nUsedY = 0; 301 } 302 303 aNewRange.aEnd.SetCol( nUsedX ); 304 aNewRange.aEnd.SetRow( nUsedY ); 305 if (!bExpand) 306 aNewRange.aStart = aNewRange.aEnd; 307 SetNewRange( aNewRange ); 308 } 309 } 310 311 // XCellCursor 312 313 void SAL_CALL ScCellCursorObj::gotoStart() throw(uno::RuntimeException) 314 { 315 // this is similar to collapseToCurrentRegion 316 //! something like gotoEdge with 4 possible directions is needed 317 318 ScUnoGuard aGuard; 319 const ScRangeList& rRanges = GetRangeList(); 320 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 321 ScRange aOneRange(*rRanges.GetObject(0)); 322 323 aOneRange.Justify(); 324 ScDocShell* pDocSh = GetDocShell(); 325 if ( pDocSh ) 326 { 327 SCCOL nStartCol = aOneRange.aStart.Col(); 328 SCROW nStartRow = aOneRange.aStart.Row(); 329 SCCOL nEndCol = aOneRange.aEnd.Col(); 330 SCROW nEndRow = aOneRange.aEnd.Row(); 331 SCTAB nTab = aOneRange.aStart.Tab(); 332 333 pDocSh->GetDocument()->GetDataArea( 334 nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_False, false ); 335 336 ScRange aNew( nStartCol, nStartRow, nTab ); 337 SetNewRange( aNew ); 338 } 339 } 340 341 void SAL_CALL ScCellCursorObj::gotoEnd() throw(uno::RuntimeException) 342 { 343 // this is similar to collapseToCurrentRegion 344 //! something like gotoEdge with 4 possible directions is needed 345 346 ScUnoGuard aGuard; 347 const ScRangeList& rRanges = GetRangeList(); 348 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 349 ScRange aOneRange(*rRanges.GetObject(0)); 350 351 aOneRange.Justify(); 352 ScDocShell* pDocSh = GetDocShell(); 353 if ( pDocSh ) 354 { 355 SCCOL nStartCol = aOneRange.aStart.Col(); 356 SCROW nStartRow = aOneRange.aStart.Row(); 357 SCCOL nEndCol = aOneRange.aEnd.Col(); 358 SCROW nEndRow = aOneRange.aEnd.Row(); 359 SCTAB nTab = aOneRange.aStart.Tab(); 360 361 pDocSh->GetDocument()->GetDataArea( 362 nTab, nStartCol, nStartRow, nEndCol, nEndRow, sal_False, false ); 363 364 ScRange aNew( nEndCol, nEndRow, nTab ); 365 SetNewRange( aNew ); 366 } 367 } 368 369 void SAL_CALL ScCellCursorObj::gotoNext() throw(uno::RuntimeException) 370 { 371 ScUnoGuard aGuard; 372 const ScRangeList& rRanges = GetRangeList(); 373 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 374 ScRange aOneRange(*rRanges.GetObject(0)); 375 376 aOneRange.Justify(); 377 ScAddress aCursor(aOneRange.aStart); // bei Block immer den Start nehmen 378 379 ScMarkData aMark; // not used with bMarked=FALSE 380 SCCOL nNewX = aCursor.Col(); 381 SCROW nNewY = aCursor.Row(); 382 SCTAB nTab = aCursor.Tab(); 383 ScDocShell* pDocSh = GetDocShell(); 384 if ( pDocSh ) 385 pDocSh->GetDocument()->GetNextPos( nNewX,nNewY, nTab, 1,0, sal_False,sal_True, aMark ); 386 //! sonst Exception oder so 387 388 SetNewRange( ScRange( nNewX, nNewY, nTab ) ); 389 } 390 391 void SAL_CALL ScCellCursorObj::gotoPrevious() throw(uno::RuntimeException) 392 { 393 ScUnoGuard aGuard; 394 const ScRangeList& rRanges = GetRangeList(); 395 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 396 ScRange aOneRange(*rRanges.GetObject(0)); 397 398 aOneRange.Justify(); 399 ScAddress aCursor(aOneRange.aStart); // bei Block immer den Start nehmen 400 401 ScMarkData aMark; // not used with bMarked=FALSE 402 SCCOL nNewX = aCursor.Col(); 403 SCROW nNewY = aCursor.Row(); 404 SCTAB nTab = aCursor.Tab(); 405 ScDocShell* pDocSh = GetDocShell(); 406 if ( pDocSh ) 407 pDocSh->GetDocument()->GetNextPos( nNewX,nNewY, nTab, -1,0, sal_False,sal_True, aMark ); 408 //! sonst Exception oder so 409 410 SetNewRange( ScRange( nNewX, nNewY, nTab ) ); 411 } 412 413 void SAL_CALL ScCellCursorObj::gotoOffset( sal_Int32 nColumnOffset, sal_Int32 nRowOffset ) 414 throw(uno::RuntimeException) 415 { 416 ScUnoGuard aGuard; 417 const ScRangeList& rRanges = GetRangeList(); 418 DBG_ASSERT( rRanges.Count() == 1, "Range? Ranges?" ); 419 ScRange aOneRange(*rRanges.GetObject(0)); 420 aOneRange.Justify(); 421 422 if ( aOneRange.aStart.Col() + nColumnOffset >= 0 && 423 aOneRange.aEnd.Col() + nColumnOffset <= MAXCOL && 424 aOneRange.aStart.Row() + nRowOffset >= 0 && 425 aOneRange.aEnd.Row() + nRowOffset <= MAXROW ) 426 { 427 ScRange aNew( (SCCOL)(aOneRange.aStart.Col() + nColumnOffset), 428 (SCROW)(aOneRange.aStart.Row() + nRowOffset), 429 aOneRange.aStart.Tab(), 430 (SCCOL)(aOneRange.aEnd.Col() + nColumnOffset), 431 (SCROW)(aOneRange.aEnd.Row() + nRowOffset), 432 aOneRange.aEnd.Tab() ); 433 SetNewRange( aNew ); 434 } 435 } 436 437 // XSheetCellRange 438 439 uno::Reference<sheet::XSpreadsheet> SAL_CALL ScCellCursorObj::getSpreadsheet() 440 throw(uno::RuntimeException) 441 { 442 ScUnoGuard aGuard; 443 return ScCellRangeObj::getSpreadsheet(); 444 } 445 446 // XCellRange 447 448 uno::Reference<table::XCell> SAL_CALL ScCellCursorObj::getCellByPosition( 449 sal_Int32 nColumn, sal_Int32 nRow ) 450 throw(lang::IndexOutOfBoundsException, uno::RuntimeException) 451 { 452 ScUnoGuard aGuard; 453 return ScCellRangeObj::getCellByPosition(nColumn,nRow); 454 } 455 456 uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByPosition( 457 sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom ) 458 throw(lang::IndexOutOfBoundsException, uno::RuntimeException) 459 { 460 ScUnoGuard aGuard; 461 return ScCellRangeObj::getCellRangeByPosition(nLeft,nTop,nRight,nBottom); 462 } 463 464 uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByName( 465 const rtl::OUString& rRange ) throw(uno::RuntimeException) 466 { 467 ScUnoGuard aGuard; 468 return ScCellRangeObj::getCellRangeByName(rRange); 469 } 470 471 // XServiceInfo 472 473 rtl::OUString SAL_CALL ScCellCursorObj::getImplementationName() throw(uno::RuntimeException) 474 { 475 return rtl::OUString::createFromAscii( "ScCellCursorObj" ); 476 } 477 478 sal_Bool SAL_CALL ScCellCursorObj::supportsService( const rtl::OUString& rServiceName ) 479 throw(uno::RuntimeException) 480 { 481 String aServiceStr( rServiceName ); 482 return aServiceStr.EqualsAscii( SCSHEETCELLCURSOR_SERVICE ) || 483 aServiceStr.EqualsAscii( SCCELLCURSOR_SERVICE ) || 484 ScCellRangeObj::supportsService(rServiceName); 485 } 486 487 uno::Sequence<rtl::OUString> SAL_CALL ScCellCursorObj::getSupportedServiceNames() 488 throw(uno::RuntimeException) 489 { 490 // get all service names from cell range 491 uno::Sequence<rtl::OUString> aParentSeq(ScCellRangeObj::getSupportedServiceNames()); 492 sal_Int32 nParentLen = aParentSeq.getLength(); 493 const rtl::OUString* pParentArr = aParentSeq.getConstArray(); 494 495 // SheetCellCursor should be first (?) 496 uno::Sequence<rtl::OUString> aTotalSeq( nParentLen + 2 ); 497 rtl::OUString* pTotalArr = aTotalSeq.getArray(); 498 pTotalArr[0] = rtl::OUString::createFromAscii( SCSHEETCELLCURSOR_SERVICE ); 499 pTotalArr[1] = rtl::OUString::createFromAscii( SCCELLCURSOR_SERVICE ); 500 501 // append cell range services 502 for (long i=0; i<nParentLen; i++) 503 pTotalArr[i+2] = pParentArr[i]; 504 505 return aTotalSeq; 506 } 507 508 509 510 511