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 <sfx2/dispatch.hxx> 36 #include <vcl/help.hxx> 37 #include <tools/poly.hxx> 38 #include <svtools/colorcfg.hxx> 39 40 #include "scresid.hxx" 41 #include "sc.hrc" 42 #include "tabvwsh.hxx" 43 #include "hdrcont.hxx" 44 #include "scmod.hxx" // Optionen 45 #include "inputopt.hxx" // Optionen 46 #include "gridmerg.hxx" 47 #include "document.hxx" 48 49 // ----------------------------------------------------------------------- 50 51 #define SC_DRAG_MIN 2 52 53 // passes in paint 54 // (selection left/right must be first because the continuous lines 55 // are partly overwritten later) 56 57 #define SC_HDRPAINT_SEL_RIGHT 0 58 #define SC_HDRPAINT_SEL_LEFT 1 59 #define SC_HDRPAINT_TOP 2 60 #define SC_HDRPAINT_SEL_TOP 3 61 #define SC_HDRPAINT_SEL_BOTTOM 4 62 #define SC_HDRPAINT_BOTTOM 5 63 #define SC_HDRPAINT_TEXT 6 64 #define SC_HDRPAINT_COUNT 7 65 66 //================================================================== 67 68 ScHeaderControl::ScHeaderControl( Window* pParent, SelectionEngine* pSelectionEngine, 69 SCCOLROW nNewSize, sal_uInt16 nNewFlags ) : 70 Window ( pParent ), 71 pSelEngine ( pSelectionEngine ), 72 nFlags ( nNewFlags ), 73 bVertical ( (nNewFlags & HDR_VERTICAL) != 0 ), 74 nSize ( nNewSize ), 75 nMarkStart ( 0 ), 76 nMarkEnd ( 0 ), 77 bMarkRange ( sal_False ), 78 bDragging ( sal_False ), 79 bIgnoreMove ( sal_False ) 80 { 81 // --- RTL --- no default mirroring for this window, the spreadsheet itself 82 // is also not mirrored 83 // #107811# mirror the vertical window for correct border drawing 84 // #106948# table layout depends on sheet format, not UI setting, so the 85 // borders of the vertical window have to be handled manually, too. 86 EnableRTL( sal_False ); 87 88 aNormFont = GetFont(); 89 aNormFont.SetTransparent( sal_True ); //! WEIGHT_NORMAL hart setzen ??? 90 aBoldFont = aNormFont; 91 aBoldFont.SetWeight( WEIGHT_BOLD ); 92 93 SetFont(aBoldFont); 94 bBoldSet = sal_True; 95 96 Size aSize = LogicToPixel( Size( 97 GetTextWidth( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("8888")) ), 98 GetTextHeight() ) ); 99 aSize.Width() += 4; // Platz fuer hervorgehobene Umrandung 100 aSize.Height() += 3; 101 SetSizePixel( aSize ); 102 103 nWidth = nSmallWidth = aSize.Width(); 104 nBigWidth = LogicToPixel( Size( GetTextWidth( 105 String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("8888888")) ), 0 ) ).Width() + 5; 106 107 SetBackground(); // sonst Probleme auf OS/2 !?!?! 108 } 109 110 void ScHeaderControl::SetWidth( long nNew ) 111 { 112 DBG_ASSERT( bVertical, "SetDigits nur fuer Zeilenkoepfe erlaubt" ); 113 if ( nNew != nWidth ) 114 { 115 Size aSize( nNew, GetSizePixel().Height() ); // Hoehe nicht aendern 116 SetSizePixel( aSize ); 117 118 nWidth = nNew; 119 120 Invalidate(); // neu zentrieren 121 } 122 } 123 124 ScHeaderControl::~ScHeaderControl() 125 { 126 } 127 128 void ScHeaderControl::DoPaint( SCCOLROW nStart, SCCOLROW nEnd ) 129 { 130 sal_Bool bLayoutRTL = IsLayoutRTL(); 131 long nLayoutSign = bLayoutRTL ? -1 : 1; 132 133 Rectangle aRect( Point(0,0), GetOutputSizePixel() ); 134 if ( bVertical ) 135 { 136 aRect.Top() = GetScrPos( nStart )-nLayoutSign; // extra pixel for line at top of selection 137 aRect.Bottom() = GetScrPos( nEnd+1 )-nLayoutSign; 138 } 139 else 140 { 141 aRect.Left() = GetScrPos( nStart )-nLayoutSign; // extra pixel for line left of selection 142 aRect.Right() = GetScrPos( nEnd+1 )-nLayoutSign; 143 } 144 Invalidate(aRect); 145 } 146 147 void ScHeaderControl::SetMark( sal_Bool bNewSet, SCCOLROW nNewStart, SCCOLROW nNewEnd ) 148 { 149 sal_Bool bEnabled = SC_MOD()->GetInputOptions().GetMarkHeader(); //! cachen? 150 if (!bEnabled) 151 bNewSet = sal_False; 152 153 // Variablen setzen 154 155 sal_Bool bOldSet = bMarkRange; 156 SCCOLROW nOldStart = nMarkStart; 157 SCCOLROW nOldEnd = nMarkEnd; 158 PutInOrder( nNewStart, nNewEnd ); 159 bMarkRange = bNewSet; 160 nMarkStart = nNewStart; 161 nMarkEnd = nNewEnd; 162 163 // Paint 164 165 if ( bNewSet ) 166 { 167 if ( bOldSet ) 168 { 169 if ( nNewStart == nOldStart ) 170 { 171 if ( nNewEnd != nOldEnd ) 172 DoPaint( Min( nNewEnd, nOldEnd ) + 1, Max( nNewEnd, nOldEnd ) ); 173 // sonst nix 174 } 175 else if ( nNewEnd == nOldEnd ) 176 DoPaint( Min( nNewStart, nOldStart ), Max( nNewStart, nOldStart ) - 1 ); 177 else if ( nNewStart > nOldEnd || nNewEnd < nOldStart ) 178 { 179 // zwei Bereiche... 180 DoPaint( nOldStart, nOldEnd ); 181 DoPaint( nNewStart, nNewEnd ); 182 } 183 else // irgendwie ueberlappend... (kommt eh nicht oft vor) 184 DoPaint( Min( nNewStart, nOldStart ), Max( nNewEnd, nOldEnd ) ); 185 } 186 else 187 DoPaint( nNewStart, nNewEnd ); // komplett neu 188 } 189 else if ( bOldSet ) 190 DoPaint( nOldStart, nOldEnd ); // komplett aufheben 191 192 // sonst war nix, is nix 193 } 194 195 long ScHeaderControl::GetScrPos( SCCOLROW nEntryNo ) 196 { 197 long nScrPos; 198 199 long nMax = ( bVertical ? GetOutputSizePixel().Height() : GetOutputSizePixel().Width() ) + 1; 200 if (nEntryNo >= nSize) 201 nScrPos = nMax; 202 else 203 { 204 nScrPos = 0; 205 for (SCCOLROW i=GetPos(); i<nEntryNo && nScrPos<nMax; i++) 206 { 207 sal_uInt16 nAdd = GetEntrySize(i); 208 if (nAdd) 209 nScrPos += nAdd; 210 else 211 { 212 SCCOLROW nHidden = GetHiddenCount(i); 213 if (nHidden > 0) 214 i += nHidden - 1; 215 } 216 } 217 } 218 219 if ( IsLayoutRTL() ) 220 nScrPos = nMax - nScrPos - 2; 221 222 return nScrPos; 223 } 224 225 // draw a rectangle across the window's width/height, with the outer part in a lighter color 226 227 void ScHeaderControl::DrawShadedRect( long nStart, long nEnd, const Color& rBaseColor ) 228 { 229 Color aWhite( COL_WHITE ); 230 231 Color aInner( rBaseColor ); // highlight color, unchanged 232 Color aCenter( rBaseColor ); 233 aCenter.Merge( aWhite, 0xd0 ); // lighten up a bit 234 Color aOuter( rBaseColor ); 235 aOuter.Merge( aWhite, 0xa0 ); // lighten up more 236 237 if ( IsMirrored() ) 238 std::swap( aInner, aOuter ); // just swap colors instead of positions 239 240 Size aWinSize = GetSizePixel(); 241 long nBarSize = bVertical ? aWinSize.Width() : aWinSize.Height(); 242 long nCenterPos = (nBarSize / 2) - 1; 243 244 SetLineColor(); 245 SetFillColor( aOuter ); 246 if (bVertical) 247 DrawRect( Rectangle( 0, nStart, nCenterPos-1, nEnd ) ); 248 else 249 DrawRect( Rectangle( nStart, 0, nEnd, nCenterPos-1 ) ); 250 SetFillColor( aCenter ); 251 if (bVertical) 252 DrawRect( Rectangle( nCenterPos, nStart, nCenterPos, nEnd ) ); 253 else 254 DrawRect( Rectangle( nStart, nCenterPos, nEnd, nCenterPos ) ); 255 SetFillColor( aInner ); 256 if (bVertical) 257 DrawRect( Rectangle( nCenterPos+1, nStart, nBarSize-1, nEnd ) ); 258 else 259 DrawRect( Rectangle( nStart, nCenterPos+1, nEnd, nBarSize-1 ) ); 260 } 261 262 // 263 // Paint 264 // 265 266 void ScHeaderControl::Paint( const Rectangle& rRect ) 267 { 268 // fuer VCL ist es wichtig, wenig Aufrufe zu haben, darum werden die aeusseren 269 // Linien zusammengefasst 270 271 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); 272 sal_Bool bHighContrast = rStyleSettings.GetHighContrastMode(); 273 sal_Bool bDark = rStyleSettings.GetFaceColor().IsDark(); 274 // Use the same distinction for bDark as in Window::DrawSelectionBackground 275 276 Color aTextColor = rStyleSettings.GetButtonTextColor(); 277 Color aSelTextColor = rStyleSettings.GetHighlightTextColor(); 278 aNormFont.SetColor( aTextColor ); 279 if ( bHighContrast ) 280 aBoldFont.SetColor( aTextColor ); 281 else 282 aBoldFont.SetColor( aSelTextColor ); 283 SetTextColor( ( bBoldSet && !bHighContrast ) ? aSelTextColor : aTextColor ); 284 285 Color aBlack( COL_BLACK ); 286 Color aSelLineColor = rStyleSettings.GetHighlightColor(); 287 aSelLineColor.Merge( aBlack, 0xe0 ); // darken just a little bit 288 289 sal_Bool bLayoutRTL = IsLayoutRTL(); 290 long nLayoutSign = bLayoutRTL ? -1 : 1; 291 sal_Bool bMirrored = IsMirrored(); 292 293 // const FunctionSet* pFuncSet = pSelEngine->GetFunctionSet(); 294 String aString; 295 sal_uInt16 nBarSize; 296 Point aScrPos; 297 Size aTextSize; 298 // Size aSize = GetOutputSizePixel(); 299 300 if (bVertical) 301 nBarSize = (sal_uInt16) GetSizePixel().Width(); 302 else 303 nBarSize = (sal_uInt16) GetSizePixel().Height(); 304 305 SCCOLROW nPos = GetPos(); 306 307 long nPStart = bVertical ? rRect.Top() : rRect.Left(); 308 long nPEnd = bVertical ? rRect.Bottom() : rRect.Right(); 309 310 long nTransStart = nPEnd + 1; 311 long nTransEnd = 0; 312 313 long nInitScrPos = 0; 314 if ( bLayoutRTL ) 315 { 316 long nTemp = nPStart; // swap nPStart / nPEnd 317 nPStart = nPEnd; 318 nPEnd = nTemp; 319 nTemp = nTransStart; // swap nTransStart / nTransEnd 320 nTransStart = nTransEnd; 321 nTransEnd = nTemp; 322 if ( bVertical ) // start loops from the end 323 nInitScrPos = GetSizePixel().Height() - 1; 324 else 325 nInitScrPos = GetSizePixel().Width() - 1; 326 } 327 328 // aeussere Linien komplett durchzeichnen 329 // Zuerst Ende der letzten Zelle finden 330 331 // long nLineEnd = -1; 332 long nLineEnd = nInitScrPos - nLayoutSign; 333 334 for (SCCOLROW i=nPos; i<nSize; i++) 335 { 336 sal_uInt16 nSizePix = GetEntrySize( i ); 337 if (nSizePix) 338 { 339 nLineEnd += nSizePix * nLayoutSign; 340 341 if ( bMarkRange && i >= nMarkStart && i <= nMarkEnd ) 342 { 343 long nLineStart = nLineEnd - ( nSizePix - 1 ) * nLayoutSign; 344 if ( nLineStart * nLayoutSign < nTransStart * nLayoutSign ) 345 nTransStart = nLineStart; 346 if ( nLineEnd * nLayoutSign > nTransEnd * nLayoutSign ) 347 nTransEnd = nLineEnd; 348 } 349 350 if ( nLineEnd * nLayoutSign > nPEnd * nLayoutSign ) 351 { 352 nLineEnd = nPEnd; 353 break; 354 } 355 } 356 else 357 { 358 SCCOLROW nHidden = GetHiddenCount(i); 359 if (nHidden > 0) 360 i += nHidden - 1; 361 } 362 } 363 364 // background is different for entry area and behind the entries 365 366 Rectangle aFillRect; 367 SetLineColor(); 368 369 if ( nLineEnd * nLayoutSign >= nInitScrPos * nLayoutSign ) 370 { 371 if ( bHighContrast ) 372 { 373 // high contrast: single-color background 374 SetFillColor( rStyleSettings.GetFaceColor() ); 375 if ( bVertical ) 376 aFillRect = Rectangle( 0, nInitScrPos, nBarSize-1, nLineEnd ); 377 else 378 aFillRect = Rectangle( nInitScrPos, 0, nLineEnd, nBarSize-1 ); 379 DrawRect( aFillRect ); 380 } 381 else 382 { 383 // normal: 3-part background 384 DrawShadedRect( nInitScrPos, nLineEnd, rStyleSettings.GetFaceColor() ); 385 } 386 } 387 388 if ( nLineEnd * nLayoutSign < nPEnd * nLayoutSign ) 389 { 390 SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::APPBACKGROUND).nColor ); 391 if ( bVertical ) 392 aFillRect = Rectangle( 0, nLineEnd+nLayoutSign, nBarSize-1, nPEnd ); 393 else 394 aFillRect = Rectangle( nLineEnd+nLayoutSign, 0, nPEnd, nBarSize-1 ); 395 DrawRect( aFillRect ); 396 } 397 398 if ( nLineEnd * nLayoutSign >= nPStart * nLayoutSign ) 399 { 400 if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign ) 401 { 402 if ( bHighContrast ) 403 { 404 if ( bDark ) 405 { 406 // solid grey background for dark face color is drawn before lines 407 408 SetLineColor(); 409 SetFillColor( COL_LIGHTGRAY ); 410 if (bVertical) 411 DrawRect( Rectangle( 0, nTransStart, nBarSize-1, nTransEnd ) ); 412 else 413 DrawRect( Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 ) ); 414 } 415 } 416 else 417 { 418 // background for selection 419 420 DrawShadedRect( nTransStart, nTransEnd, rStyleSettings.GetHighlightColor() ); 421 } 422 } 423 424 #if 0 425 // 3D border is no longer used 426 SetLineColor( rStyleSettings.GetLightColor() ); 427 if (bVertical) 428 DrawLine( Point( 0, nPStart ), Point( 0, nLineEnd ) ); 429 else 430 DrawLine( Point( nPStart, 0 ), Point( nLineEnd, 0 ) ); 431 #endif 432 433 SetLineColor( rStyleSettings.GetDarkShadowColor() ); 434 if (bVertical) 435 { 436 long nDarkPos = bMirrored ? 0 : nBarSize-1; 437 DrawLine( Point( nDarkPos, nPStart ), Point( nDarkPos, nLineEnd ) ); 438 } 439 else 440 DrawLine( Point( nPStart, nBarSize-1 ), Point( nLineEnd, nBarSize-1 ) ); 441 442 // line in different color for selection 443 if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && !bHighContrast ) 444 { 445 SetLineColor( aSelLineColor ); 446 if (bVertical) 447 { 448 long nDarkPos = bMirrored ? 0 : nBarSize-1; 449 DrawLine( Point( nDarkPos, nTransStart ), Point( nDarkPos, nTransEnd ) ); 450 } 451 else 452 DrawLine( Point( nTransStart, nBarSize-1 ), Point( nTransEnd, nBarSize-1 ) ); 453 } 454 } 455 456 // 457 // loop through entries several times to avoid changing the line color too often 458 // and to allow merging of lines 459 // 460 461 ScGridMerger aGrid( this, 1, 1 ); 462 463 // start at SC_HDRPAINT_BOTTOM instead of 0 - selection doesn't get different 464 // borders, light border at top isn't used anymore 465 // use SC_HDRPAINT_SEL_BOTTOM for different color 466 467 for (sal_uInt16 nPass = SC_HDRPAINT_SEL_BOTTOM; nPass < SC_HDRPAINT_COUNT; nPass++) 468 { 469 // set line color etc. before entry loop 470 switch ( nPass ) 471 { 472 case SC_HDRPAINT_SEL_BOTTOM: 473 // same as non-selected for high contrast 474 SetLineColor( bHighContrast ? rStyleSettings.GetDarkShadowColor() : aSelLineColor ); 475 break; 476 case SC_HDRPAINT_BOTTOM: 477 SetLineColor( rStyleSettings.GetDarkShadowColor() ); 478 break; 479 case SC_HDRPAINT_TEXT: 480 // DrawSelectionBackground is used only for high contrast on light background 481 if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && bHighContrast && !bDark ) 482 { 483 // Transparent selection background is drawn after lines, before text. 484 // #109814# Use DrawSelectionBackground to make sure there is a visible 485 // difference. The case of a dark face color, where DrawSelectionBackground 486 // would just paint over the lines, is handled separately (bDark). 487 // Otherwise, GetHighlightColor is used with 80% transparency. 488 // The window's background color (SetBackground) has to be the background 489 // of the cell area, for the contrast comparison in DrawSelectionBackground. 490 491 Rectangle aTransRect; 492 if (bVertical) 493 aTransRect = Rectangle( 0, nTransStart, nBarSize-1, nTransEnd ); 494 else 495 aTransRect = Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 ); 496 SetBackground( Color( rStyleSettings.GetFaceColor() ) ); 497 DrawSelectionBackground( aTransRect, 0, sal_True, sal_False, sal_False ); 498 SetBackground(); 499 } 500 break; 501 } 502 503 SCCOLROW nCount=0; 504 long nScrPos=nInitScrPos; 505 do 506 { 507 if (bVertical) 508 aScrPos = Point( 0, nScrPos ); 509 else 510 aScrPos = Point( nScrPos, 0 ); 511 512 SCCOLROW nEntryNo = nCount + nPos; 513 if ( nEntryNo >= nSize ) // MAXCOL/MAXROW 514 nScrPos = nPEnd + nLayoutSign; // beyond nPEnd -> stop 515 else 516 { 517 sal_uInt16 nSizePix = GetEntrySize( nEntryNo ); 518 519 if (nSizePix == 0) 520 { 521 SCCOLROW nHidden = GetHiddenCount(nEntryNo); 522 if (nHidden > 0) 523 nCount += nHidden - 1; 524 } 525 else if ((nScrPos+nSizePix*nLayoutSign)*nLayoutSign >= nPStart*nLayoutSign) 526 { 527 Point aEndPos(aScrPos); 528 if (bVertical) 529 aEndPos = Point( aScrPos.X()+nBarSize-1, aScrPos.Y()+(nSizePix-1)*nLayoutSign ); 530 else 531 aEndPos = Point( aScrPos.X()+(nSizePix-1)*nLayoutSign, aScrPos.Y()+nBarSize-1 ); 532 533 sal_Bool bMark = bMarkRange && nEntryNo >= nMarkStart && nEntryNo <= nMarkEnd; 534 sal_Bool bNextToMark = bMarkRange && nEntryNo + 1 >= nMarkStart && nEntryNo <= nMarkEnd; 535 536 switch ( nPass ) 537 { 538 case SC_HDRPAINT_SEL_BOTTOM: 539 case SC_HDRPAINT_BOTTOM: 540 if ( nPass == ( bNextToMark ? SC_HDRPAINT_SEL_BOTTOM : SC_HDRPAINT_BOTTOM ) ) 541 { 542 if (bVertical) 543 aGrid.AddHorLine( aScrPos.X(), aEndPos.X(), aEndPos.Y() ); 544 else 545 aGrid.AddVerLine( aEndPos.X(), aScrPos.Y(), aEndPos.Y() ); 546 547 // thick bottom for hidden rows 548 // (drawn directly, without aGrid) 549 if ( nEntryNo+1 < nSize ) 550 if ( GetEntrySize(nEntryNo+1)==0 ) 551 { 552 if (bVertical) 553 DrawLine( Point(aScrPos.X(),aEndPos.Y()-nLayoutSign), 554 Point(aEndPos.X(),aEndPos.Y()-nLayoutSign) ); 555 else 556 DrawLine( Point(aEndPos.X()-nLayoutSign,aScrPos.Y()), 557 Point(aEndPos.X()-nLayoutSign,aEndPos.Y()) ); 558 } 559 } 560 break; 561 562 case SC_HDRPAINT_TEXT: 563 if ( nSizePix > 1 ) // minimal check for small columns/rows 564 { 565 if ( bMark != bBoldSet ) 566 { 567 if (bMark) 568 SetFont(aBoldFont); 569 else 570 SetFont(aNormFont); 571 bBoldSet = bMark; 572 } 573 aString = GetEntryText( nEntryNo ); 574 aTextSize.Width() = GetTextWidth( aString ); 575 aTextSize.Height() = GetTextHeight(); 576 577 Point aTxtPos(aScrPos); 578 if (bVertical) 579 { 580 aTxtPos.X() += (nBarSize-aTextSize.Width())/2; 581 aTxtPos.Y() += (nSizePix*nLayoutSign-aTextSize.Height())/2; 582 if ( bMirrored ) 583 aTxtPos.X() += 1; // dark border is left instead of right 584 } 585 else 586 { 587 aTxtPos.X() += (nSizePix*nLayoutSign-aTextSize.Width()+1)/2; 588 aTxtPos.Y() += (nBarSize-aTextSize.Height())/2; 589 } 590 DrawText( aTxtPos, aString ); 591 } 592 break; 593 } 594 595 // bei Selektion der ganzen Zeile/Spalte: 596 // InvertRect( Rectangle( aScrPos, aEndPos ) ); 597 } 598 nScrPos += nSizePix * nLayoutSign; // also if before the visible area 599 } 600 ++nCount; 601 } 602 while ( nScrPos * nLayoutSign <= nPEnd * nLayoutSign ); 603 604 aGrid.Flush(); 605 } 606 } 607 608 // 609 // Maus - Handling 610 // 611 612 SCCOLROW ScHeaderControl::GetMousePos( const MouseEvent& rMEvt, sal_Bool& rBorder ) 613 { 614 sal_Bool bFound=sal_False; 615 SCCOLROW nCount = 1; 616 SCCOLROW nPos = GetPos(); 617 SCCOLROW nHitNo = nPos; 618 long nScrPos; 619 long nMousePos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X(); 620 long nDif; 621 Size aSize = GetOutputSizePixel(); 622 long nWinSize = bVertical ? aSize.Height() : aSize.Width(); 623 624 sal_Bool bLayoutRTL = IsLayoutRTL(); 625 long nLayoutSign = bLayoutRTL ? -1 : 1; 626 long nEndPos = bLayoutRTL ? -1 : nWinSize; 627 628 nScrPos = GetScrPos( nPos ) - nLayoutSign; 629 do 630 { 631 SCCOLROW nEntryNo = nCount + nPos; 632 633 // nScrPos = GetScrPos( nEntryNo ) - 1; 634 635 if (nEntryNo > nSize) 636 nScrPos = nEndPos + nLayoutSign; 637 else 638 nScrPos += GetEntrySize( nEntryNo - 1 ) * nLayoutSign; //! GetHiddenCount() ?? 639 640 nDif = nMousePos - nScrPos; 641 if (nDif >= -2 && nDif <= 2 && nCount > 0) 642 { 643 bFound=sal_True; 644 nHitNo=nEntryNo-1; 645 } 646 else if (nDif * nLayoutSign >= 0 && nEntryNo < nSize) 647 nHitNo = nEntryNo; 648 ++nCount; 649 } 650 while ( nScrPos * nLayoutSign < nEndPos * nLayoutSign && nDif * nLayoutSign > 0 ); 651 652 rBorder = bFound; 653 return nHitNo; 654 } 655 656 bool ScHeaderControl::IsSelectionAllowed(SCCOLROW nPos) const 657 { 658 ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current()); 659 if (!pViewSh) 660 return false; 661 662 ScViewData* pViewData = pViewSh->GetViewData(); 663 sal_uInt16 nTab = pViewData->GetTabNo(); 664 ScDocument* pDoc = pViewData->GetDocument(); 665 const ScTableProtection* pProtect = pDoc->GetTabProtection(nTab); 666 bool bSelectAllowed = true; 667 if ( pProtect && pProtect->isProtected() ) 668 { 669 // This sheet is protected. Check if a context menu is allowed on this cell. 670 bool bCellsProtected = false; 671 if (bVertical) 672 { 673 // row header 674 SCROW nRPos = static_cast<SCROW>(nPos); 675 bCellsProtected = pDoc->HasAttrib(0, nRPos, nTab, MAXCOL, nRPos, nTab, HASATTR_PROTECTED); 676 } 677 else 678 { 679 // column header 680 SCCOL nCPos = static_cast<SCCOL>(nPos); 681 bCellsProtected = pDoc->HasAttrib(nCPos, 0, nTab, nCPos, MAXROW, nTab, HASATTR_PROTECTED); 682 } 683 684 bool bSelProtected = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS); 685 bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS); 686 687 if (bCellsProtected) 688 bSelectAllowed = bSelProtected; 689 else 690 bSelectAllowed = bSelUnprotected; 691 } 692 return bSelectAllowed; 693 } 694 695 void ScHeaderControl::MouseButtonDown( const MouseEvent& rMEvt ) 696 { 697 if (IsDisabled()) 698 return; 699 700 bIgnoreMove = sal_False; 701 SelectWindow(); 702 703 sal_Bool bFound; 704 SCCOLROW nHitNo = GetMousePos( rMEvt, bFound ); 705 if (!IsSelectionAllowed(nHitNo)) 706 return; 707 708 if ( bFound && rMEvt.IsLeft() && ResizeAllowed() ) 709 { 710 nDragNo = nHitNo; 711 sal_uInt16 nClicks = rMEvt.GetClicks(); 712 if ( nClicks && nClicks%2==0 ) 713 { 714 SetEntrySize( nDragNo, HDR_SIZE_OPTIMUM ); 715 SetPointer( Pointer( POINTER_ARROW ) ); 716 } 717 else 718 { 719 if (bVertical) 720 nDragStart = rMEvt.GetPosPixel().Y(); 721 else 722 nDragStart = rMEvt.GetPosPixel().X(); 723 nDragPos = nDragStart; 724 ShowDragHelp(); 725 DrawInvert( nDragPos ); 726 727 // CaptureMouse(); 728 StartTracking(); 729 bDragging = sal_True; 730 bDragMoved = sal_False; 731 } 732 } 733 else if (rMEvt.IsLeft()) 734 { 735 pSelEngine->SetWindow( this ); 736 Point aPoint; 737 Rectangle aVis( aPoint,GetOutputSizePixel() ); 738 if (bVertical) 739 aVis.Left() = LONG_MIN, aVis.Right() = LONG_MAX; 740 else 741 aVis.Top() = LONG_MIN, aVis.Bottom() = LONG_MAX; 742 pSelEngine->SetVisibleArea( aVis ); 743 744 SetMarking( sal_True ); // muss vor SelMouseButtonDown sein 745 pSelEngine->SelMouseButtonDown( rMEvt ); 746 747 // #74215# In column/row headers a simple click already is a selection. 748 // -> Call SelMouseMove to ensure CreateAnchor is called (and DestroyAnchor 749 // if the next click is somewhere else with Control key). 750 pSelEngine->SelMouseMove( rMEvt ); 751 752 if (IsMouseCaptured()) 753 { 754 // Tracking statt CaptureMouse, damit sauber abgebrochen werden kann 755 //! Irgendwann sollte die SelectionEngine selber StartTracking rufen!?! 756 ReleaseMouse(); 757 StartTracking(); 758 } 759 } 760 } 761 762 void ScHeaderControl::MouseButtonUp( const MouseEvent& rMEvt ) 763 { 764 if ( IsDisabled() ) 765 return; 766 767 SetMarking( sal_False ); 768 bIgnoreMove = sal_False; 769 // sal_Bool bFound; 770 // SCCOLROW nHitNo = GetMousePos( rMEvt, bFound ); 771 772 if ( bDragging ) 773 { 774 DrawInvert( nDragPos ); 775 ReleaseMouse(); 776 bDragging = sal_False; 777 778 long nScrPos = GetScrPos( nDragNo ); 779 long nMousePos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X(); 780 sal_Bool bLayoutRTL = IsLayoutRTL(); 781 long nNewWidth = bLayoutRTL ? ( nScrPos - nMousePos + 1 ) 782 : ( nMousePos + 2 - nScrPos ); 783 784 if ( nNewWidth < 0 /* && !IsSelected(nDragNo) */ ) 785 { 786 SCCOLROW nStart = 0; 787 SCCOLROW nEnd = nDragNo; 788 while (nNewWidth < 0) 789 { 790 nStart = nDragNo; 791 if (nDragNo>0) 792 { 793 --nDragNo; 794 nNewWidth += GetEntrySize( nDragNo ); //! GetHiddenCount() ??? 795 } 796 else 797 nNewWidth = 0; 798 } 799 HideEntries( nStart, nEnd ); 800 } 801 else 802 { 803 if (nNewWidth<0) nNewWidth=0; 804 if (bDragMoved) 805 SetEntrySize( nDragNo, (sal_uInt16) nNewWidth ); 806 } 807 } 808 else 809 { 810 pSelEngine->SelMouseButtonUp( rMEvt ); 811 ReleaseMouse(); 812 } 813 } 814 815 void ScHeaderControl::MouseMove( const MouseEvent& rMEvt ) 816 { 817 if ( IsDisabled() ) 818 { 819 SetPointer( Pointer( POINTER_ARROW ) ); 820 return; 821 } 822 823 sal_Bool bFound; 824 (void)GetMousePos( rMEvt, bFound ); 825 826 if ( bDragging ) 827 { 828 long nNewPos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X(); 829 if ( nNewPos != nDragPos ) 830 { 831 DrawInvert( nDragPos ); 832 nDragPos = nNewPos; 833 ShowDragHelp(); 834 DrawInvert( nDragPos ); 835 836 if (nDragPos <= nDragStart-SC_DRAG_MIN || nDragPos >= nDragStart+SC_DRAG_MIN) 837 bDragMoved = sal_True; 838 } 839 } 840 else 841 { 842 if ( bFound && rMEvt.GetButtons()==0 && ResizeAllowed() ) 843 SetPointer( Pointer( bVertical ? POINTER_VSIZEBAR : POINTER_HSIZEBAR ) ); 844 else 845 SetPointer( Pointer( POINTER_ARROW ) ); 846 847 if (!bIgnoreMove) 848 pSelEngine->SelMouseMove( rMEvt ); 849 } 850 } 851 852 void ScHeaderControl::Tracking( const TrackingEvent& rTEvt ) 853 { 854 // Weil die SelectionEngine kein Tracking kennt, die Events nur auf 855 // die verschiedenen MouseHandler verteilen... 856 857 if ( rTEvt.IsTrackingCanceled() ) 858 StopMarking(); 859 else if ( rTEvt.IsTrackingEnded() ) 860 MouseButtonUp( rTEvt.GetMouseEvent() ); 861 else 862 MouseMove( rTEvt.GetMouseEvent() ); 863 } 864 865 void ScHeaderControl::Command( const CommandEvent& rCEvt ) 866 { 867 sal_uInt16 nCmd = rCEvt.GetCommand(); 868 if ( nCmd == COMMAND_CONTEXTMENU ) 869 { 870 StopMarking(); // Selektion / Dragging beenden 871 872 // Popup ausfuehren 873 874 ScTabViewShell* pViewSh = PTR_CAST( ScTabViewShell, 875 SfxViewShell::Current() ); 876 if ( pViewSh ) 877 { 878 if ( rCEvt.IsMouseEvent() ) 879 { 880 // #i18735# select the column/row under the mouse pointer 881 ScViewData* pViewData = pViewSh->GetViewData(); 882 883 SelectWindow(); // also deselects drawing objects, stops draw text edit 884 if ( pViewData->HasEditView( pViewData->GetActivePart() ) ) 885 SC_MOD()->InputEnterHandler(); // always end edit mode 886 887 MouseEvent aMEvt( rCEvt.GetMousePosPixel() ); 888 sal_Bool bBorder; 889 SCCOLROW nPos = GetMousePos( aMEvt, bBorder ); 890 if (!IsSelectionAllowed(nPos)) 891 // Selecting this cell is not allowed, neither is context menu. 892 return; 893 894 SCTAB nTab = pViewData->GetTabNo(); 895 ScRange aNewRange; 896 if ( bVertical ) 897 aNewRange = ScRange( 0, sal::static_int_cast<SCROW>(nPos), nTab, 898 MAXCOL, sal::static_int_cast<SCROW>(nPos), nTab ); 899 else 900 aNewRange = ScRange( sal::static_int_cast<SCCOL>(nPos), 0, nTab, 901 sal::static_int_cast<SCCOL>(nPos), MAXROW, nTab ); 902 903 // see if any part of the range is already selected 904 sal_Bool bSelected = sal_False; 905 ScRangeList aRanges; 906 pViewData->GetMarkData().FillRangeListWithMarks( &aRanges, sal_False ); 907 sal_uLong nRangeCount = aRanges.Count(); 908 for (sal_uLong i=0; i<nRangeCount && !bSelected; i++) 909 if ( aRanges.GetObject(i)->Intersects( aNewRange ) ) 910 bSelected = sal_True; 911 912 // select the range if no part of it was selected 913 if ( !bSelected ) 914 pViewSh->MarkRange( aNewRange ); 915 } 916 917 ScResId aResId( bVertical ? RID_POPUP_ROWHEADER : RID_POPUP_COLHEADER ); 918 pViewSh->GetDispatcher()->ExecutePopup( aResId ); 919 } 920 } 921 else if ( nCmd == COMMAND_STARTDRAG ) 922 { 923 pSelEngine->Command( rCEvt ); 924 } 925 } 926 927 void ScHeaderControl::StopMarking() 928 { 929 if ( bDragging ) 930 { 931 DrawInvert( nDragPos ); 932 bDragging = sal_False; 933 } 934 935 SetMarking( sal_False ); 936 bIgnoreMove = sal_True; 937 938 // #86260# don't call pSelEngine->Reset, so selection across the parts of 939 // a split/frozen view is possible 940 941 ReleaseMouse(); 942 } 943 944 void ScHeaderControl::ShowDragHelp() 945 { 946 if (Help::IsQuickHelpEnabled()) 947 { 948 long nScrPos = GetScrPos( nDragNo ); 949 sal_Bool bLayoutRTL = IsLayoutRTL(); 950 long nVal = bLayoutRTL ? ( nScrPos - nDragPos + 1 ) 951 : ( nDragPos + 2 - nScrPos ); 952 953 String aHelpStr = GetDragHelp( nVal ); 954 Point aPos = OutputToScreenPixel( Point(0,0) ); 955 Size aSize = GetSizePixel(); 956 957 Point aMousePos = OutputToScreenPixel(GetPointerPosPixel()); 958 959 Rectangle aRect; 960 sal_uInt16 nAlign; 961 if (!bVertical) 962 { 963 // oberhalb 964 aRect.Left() = aMousePos.X(); 965 aRect.Top() = aPos.Y() - 4; 966 nAlign = QUICKHELP_BOTTOM|QUICKHELP_CENTER; 967 } 968 else 969 { 970 // rechts oben 971 aRect.Left() = aPos.X() + aSize.Width() + 8; 972 aRect.Top() = aMousePos.Y() - 2; 973 nAlign = QUICKHELP_LEFT|QUICKHELP_BOTTOM; 974 } 975 976 aRect.Right() = aRect.Left(); 977 aRect.Bottom() = aRect.Top(); 978 979 Help::ShowQuickHelp(this, aRect, aHelpStr, nAlign); 980 } 981 } 982 983 void ScHeaderControl::RequestHelp( const HelpEvent& rHEvt ) 984 { 985 // Wenn eigene QuickHelp angezeigt wird, nicht durch RequestHelp 986 // wieder wegnehmen lassen 987 988 sal_Bool bOwn = bDragging && Help::IsQuickHelpEnabled(); 989 if (!bOwn) 990 Window::RequestHelp(rHEvt); 991 } 992 993 // ----------------------------------------------------------------------- 994 // Dummys fuer virtuelle Methoden 995 // ----------------------------------------------------------------------- 996 997 SCCOLROW ScHeaderControl::GetHiddenCount( SCCOLROW nEntryNo ) 998 { 999 SCCOLROW nHidden = 0; 1000 while ( nEntryNo < nSize && GetEntrySize( nEntryNo ) == 0 ) 1001 { 1002 ++nEntryNo; 1003 ++nHidden; 1004 } 1005 return nHidden; 1006 } 1007 1008 sal_Bool ScHeaderControl::IsLayoutRTL() 1009 { 1010 return sal_False; 1011 } 1012 1013 sal_Bool ScHeaderControl::IsMirrored() 1014 { 1015 return sal_False; 1016 } 1017 1018 sal_Bool ScHeaderControl::IsDisabled() 1019 { 1020 return sal_False; 1021 } 1022 1023 sal_Bool ScHeaderControl::ResizeAllowed() 1024 { 1025 return sal_True; 1026 } 1027 1028 void ScHeaderControl::SelectWindow() 1029 { 1030 } 1031 1032 void ScHeaderControl::DrawInvert( long /* nDragPos */ ) 1033 { 1034 } 1035 1036 String ScHeaderControl::GetDragHelp( long /* nVal */ ) 1037 { 1038 return EMPTY_STRING; 1039 } 1040 1041 void ScHeaderControl::SetMarking( sal_Bool /* bSet */ ) 1042 { 1043 } 1044 1045 1046 1047