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
ScHeaderControl(Window * pParent,SelectionEngine * pSelectionEngine,SCCOLROW nNewSize,sal_uInt16 nNewFlags)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
SetWidth(long nNew)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
~ScHeaderControl()120 ScHeaderControl::~ScHeaderControl()
121 {
122 }
123
DoPaint(SCCOLROW nStart,SCCOLROW nEnd)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
SetMark(sal_Bool bNewSet,SCCOLROW nNewStart,SCCOLROW nNewEnd)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
GetScrPos(SCCOLROW nEntryNo)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
DrawShadedRect(long nStart,long nEnd,const Color & rBaseColor)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
Paint(const Rectangle & rRect)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
GetMousePos(const MouseEvent & rMEvt,sal_Bool & rBorder)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
IsSelectionAllowed(SCCOLROW nPos) const652 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
MouseButtonDown(const MouseEvent & rMEvt)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
MouseButtonUp(const MouseEvent & rMEvt)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
MouseMove(const MouseEvent & rMEvt)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
Tracking(const TrackingEvent & rTEvt)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
Command(const CommandEvent & rCEvt)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
StopMarking()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
ShowDragHelp()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
RequestHelp(const HelpEvent & rHEvt)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
GetHiddenCount(SCCOLROW nEntryNo)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
IsLayoutRTL()1004 sal_Bool ScHeaderControl::IsLayoutRTL()
1005 {
1006 return sal_False;
1007 }
1008
IsMirrored()1009 sal_Bool ScHeaderControl::IsMirrored()
1010 {
1011 return sal_False;
1012 }
1013
IsDisabled()1014 sal_Bool ScHeaderControl::IsDisabled()
1015 {
1016 return sal_False;
1017 }
1018
ResizeAllowed()1019 sal_Bool ScHeaderControl::ResizeAllowed()
1020 {
1021 return sal_True;
1022 }
1023
SelectWindow()1024 void ScHeaderControl::SelectWindow()
1025 {
1026 }
1027
DrawInvert(long)1028 void ScHeaderControl::DrawInvert( long /* nDragPos */ )
1029 {
1030 }
1031
GetDragHelp(long)1032 String ScHeaderControl::GetDragHelp( long /* nVal */ )
1033 {
1034 return EMPTY_STRING;
1035 }
1036
SetMarking(sal_Bool)1037 void ScHeaderControl::SetMarking( sal_Bool /* bSet */ )
1038 {
1039 }
1040
1041
1042
1043