xref: /trunk/main/sc/source/ui/view/hdrcont.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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