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