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