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