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