Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/sc/source/ui/view/hdrcont.cxx
Line
Count
Source (jump to first uncovered line)
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/commandevent.hxx>
22
#include <vcl/help.hxx>
23
#include <vcl/settings.hxx>
24
#include <svtools/colorcfg.hxx>
25
#include <osl/diagnose.h>
26
27
#include <tabvwsh.hxx>
28
#include <hdrcont.hxx>
29
#include <dbdata.hxx>
30
#include <scmod.hxx>
31
#include <inputopt.hxx>
32
#include <gridmerg.hxx>
33
#include <document.hxx>
34
#include <markdata.hxx>
35
#include <tabview.hxx>
36
#include <viewdata.hxx>
37
#include <columnspanset.hxx>
38
#include <officecfg/Office/Common.hxx>
39
40
0
#define SC_DRAG_MIN     2
41
42
//  passes in paint
43
//  (selection left/right must be first because the continuous lines
44
//  are partly overwritten later)
45
46
0
#define SC_HDRPAINT_SEL_BOTTOM  4
47
0
#define SC_HDRPAINT_BOTTOM      5
48
0
#define SC_HDRPAINT_TEXT        6
49
0
#define SC_HDRPAINT_COUNT       7
50
51
ScHeaderControl::ScHeaderControl( vcl::Window* pParent, SelectionEngine* pSelectionEngine,
52
                                  SCCOLROW nNewSize, bool bNewVertical, ScTabView* pTab ) :
53
0
            Window      ( pParent ),
54
0
            pSelEngine  ( pSelectionEngine ),
55
0
            aShowHelpTimer("sc HeaderControl Popover Timer"),
56
0
            bVertical   ( bNewVertical ),
57
0
            nSize       ( nNewSize ),
58
0
            nMarkStart  ( 0 ),
59
0
            nMarkEnd    ( 0 ),
60
0
            bMarkRange  ( false ),
61
0
            bDragging   ( false ),
62
0
            nDragNo     ( 0 ),
63
0
            nDragStart  ( 0 ),
64
0
            nDragPos    ( 0 ),
65
0
            nTipVisible ( nullptr ),
66
0
            bDragMoved  ( false ),
67
0
            bIgnoreMove ( false ),
68
0
            bInRefMode  ( false ),
69
0
            pTabView    ( pTab )
