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 --------------------------------------------------------------- 34 35 #include "scitems.hxx" 36 #include <editeng/eeitem.hxx> 37 38 39 #include <vcl/timer.hxx> 40 #include <vcl/msgbox.hxx> 41 #include <sfx2/app.hxx> 42 #include <sfx2/viewfrm.hxx> 43 #include <sfx2/bindings.hxx> 44 #include <sfx2/childwin.hxx> 45 46 #include "attrib.hxx" 47 #include "pagedata.hxx" 48 #include "tabview.hxx" 49 #include "tabvwsh.hxx" 50 #include "printfun.hxx" 51 #include "stlpool.hxx" 52 #include "docsh.hxx" 53 #include "gridwin.hxx" 54 #include "olinewin.hxx" 55 #include "uiitems.hxx" 56 #include "sc.hrc" 57 #include "viewutil.hxx" 58 #include "colrowba.hxx" 59 #include "waitoff.hxx" 60 #include "globstr.hrc" 61 #include "scmod.hxx" 62 63 #define SC_BLOCKMODE_NONE 0 64 #define SC_BLOCKMODE_NORMAL 1 65 #define SC_BLOCKMODE_OWN 2 66 67 68 69 // 70 // Markier - Funktionen 71 // 72 73 void ScTabView::PaintMarks(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) 74 { 75 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 76 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 77 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 78 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 79 80 sal_Bool bLeft = (nStartCol==0 && nEndCol==MAXCOL); 81 sal_Bool bTop = (nStartRow==0 && nEndRow==MAXROW); 82 83 if (bLeft) 84 PaintLeftArea( nStartRow, nEndRow ); 85 if (bTop) 86 PaintTopArea( nStartCol, nEndCol ); 87 88 aViewData.GetDocument()->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, 89 aViewData.GetTabNo() ); 90 PaintArea( nStartCol, nStartRow, nEndCol, nEndRow, SC_UPDATE_MARKS ); 91 } 92 93 sal_Bool ScTabView::IsMarking( SCCOL nCol, SCROW nRow, SCTAB nTab ) const 94 { 95 return bIsBlockMode 96 && nBlockStartX == nCol 97 && nBlockStartY == nRow 98 && nBlockStartZ == nTab; 99 } 100 101 void ScTabView::InitOwnBlockMode() 102 { 103 if (!bIsBlockMode) 104 { 105 // Wenn keine (alte) Markierung mehr da ist, Anker in SelectionEngine loeschen: 106 107 ScMarkData& rMark = aViewData.GetMarkData(); 108 if (!rMark.IsMarked() && !rMark.IsMultiMarked()) 109 GetSelEngine()->CursorPosChanging( sal_False, sal_False ); 110 111 // bIsBlockMode = sal_True; 112 bIsBlockMode = SC_BLOCKMODE_OWN; //! Variable umbenennen! 113 nBlockStartX = 0; 114 nBlockStartY = 0; 115 nBlockStartZ = 0; 116 nBlockEndX = 0; 117 nBlockEndY = 0; 118 nBlockEndZ = 0; 119 120 SelectionChanged(); // Status wird mit gesetzer Markierung abgefragt 121 } 122 } 123 124 void ScTabView::InitBlockMode( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, 125 sal_Bool bTestNeg, sal_Bool bCols, sal_Bool bRows ) 126 { 127 if (!bIsBlockMode) 128 { 129 if (!ValidCol(nCurX)) nCurX = MAXCOL; 130 if (!ValidRow(nCurY)) nCurY = MAXROW; 131 132 ScMarkData& rMark = aViewData.GetMarkData(); 133 SCTAB nTab = aViewData.GetTabNo(); 134 135 // Teil von Markierung aufheben? 136 if (bTestNeg) 137 { 138 if ( bCols ) 139 bBlockNeg = rMark.IsColumnMarked( nCurX ); 140 else if ( bRows ) 141 bBlockNeg = rMark.IsRowMarked( nCurY ); 142 else 143 bBlockNeg = rMark.IsCellMarked( nCurX, nCurY ); 144 } 145 else 146 bBlockNeg = sal_False; 147 rMark.SetMarkNegative(bBlockNeg); 148 149 // bIsBlockMode = sal_True; 150 bIsBlockMode = SC_BLOCKMODE_NORMAL; //! Variable umbenennen! 151 bBlockCols = bCols; 152 bBlockRows = bRows; 153 nBlockStartX = nBlockStartXOrig = nCurX; 154 nBlockStartY = nBlockStartYOrig = nCurY; 155 nBlockStartZ = nCurZ; 156 nBlockEndX = nOldCurX = nBlockStartX; 157 nBlockEndY = nOldCurY = nBlockStartY; 158 nBlockEndZ = nBlockStartZ; 159 160 if (bBlockCols) 161 { 162 nBlockStartY = nBlockStartYOrig = 0; 163 nBlockEndY = MAXROW; 164 } 165 166 if (bBlockRows) 167 { 168 nBlockStartX = nBlockStartXOrig = 0; 169 nBlockEndX = MAXCOL; 170 } 171 172 rMark.SetMarkArea( ScRange( nBlockStartX,nBlockStartY, nTab, nBlockEndX,nBlockEndY, nTab ) ); 173 174 #ifdef OLD_SELECTION_PAINT 175 InvertBlockMark( nBlockStartX,nBlockStartY,nBlockEndX,nBlockEndY ); 176 #endif 177 UpdateSelectionOverlay(); 178 179 bNewStartIfMarking = sal_False; // use only once 180 } 181 } 182 183 void ScTabView::SetNewStartIfMarking() 184 { 185 bNewStartIfMarking = sal_True; 186 } 187 188 void ScTabView::DoneBlockMode( sal_Bool bContinue ) // Default FALSE 189 { 190 // Wenn zwischen Tabellen- und Header SelectionEngine gewechselt wird, 191 // wird evtl. DeselectAll gerufen, weil die andere Engine keinen Anker hat. 192 // Mit bMoveIsShift wird verhindert, dass dann die Selektion aufgehoben wird. 193 194 if (bIsBlockMode && !bMoveIsShift) 195 { 196 ScMarkData& rMark = aViewData.GetMarkData(); 197 sal_Bool bFlag = rMark.GetMarkingFlag(); 198 rMark.SetMarking(sal_False); 199 200 if (bBlockNeg && !bContinue) 201 rMark.MarkToMulti(); 202 203 if (bContinue) 204 rMark.MarkToMulti(); 205 else 206 { 207 // Die Tabelle kann an dieser Stelle ungueltig sein, weil DoneBlockMode 208 // aus SetTabNo aufgerufen wird 209 // (z.B. wenn die aktuelle Tabelle von einer anderen View aus geloescht wird) 210 211 SCTAB nTab = aViewData.GetTabNo(); 212 ScDocument* pDoc = aViewData.GetDocument(); 213 if ( pDoc->HasTable(nTab) ) 214 PaintBlock( sal_True ); // sal_True -> Block loeschen 215 else 216 rMark.ResetMark(); 217 } 218 // bIsBlockMode = sal_False; 219 bIsBlockMode = SC_BLOCKMODE_NONE; //! Variable umbenennen! 220 221 rMark.SetMarking(bFlag); 222 rMark.SetMarkNegative(sal_False); 223 } 224 } 225 226 void ScTabView::MarkCursor( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, 227 sal_Bool bCols, sal_Bool bRows, sal_Bool bCellSelection ) 228 { 229 if (!ValidCol(nCurX)) nCurX = MAXCOL; 230 if (!ValidRow(nCurY)) nCurY = MAXROW; 231 232 if (!bIsBlockMode) 233 { 234 DBG_ERROR( "MarkCursor nicht im BlockMode" ); 235 InitBlockMode( nCurX, nCurY, nCurZ, sal_False, bCols, bRows ); 236 } 237 238 if (bCols) 239 nCurY = MAXROW; 240 if (bRows) 241 nCurX = MAXCOL; 242 243 ScMarkData& rMark = aViewData.GetMarkData(); 244 DBG_ASSERT(rMark.IsMarked() || rMark.IsMultiMarked(), "MarkCursor, !IsMarked()"); 245 ScRange aMarkRange; 246 rMark.GetMarkArea(aMarkRange); 247 if (( aMarkRange.aStart.Col() != nBlockStartX && aMarkRange.aEnd.Col() != nBlockStartX ) || 248 ( aMarkRange.aStart.Row() != nBlockStartY && aMarkRange.aEnd.Row() != nBlockStartY ) || 249 ( bIsBlockMode == SC_BLOCKMODE_OWN )) 250 { 251 // Markierung ist veraendert worden 252 // (z.B. MarkToSimple, wenn per negativ alles bis auf ein Rechteck geloescht wurde) 253 // oder nach InitOwnBlockMode wird mit Shift-Klick weitermarkiert... 254 255 sal_Bool bOldShift = bMoveIsShift; 256 bMoveIsShift = sal_False; // wirklich umsetzen 257 DoneBlockMode(sal_False); //! direkt Variablen setzen? (-> kein Geflacker) 258 bMoveIsShift = bOldShift; 259 260 InitBlockMode( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), 261 nBlockStartZ, rMark.IsMarkNegative(), bCols, bRows ); 262 } 263 264 SCCOL nOldBlockEndX = nBlockEndX; 265 SCROW nOldBlockEndY = nBlockEndY; 266 267 if ( nCurX != nOldCurX || nCurY != nOldCurY ) 268 { 269 // Current cursor has moved 270 271 SCTAB nTab = nCurZ; 272 273 #ifdef OLD_SELECTION_PAINT 274 SCCOL nDrawStartCol; 275 SCROW nDrawStartRow; 276 SCCOL nDrawEndCol; 277 SCROW nDrawEndRow; 278 #endif 279 280 // Set old selection area 281 ScUpdateRect aRect( nBlockStartX, nBlockStartY, nOldBlockEndX, nOldBlockEndY ); 282 283 if ( bCellSelection ) 284 { 285 // Expand selection area accordingly when the current selection ends 286 // with a merged cell. 287 SCsCOL nCurXOffset = 0; 288 SCsCOL nBlockStartXOffset = 0; 289 SCsROW nCurYOffset = 0; 290 SCsROW nBlockStartYOffset = 0; 291 sal_Bool bBlockStartMerged = sal_False; 292 const ScMergeAttr* pMergeAttr = NULL; 293 ScDocument* pDocument = aViewData.GetDocument(); 294 295 // The following block checks whether or not the "BlockStart" (anchor) 296 // cell is merged. If it's merged, it'll then move the position of the 297 // anchor cell to the corner that's diagonally opposite of the 298 // direction of a current selection area. For instance, if a current 299 // selection is moving in the upperleft direction, the anchor cell will 300 // move to the lower-right corner of the merged anchor cell, and so on. 301 302 pMergeAttr = static_cast<const ScMergeAttr*>( 303 pDocument->GetAttr( nBlockStartXOrig, nBlockStartYOrig, nTab, ATTR_MERGE ) ); 304 if ( pMergeAttr->IsMerged() ) 305 { 306 SCsCOL nColSpan = pMergeAttr->GetColMerge(); 307 SCsROW nRowSpan = pMergeAttr->GetRowMerge(); 308 309 if ( !( nCurX >= nBlockStartXOrig + nColSpan - 1 && nCurY >= nBlockStartYOrig + nRowSpan - 1 ) ) 310 { 311 nBlockStartX = nCurX >= nBlockStartXOrig ? nBlockStartXOrig : nBlockStartXOrig + nColSpan - 1; 312 nBlockStartY = nCurY >= nBlockStartYOrig ? nBlockStartYOrig : nBlockStartYOrig + nRowSpan - 1; 313 nCurXOffset = nCurX >= nBlockStartXOrig && nCurX < nBlockStartXOrig + nColSpan - 1 ? 314 nBlockStartXOrig - nCurX + nColSpan - 1 : 0; 315 nCurYOffset = nCurY >= nBlockStartYOrig && nCurY < nBlockStartYOrig + nRowSpan - 1 ? 316 nBlockStartYOrig - nCurY + nRowSpan - 1 : 0; 317 bBlockStartMerged = sal_True; 318 } 319 } 320 321 // The following block checks whether or not the current cell is 322 // merged. If it is, it'll then set the appropriate X & Y offset 323 // values (nCurXOffset & nCurYOffset) such that the selection area will 324 // grow by those specified offset amounts. Note that the values of 325 // nCurXOffset/nCurYOffset may also be specified in the previous code 326 // block, in which case whichever value is greater will take on. 327 328 pMergeAttr = static_cast<const ScMergeAttr*>( 329 pDocument->GetAttr( nCurX, nCurY, nTab, ATTR_MERGE ) ); 330 if ( pMergeAttr->IsMerged() ) 331 { 332 SCsCOL nColSpan = pMergeAttr->GetColMerge(); 333 SCsROW nRowSpan = pMergeAttr->GetRowMerge(); 334 335 if ( !( nBlockStartX >= nCurX + nColSpan - 1 && nBlockStartY >= nCurY + nRowSpan - 1 ) ) 336 { 337 if ( nBlockStartX <= nCurX + nColSpan - 1 ) 338 { 339 SCsCOL nCurXOffsetTemp = nCurX < nCurX + nColSpan - 1 ? nColSpan - 1 : 0; 340 nCurXOffset = nCurXOffset > nCurXOffsetTemp ? nCurXOffset : nCurXOffsetTemp; 341 } 342 if ( nBlockStartY <= nCurY + nRowSpan - 1 ) 343 { 344 SCsROW nCurYOffsetTemp = nCurY < nCurY + nRowSpan - 1 ? nRowSpan - 1 : 0; 345 nCurYOffset = nCurYOffset > nCurYOffsetTemp ? nCurYOffset : nCurYOffsetTemp; 346 } 347 if ( !( nBlockStartX <= nCurX && nBlockStartY <= nCurY ) && 348 !( nBlockStartX > nCurX + nColSpan - 1 && nBlockStartY > nCurY + nRowSpan - 1 ) ) 349 { 350 nBlockStartXOffset = nBlockStartX > nCurX && nBlockStartX <= nCurX + nColSpan - 1 ? nCurX - nBlockStartX : 0; 351 nBlockStartYOffset = nBlockStartY > nCurY && nBlockStartY <= nCurY + nRowSpan - 1 ? nCurY - nBlockStartY : 0; 352 } 353 } 354 } 355 else 356 { 357 // The current cell is not merged. Move the anchor cell to its 358 // original position. 359 if ( !bBlockStartMerged ) 360 { 361 nBlockStartX = nBlockStartXOrig; 362 nBlockStartY = nBlockStartYOrig; 363 } 364 } 365 366 nBlockStartX = nBlockStartX + nBlockStartXOffset >= 0 ? nBlockStartX + nBlockStartXOffset : 0; 367 nBlockStartY = nBlockStartY + nBlockStartYOffset >= 0 ? nBlockStartY + nBlockStartYOffset : 0; 368 nBlockEndX = nCurX + nCurXOffset > MAXCOL ? MAXCOL : nCurX + nCurXOffset; 369 nBlockEndY = nCurY + nCurYOffset > MAXROW ? MAXROW : nCurY + nCurYOffset; 370 } 371 else 372 { 373 nBlockEndX = nCurX; 374 nBlockEndY = nCurY; 375 } 376 // end of "if ( bCellSelection )" 377 378 // Set new selection area 379 aRect.SetNew( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY ); 380 rMark.SetMarkArea( ScRange( nBlockStartX, nBlockStartY, nTab, nBlockEndX, nBlockEndY, nTab ) ); 381 382 #ifdef OLD_SELECTION_PAINT 383 sal_Bool bCont; 384 sal_Bool bDraw = aRect.GetXorDiff( nDrawStartCol, nDrawStartRow, 385 nDrawEndCol, nDrawEndRow, bCont ); 386 if ( bDraw ) 387 { 388 //? PutInOrder( nDrawStartCol, nDrawEndCol ); 389 //? PutInOrder( nDrawStartRow, nDrawEndRow ); 390 391 HideAllCursors(); 392 InvertBlockMark( nDrawStartCol, nDrawStartRow, nDrawEndCol, nDrawEndRow ); 393 if (bCont) 394 { 395 aRect.GetContDiff( nDrawStartCol, nDrawStartRow, nDrawEndCol, nDrawEndRow ); 396 InvertBlockMark( nDrawStartCol, nDrawStartRow, nDrawEndCol, nDrawEndRow ); 397 } 398 ShowAllCursors(); 399 } 400 #endif 401 UpdateSelectionOverlay(); 402 403 nOldCurX = nCurX; 404 nOldCurY = nCurY; 405 406 aViewData.GetViewShell()->UpdateInputHandler(); 407 // InvalidateAttribs(); 408 } 409 410 if ( !bCols && !bRows ) 411 aHdrFunc.SetAnchorFlag( sal_False ); 412 } 413 414 void ScTabView::UpdateSelectionOverlay() 415 { 416 for (sal_uInt16 i=0; i<4; i++) 417 if ( pGridWin[i] && pGridWin[i]->IsVisible() ) 418 pGridWin[i]->UpdateSelectionOverlay(); 419 } 420 421 void ScTabView::UpdateShrinkOverlay() 422 { 423 for (sal_uInt16 i=0; i<4; i++) 424 if ( pGridWin[i] && pGridWin[i]->IsVisible() ) 425 pGridWin[i]->UpdateShrinkOverlay(); 426 } 427 428 void ScTabView::UpdateAllOverlays() 429 { 430 for (sal_uInt16 i=0; i<4; i++) 431 if ( pGridWin[i] && pGridWin[i]->IsVisible() ) 432 pGridWin[i]->UpdateAllOverlays(); 433 } 434 435 //! 436 //! PaintBlock in zwei Methoden aufteilen: RepaintBlock und RemoveBlock o.ae. 437 //! 438 439 void ScTabView::PaintBlock( sal_Bool bReset ) 440 { 441 ScDocument* pDoc = aViewData.GetDocument(); 442 ScMarkData& rMark = aViewData.GetMarkData(); 443 SCTAB nTab = aViewData.GetTabNo(); 444 sal_Bool bMark = rMark.IsMarked(); 445 sal_Bool bMulti = rMark.IsMultiMarked(); 446 if (bMark || bMulti) 447 { 448 ScRange aMarkRange; 449 HideAllCursors(); 450 if (bMulti) 451 { 452 sal_Bool bFlag = rMark.GetMarkingFlag(); 453 rMark.SetMarking(sal_False); 454 rMark.MarkToMulti(); 455 rMark.GetMultiMarkArea(aMarkRange); 456 rMark.MarkToSimple(); 457 rMark.SetMarking(bFlag); 458 459 bMark = rMark.IsMarked(); 460 bMulti = rMark.IsMultiMarked(); 461 } 462 else 463 rMark.GetMarkArea(aMarkRange); 464 465 nBlockStartX = aMarkRange.aStart.Col(); 466 nBlockStartY = aMarkRange.aStart.Row(); 467 nBlockStartZ = aMarkRange.aStart.Tab(); 468 nBlockEndX = aMarkRange.aEnd.Col(); 469 nBlockEndY = aMarkRange.aEnd.Row(); 470 nBlockEndZ = aMarkRange.aEnd.Tab(); 471 472 sal_Bool bDidReset = sal_False; 473 474 if ( nTab>=nBlockStartZ && nTab<=nBlockEndZ ) 475 { 476 if ( bReset ) 477 { 478 // Invertieren beim Loeschen nur auf aktiver View 479 if ( aViewData.IsActive() ) 480 { 481 sal_uInt16 i; 482 if ( bMulti ) 483 { 484 #ifdef OLD_SELECTION_PAINT 485 for (i=0; i<4; i++) 486 if (pGridWin[i] && pGridWin[i]->IsVisible()) 487 pGridWin[i]->InvertSimple( nBlockStartX, nBlockStartY, 488 nBlockEndX, nBlockEndY, 489 sal_True, sal_True ); 490 #endif 491 rMark.ResetMark(); 492 UpdateSelectionOverlay(); 493 bDidReset = sal_True; 494 } 495 else 496 { 497 #ifdef OLD_SELECTION_PAINT 498 // (mis)use InvertBlockMark to remove all of the selection 499 // -> set bBlockNeg (like when removing parts of a selection) 500 // and convert everything to Multi 501 502 rMark.MarkToMulti(); 503 sal_Bool bOld = bBlockNeg; 504 bBlockNeg = sal_True; 505 // #73130# (negative) MarkArea must be set in case of repaint 506 rMark.SetMarkArea( ScRange( nBlockStartX,nBlockStartY, nTab, 507 nBlockEndX,nBlockEndY, nTab ) ); 508 509 InvertBlockMark( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY ); 510 511 bBlockNeg = bOld; 512 #endif 513 rMark.ResetMark(); 514 UpdateSelectionOverlay(); 515 bDidReset = sal_True; 516 } 517 518 // repaint if controls are touched (#69680# in both cases) 519 // #i74768# Forms are rendered by DrawingLayer's EndDrawLayers() 520 static bool bSuppressControlExtraStuff(true); 521 522 if(!bSuppressControlExtraStuff) 523 { 524 Rectangle aMMRect = pDoc->GetMMRect(nBlockStartX,nBlockStartY,nBlockEndX,nBlockEndY, nTab); 525 if (pDoc->HasControl( nTab, aMMRect )) 526 { 527 for (i=0; i<4; i++) 528 { 529 if (pGridWin[i] && pGridWin[i]->IsVisible()) 530 { 531 // MapMode muss logischer (1/100mm) sein !!! 532 pDoc->InvalidateControls( pGridWin[i], nTab, aMMRect ); 533 pGridWin[i]->Update(); 534 } 535 } 536 } 537 } 538 } 539 } 540 else 541 PaintMarks( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY ); 542 } 543 544 if ( bReset && !bDidReset ) 545 rMark.ResetMark(); 546 547 ShowAllCursors(); 548 } 549 } 550 551 void ScTabView::SelectAll( sal_Bool bContinue ) 552 { 553 ScMarkData& rMark = aViewData.GetMarkData(); 554 SCTAB nTab = aViewData.GetTabNo(); 555 556 if (rMark.IsMarked()) 557 { 558 ScRange aMarkRange; 559 rMark.GetMarkArea( aMarkRange ); 560 if ( aMarkRange == ScRange( 0,0,nTab, MAXCOL,MAXROW,nTab ) ) 561 return; 562 } 563 564 DoneBlockMode( bContinue ); 565 InitBlockMode( 0,0,nTab ); 566 MarkCursor( MAXCOL,MAXROW,nTab ); 567 568 SelectionChanged(); 569 } 570 571 void ScTabView::SelectAllTables() 572 { 573 ScDocument* pDoc = aViewData.GetDocument(); 574 ScMarkData& rMark = aViewData.GetMarkData(); 575 // SCTAB nTab = aViewData.GetTabNo(); 576 SCTAB nCount = pDoc->GetTableCount(); 577 578 if (nCount>1) 579 { 580 for (SCTAB i=0; i<nCount; i++) 581 rMark.SelectTable( i, sal_True ); 582 583 // Markierungen werden per Default nicht pro Tabelle gehalten 584 // pDoc->ExtendMarksFromTable( nTab ); 585 586 aViewData.GetDocShell()->PostPaintExtras(); 587 SfxBindings& rBind = aViewData.GetBindings(); 588 rBind.Invalidate( FID_FILL_TAB ); 589 rBind.Invalidate( FID_TAB_DESELECTALL ); 590 } 591 } 592 593 void ScTabView::DeselectAllTables() 594 { 595 ScDocument* pDoc = aViewData.GetDocument(); 596 ScMarkData& rMark = aViewData.GetMarkData(); 597 SCTAB nTab = aViewData.GetTabNo(); 598 SCTAB nCount = pDoc->GetTableCount(); 599 600 for (SCTAB i=0; i<nCount; i++) 601 rMark.SelectTable( i, ( i == nTab ) ); 602 603 aViewData.GetDocShell()->PostPaintExtras(); 604 SfxBindings& rBind = aViewData.GetBindings(); 605 rBind.Invalidate( FID_FILL_TAB ); 606 rBind.Invalidate( FID_TAB_DESELECTALL ); 607 } 608 609 sal_Bool lcl_FitsInWindow( double fScaleX, double fScaleY, sal_uInt16 nZoom, 610 long nWindowX, long nWindowY, ScDocument* pDoc, SCTAB nTab, 611 SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, 612 SCCOL nFixPosX, SCROW nFixPosY ) 613 { 614 double fZoomFactor = (double)Fraction(nZoom,100); 615 fScaleX *= fZoomFactor; 616 fScaleY *= fZoomFactor; 617 618 long nBlockX = 0; 619 SCCOL nCol; 620 for (nCol=0; nCol<nFixPosX; nCol++) 621 { 622 // for frozen panes, add both parts 623 sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab ); 624 if (nColTwips) 625 { 626 nBlockX += (long)(nColTwips * fScaleX); 627 if (nBlockX > nWindowX) 628 return sal_False; 629 } 630 } 631 for (nCol=nStartCol; nCol<=nEndCol; nCol++) 632 { 633 sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab ); 634 if (nColTwips) 635 { 636 nBlockX += (long)(nColTwips * fScaleX); 637 if (nBlockX > nWindowX) 638 return sal_False; 639 } 640 } 641 642 long nBlockY = 0; 643 for (SCROW nRow = 0; nRow <= nFixPosY-1; ++nRow) 644 { 645 if (pDoc->RowHidden(nRow, nTab)) 646 continue; 647 648 // for frozen panes, add both parts 649 sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab); 650 if (nRowTwips) 651 { 652 nBlockY += (long)(nRowTwips * fScaleY); 653 if (nBlockY > nWindowY) 654 return sal_False; 655 } 656 } 657 for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow) 658 { 659 sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab); 660 if (nRowTwips) 661 { 662 nBlockY += (long)(nRowTwips * fScaleY); 663 if (nBlockY > nWindowY) 664 return sal_False; 665 } 666 } 667 668 return sal_True; 669 } 670 671 sal_uInt16 ScTabView::CalcZoom( SvxZoomType eType, sal_uInt16 nOldZoom ) 672 { 673 sal_uInt16 nZoom = 0; // Ergebnis 674 675 switch ( eType ) 676 { 677 case SVX_ZOOM_PERCENT: // rZoom ist kein besonderer prozentualer Wert 678 nZoom = nOldZoom; 679 break; 680 681 case SVX_ZOOM_OPTIMAL: // nZoom entspricht der optimalen Gr"o\se 682 { 683 ScMarkData& rMark = aViewData.GetMarkData(); 684 ScDocument* pDoc = aViewData.GetDocument(); 685 686 if (!rMark.IsMarked() && !rMark.IsMultiMarked()) 687 nZoom = 100; // nothing selected 688 else 689 { 690 SCTAB nTab = aViewData.GetTabNo(); 691 ScRange aMarkRange; 692 if ( aViewData.GetSimpleArea( aMarkRange ) != SC_MARK_SIMPLE ) 693 rMark.GetMultiMarkArea( aMarkRange ); 694 695 SCCOL nStartCol = aMarkRange.aStart.Col(); 696 SCROW nStartRow = aMarkRange.aStart.Row(); 697 SCTAB nStartTab = aMarkRange.aStart.Tab(); 698 SCCOL nEndCol = aMarkRange.aEnd.Col(); 699 SCROW nEndRow = aMarkRange.aEnd.Row(); 700 SCTAB nEndTab = aMarkRange.aEnd.Tab(); 701 702 if ( nTab < nStartTab && nTab > nEndTab ) 703 nTab = nStartTab; 704 705 ScSplitPos eUsedPart = aViewData.GetActivePart(); 706 707 SCCOL nFixPosX = 0; 708 SCROW nFixPosY = 0; 709 if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX ) 710 { 711 // use right part 712 eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT; 713 nFixPosX = aViewData.GetFixPosX(); 714 if ( nStartCol < nFixPosX ) 715 nStartCol = nFixPosX; 716 } 717 if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX ) 718 { 719 // use bottom part 720 eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT; 721 nFixPosY = aViewData.GetFixPosY(); 722 if ( nStartRow < nFixPosY ) 723 nStartRow = nFixPosY; 724 } 725 726 if (pGridWin[eUsedPart]) 727 { 728 // Because scale is rounded to pixels, the only reliable way to find 729 // the right scale is to check if a zoom fits 730 731 Size aWinSize = pGridWin[eUsedPart]->GetOutputSizePixel(); 732 733 // for frozen panes, use sum of both parts for calculation 734 735 if ( nFixPosX != 0 ) 736 aWinSize.Width() += GetGridWidth( SC_SPLIT_LEFT ); 737 if ( nFixPosY != 0 ) 738 aWinSize.Height() += GetGridHeight( SC_SPLIT_TOP ); 739 740 ScDocShell* pDocSh = aViewData.GetDocShell(); 741 double nPPTX = ScGlobal::nScreenPPTX / pDocSh->GetOutputFactor(); 742 double nPPTY = ScGlobal::nScreenPPTY; 743 744 sal_uInt16 nMin = MINZOOM; 745 sal_uInt16 nMax = MAXZOOM; 746 while ( nMax > nMin ) 747 { 748 sal_uInt16 nTest = (nMin+nMax+1)/2; 749 if ( lcl_FitsInWindow( 750 nPPTX, nPPTY, nTest, aWinSize.Width(), aWinSize.Height(), 751 pDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow, 752 nFixPosX, nFixPosY ) ) 753 nMin = nTest; 754 else 755 nMax = nTest-1; 756 } 757 DBG_ASSERT( nMin == nMax, "Schachtelung ist falsch" ); 758 nZoom = nMin; 759 760 if ( nZoom != nOldZoom ) 761 { 762 // scroll to block only in active split part 763 // (the part for which the size was calculated) 764 765 if ( nStartCol <= nEndCol ) 766 aViewData.SetPosX( WhichH(eUsedPart), nStartCol ); 767 if ( nStartRow <= nEndRow ) 768 aViewData.SetPosY( WhichV(eUsedPart), nStartRow ); 769 } 770 } 771 } 772 } 773 break; 774 775 case SVX_ZOOM_WHOLEPAGE: // nZoom entspricht der ganzen Seite oder 776 case SVX_ZOOM_PAGEWIDTH: // nZoom entspricht der Seitenbreite 777 { 778 SCTAB nCurTab = aViewData.GetTabNo(); 779 ScDocument* pDoc = aViewData.GetDocument(); 780 ScStyleSheetPool* pStylePool = pDoc->GetStyleSheetPool(); 781 SfxStyleSheetBase* pStyleSheet = 782 pStylePool->Find( pDoc->GetPageStyle( nCurTab ), 783 SFX_STYLE_FAMILY_PAGE ); 784 785 DBG_ASSERT( pStyleSheet, "PageStyle not found :-/" ); 786 787 if ( pStyleSheet ) 788 { 789 ScPrintFunc aPrintFunc( aViewData.GetDocShell(), 790 aViewData.GetViewShell()->GetPrinter(sal_True), 791 nCurTab ); 792 793 Size aPageSize = aPrintFunc.GetDataSize(); 794 795 // use the size of the largest GridWin for normal split, 796 // or both combined for frozen panes, with the (document) size 797 // of the frozen part added to the page size 798 // (with frozen panes, the size of the individual parts 799 // depends on the scale that is to be calculated) 800 801 if ( !pGridWin[SC_SPLIT_BOTTOMLEFT] ) return 0; 802 Size aWinSize = pGridWin[SC_SPLIT_BOTTOMLEFT]->GetOutputSizePixel(); 803 ScSplitMode eHMode = aViewData.GetHSplitMode(); 804 if ( eHMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_BOTTOMRIGHT] ) 805 { 806 long nOtherWidth = pGridWin[SC_SPLIT_BOTTOMRIGHT]-> 807 GetOutputSizePixel().Width(); 808 if ( eHMode == SC_SPLIT_FIX ) 809 { 810 aWinSize.Width() += nOtherWidth; 811 for ( SCCOL nCol = aViewData.GetPosX(SC_SPLIT_LEFT); 812 nCol < aViewData.GetFixPosX(); nCol++ ) 813 aPageSize.Width() += pDoc->GetColWidth( nCol, nCurTab ); 814 } 815 else if ( nOtherWidth > aWinSize.Width() ) 816 aWinSize.Width() = nOtherWidth; 817 } 818 ScSplitMode eVMode = aViewData.GetVSplitMode(); 819 if ( eVMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_TOPLEFT] ) 820 { 821 long nOtherHeight = pGridWin[SC_SPLIT_TOPLEFT]-> 822 GetOutputSizePixel().Height(); 823 if ( eVMode == SC_SPLIT_FIX ) 824 { 825 aWinSize.Height() += nOtherHeight; 826 aPageSize.Height() += pDoc->GetRowHeight( 827 aViewData.GetPosY(SC_SPLIT_TOP), 828 aViewData.GetFixPosY()-1, nCurTab); 829 } 830 else if ( nOtherHeight > aWinSize.Height() ) 831 aWinSize.Height() = nOtherHeight; 832 } 833 834 double nPPTX = ScGlobal::nScreenPPTX / aViewData.GetDocShell()->GetOutputFactor(); 835 double nPPTY = ScGlobal::nScreenPPTY; 836 837 long nZoomX = (long) ( aWinSize.Width() * 100 / 838 ( aPageSize.Width() * nPPTX ) ); 839 long nZoomY = (long) ( aWinSize.Height() * 100 / 840 ( aPageSize.Height() * nPPTY ) ); 841 long nNew = nZoomX; 842 843 if (eType == SVX_ZOOM_WHOLEPAGE && nZoomY < nNew) 844 nNew = nZoomY; 845 846 nZoom = (sal_uInt16) nNew; 847 } 848 } 849 break; 850 851 default: 852 DBG_ERROR("Unknown Zoom-Revision"); 853 nZoom = 0; 854 } 855 856 return nZoom; 857 } 858 859 // wird z.B. gerufen, wenn sich das View-Fenster verschiebt: 860 861 void ScTabView::StopMarking() 862 { 863 ScSplitPos eActive = aViewData.GetActivePart(); 864 if (pGridWin[eActive]) 865 pGridWin[eActive]->StopMarking(); 866 867 ScHSplitPos eH = WhichH(eActive); 868 if (pColBar[eH]) 869 pColBar[eH]->StopMarking(); 870 871 ScVSplitPos eV = WhichV(eActive); 872 if (pRowBar[eV]) 873 pRowBar[eV]->StopMarking(); 874 } 875 876 void ScTabView::HideNoteMarker() 877 { 878 for (sal_uInt16 i=0; i<4; i++) 879 if (pGridWin[i] && pGridWin[i]->IsVisible()) 880 pGridWin[i]->HideNoteMarker(); 881 } 882 883 void ScTabView::MakeDrawLayer() 884 { 885 if (!pDrawView) 886 { 887 aViewData.GetDocShell()->MakeDrawLayer(); 888 889 // pDrawView wird per Notify gesetzt 890 DBG_ASSERT(pDrawView,"ScTabView::MakeDrawLayer funktioniert nicht"); 891 892 // #114409# 893 for(sal_uInt16 a(0); a < 4; a++) 894 { 895 if(pGridWin[a]) 896 { 897 pGridWin[a]->DrawLayerCreated(); 898 } 899 } 900 } 901 } 902 903 void ScTabView::ErrorMessage( sal_uInt16 nGlobStrId ) 904 { 905 if ( SC_MOD()->IsInExecuteDrop() ) 906 { 907 // #i28468# don't show error message when called from Drag&Drop, silently abort instead 908 return; 909 } 910 911 StopMarking(); // falls per Focus aus MouseButtonDown aufgerufen 912 913 Window* pParent = aViewData.GetDialogParent(); 914 ScWaitCursorOff aWaitOff( pParent ); 915 sal_Bool bFocus = pParent && pParent->HasFocus(); 916 917 if(nGlobStrId==STR_PROTECTIONERR) 918 { 919 if(aViewData.GetDocShell()->IsReadOnly()) 920 { 921 nGlobStrId=STR_READONLYERR; 922 } 923 } 924 925 InfoBox aBox( pParent, ScGlobal::GetRscString( nGlobStrId ) ); 926 aBox.Execute(); 927 if (bFocus) 928 pParent->GrabFocus(); 929 } 930 931 Window* ScTabView::GetParentOrChild( sal_uInt16 nChildId ) 932 { 933 SfxViewFrame* pViewFrm = aViewData.GetViewShell()->GetViewFrame(); 934 935 if ( pViewFrm->HasChildWindow(nChildId) ) 936 { 937 SfxChildWindow* pChild = pViewFrm->GetChildWindow(nChildId); 938 if (pChild) 939 { 940 Window* pWin = pChild->GetWindow(); 941 if (pWin && pWin->IsVisible()) 942 return pWin; 943 } 944 } 945 946 return aViewData.GetDialogParent(); 947 } 948 949 void ScTabView::UpdatePageBreakData( sal_Bool bForcePaint ) 950 { 951 ScPageBreakData* pNewData = NULL; 952 953 if (aViewData.IsPagebreakMode()) 954 { 955 ScDocShell* pDocSh = aViewData.GetDocShell(); 956 ScDocument* pDoc = pDocSh->GetDocument(); 957 SCTAB nTab = aViewData.GetTabNo(); 958 959 sal_uInt16 nCount = pDoc->GetPrintRangeCount(nTab); 960 if (!nCount) 961 nCount = 1; 962 pNewData = new ScPageBreakData(nCount); 963 964 ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab, 0,0,NULL, NULL, pNewData ); 965 // ScPrintFunc fuellt im ctor die PageBreakData 966 if ( nCount > 1 ) 967 { 968 aPrintFunc.ResetBreaks(nTab); 969 pNewData->AddPages(); 970 } 971 972 // Druckbereiche veraendert? 973 if ( bForcePaint || ( pPageBreakData && !pPageBreakData->IsEqual( *pNewData ) ) ) 974 PaintGrid(); 975 } 976 977 delete pPageBreakData; 978 pPageBreakData = pNewData; 979 } 980 981 982 983