xref: /AOO41X/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