70
0
{
71
    // RTL: no default mirroring for this window, the spreadsheet itself
72
    // is also not mirrored
73
    // mirror the vertical window for correct border drawing
74
    // table layout depends on sheet format, not UI setting, so the
75
    // borders of the vertical window have to be handled manually, too.
76
0
    EnableRTL( false );
77
78
0
    aNormFont = GetFont();
79
0
    aNormFont.SetTransparent( true );       //! hard-set WEIGHT_NORMAL ???
80
0
    aBoldFont = aNormFont;
81
0
    aBoldFont.SetWeight( WEIGHT_BOLD );
82
0
    aAutoFilterFont = aNormFont;
83
84
0
    SetFont(aBoldFont);
85
0
    bBoldSet = true;
86
0
    bAutoFilterSet = false;
87
88
0
    Size aSize = LogicToPixel( Size(
89
0
        GetTextWidth(u"8888"_ustr),
90
0
        GetTextHeight() ) );
91
0
    aSize.AdjustWidth(4 );    // place for highlight border
92
0
    aSize.AdjustHeight(3 );
93
0
    SetSizePixel( aSize );
94
95
0
    nWidth = nSmallWidth = aSize.Width();
96
0
    nBigWidth = LogicToPixel( Size( GetTextWidth(u"8888888"_ustr), 0 ) ).Width() + 5;
97
98
0
    aShowHelpTimer.SetInvokeHandler(LINK(this, ScHeaderControl, ShowDragHelpHdl));
99
0
    aShowHelpTimer.SetTimeout(GetSettings().GetMouseSettings().GetDoubleClickTime());
100
101
0
    SetBackground();
102
0
}
103
104
void ScHeaderControl::dispose()
105
0
{
106
0
    aShowHelpTimer.Stop();
107
0
    vcl::Window::dispose();
108
0
}
109
110
void ScHeaderControl::SetWidth( tools::Long nNew )
111
0
{
112
0
    OSL_ENSURE( bVertical, "SetWidth works only on row headers" );
113
0
    if ( nNew != nWidth )
114
0
    {
115
0
        Size aSize( nNew, GetSizePixel().Height() );
116
0
        SetSizePixel( aSize );
117
118
0
        nWidth = nNew;
119
120
0
        Invalidate();
121
0
    }
122
0
}
123
124
ScHeaderControl::~ScHeaderControl()
125
0
{
126
0
}
127
128
void ScHeaderControl::DoPaint( SCCOLROW nStart, SCCOLROW nEnd )
129
0
{
130
0
    bool bLayoutRTL = IsLayoutRTL();
131
0
    tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
132
133
0
    tools::Rectangle aRect( Point(0,0), GetOutputSizePixel() );
134
0
    if ( bVertical )
135
0
    {
136
0
        aRect.SetTop( GetScrPos( nStart )-nLayoutSign );      // extra pixel for line at top of selection
137
0
        aRect.SetBottom( GetScrPos( nEnd+1 )-nLayoutSign );
138
0
    }
139
0
    else
140
0
    {
141
0
        aRect.SetLeft( GetScrPos( nStart )-nLayoutSign );     // extra pixel for line left of selection
142
0
        aRect.SetRight( GetScrPos( nEnd+1 )-nLayoutSign );
143
0
    }
144
0
    Invalidate(aRect);
145
0
}
146
147
void ScHeaderControl::SetMark( bool bNewSet, SCCOLROW nNewStart, SCCOLROW nNewEnd )
148
0
{
149
0
    bool bEnabled = ScModule::get()->GetInputOptions().GetMarkHeader(); //! cache?
150
0
    if (!bEnabled)
151
0
        bNewSet = false;
152
153
0
    bool bOldSet       = bMarkRange;
154
0
    SCCOLROW nOldStart = nMarkStart;
155
0
    SCCOLROW nOldEnd   = nMarkEnd;
156
0
    PutInOrder( nNewStart, nNewEnd );
157
0
    bMarkRange = bNewSet;
158
0
    nMarkStart = nNewStart;
159
0
    nMarkEnd   = nNewEnd;
160
161
    //  Paint
162
163
0
    if ( bNewSet )
164
0
    {
165
0
        if ( bOldSet )
166
0
        {
167
0
            if ( nNewStart == nOldStart )
168
0
            {
169
0
                if ( nNewEnd != nOldEnd )
170
0
                    DoPaint( std::min( nNewEnd, nOldEnd ) + 1, std::max( nNewEnd, nOldEnd ) );
171
0
            }
172
0
            else if ( nNewEnd == nOldEnd )
173
0
                DoPaint( std::min( nNewStart, nOldStart ), std::max( nNewStart, nOldStart ) - 1 );
174
0
            else if ( nNewStart > nOldEnd || nNewEnd < nOldStart )
175
0
            {
176
                //  two areas
177
0
                DoPaint( nOldStart, nOldEnd );
178
0
                DoPaint( nNewStart, nNewEnd );
179
0
            }
180
0
            else //  somehow overlapping... (it is not often)
181
0
                DoPaint( std::min( nNewStart, nOldStart ), std::max( nNewEnd, nOldEnd ) );
182
0
        }
183
0
        else
184
0
            DoPaint( nNewStart, nNewEnd );      //  completely new selection
185
0
    }
186
0
    else if ( bOldSet )
187
0
        DoPaint( nOldStart, nOldEnd );          //  cancel selection
188
0
}
189
190
tools::Long ScHeaderControl::GetScrPos( SCCOLROW nEntryNo ) const
191
0
{
192
0
    tools::Long nScrPos;
193
194
0
    tools::Long nMax = ( bVertical ? GetOutputSizePixel().Height() : GetOutputSizePixel().Width() ) + 1;
195
0
    if (nEntryNo >= nSize)
196
0
        nScrPos = nMax;
197
0
    else
198
0
    {
199
0
        nScrPos = 0;
200
0
        for (SCCOLROW i=GetPos(); i<nEntryNo && nScrPos<nMax; i++)
201
0
        {
202
0
            sal_uInt16 nAdd = GetEntrySize(i);
203
0
            if (nAdd)
204
0
                nScrPos += nAdd;
205
0
            else
206
0
            {
207
0
                SCCOLROW nHidden = GetHiddenCount(i);
208
0
                if (nHidden > 0)
209
0
                    i += nHidden - 1;
210
0
            }
211
0
        }
212
0
    }
213
214
0
    if ( IsLayoutRTL() )
215
0
        nScrPos = nMax - nScrPos - 2;
216
217
0
    return nScrPos;
218
0
}
219
220
void ScHeaderControl::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect )
221
0
{
222
    // It is important for VCL to have few calls, that is why the outer lines are
223
    // grouped together
224
225
0
    const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
226
0
    bool bHighContrast = rStyleSettings.GetHighContrastMode();
227
0
    bool bDark = rStyleSettings.GetFaceColor().IsDark();
228
    // Use the same distinction for bDark as in Window::DrawSelectionBackground
229
230
0
    Color aTextColor = rStyleSettings.GetButtonTextColor();
231
0
    Color aSelTextColor = rStyleSettings.GetHighlightTextColor();
232
0
    Color aAFilterTextColor = rStyleSettings.GetButtonTextColor();
233
0
    aAFilterTextColor.Merge(COL_LIGHTBLUE, bDark ? 150 : 10); // color of filtered row numbers
234
0
    aNormFont.SetColor( aTextColor );
235
0
    aAutoFilterFont.SetColor(aAFilterTextColor);
236
0
    if ( bHighContrast )
237
0
        aBoldFont.SetColor( aTextColor );
238
0
    else
239
0
        aBoldFont.SetColor( aSelTextColor );
240
241
0
    if (bAutoFilterSet)
242
0
        SetTextColor(aAFilterTextColor);
243
0
    else
244
0
        SetTextColor((bBoldSet && !bHighContrast) ? aSelTextColor : aTextColor);
245
246
0
    ScModule* mod = ScModule::get();
247
0
    Color aSelLineColor = mod->GetColorConfig().GetColorValue(svtools::CALCCELLFOCUS).nColor;
248
0
    aSelLineColor.Merge( COL_BLACK, 0xe0 );        // darken just a little bit
249
250
0
    bool bLayoutRTL = IsLayoutRTL();
251
0
    tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
252
0
    bool bMirrored = IsMirrored();
253
254
0
    OUString            aString;
255
0
    sal_uInt16          nBarSize;
256
0
    Point               aScrPos;
257
0
    Size                aTextSize;
258
259
0
    if (bVertical)
260
0
        nBarSize = static_cast<sal_uInt16>(GetSizePixel().Width());
261
0
    else
262
0
        nBarSize = static_cast<sal_uInt16>(GetSizePixel().Height());
263
264
0
    SCCOLROW    nPos = GetPos();
265
266
0
    tools::Long nPStart = bVertical ? rRect.Top() : rRect.Left();
267
0
    tools::Long nPEnd = bVertical ? rRect.Bottom() : rRect.Right();
268
269
0
    tools::Long nTransStart = nPEnd + 1;
270
0
    tools::Long nTransEnd = 0;
271
272
0
    tools::Long nInitScrPos = 0;
273
0
    if ( bLayoutRTL )
274
0
    {
275
0
        std::swap(nPStart, nPEnd);
276
0
        std::swap(nTransStart, nTransEnd);
277
0
        if ( bVertical )            // start loops from the end
278
0
            nInitScrPos = GetSizePixel().Height() - 1;
279
0
        else
280
0
            nInitScrPos = GetSizePixel().Width() - 1;
281
0
    }
282
283
    // complete the painting of the outer lines
284
    // first find the end of the last cell
285
286
0
    tools::Long nLineEnd = nInitScrPos - nLayoutSign;
287
288
0
    for (SCCOLROW i=nPos; i<nSize; i++)
289
0
    {
290
0
        sal_uInt16 nSizePix = GetEntrySize( i );
291
0
        if (nSizePix)
292
0
        {
293
0
            nLineEnd += nSizePix * nLayoutSign;
294
295
0
            if ( bMarkRange && i >= nMarkStart && i <= nMarkEnd )
296
0
            {
297
0
                tools::Long nLineStart = nLineEnd - ( nSizePix - 1 ) * nLayoutSign;
298
0
                if ( nLineStart * nLayoutSign < nTransStart * nLayoutSign )
299
0
                    nTransStart = nLineStart;
300
0
                if ( nLineEnd * nLayoutSign > nTransEnd * nLayoutSign )
301
0
                    nTransEnd = nLineEnd;
302
0
            }
303
304
0
            if ( nLineEnd * nLayoutSign > nPEnd * nLayoutSign )
305
0
            {
306
0
                nLineEnd = nPEnd;
307
0
                break;
308
0
            }
309
0
        }
310
0
        else
311
0
        {
312
0
            SCCOLROW nHidden = GetHiddenCount(i);
313
0
            if (nHidden > 0)
314
0
                i += nHidden - 1;
315
0
        }
316
0
    }
317
318
    //  background is different for entry area and behind the entries
319
320
0
    tools::Rectangle aFillRect;
321
0
    GetOutDev()->SetLineColor();
322
323
0
    if ( nLineEnd * nLayoutSign >= nInitScrPos * nLayoutSign )
324
0
    {
325
0
        Color aFaceColor(rStyleSettings.GetFaceColor());
326
0
        if (bDark)
327
0
            aFaceColor.IncreaseLuminance(20);
328
0
        else
329
0
            aFaceColor.DecreaseLuminance(20);
330
0
        GetOutDev()->SetFillColor( aFaceColor );
331
0
        if ( bVertical )
332
0
            aFillRect = tools::Rectangle( 0, nInitScrPos, nBarSize-1, nLineEnd );
333
0
        else
334
0
            aFillRect = tools::Rectangle( nInitScrPos, 0, nLineEnd, nBarSize-1 );
335
0
        GetOutDev()->DrawRect( aFillRect );
336
0
    }
337
338
0
    if ( nLineEnd * nLayoutSign < nPEnd * nLayoutSign )
339
0
    {
340
0
        GetOutDev()->SetFillColor( mod->GetColorConfig().GetColorValue(svtools::APPBACKGROUND).nColor );
341
0
        if ( bVertical )
342
0
            aFillRect = tools::Rectangle( 0, nLineEnd+nLayoutSign, nBarSize-1, nPEnd );
343
0
        else
344
0
            aFillRect = tools::Rectangle( nLineEnd+nLayoutSign, 0, nPEnd, nBarSize-1 );
345
0
        GetOutDev()->DrawRect( aFillRect );
346
0
    }
347
348
0
    if ( nLineEnd * nLayoutSign >= nPStart * nLayoutSign )
349
0
    {
350
0
        if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign )
351
0
        {
352
0
            if (bVertical)
353
0
                aFillRect = tools::Rectangle( 0, nTransStart, nBarSize-1, nTransEnd );
354
0
            else
355
0
                aFillRect = tools::Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 );
356
357
0
            if ( bHighContrast )
358
0
            {
359
0
                if ( bDark )
360
0
                {
361
                    //  solid grey background for dark face color is drawn before lines
362
0
                    GetOutDev()->SetLineColor();
363
0
                    GetOutDev()->SetFillColor( COL_LIGHTGRAY );
364
0
                    GetOutDev()->DrawRect( aFillRect );
365
0
                }
366
0
            }
367
0
            else
368
0
            {
369
                // background for selection
370
0
                GetOutDev()->SetLineColor();
371
0
                Color aColor = mod->GetColorConfig().GetColorValue(svtools::CALCCELLFOCUS).nColor;
372
// merging the highlightcolor (which is used if accent does not exist) with the background
373
// fails in many cases such as Breeze Dark (highlight is too close to background) and
374
// Breeze Light (font color is white and not readable anymore)
375
#ifdef MACOSX
376
                aColor.Merge( rStyleSettings.GetFaceColor(), 80 );
377
#endif
378
0
                GetOutDev()->SetFillColor( aColor );
379
0
                GetOutDev()->DrawRect( aFillRect );
380
0
            }
381
0
        }
382
383
0
        GetOutDev()->SetLineColor( rStyleSettings.GetShadowColor() );
384
0
        if (bVertical)
385
0
        {
386
0
            GetOutDev()->DrawLine( Point( 0, nPStart ), Point( 0, nLineEnd ) ); //left
387
0
            GetOutDev()->DrawLine( Point( nBarSize-1, nPStart ), Point( nBarSize-1, nLineEnd ) ); //right
388
0
        }
389
0
        else
390
0
        {
391
0
            GetOutDev()->DrawLine( Point( nPStart, nBarSize-1 ), Point( nLineEnd, nBarSize-1 ) ); //bottom
392
0
            GetOutDev()->DrawLine( Point( nPStart, 0 ), Point( nLineEnd, 0 ) ); //top
393
0
        }
394
0
    }
395
396
    // tdf#89841 Use blue row numbers when Autofilter selected
397
0
    std::vector<sc::ColRowSpan> aSpans;
398
0
    if (bVertical && pTabView)
399
0
    {
400
0
        SCTAB nTab = pTabView->GetViewData().GetTabNo();
401
0
        ScDocument& rDoc = pTabView->GetViewData().GetDocument();
402
403
0
        ScDBData* pDBData = rDoc.GetAnonymousDBData(nTab);
404
0
        if (pDBData && pDBData->HasAutoFilter())
405
0
        {
406
0
            SCSIZE nSelected = 0;
407
0
            SCSIZE nTotal = 0;
408
0
            pDBData->GetFilterSelCount(nSelected, nTotal);
409
0
            if (nTotal > nSelected)
410
0
            {
411
0
                ScRange aRange;
412
0
                pDBData->GetArea(aRange);
413
0
                SCCOLROW nStartRow = static_cast<SCCOLROW>(aRange.aStart.Row());
414
0
                SCCOLROW nEndRow = static_cast<SCCOLROW>(aRange.aEnd.Row());
415
0
                if (pDBData->HasHeader())
416
0
                    nStartRow++;
417
0
                aSpans.push_back(sc::ColRowSpan(nStartRow, nEndRow));
418
0
            }
419
0
        }
420
421
0
        ScDBCollection* pDocColl = rDoc.GetDBCollection();
422
0
        if (!pDocColl->empty())
423
0
        {
424
0
            ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
425
0
            for (const auto& rxDB : rDBs)
426
0
            {
427
0
                if (rxDB->GetTab() == nTab && rxDB->HasAutoFilter())
428
0
                {
429
0
                    SCSIZE nSelected = 0;
430
0
                    SCSIZE nTotal = 0;
431
0
                    rxDB->GetFilterSelCount(nSelected, nTotal);
432
0
                    if (nTotal > nSelected)
433
0
                    {
434
0
                        ScRange aRange;
435
0
                        rxDB->GetArea(aRange);
436
0
                        SCCOLROW nStartRow = static_cast<SCCOLROW>(aRange.aStart.Row());
437
0
                        SCCOLROW nEndRow = static_cast<SCCOLROW>(aRange.aEnd.Row());
438
0
                        if (rxDB->HasHeader())
439
0
                            nStartRow++;
440
0
                        aSpans.push_back(sc::ColRowSpan(nStartRow, nEndRow));
441
0
                    }
442
0
                }
443
0
            }
444
0
        }
445
0
    }
446
447
    //  loop through entries several times to avoid changing the line color too often
448
    //  and to allow merging of lines
449
450
0
    ScGridMerger aGrid( GetOutDev(), 1, 1 );
451
452
    //  start at SC_HDRPAINT_BOTTOM instead of 0 - selection doesn't get different
453
    //  borders, light border at top isn't used anymore
454
    //  use SC_HDRPAINT_SEL_BOTTOM for different color
455
456
0
    for (sal_uInt16 nPass = SC_HDRPAINT_SEL_BOTTOM; nPass < SC_HDRPAINT_COUNT; nPass++)
457
0
    {
458
        //  set line color etc. before entry loop
459
0
        switch ( nPass )
460
0
        {
461
0
            case SC_HDRPAINT_SEL_BOTTOM:
462
                // same as non-selected for high contrast
463
0
                GetOutDev()->SetLineColor( bHighContrast ? rStyleSettings.GetShadowColor() : aSelLineColor );
464
0
                break;
465
0
            case SC_HDRPAINT_BOTTOM:
466
0
                GetOutDev()->SetLineColor( rStyleSettings.GetShadowColor() );
467
0
                break;
468
0
            case SC_HDRPAINT_TEXT:
469
                // DrawSelectionBackground is used only for high contrast on light background
470
0
                if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && bHighContrast && !bDark )
471
0
                {
472
                    //  Transparent selection background is drawn after lines, before text.
473
                    //  Use DrawSelectionBackground to make sure there is a visible
474
                    //  difference. The case of a dark face color, where DrawSelectionBackground
475
                    //  would just paint over the lines, is handled separately (bDark).
476
                    //  Otherwise, GetHighlightColor is used with 80% transparency.
477
                    //  The window's background color (SetBackground) has to be the background
478
                    //  of the cell area, for the contrast comparison in DrawSelectionBackground.
479
480
0
                    tools::Rectangle aTransRect;
481
0
                    if (bVertical)
482
0
                        aTransRect = tools::Rectangle( 0, nTransStart, nBarSize-1, nTransEnd );
483
0
                    else
484
0
                        aTransRect = tools::Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 );
485
0
                    SetBackground( rStyleSettings.GetFaceColor() );
486
0
                    DrawSelectionBackground( aTransRect, 0, true, false );
487
0
                    SetBackground();
488
0
                }
489
0
                break;
490
0
        }
491
492
0
        SCCOLROW    nCount=0;
493
0
        tools::Long    nScrPos=nInitScrPos;
494
0
        do
495
0
        {
496
0
            if (bVertical)
497
0
                aScrPos = Point( 0, nScrPos );
498
0
            else
499
0
                aScrPos = Point( nScrPos, 0 );
500
501
0
            SCCOLROW    nEntryNo = nCount + nPos;
502
0
            if ( nEntryNo >= nSize )                // rDoc.MaxCol()/rDoc.MaxRow()
503
0
                nScrPos = nPEnd + nLayoutSign;      //  beyond nPEnd -> stop
504
0
            else
505
0
            {
506
0
                sal_uInt16 nSizePix = GetEntrySize( nEntryNo );
507
508
0
                if (nSizePix == 0)
509
0
                {
510
0
                    SCCOLROW nHidden = GetHiddenCount(nEntryNo);
511
0
                    if (nHidden > 0)
512
0
                        nCount += nHidden - 1;
513
0
                }
514
0
                else if ((nScrPos+nSizePix*nLayoutSign)*nLayoutSign >= nPStart*nLayoutSign)
515
0
                {
516
0
                    Point aEndPos(aScrPos);
517
0
                    if (bVertical)
518
0
                        aEndPos = Point( aScrPos.X()+nBarSize-1, aScrPos.Y()+(nSizePix-1)*nLayoutSign );
519
0
                    else
520
0
                        aEndPos = Point( aScrPos.X()+(nSizePix-1)*nLayoutSign, aScrPos.Y()+nBarSize-1 );
521
522
0
                    bool bMark = bMarkRange && nEntryNo >= nMarkStart && nEntryNo <= nMarkEnd;
523
0
                    bool bNextToMark = bMarkRange && nEntryNo + 1 >= nMarkStart && nEntryNo <= nMarkEnd;
524
525
0
                    switch ( nPass )
526
0
                    {
527
0
                        case SC_HDRPAINT_SEL_BOTTOM:
528
0
                        case SC_HDRPAINT_BOTTOM:
529
0
                            if ( nPass == ( bNextToMark ? SC_HDRPAINT_SEL_BOTTOM : SC_HDRPAINT_BOTTOM ) )
530
0
                            {
531
0
                                if (bVertical)
532
0
                                    aGrid.AddHorLine(/* here we work in pixels */ true, aScrPos.X(), aEndPos.X(), aEndPos.Y());
533
0
                                else
534
0
                                    aGrid.AddVerLine(/* here we work in pixels */ true, aEndPos.X(), aScrPos.Y(), aEndPos.Y());
535
536
                                //  thick bottom for hidden rows
537
                                //  (drawn directly, without aGrid)
538
0
                                if ( nEntryNo+1 < nSize )
539
0
                                    if ( GetEntrySize(nEntryNo+1)==0 )
540
0
                                    {
541
0
                                        if (bVertical)
542
0
                                            GetOutDev()->DrawLine( Point(aScrPos.X(),aEndPos.Y()-nLayoutSign),
543
0
                                                      Point(aEndPos.X(),aEndPos.Y()-nLayoutSign) );
544
0
                                        else
545
0
                                            GetOutDev()->DrawLine( Point(aEndPos.X()-nLayoutSign,aScrPos.Y()),
546
0
                                                      Point(aEndPos.X()-nLayoutSign,aEndPos.Y()) );
547
0
                                    }
548
0
                            }
549
0
                            break;
550
551
0
                        case SC_HDRPAINT_TEXT:
552
0
                            if ( nSizePix > 1 )     // minimal check for small columns/rows
553
0
                            {
554
0
                                if (bVertical)
555
0
                                {
556
0
                                    bool bAutoFilterPos = false;
557
0
                                    for (const auto& rSpan : aSpans)
558
0
                                    {
559
0
                                        if (nEntryNo >= rSpan.mnStart && nEntryNo <= rSpan.mnEnd)
560
0
                                        {
561
0
                                            bAutoFilterPos = true;
562
0
                                            break;
563
0
                                        }
564
0
                                    }
565
566
0
                                    if (bMark != bBoldSet || bAutoFilterPos != bAutoFilterSet)
567
0
                                    {
568
0
                                        if (bMark)
569
0
                                            SetFont(aBoldFont);
570
0
                                        else if (bAutoFilterPos)
571
0
                                            SetFont(aAutoFilterFont);
572
0
                                        else
573
0
                                            SetFont(aNormFont);
574
0
                                        bBoldSet = bMark;
575
0
                                        bAutoFilterSet = bAutoFilterPos && !bMark;
576
0
                                    }
577
0
                                }
578
0
                                else
579
0
                                {
580
0
                                    if (bMark != bBoldSet)
581
0
                                    {
582
0
                                        if (bMark)
583
0
                                            SetFont(aBoldFont);
584
0
                                        else
585
0
                                            SetFont(aNormFont);
586
0
                                        bBoldSet = bMark;
587
0
                                    }
588
0
                                }
589
590
0
                                aString = GetEntryText( nEntryNo );
591
0
                                aTextSize.setWidth( GetTextWidth( aString ) );
592
0
                                aTextSize.setHeight( GetTextHeight() );
593
594
0
                                Point aTxtPos(aScrPos);
595
0
                                if (bVertical)
596
0
                                {
597
0
                                    aTxtPos.AdjustX((nBarSize-aTextSize.Width())/2 );
598
0
                                    aTxtPos.AdjustY((nSizePix*nLayoutSign-aTextSize.Height())/2 );
599
0
                                    if ( bMirrored )
600
0
                                        aTxtPos.AdjustX(1 );   // dark border is left instead of right
601
0
                                }
602
0
                                else
603
0
                                {
604
0
                                    aTxtPos.AdjustX((nSizePix*nLayoutSign-aTextSize.Width()+1)/2 );
605
0
                                    aTxtPos.AdjustY((nBarSize-aTextSize.Height())/2 );
606
0
                                }
607
0
                                GetOutDev()->DrawText( aTxtPos, aString );
608
0
                            }
609
0
                            break;
610
0
                    }
611
612
                    // when selecting the complete row/column:
613
                    //  InvertRect( Rectangle( aScrPos, aEndPos ) );
614
0
                }
615
0
                nScrPos += nSizePix * nLayoutSign;      // also if before the visible area
616
0
            }
617
0
            ++nCount;
618
0
        }
619
0
        while ( nScrPos * nLayoutSign <= nPEnd * nLayoutSign );
620
621
0
        aGrid.Flush();
622
0
    }
623
0
}
624
625
SCCOLROW ScHeaderControl::GetMousePos(const Point& rPos, bool& rBorder) const
626
0
{
627
0
    bool        bFound = false;
628
0
    SCCOLROW    nPos = GetPos();
629
0
    SCCOLROW    nHitNo = nPos;
630
0
    SCCOLROW    nEntryNo = 1 + nPos;
631
0
    tools::Long    nScrPos;
632
0
    tools::Long    nMousePos = bVertical ? rPos.Y() : rPos.X();
633
0
    tools::Long    nDif;
634
0
    Size    aSize = GetOutputSizePixel();
635
0
    tools::Long    nWinSize = bVertical ? aSize.Height() : aSize.Width();
636
637
0
    bool bLayoutRTL = IsLayoutRTL();
638
0
    tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
639
0
    tools::Long nEndPos = bLayoutRTL ? -1 : nWinSize;
640
641
0
    nScrPos = GetScrPos( nPos ) - nLayoutSign;
642
0
    do
643
0
    {
644
0
        if (nEntryNo > nSize)
645
0
            nScrPos = nEndPos + nLayoutSign;
646
0
        else
647
0
            nScrPos += GetEntrySize( nEntryNo - 1 ) * nLayoutSign;      //! GetHiddenCount() ??
648
649
0
        nDif = nMousePos - nScrPos;
650
0
        if (nDif >= -5 && nDif <= 5)
651
0
        {
652
0
            bFound = true;
653
0
            nHitNo=nEntryNo-1;
654
0
        }
655
0
        else if (nDif * nLayoutSign >= 0 && nEntryNo < nSize)
656
0
            nHitNo = nEntryNo;
657
0
        ++nEntryNo;
658
0
    }
659
0
    while ( nScrPos * nLayoutSign < nEndPos * nLayoutSign && nDif * nLayoutSign > 0 );
660
661
0
    rBorder = bFound;
662
0
    return nHitNo;
663
0
}
664
665
bool ScHeaderControl::IsSelectionAllowed(SCCOLROW nPos) const
666
0
{
667
0
    ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
668
0
    if (!pViewSh)
669
0
        return false;
670
671
0
    ScViewData& rViewData = pViewSh->GetViewData();
672
0
    sal_uInt16 nTab = rViewData.GetTabNo();
673
0
    ScDocument& rDoc = rViewData.GetDocument();
674
0
    const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
675
0
    bool bSelectAllowed = true;
676
0
    if ( pProtect && pProtect->isProtected() )
677
0
    {
678
        // This sheet is protected.  Check if a context menu is allowed on this cell.
679
0
        bool bCellsProtected = false;
680
0
        if (bVertical)
681
0
        {
682
            // row header
683
0
            SCROW nRPos = static_cast<SCROW>(nPos);
684
0
            bCellsProtected = rDoc.HasAttrib(0, nRPos, nTab, rDoc.MaxCol(), nRPos, nTab, HasAttrFlags::Protected);
685
0
        }
686
0
        else
687
0
        {
688
            // column header
689
0
            SCCOL nCPos = static_cast<SCCOL>(nPos);
690
0
            bCellsProtected = rDoc.HasAttrib(nCPos, 0, nTab, nCPos, rDoc.MaxRow(), nTab, HasAttrFlags::Protected);
691
0
        }
692
693
0
        bool bSelProtected   = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
694
0
        bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
695
696
0
        if (bCellsProtected)
697
0
            bSelectAllowed = bSelProtected;
698
0
        else
699
0
            bSelectAllowed = bSelUnprotected;
700
0
    }
701
0
    return bSelectAllowed;
702
0
}
703
704
void ScHeaderControl::MouseButtonDown( const MouseEvent& rMEvt )
705
0
{
706
0
    if (IsDisabled())
707
0
        return;
708
709
0
    bIgnoreMove = false;
710
0
    SelectWindow();
711
712
0
    bool bIsBorder;
713
0
    SCCOLROW nHitNo = GetMousePos(rMEvt.GetPosPixel(), bIsBorder);
714
0
    if (!IsSelectionAllowed(nHitNo))
715
0
        return;
716
0
    if ( ! rMEvt.IsLeft() )
717
0
        return;
718
0
    if (ScModule::get()->IsFormulaMode())
719
0
    {
720
0
        if( !pTabView )
721
0
            return;
722
0
        SCTAB nTab = pTabView->GetViewData().GetTabNo();
723
0
        if( !rMEvt.IsShift() )
724
0
            pTabView->DoneRefMode( rMEvt.IsMod1() );
725
0
        ScDocument& rDoc = pTabView->GetViewData().GetDocument();
726
0
        if( !bVertical )
727
0
        {
728
0
            pTabView->InitRefMode( nHitNo, 0, nTab, SC_REFTYPE_REF );
729
0
            pTabView->UpdateRef( nHitNo, rDoc.MaxRow(), nTab );
730
0
        }
731
0
        else
732
0
        {
733
0
            pTabView->InitRefMode( 0, nHitNo, nTab, SC_REFTYPE_REF );
734
0
            pTabView->UpdateRef( rDoc.MaxCol(), nHitNo, nTab );
735
0
        }
736
0
        bInRefMode = true;
737
0
        return;
738
0
    }
739
0
    if ( bIsBorder && ResizeAllowed() )
740
0
    {
741
0
        nDragNo = nHitNo;
742
0
        sal_uInt16 nClicks = rMEvt.GetClicks();
743
0
        if ( nClicks && nClicks%2==0 )
744
0
        {
745
0
            SetEntrySize( nDragNo, HDR_SIZE_OPTIMUM );
746
0
            SetPointer( PointerStyle::Arrow );
747
0
        }
748
0
        else
749
0
        {
750
0
            if (bVertical)
751
0
                nDragStart = rMEvt.GetPosPixel().Y();
752
0
            else
753
0
                nDragStart = rMEvt.GetPosPixel().X();
754
0
            nDragPos = nDragStart;
755
            // tdf#140833 launch help tip to show after the double click time has expired
756
            // so under gtk the popover isn't active when the double click is processed
757
            // by gtk because under load on wayland the double click is getting handled
758
            // by something else and getting sent to the window underneath our window
759
0
            aShowHelpTimer.Start();
760
0
            DrawInvert( nDragPos );
761
762
0
            StartTracking();
763
0
            bDragging = true;
764
0
            bDragMoved = false;
765
0
        }
766
0
    }
767
0
    else
768
0
    {
769
0
        pSelEngine->SetWindow( this );
770
0
        tools::Rectangle aVis( Point(), GetOutputSizePixel() );
771
0
        if (bVertical)
772
0
        {
773
0
            aVis.SetLeft( LONG_MIN );
774
0
            aVis.SetRight( LONG_MAX );
775
0
        }
776
0
        else
777
0
        {
778
0
            aVis.SetTop( LONG_MIN );
779
0
            aVis.SetBottom( LONG_MAX );
780
0
        }
781
0
        pSelEngine->SetVisibleArea( aVis );
782
783
0
        SetMarking( true );     //  must precede SelMouseButtonDown
784
0
        pSelEngine->SelMouseButtonDown( rMEvt );
785
786
        //  In column/row headers a simple click already is a selection.
787
        //  -> Call SelMouseMove to ensure CreateAnchor is called (and DestroyAnchor
788
        //  if the next click is somewhere else with Control key).
789
0
        pSelEngine->SelMouseMove( rMEvt );
790
791
0
        if (IsMouseCaptured())
792
0
        {
793
            // tracking instead of CaptureMouse, so it can be cancelled cleanly
794
            //! someday SelectionEngine itself should call StartTracking!?!
795
0
            ReleaseMouse();
796
0
            StartTracking();
797
0
        }
798
0
    }
799
0
}
800
801
void ScHeaderControl::MouseButtonUp( const MouseEvent& rMEvt )
802
0
{
803
0
    if ( IsDisabled() )
804
0
        return;
805
806
0
    if (ScModule* mod = ScModule::get(); mod->IsFormulaMode())
807
0
    {
808
0
        mod->EndReference();
809
0
        bInRefMode = false;
810
0
        return;
811
0
    }
812
813
0
    SetMarking( false );
814
0
    bIgnoreMove = false;
815
816
0
    if ( bDragging )
817
0
    {
818
0
        DrawInvert( nDragPos );
819
0
        ReleaseMouse();
820
0
        HideDragHelp();
821
0
        bDragging = false;
822
823
0
        tools::Long nScrPos    = GetScrPos( nDragNo );
824
0
        tools::Long nMousePos  = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
825
0
        bool bLayoutRTL = IsLayoutRTL();
826
0
        tools::Long nNewWidth  = bLayoutRTL ? ( nScrPos - nMousePos + 1 )
827
0
                                     : ( nMousePos + 2 - nScrPos );
828
829
0
        if ( nNewWidth < 0 /* && !IsSelected(nDragNo) */ )
830
0
        {
831
0
            SCCOLROW nStart = 0;
832
0
            SCCOLROW nEnd = nDragNo;
833
0
            while (nNewWidth < 0)
834
0
            {
835
0
                nStart = nDragNo;
836
0
                if (nDragNo>0)
837
0
                {
838
0
                    --nDragNo;
839
0
                    nNewWidth += GetEntrySize( nDragNo );   //! GetHiddenCount() ???
840
0
                }
841
0
                else
842
0
                    nNewWidth = 0;
843
0
            }
844
0
            HideEntries( nStart, nEnd );
845
0
        }
846
0
        else
847
0
        {
848
0
            if (bDragMoved)
849
0
                SetEntrySize( nDragNo, static_cast<sal_uInt16>(nNewWidth) );
850
0
        }
851
0
    }
852
0
    else
853
0
    {
854
0
        pSelEngine->SelMouseButtonUp( rMEvt );
855
0
        ReleaseMouse();
856
0
    }
857
0
}
858
859
void ScHeaderControl::MouseMove( const MouseEvent& rMEvt )
860
0
{
861
0
    if ( IsDisabled() )
862
0
    {
863
0
        SetPointer( PointerStyle::Arrow );
864
0
        return;
865
0
    }
866
867
0
    if (bInRefMode && rMEvt.IsLeft() && ScModule::get()->IsFormulaMode())
868
0
    {
869
0
        if( !pTabView )
870
0
            return;
871
0
        bool bTmp;
872
0
        SCCOLROW nHitNo = GetMousePos(rMEvt.GetPosPixel(), bTmp);
873
0
        SCTAB nTab = pTabView->GetViewData().GetTabNo();
874
0
        ScDocument& rDoc = pTabView->GetViewData().GetDocument();
875
0
        if( !bVertical )
876
0
            pTabView->UpdateRef( nHitNo, rDoc.MaxRow(), nTab );
877
0
        else
878
0
            pTabView->UpdateRef( rDoc.MaxCol(), nHitNo, nTab );
879
880
0
        return;
881
0
    }
882
883
0
    if ( bDragging )
884
0
    {
885
0
        tools::Long nNewPos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
886
0
        if ( nNewPos != nDragPos )
887
0
        {
888
0
            DrawInvert( nDragPos );
889
0
            nDragPos = nNewPos;
890
0
            ShowDragHelp();
891
0
            DrawInvert( nDragPos );
892
893
0
            if (nDragPos <= nDragStart-SC_DRAG_MIN || nDragPos >= nDragStart+SC_DRAG_MIN)
894
0
                bDragMoved = true;
895
0
        }
896
0
    }
897
0
    else
898
0
    {
899
0
        bool bIsBorder;
900
0
        (void)GetMousePos(rMEvt.GetPosPixel(), bIsBorder);
901
902
0
        if ( bIsBorder && rMEvt.GetButtons()==0 && ResizeAllowed() )
903
0
            SetPointer( bVertical ? PointerStyle::VSizeBar : PointerStyle::HSizeBar );
904
0
        else
905
0
            SetPointer( PointerStyle::Arrow );
906
907
0
        if (!bIgnoreMove)
908
0
            pSelEngine->SelMouseMove( rMEvt );
909
0
    }
910
0
}
911
912
void ScHeaderControl::Tracking( const TrackingEvent& rTEvt )
913
0
{
914
    // Distribute the tracking events to the various MouseEvents, because
915
    // SelectionEngine does not know anything about Tracking
916
917
0
    if ( rTEvt.IsTrackingCanceled() )
918
0
        StopMarking();
919
0
    else if ( rTEvt.IsTrackingEnded() )
920
0
        MouseButtonUp( rTEvt.GetMouseEvent() );
921
0
    else
922
0
        MouseMove( rTEvt.GetMouseEvent() );
923
0
}
924
925
void ScHeaderControl::Command( const CommandEvent& rCEvt )
926
0
{
927
0
    CommandEventId nCmd = rCEvt.GetCommand();
928
0
    if ( nCmd == CommandEventId::ContextMenu )
929
0
    {
930
0
        StopMarking();      // finish selection / dragging
931
932
        // execute popup menu
933
934
0
        ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( SfxViewShell::Current() );
935
0
        if ( pViewSh )
936
0
        {
937
0
            if ( rCEvt.IsMouseEvent() )
938
0
            {
939
                // #i18735# select the column/row under the mouse pointer
940
0
                ScViewData& rViewData = pViewSh->GetViewData();
941
942
0
                SelectWindow();     // also deselects drawing objects, stops draw text edit
943
0
                if ( rViewData.HasEditView( rViewData.GetActivePart() ) )
944
0
                    ScModule::get()->InputEnterHandler(); // always end edit mode
945
946
0
                bool bBorder;
947
0
                SCCOLROW nPos = GetMousePos(rCEvt.GetMousePosPixel(), bBorder );
948
0
                if (!IsSelectionAllowed(nPos))
949
                    // Selecting this cell is not allowed, neither is context menu.
950
0
                    return;
951
952
0
                SCTAB nTab = rViewData.GetTabNo();
953
0
                ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
954
0
                ScRange aNewRange;
955
0
                if ( bVertical )
956
0
                    aNewRange = ScRange( 0, sal::static_int_cast<SCROW>(nPos), nTab,
957
0
                                         rDoc.MaxCol(), sal::static_int_cast<SCROW>(nPos), nTab );
958
0
                else
959
0
                    aNewRange = ScRange( sal::static_int_cast<SCCOL>(nPos), 0, nTab,
960
0
                                         sal::static_int_cast<SCCOL>(nPos), rDoc.MaxRow(), nTab );
961
962
                // see if any part of the range is already selected
963
0
                ScRangeList aRanges;
964
0
                rViewData.GetMarkData().FillRangeListWithMarks( &aRanges, false );
965
0
                bool bSelected = aRanges.Intersects(aNewRange);
966
967
                // select the range if no part of it was selected
968
0
                if ( !bSelected )
969
0
                    pViewSh->MarkRange( aNewRange );
970
0
            }
971
972
0
            pViewSh->GetDispatcher()->ExecutePopup( bVertical ? u"rowheader"_ustr : u"colheader"_ustr );
973
0
        }
974
0
    }
975
0
    else if ( nCmd == CommandEventId::StartDrag )
976
0
    {
977
0
        pSelEngine->Command( rCEvt );
978
0
    }
979
0
}
980
981
void ScHeaderControl::StopMarking()
982
0
{
983
0
    if ( bDragging )
984
0
    {
985
0
        DrawInvert( nDragPos );
986
0
        HideDragHelp();
987
0
        bDragging = false;
988
0
    }
989
990
0
    SetMarking( false );
991
0
    bIgnoreMove = true;
992
993
    //  don't call pSelEngine->Reset, so selection across the parts of
994
    //  a split/frozen view is possible
995
0
    if (IsMouseCaptured())
996
0
        ReleaseMouse();
997
0
}
998
999
IMPL_LINK_NOARG(ScHeaderControl, ShowDragHelpHdl, Timer*, void)
1000
0
{
1001
0
    ShowDragHelp();
1002
0
}
1003
1004
void ScHeaderControl::ShowDragHelp()
1005
0
{
1006
0
    aShowHelpTimer.Stop();
1007
0
    if (!Help::IsQuickHelpEnabled())
1008
0
        return;
1009
1010
0
    tools::Long nScrPos    = GetScrPos( nDragNo );
1011
0
    bool bLayoutRTL = IsLayoutRTL();
1012
0
    tools::Long nVal = bLayoutRTL ? ( nScrPos - nDragPos + 1 )
1013
0
                           : ( nDragPos + 2 - nScrPos );
1014
1015
0
    OUString aHelpStr = GetDragHelp( nVal );
1016
0
    Point aPos = OutputToScreenPixel( Point(0,0) );
1017
0
    Size aSize = GetSizePixel();
1018
1019
0
    Point aMousePos = OutputToScreenPixel(GetPointerPosPixel());
1020
1021
0
    tools::Rectangle aRect;
1022
0
    QuickHelpFlags nAlign;
1023
0
    if (!bVertical)
1024
0
    {
1025
        // above
1026
0
        aRect.SetLeft( aMousePos.X() );
1027
0
        aRect.SetTop( aPos.Y() - 4 );
1028
0
        nAlign       = QuickHelpFlags::Bottom|QuickHelpFlags::Center;
1029
0
    }
1030
0
    else
1031
0
    {
1032
        // top right
1033
0
        aRect.SetLeft( aPos.X() + aSize.Width() + 8 );
1034
0
        aRect.SetTop( aMousePos.Y() - 2 );
1035
0
        nAlign       = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
1036
0
    }
1037
1038
0
    aRect.SetRight( aRect.Left() );
1039
0
    aRect.SetBottom( aRect.Top() );
1040
1041
0
    if (nTipVisible)
1042
0
        Help::HidePopover(this, nTipVisible);
1043
0
    nTipVisible = Help::ShowPopover(this, aRect, aHelpStr, nAlign);
1044
0
}
1045
1046
void ScHeaderControl::HideDragHelp()
1047
0
{
1048
0
    aShowHelpTimer.Stop();
1049
0
    if (nTipVisible)
1050
0
    {
1051
0
        Help::HidePopover(this, nTipVisible);
1052
0
        nTipVisible = nullptr;
1053
0
    }
1054
0
}
1055
1056
void ScHeaderControl::RequestHelp( const HelpEvent& rHEvt )
1057
0
{
1058
    //  If the own QuickHelp is displayed, don't let RequestHelp remove it
1059
1060
0
    bool bOwn = bDragging && Help::IsQuickHelpEnabled();
1061
0
    if (!bOwn)
1062
0
        Window::RequestHelp(rHEvt);
1063
0
}
1064
1065
//                  dummies for virtual methods
1066
1067
SCCOLROW ScHeaderControl::GetHiddenCount( SCCOLROW nEntryNo ) const
1068
0
{
1069
0
    SCCOLROW nHidden = 0;
1070
0
    while ( nEntryNo < nSize && GetEntrySize( nEntryNo ) == 0 )
1071
0
    {
1072
0
        ++nEntryNo;
1073
0
        ++nHidden;
1074
0
    }
1075
0
    return nHidden;
1076
0
}
1077
1078
bool ScHeaderControl::IsLayoutRTL() const
1079
0
{
1080
0
    return false;
1081
0
}
1082
1083
bool ScHeaderControl::IsMirrored() const
1084
0
{
1085
0
    return false;
1086
0
}
1087
1088
bool ScHeaderControl::IsDisabled() const
1089
0
{
1090
0
    return false;
1091
0
}
1092
1093
bool ScHeaderControl::ResizeAllowed() const
1094
0
{
1095
0
    return true;
1096
0
}
1097
1098
void ScHeaderControl::SelectWindow()
1099
0
{
1100
0
}
1101
1102
void ScHeaderControl::DrawInvert( tools::Long /* nDragPos */ )
1103
0
{
1104
0
}
1105
1106
OUString ScHeaderControl::GetDragHelp( tools::Long /* nVal */ )
1107
0
{
1108
0
    return OUString();
1109
0
}
1110
1111
void ScHeaderControl::SetMarking( bool /* bSet */ )
1112
0
{
1113
0
}
1114
1115
void ScHeaderControl::GetMarkRange(SCCOLROW& rStart, SCCOLROW& rEnd) const
1116
0
{
1117
0
    rStart = nMarkStart;
1118
0
    rEnd = nMarkEnd;
1119
0
}
1120
1121
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */