Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svtools/source/brwbox/brwbox1.cxx
Line
Count
Source
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 <comphelper/diagnose_ex.hxx>
21
#include <svtools/brwbox.hxx>
22
#include <svtools/brwhead.hxx>
23
#include <svtools/scrolladaptor.hxx>
24
#include <o3tl/numeric.hxx>
25
#include <o3tl/safeint.hxx>
26
#include "datwin.hxx"
27
#include <osl/diagnose.h>
28
#include <tools/debug.hxx>
29
#include <tools/fract.hxx>
30
#include <sal/log.hxx>
31
#include <vcl/InterimItemWindow.hxx>
32
#include <vcl/svapp.hxx>
33
#include <vcl/weld/Entry.hxx>
34
#include <vcl/weld/weld.hxx>
35
#include <vcl/weld/Builder.hxx>
36
37
#include <algorithm>
38
#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
39
#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
40
#include <com/sun/star/accessibility/AccessibleEventId.hpp>
41
#include <com/sun/star/lang/XComponent.hpp>
42
#include <tools/multisel.hxx>
43
44
45
0
#define SCROLL_FLAGS (ScrollFlags::Clip | ScrollFlags::NoChildren)
46
47
using namespace com::sun::star::accessibility::AccessibleTableModelChangeType;
48
using com::sun::star::accessibility::AccessibleTableModelChange;
49
using namespace com::sun::star::accessibility;
50
using namespace ::com::sun::star::uno;
51
using namespace svt;
52
53
namespace
54
{
55
56
void disposeAndClearHeaderCell(BrowseBox::THeaderCellMap& _rHeaderCell)
57
0
{
58
0
    ::std::for_each(
59
0
        _rHeaderCell.begin(), _rHeaderCell.end(),
60
0
        [](const BrowseBox::THeaderCellMap::value_type& rType)
61
0
        {
62
0
            css::uno::Reference<css::lang::XComponent> xComp(rType.second, css::uno::UNO_QUERY);
63
0
            OSL_ENSURE(xComp.is() || !rType.second.is(),
64
0
                       "THeaderCellMapFunctorDispose: invalid accessible cell (no XComponent)!");
65
0
            if (xComp.is())
66
0
                try
67
0
                {
68
0
                    xComp->dispose();
69
0
                }
70
0
                catch (const css::uno::Exception&)
71
0
                {
72
0
                    TOOLS_WARN_EXCEPTION("svtools", "THeaderCellMapFunctorDispose");
73
0
                }
74
0
        });
75
0
    _rHeaderCell.clear();
76
0
}
77
}
78
79
// we're just measuring the "real" NavigationBar
80
class MeasureStatusBar final : public InterimItemWindow
81
{
82
private:
83
    std::unique_ptr<weld::Label> m_xRecordText;
84
    std::unique_ptr<weld::Entry> m_xAbsolute;
85
    std::unique_ptr<weld::Label> m_xRecordOf;
86
    std::unique_ptr<weld::Label> m_xRecordCount;
87
public:
88
    MeasureStatusBar(vcl::Window *pParent)
89
0
        : InterimItemWindow(pParent, u"svx/ui/navigationbar.ui"_ustr, u"NavigationBar"_ustr)
90
0
        , m_xRecordText(m_xBuilder->weld_label(u"recordtext"_ustr))
91
0
        , m_xAbsolute(m_xBuilder->weld_entry(u"entry-noframe"_ustr))
92
0
        , m_xRecordOf(m_xBuilder->weld_label(u"recordof"_ustr))
93
0
        , m_xRecordCount(m_xBuilder->weld_label(u"recordcount"_ustr))
94
0
    {
95
0
        vcl::Font aApplFont(Application::GetSettings().GetStyleSettings().GetToolFont());
96
0
        m_xAbsolute->set_font(aApplFont);
97
0
        m_xRecordText->set_font(aApplFont);
98
0
        m_xRecordOf->set_font(aApplFont);
99
0
        m_xRecordCount->set_font(aApplFont);
100
101
0
        SetSizePixel(get_preferred_size());
102
0
    }
103
104
    virtual void dispose() override
105
0
    {
106
0
        m_xRecordCount.reset();
107
0
        m_xRecordOf.reset();
108
0
        m_xAbsolute.reset();
109
0
        m_xRecordText.reset();
110
0
        InterimItemWindow::dispose();
111
0
    }
112
};
113
114
tools::Long BrowseBox::GetBarHeight() const
115
0
{
116
0
    tools::Long nScrollBarSize = GetSettings().GetStyleSettings().GetScrollBarSize();
117
0
    if (!m_bNavigationBar)
118
0
        return nScrollBarSize;
119
120
    // tdf#115941 because some platforms have things like overlay scrollbars, take a max
121
    // of a statusbar height and a scrollbar height as the control area height
122
123
    // (we can't ask the scrollbars for their size cause if we're zoomed they still have to be
124
    // resized - which is done in UpdateScrollbars)
125
0
    return std::max(aStatusBarHeight->GetSizePixel().Height(), nScrollBarSize);
126
0
}
127
128
BrowseBox::BrowseBox( vcl::Window* pParent, WinBits nBits, BrowserMode nMode )
129
0
    :Control( pParent, nBits | WB_3DLOOK )
130
0
    ,DragSourceHelper( this )
131
0
    ,DropTargetHelper( this )
132
0
    ,aHScroll( VclPtr<ScrollAdaptor>::Create(this, true) )
133
    // see NavigationBar ctor, here we just want to know its height
134
0
    ,aStatusBarHeight(VclPtr<MeasureStatusBar>::Create(this))
135
0
    ,m_nCornerHeight(0)
136
0
    ,m_nCornerWidth(0)
137
0
    ,m_nActualCornerWidth(0)
138
0
    ,m_bNavigationBar(false)
139
0
{
140
0
    bMultiSelection = false;
141
0
    pColSel = nullptr;
142
0
    pVScroll = nullptr;
143
0
    pDataWin = VclPtr<BrowserDataWin>::Create( this ).get();
144
145
0
    InitSettings_Impl( this );
146
0
    InitSettings_Impl( pDataWin );
147
148
0
    bBootstrapped = false;
149
0
    m_nDataRowHeight = 0;
150
0
    nTitleLines = 1;
151
0
    nFirstCol = 0;
152
0
    nTopRow = 0;
153
0
    nCurRow = BROWSER_ENDOFSELECTION;
154
0
    nCurColId = 0;
155
0
    nResizeX = 0;
156
0
    nMinResizeX = 0;
157
0
    nDragX = 0;
158
0
    nResizeCol = 0;
159
0
    bResizing = false;
160
0
    bSelect = false;
161
0
    bSelecting = false;
162
0
    bScrolling = false;
163
0
    bSelectionIsVisible = false;
164
0
    bNotToggleSel = false;
165
0
    bRowDividerDrag = false;
166
0
    bHit = false;
167
0
    mbInteractiveRowHeight = false;
168
0
    bHideSelect = false;
169
0
    bHideCursor = TRISTATE_FALSE;
170
0
    nRowCount = 0;
171
0
    m_bFocusOnlyCursor = true;
172
0
    m_aCursorColor = COL_TRANSPARENT;
173
0
    m_nCurrentMode = BrowserMode::NONE;
174
0
    nControlAreaWidth = USHRT_MAX;
175
0
    uRow.nSel = BROWSER_ENDOFSELECTION;
176
177
0
    aHScroll->SetLineSize(1);
178
0
    aHScroll->SetScrollHdl( LINK( this, BrowseBox, HorzScrollHdl ) );
179
0
    pDataWin->Show();
180
181
0
    SetMode( nMode );
182
0
    bSelectionIsVisible = bKeepHighlight;
183
0
    bHasFocus = HasChildPathFocus();
184
0
    pDataWin->nCursorHidden =
185
0
        ( bHasFocus ? 0 : 1 ) + ( GetUpdateMode() ? 0 : 1 );
186
0
}
187
188
BrowseBox::~BrowseBox()
189
0
{
190
0
    disposeOnce();
191
0
}
192
193
void BrowseBox::DisposeAccessible()
194
0
{
195
0
    if (m_xAccessible)
196
0
    {
197
0
        disposeAndClearHeaderCell(m_aColHeaderCellMap);
198
0
        disposeAndClearHeaderCell(m_aRowHeaderCellMap);
199
0
        m_xAccessible->dispose();
200
0
        m_xAccessible = nullptr;
201
0
    }
202
0
}
203
204
void BrowseBox::dispose()
205
0
{
206
0
    SAL_INFO("svtools", "BrowseBox:dispose " << this );
207
208
0
    DisposeAccessible();
209
210
0
    Hide();
211
0
    pDataWin->pHeaderBar.disposeAndClear();
212
0
    pDataWin.disposeAndClear();
213
0
    pVScroll.disposeAndClear();
214
0
    aHScroll.disposeAndClear();
215
0
    aStatusBarHeight.disposeAndClear();
216
217
    // free columns-space
218
0
    mvCols.clear();
219
0
    pColSel.reset();
220
0
    if ( bMultiSelection )
221
0
        delete uRow.pSel;
222
0
    DragSourceHelper::dispose();
223
0
    DropTargetHelper::dispose();
224
0
    Control::dispose();
225
0
}
226
227
228
short BrowseBox::GetCursorHideCount() const
229
0
{
230
0
    return pDataWin->nCursorHidden;
231
0
}
232
233
234
void BrowseBox::DoShowCursor()
235
0
{
236
0
    if (!pDataWin)
237
0
        return;
238
0
    short nHiddenCount = --pDataWin->nCursorHidden;
239
0
    if (PaintCursorIfHiddenOnce())
240
0
    {
241
0
        if (1 == nHiddenCount)
242
0
            DrawCursor();
243
0
    }
244
0
    else
245
0
    {
246
0
        if (0 == nHiddenCount)
247
0
            DrawCursor();
248
0
    }
249
0
}
250
251
252
void BrowseBox::DoHideCursor()
253
0
{
254
0
    short nHiddenCount = ++pDataWin->nCursorHidden;
255
0
    if (PaintCursorIfHiddenOnce())
256
0
    {
257
0
        if (2 == nHiddenCount)
258
0
            DrawCursor();
259
0
    }
260
0
    else
261
0
    {
262
0
        if (1 == nHiddenCount)
263
0
            DrawCursor();
264
0
    }
265
0
}
266
267
268
void BrowseBox::SetRealRowCount( const OUString &rRealRowCount )
269
0
{
270
0
    pDataWin->aRealRowCount = rRealRowCount;
271
0
}
272
273
274
void BrowseBox::SetFont( const vcl::Font& rNewFont )
275
0
{
276
0
    pDataWin->SetFont( rNewFont );
277
0
    ImpGetDataRowHeight();
278
0
}
279
280
const vcl::Font& BrowseBox::GetFont() const
281
0
{
282
0
    return pDataWin->GetFont();
283
0
}
284
285
tools::Long BrowseBox::GetDefaultColumnWidth( const OUString& _rText ) const
286
0
{
287
0
    return pDataWin->GetTextWidth( _rText ) + pDataWin->GetTextWidth(OUString('0')) * 4;
288
0
}
289
290
291
void BrowseBox::InsertHandleColumn( tools::Long nWidth )
292
0
{
293
294
#if OSL_DEBUG_LEVEL > 0
295
    OSL_ENSURE( ColCount() == 0 || mvCols[0]->GetId() != HandleColumnId , "BrowseBox::InsertHandleColumn: there is already a handle column" );
296
    {
297
        for (auto const & col : mvCols)
298
            OSL_ENSURE( col->GetId() != HandleColumnId, "BrowseBox::InsertHandleColumn: there is a non-Handle column with handle ID" );
299
    }
300
#endif
301
302
0
    mvCols.insert( mvCols.begin(), std::unique_ptr<BrowserColumn>(new BrowserColumn( 0, OUString(), nWidth, GetZoom() )) );
303
0
    FreezeColumn( 0 );
304
305
    // adjust headerbar
306
0
    if ( pDataWin->pHeaderBar )
307
0
    {
308
0
        pDataWin->pHeaderBar->SetPosSizePixel(
309
0
                    Point(nWidth, 0),
310
0
                    Size( GetOutputSizePixel().Width() - nWidth, GetTitleHeight() )
311
0
                    );
312
0
    }
313
314
0
    ColumnInserted( 0 );
315
0
}
316
317
318
void BrowseBox::InsertDataColumn( sal_uInt16 nItemId, const OUString& rText,
319
        tools::Long nWidth, HeaderBarItemBits nBits, sal_uInt16 nPos )
320
0
{
321
322
0
    OSL_ENSURE( nItemId != HandleColumnId, "BrowseBox::InsertDataColumn: nItemId is HandleColumnId" );
323
0
    OSL_ENSURE( nItemId != BROWSER_INVALIDID, "BrowseBox::InsertDataColumn: nItemId is reserved value BROWSER_INVALIDID" );
324
325
#if OSL_DEBUG_LEVEL > 0
326
    {
327
        for (auto const& col : mvCols)
328
            OSL_ENSURE( col->GetId() != nItemId, "BrowseBox::InsertDataColumn: duplicate column Id" );
329
    }
330
#endif
331
332
0
    if ( nPos < mvCols.size() )
333
0
    {
334
0
        mvCols.emplace( mvCols.begin() + nPos, new BrowserColumn( nItemId, rText, nWidth, GetZoom() ) );
335
0
    }
336
0
    else
337
0
    {
338
0
        mvCols.emplace_back( new BrowserColumn( nItemId, rText, nWidth, GetZoom() ) );
339
0
    }
340
0
    if ( nCurColId == 0 )
341
0
        nCurColId = nItemId;
342
343
0
    if ( pDataWin->pHeaderBar )
344
0
    {
345
        // Handle column not in the header bar
346
0
        sal_uInt16 nHeaderPos = nPos;
347
0
        if (nHeaderPos != HEADERBAR_APPEND && GetColumnId(0) == HandleColumnId )
348
0
            nHeaderPos--;
349
0
        pDataWin->pHeaderBar->InsertItem(
350
0
                nItemId, rText, nWidth, nBits, nHeaderPos );
351
0
    }
352
0
    ColumnInserted( nPos );
353
0
}
354
355
sal_uInt16 BrowseBox::ToggleSelectedColumn()
356
0
{
357
0
    sal_uInt16 nSelectedColId = BROWSER_INVALIDID;
358
0
    if ( pColSel && pColSel->GetSelectCount() )
359
0
    {
360
0
        DoHideCursor();
361
0
        ToggleSelection();
362
0
        tools::Long nSelected = pColSel->FirstSelected();
363
0
        if (nSelected != static_cast<tools::Long>(SFX_ENDOFSELECTION))
364
0
            nSelectedColId = mvCols[nSelected]->GetId();
365
0
        pColSel->SelectAll(false);
366
0
    }
367
0
    return nSelectedColId;
368
0
}
369
370
void BrowseBox::SetToggledSelectedColumn(sal_uInt16 _nSelectedColumnId)
371
0
{
372
0
    if ( pColSel && _nSelectedColumnId != BROWSER_INVALIDID )
373
0
    {
374
0
        pColSel->Select( GetColumnPos( _nSelectedColumnId ) );
375
0
        ToggleSelection();
376
0
        SAL_INFO("svtools", "BrowseBox::SetToggledSelectedColumn " << this );
377
0
        DoShowCursor();
378
0
    }
379
0
}
380
381
void BrowseBox::FreezeColumn( sal_uInt16 nItemId )
382
0
{
383
    // get the position in the current array
384
0
    size_t nItemPos = GetColumnPos( nItemId );
385
0
    if ( nItemPos >= mvCols.size() )
386
        // not available!
387
0
        return;
388
389
    // doesn't the state change?
390
0
    if ( mvCols[ nItemPos ]->IsFrozen() )
391
0
        return;
392
393
    // remark the column selection
394
0
    sal_uInt16 nSelectedColId = ToggleSelectedColumn();
395
396
    // to be moved?
397
0
    if ( nItemPos != 0 && !mvCols[ nItemPos-1 ]->IsFrozen() )
398
0
    {
399
        // move to the right of the last frozen column
400
0
        sal_uInt16 nFirstScrollable = FrozenColCount();
401
0
        std::unique_ptr<BrowserColumn> pColumn = std::move(mvCols[ nItemPos ]);
402
0
        mvCols.erase( mvCols.begin() + nItemPos );
403
0
        nItemPos = nFirstScrollable;
404
0
        mvCols.insert( mvCols.begin() + nItemPos, std::move(pColumn) );
405
0
    }
406
407
    // adjust the number of the first scrollable and visible column
408
0
    if ( nFirstCol <= nItemPos )
409
0
        nFirstCol = nItemPos + 1;
410
411
    // toggle the freeze-state of the column
412
0
    mvCols[ nItemPos ]->Freeze();
413
414
    // align the scrollbar-range
415
0
    UpdateScrollbars();
416
417
    // repaint
418
0
    Control::Invalidate();
419
0
    pDataWin->Invalidate();
420
421
    // remember the column selection
422
0
    SetToggledSelectedColumn(nSelectedColId);
423
0
}
424
425
426
void BrowseBox::SetColumnPos( sal_uInt16 nColumnId, sal_uInt16 nPos )
427
0
{
428
    // never set pos of the handle column
429
0
    if ( nColumnId == HandleColumnId )
430
0
        return;
431
432
    // get the position in the current array
433
0
    sal_uInt16 nOldPos = GetColumnPos( nColumnId );
434
0
    if ( nOldPos >= mvCols.size() )
435
        // not available!
436
0
        return;
437
438
    // does the state change?
439
0
    if (nOldPos == nPos)
440
0
        return;
441
442
    // remark the column selection
443
0
    sal_uInt16 nSelectedColId = ToggleSelectedColumn();
444
445
    // determine old column area
446
0
    Size aDataWinSize( pDataWin->GetSizePixel() );
447
0
    if ( pDataWin->pHeaderBar )
448
0
        aDataWinSize.AdjustHeight(pDataWin->pHeaderBar->GetSizePixel().Height() );
449
450
0
    tools::Rectangle aFromRect( GetFieldRect( nColumnId) );
451
0
    aFromRect.AdjustRight(2*MIN_COLUMNWIDTH );
452
453
0
    sal_uInt16 nNextPos = nOldPos + 1;
454
0
    if ( nOldPos > nPos )
455
0
        nNextPos = nOldPos - 1;
456
457
0
    BrowserColumn *pNextCol = mvCols[ nNextPos ].get();
458
0
    tools::Rectangle aNextRect(GetFieldRect( pNextCol->GetId() ));
459
460
    // move column internally
461
0
    {
462
0
        std::unique_ptr<BrowserColumn> pTemp = std::move(mvCols[nOldPos]);
463
0
        mvCols.erase( mvCols.begin() + nOldPos );
464
0
        mvCols.insert( mvCols.begin() + nPos, std::move(pTemp) );
465
0
    }
466
467
    // determine new column area
468
0
    tools::Rectangle aToRect( GetFieldRect( nColumnId ) );
469
0
    aToRect.AdjustRight(2*MIN_COLUMNWIDTH );
470
471
    // do scroll, let redraw
472
0
    if( pDataWin->GetBackground().IsScrollable() )
473
0
    {
474
0
        tools::Long nScroll = -aFromRect.GetWidth();
475
0
        tools::Rectangle aScrollArea;
476
0
        if ( nOldPos > nPos )
477
0
        {
478
0
            tools::Long nFrozenWidth = GetFrozenWidth();
479
0
            if ( aToRect.Left() < nFrozenWidth )
480
0
                aToRect.SetLeft( nFrozenWidth );
481
0
            aScrollArea = tools::Rectangle(Point(aToRect.Left(),0),
482
0
                                    Point(aNextRect.Right(),aDataWinSize.Height()));
483
0
            nScroll *= -1; // reverse direction
484
0
        }
485
0
        else
486
0
            aScrollArea = tools::Rectangle(Point(aNextRect.Left(),0),
487
0
                                    Point(aToRect.Right(),aDataWinSize.Height()));
488
489
0
        pDataWin->Scroll( nScroll, 0, aScrollArea );
490
0
        aToRect.SetTop( 0 );
491
0
        aToRect.SetBottom( aScrollArea.Bottom() );
492
0
        Invalidate( aToRect );
493
0
    }
494
0
    else
495
0
        pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
496
497
    // adjust header bar positions
498
0
    if ( pDataWin->pHeaderBar )
499
0
    {
500
0
        sal_uInt16 nNewPos = nPos;
501
0
        if ( GetColumnId(0) == HandleColumnId )
502
0
            --nNewPos;
503
0
        pDataWin->pHeaderBar->MoveItem(nColumnId,nNewPos);
504
0
    }
505
    // remember the column selection
506
0
    SetToggledSelectedColumn(nSelectedColId);
507
508
0
    if ( !isAccessibleAlive() )
509
0
        return;
510
511
0
    commitTableEvent(
512
0
        AccessibleEventId::TABLE_MODEL_CHANGED,
513
0
        Any( AccessibleTableModelChange(
514
0
                    COLUMNS_REMOVED,
515
0
                    -1,
516
0
                    -1,
517
0
                    nOldPos,
518
0
                    nOldPos
519
0
                )
520
0
        ),
521
0
        Any()
522
0
    );
523
524
0
    commitTableEvent(
525
0
        AccessibleEventId::TABLE_MODEL_CHANGED,
526
0
        Any( AccessibleTableModelChange(
527
0
                    COLUMNS_INSERTED,
528
0
                    -1,
529
0
                    -1,
530
0
                    nPos,
531
0
                    nPos
532
0
                )
533
0
        ),
534
0
        Any()
535
0
    );
536
537
0
}
538
539
540
void BrowseBox::SetColumnTitle( sal_uInt16 nItemId, const OUString& rTitle )
541
0
{
542
543
    // never set title of the handle-column
544
0
    if ( nItemId == HandleColumnId )
545
0
        return;
546
547
    // get the position in the current array
548
0
    sal_uInt16 nItemPos = GetColumnPos( nItemId );
549
0
    if ( nItemPos >= mvCols.size() )
550
        // not available!
551
0
        return;
552
553
    // does the state change?
554
0
    BrowserColumn *pCol = mvCols[ nItemPos ].get();
555
0
    if ( pCol->Title() == rTitle )
556
0
        return;
557
558
0
    OUString sOld(pCol->Title());
559
560
0
    pCol->Title() = rTitle;
561
562
    // adjust headerbar column
563
0
    if ( pDataWin->pHeaderBar )
564
0
        pDataWin->pHeaderBar->SetItemText( nItemId, rTitle );
565
0
    else
566
0
    {
567
        // redraw visible columns
568
0
        if ( GetUpdateMode() && ( pCol->IsFrozen() || nItemPos > nFirstCol ) )
569
0
            Invalidate( tools::Rectangle( Point(0,0),
570
0
                Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
571
0
    }
572
573
0
    if ( isAccessibleAlive() )
574
0
    {
575
0
        commitTableEvent(AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED,
576
0
            Any( rTitle ),
577
0
            Any( sOld )
578
0
        );
579
0
    }
580
0
}
581
582
583
void BrowseBox::SetColumnWidth( sal_uInt16 nItemId, tools::Long nWidth )
584
0
{
585
586
    // get the position in the current array
587
0
    size_t nItemPos = GetColumnPos( nItemId );
588
0
    if ( nItemPos >= mvCols.size() )
589
0
        return;
590
591
    // does the state change?
592
0
    if ( nWidth < LONG_MAX && mvCols[ nItemPos ]->Width() == nWidth )
593
0
        return;
594
595
0
    tools::Long nOldWidth = mvCols[ nItemPos ]->Width();
596
597
    // adjust last column, if necessary
598
0
    if ( nItemPos == mvCols.size() - 1 )
599
0
    {
600
0
        if ( IsVisible() )
601
0
        {
602
0
            tools::Long nMaxWidth = pDataWin->GetSizePixel().Width();
603
0
            nMaxWidth -= pDataWin->bAutoSizeLastCol
604
0
                ? GetFieldRect(nItemId).Left()
605
0
                : GetFrozenWidth();
606
0
            if ( pDataWin->bAutoSizeLastCol || nWidth > nMaxWidth )
607
0
            {
608
0
                nWidth = nMaxWidth > 16 ? nMaxWidth : nOldWidth;
609
0
            }
610
0
        }
611
0
        else if ( nWidth == LONG_MAX )
612
0
        {
613
            // If we can’t calculate the maximum width because the window isn’t visible then it’s
614
            // better to leave the width as it is than to set it to LONG_MAX. The last column width
615
            // will be recalculated when the window is shown anyway because the window will be
616
            // resized.
617
0
            return;
618
0
        }
619
0
    }
620
621
    // OV
622
    // In AutoSizeLastColumn(), we call SetColumnWidth with nWidth==0xffff.
623
    // Thus, check here, if the width has actually changed.
624
0
    if( nOldWidth == nWidth )
625
0
        return;
626
627
    // do we want to display the change immediately?
628
0
    bool bUpdate = GetUpdateMode() &&
629
0
                   ( mvCols[ nItemPos ]->IsFrozen() || nItemPos >= nFirstCol );
630
631
0
    if ( bUpdate )
632
0
    {
633
        // Selection hidden
634
0
        DoHideCursor();
635
0
        ToggleSelection();
636
        //!pDataWin->Update();
637
        //!Control::Update();
638
0
    }
639
640
    // set width
641
0
    mvCols[ nItemPos ]->SetWidth(nWidth, GetZoom());
642
643
    // scroll and invalidate
644
0
    if ( bUpdate )
645
0
    {
646
        // get X-Pos of the column changed
647
0
        tools::Long nX = 0;
648
0
        for ( size_t nCol = 0; nCol < nItemPos; ++nCol )
649
0
        {
650
0
            BrowserColumn *pCol = mvCols[ nCol ].get();
651
0
            if ( pCol->IsFrozen() || nCol >= nFirstCol )
652
0
                nX += pCol->Width();
653
0
        }
654
655
        // actually scroll+invalidate
656
0
        pDataWin->GetOutDev()->SetClipRegion();
657
0
        bool bSelVis = bSelectionIsVisible;
658
0
        bSelectionIsVisible = false;
659
0
        if( GetBackground().IsScrollable() )
660
0
        {
661
662
0
            tools::Rectangle aScrRect( nX + std::min( nOldWidth, nWidth ), 0,
663
0
                                GetSizePixel().Width() , // the header is longer than the datawin
664
0
                                pDataWin->GetPosPixel().Y() - 1 );
665
0
            Control::Scroll( nWidth-nOldWidth, 0, aScrRect, SCROLL_FLAGS );
666
0
            aScrRect.SetBottom( pDataWin->GetSizePixel().Height() );
667
0
            pDataWin->Scroll( nWidth-nOldWidth, 0, aScrRect, SCROLL_FLAGS );
668
0
            tools::Rectangle aInvRect( nX, 0, nX + std::max( nWidth, nOldWidth ), USHRT_MAX );
669
0
            Control::Invalidate( aInvRect, InvalidateFlags::NoChildren );
670
0
            pDataWin->Invalidate( aInvRect );
671
0
        }
672
0
        else
673
0
        {
674
0
            Control::Invalidate( InvalidateFlags::NoChildren );
675
0
            pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
676
0
        }
677
678
679
        //!pDataWin->Update();
680
        //!Control::Update();
681
0
        bSelectionIsVisible = bSelVis;
682
0
        ToggleSelection();
683
0
        DoShowCursor();
684
0
    }
685
0
    UpdateScrollbars();
686
687
    // adjust headerbar column
688
0
    if ( pDataWin->pHeaderBar )
689
0
        pDataWin->pHeaderBar->SetItemSize(
690
0
                nItemId ? nItemId : USHRT_MAX - 1, nWidth );
691
692
    // adjust last column
693
0
    if ( nItemPos != mvCols.size() - 1 )
694
0
        AutoSizeLastColumn();
695
0
}
696
697
698
void BrowseBox::AutoSizeLastColumn()
699
0
{
700
0
    if ( pDataWin->bAutoSizeLastCol &&
701
0
         pDataWin->GetUpdateMode() )
702
0
    {
703
0
        sal_uInt16 nId = GetColumnId( static_cast<sal_uInt16>(mvCols.size()) - 1 );
704
0
        SetColumnWidth( nId, LONG_MAX );
705
0
        ColumnResized( nId );
706
0
    }
707
0
}
708
709
710
void BrowseBox::RemoveColumn( sal_uInt16 nItemId )
711
0
{
712
713
    // get column position
714
0
    sal_uInt16 nPos = GetColumnPos(nItemId);
715
0
    if ( nPos >= ColCount() )
716
        // not available
717
0
        return;
718
719
    // correct column selection
720
0
    if ( pColSel )
721
0
        pColSel->Remove( nPos );
722
723
    // correct column cursor
724
0
    if ( nCurColId == nItemId )
725
0
        nCurColId = 0;
726
727
    // delete column
728
0
    mvCols.erase( mvCols.begin() + nPos );
729
0
    if ( nFirstCol >= nPos && nFirstCol > FrozenColCount() )
730
0
    {
731
0
        OSL_ENSURE(nFirstCol > 0,"FirstCol must be greater zero!");
732
0
        --nFirstCol;
733
0
    }
734
735
    // handlecolumn not in headerbar
736
0
    if (nItemId)
737
0
    {
738
0
        if ( pDataWin->pHeaderBar )
739
0
            pDataWin->pHeaderBar->RemoveItem( nItemId );
740
0
    }
741
0
    else
742
0
    {
743
        // adjust headerbar
744
0
        if ( pDataWin->pHeaderBar )
745
0
        {
746
0
            pDataWin->pHeaderBar->SetPosSizePixel(
747
0
                        Point(0, 0),
748
0
                        Size( GetOutputSizePixel().Width(), GetTitleHeight() )
749
0
                        );
750
0
        }
751
0
    }
752
753
    // correct vertical scrollbar
754
0
    UpdateScrollbars();
755
756
    // trigger repaint, if necessary
757
0
    if ( GetUpdateMode() )
758
0
    {
759
0
        pDataWin->Invalidate();
760
0
        Control::Invalidate();
761
0
        if ( pDataWin->bAutoSizeLastCol && nPos ==ColCount() )
762
0
            SetColumnWidth( GetColumnId( nPos - 1 ), LONG_MAX );
763
0
    }
764
765
0
    if ( !isAccessibleAlive() )
766
0
        return;
767
768
0
    commitTableEvent(
769
0
        AccessibleEventId::TABLE_MODEL_CHANGED,
770
0
        Any( AccessibleTableModelChange(COLUMNS_REMOVED,
771
0
                                                -1,
772
0
                                                -1,
773
0
                                                nPos,
774
0
                                                nPos
775
0
                                           )
776
0
        ),
777
0
        Any()
778
0
    );
779
780
0
    commitHeaderBarEvent(
781
0
        AccessibleEventId::CHILD,
782
0
        Any(),
783
0
        Any( CreateAccessibleColumnHeader( nPos ) ),
784
0
        true
785
0
    );
786
0
}
787
788
789
void BrowseBox::RemoveColumns()
790
0
{
791
0
    size_t nOldCount = mvCols.size();
792
793
    // remove all columns
794
0
    mvCols.clear();
795
796
    // correct column selection
797
0
    if ( pColSel )
798
0
    {
799
0
        pColSel->SelectAll(false);
800
0
        pColSel->SetTotalRange( Range( 0, 0 ) );
801
0
    }
802
803
    // correct column cursor
804
0
    nCurColId = 0;
805
0
    nFirstCol = 0;
806
807
0
    if ( pDataWin->pHeaderBar )
808
0
        pDataWin->pHeaderBar->Clear( );
809
810
    // correct vertical scrollbar
811
0
    UpdateScrollbars();
812
813
    // trigger repaint if necessary
814
0
    if ( GetUpdateMode() )
815
0
    {
816
0
        pDataWin->Invalidate();
817
0
        Control::Invalidate();
818
0
    }
819
820
0
    if ( !isAccessibleAlive() )
821
0
        return;
822
823
0
    if ( mvCols.size() == nOldCount )
824
0
        return;
825
826
    // all columns should be removed, so we remove the column header bar and append it again
827
    // to avoid to notify every column remove
828
0
    commitBrowseBoxEvent(
829
0
        AccessibleEventId::CHILD,
830
0
        Any(),
831
0
        Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar))
832
0
    );
833
834
    // and now append it again
835
0
    commitBrowseBoxEvent(
836
0
        AccessibleEventId::CHILD,
837
0
        Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar)),
838
0
        Any()
839
0
    );
840
841
    // notify a table model change
842
0
    commitTableEvent(
843
0
        AccessibleEventId::TABLE_MODEL_CHANGED,
844
0
        Any ( AccessibleTableModelChange( COLUMNS_REMOVED,
845
0
                        -1,
846
0
                        -1,
847
0
                        0,
848
0
                        nOldCount
849
0
                    )
850
0
                ),
851
0
        Any()
852
0
    );
853
0
}
854
855
856
const OUString & BrowseBox::GetColumnTitle( sal_uInt16 nId ) const
857
0
{
858
859
0
    sal_uInt16 nItemPos = GetColumnPos( nId );
860
0
    if ( nItemPos >= mvCols.size() )
861
0
        return EMPTY_OUSTRING;
862
0
    return mvCols[ nItemPos ]->Title();
863
0
}
864
865
sal_Int32 BrowseBox::GetRowCount() const
866
0
{
867
0
    return nRowCount;
868
0
}
869
870
sal_uInt16 BrowseBox::ColCount() const
871
0
{
872
0
    return static_cast<sal_uInt16>(mvCols.size());
873
0
}
874
875
tools::Long BrowseBox::ImpGetDataRowHeight() const
876
0
{
877
0
    BrowseBox *pThis = const_cast<BrowseBox*>(this);
878
0
    pThis->m_nDataRowHeight = pThis->CalcReverseZoom(pDataWin->GetTextHeight() + 4);
879
0
    pThis->Resize();
880
0
    pDataWin->Invalidate();
881
0
    return m_nDataRowHeight;
882
0
}
883
884
void BrowseBox::SetDataRowHeight( tools::Long nPixel )
885
0
{
886
887
0
    m_nDataRowHeight = CalcReverseZoom(nPixel);
888
0
    Resize();
889
0
    pDataWin->Invalidate();
890
0
}
891
892
void BrowseBox::SetTitleLines( sal_uInt16 nLines )
893
0
{
894
895
0
    nTitleLines = nLines;
896
0
}
897
898
sal_Int32 BrowseBox::ScrollColumns( sal_Int32 nCols )
899
0
{
900
901
0
    if ( nFirstCol + nCols < 0 ||
902
0
         o3tl::make_unsigned(nFirstCol + nCols) >= mvCols.size() )
903
0
        return 0;
904
905
    // implicitly hides cursor while scrolling
906
0
    StartScroll();
907
0
    bScrolling = true;
908
0
    bool bScrollable = pDataWin->GetBackground().IsScrollable();
909
0
    bool bInvalidateView = false;
910
911
    // scrolling one column to the right?
912
0
    if ( nCols == 1 )
913
0
    {
914
        // update internal value and scrollbar
915
0
        ++nFirstCol;
916
0
        aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
917
918
0
        if ( !bScrollable )
919
0
        {
920
0
            bInvalidateView = true;
921
0
        }
922
0
        else
923
0
        {
924
0
            tools::Long nDelta = mvCols[ nFirstCol-1 ]->Width();
925
0
            tools::Long nFrozenWidth = GetFrozenWidth();
926
927
0
            tools::Rectangle aScrollRect(  Point( nFrozenWidth + nDelta, 0 ),
928
0
                                    Size ( GetOutputSizePixel().Width() - nFrozenWidth - nDelta,
929
0
                                           GetTitleHeight() - 1
930
0
                                         ) );
931
932
            // scroll the header bar area (if there is no dedicated HeaderBar control)
933
0
            if ( !pDataWin->pHeaderBar && nTitleLines )
934
0
            {
935
                // actually scroll
936
0
                Scroll( -nDelta, 0, aScrollRect, SCROLL_FLAGS );
937
938
                // invalidate the area of the column which was scrolled out to the left hand side
939
0
                tools::Rectangle aInvalidateRect( aScrollRect );
940
0
                aInvalidateRect.SetLeft( nFrozenWidth );
941
0
                aInvalidateRect.SetRight( nFrozenWidth + nDelta - 1 );
942
0
                Invalidate( aInvalidateRect );
943
0
            }
944
945
            // scroll the data-area
946
0
            aScrollRect.SetBottom( pDataWin->GetOutputSizePixel().Height() );
947
948
            // actually scroll
949
0
            pDataWin->Scroll( -nDelta, 0, aScrollRect, SCROLL_FLAGS );
950
951
            // invalidate the area of the column which was scrolled out to the left hand side
952
0
            aScrollRect.SetLeft( nFrozenWidth );
953
0
            aScrollRect.SetRight( nFrozenWidth + nDelta - 1 );
954
0
            pDataWin->Invalidate( aScrollRect );
955
0
        }
956
0
    }
957
958
    // scrolling one column to the left?
959
0
    else if ( nCols == -1 )
960
0
    {
961
0
        --nFirstCol;
962
0
        aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
963
964
0
        if ( !bScrollable )
965
0
        {
966
0
            bInvalidateView = true;
967
0
        }
968
0
        else
969
0
        {
970
0
            tools::Long nDelta = mvCols[ nFirstCol ]->Width();
971
0
            tools::Long nFrozenWidth = GetFrozenWidth();
972
973
0
            tools::Rectangle aScrollRect(  Point(  nFrozenWidth, 0 ),
974
0
                                    Size (  GetOutputSizePixel().Width() - nFrozenWidth,
975
0
                                            GetTitleHeight() - 1
976
0
                                         ) );
977
978
            // scroll the header bar area (if there is no dedicated HeaderBar control)
979
0
            if ( !pDataWin->pHeaderBar && nTitleLines )
980
0
            {
981
0
                Scroll( nDelta, 0, aScrollRect, SCROLL_FLAGS );
982
0
            }
983
984
            // scroll the data-area
985
0
            aScrollRect.SetBottom( pDataWin->GetOutputSizePixel().Height() );
986
0
            pDataWin->Scroll( nDelta, 0, aScrollRect, SCROLL_FLAGS );
987
0
        }
988
0
    }
989
0
    else
990
0
    {
991
0
        if ( GetUpdateMode() )
992
0
        {
993
0
            Invalidate( tools::Rectangle(
994
0
                Point( GetFrozenWidth(), 0 ),
995
0
                Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
996
0
            pDataWin->Invalidate( tools::Rectangle(
997
0
                Point( GetFrozenWidth(), 0 ),
998
0
                pDataWin->GetSizePixel() ) );
999
0
        }
1000
1001
0
        nFirstCol = nFirstCol + static_cast<sal_uInt16>(nCols);
1002
0
        aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
1003
0
    }
1004
1005
    // adjust external headerbar, if necessary
1006
0
    if ( pDataWin->pHeaderBar )
1007
0
    {
1008
0
        tools::Long nWidth = 0;
1009
0
        for ( size_t nCol = 0;
1010
0
              nCol < mvCols.size() && nCol < nFirstCol;
1011
0
              ++nCol )
1012
0
        {
1013
            // not the handle column
1014
0
            if ( mvCols[ nCol ]->GetId() )
1015
0
                nWidth += mvCols[ nCol ]->Width();
1016
0
        }
1017
1018
0
        pDataWin->pHeaderBar->SetOffset( nWidth );
1019
0
    }
1020
1021
0
    if( bInvalidateView )
1022
0
    {
1023
0
        Control::Invalidate( InvalidateFlags::NoChildren );
1024
0
        pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
1025
0
    }
1026
1027
    // implicitly show cursor after scrolling
1028
0
    if ( nCols )
1029
0
    {
1030
0
        pDataWin->Update();
1031
0
        PaintImmediately();
1032
0
    }
1033
0
    bScrolling = false;
1034
0
    EndScroll();
1035
1036
0
    return nCols;
1037
0
}
1038
1039
1040
sal_Int32 BrowseBox::ScrollRows( sal_Int32 nRows )
1041
0
{
1042
    // compute new top row
1043
0
    sal_Int32 nTmpMin = std::min( static_cast<sal_Int32>(nTopRow + nRows), static_cast<sal_Int32>(nRowCount - 1) );
1044
1045
0
    sal_Int32 nNewTopRow = std::max<sal_Int32>( nTmpMin, 0 );
1046
1047
0
    if ( nNewTopRow == nTopRow )
1048
0
        return 0;
1049
1050
0
    sal_uInt16 nVisibleRows =
1051
0
        static_cast<sal_uInt16>(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1052
1053
0
    VisibleRowsChanged(nNewTopRow, nVisibleRows);
1054
1055
    // compute new top row again (nTopRow might have changed!)
1056
0
    nTmpMin = std::min( static_cast<tools::Long>(nTopRow + nRows), static_cast<tools::Long>(nRowCount - 1) );
1057
1058
0
    nNewTopRow = std::max<tools::Long>( nTmpMin, 0 );
1059
1060
0
    StartScroll();
1061
1062
    // scroll area on screen and/or repaint
1063
0
    tools::Long nDeltaY = GetDataRowHeight() * ( nNewTopRow - nTopRow );
1064
0
    sal_Int32 nOldTopRow = nTopRow;
1065
0
    nTopRow = nNewTopRow;
1066
1067
0
    if ( GetUpdateMode() )
1068
0
    {
1069
0
        pVScroll->SetRange( Range( 0L, nRowCount ) );
1070
0
        pVScroll->SetThumbPos( nTopRow );
1071
1072
0
        if( pDataWin->GetBackground().IsScrollable() &&
1073
0
            std::abs( nDeltaY ) > 0 &&
1074
0
            std::abs( nDeltaY ) < pDataWin->GetSizePixel().Height() )
1075
0
        {
1076
0
            pDataWin->Scroll( 0, static_cast<short>(-nDeltaY), SCROLL_FLAGS );
1077
0
        }
1078
0
        else
1079
0
            pDataWin->Invalidate();
1080
1081
0
        if ( nTopRow - nOldTopRow )
1082
0
            pDataWin->Update();
1083
0
    }
1084
1085
0
    EndScroll();
1086
1087
0
    return nTopRow - nOldTopRow;
1088
0
}
1089
1090
1091
void BrowseBox::RowModified( sal_Int32 nRow, sal_uInt16 nColId )
1092
0
{
1093
1094
0
    if ( !GetUpdateMode() )
1095
0
        return;
1096
1097
0
    tools::Rectangle aRect;
1098
0
    if ( nColId == BROWSER_INVALIDID )
1099
        // invalidate the whole row
1100
0
        aRect = tools::Rectangle( Point( 0, (nRow-nTopRow) * GetDataRowHeight() ),
1101
0
                    Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) );
1102
0
    else
1103
0
    {
1104
        // invalidate the specific field
1105
0
        aRect = GetFieldRectPixel( nRow, nColId, false );
1106
0
    }
1107
0
    pDataWin->Invalidate( aRect );
1108
0
}
1109
1110
1111
void BrowseBox::Clear()
1112
0
{
1113
    // adjust the total number of rows
1114
0
    DoHideCursor();
1115
0
    sal_Int32 nOldRowCount = nRowCount;
1116
0
    nRowCount = 0;
1117
0
    if(bMultiSelection)
1118
0
    {
1119
0
        assert(uRow.pSel);
1120
0
        uRow.pSel->Reset();
1121
0
    }
1122
0
    else
1123
0
        uRow.nSel = BROWSER_ENDOFSELECTION;
1124
0
    nCurRow = BROWSER_ENDOFSELECTION;
1125
0
    nTopRow = 0;
1126
0
    nCurColId = 0;
1127
1128
    // nFirstCol may not be reset, else the scrolling code will become confused.
1129
    // nFirstCol may only be changed when adding or deleting columns
1130
    // nFirstCol = 0; -> wrong!
1131
0
    aHScroll->SetThumbPos( 0 );
1132
0
    pVScroll->SetThumbPos( 0 );
1133
1134
0
    Invalidate();
1135
0
    UpdateScrollbars();
1136
0
    SetNoSelection();
1137
0
    DoShowCursor();
1138
0
    CursorMoved();
1139
1140
0
    if ( !isAccessibleAlive() )
1141
0
        return;
1142
1143
    // all rows should be removed, so we remove the row header bar and append it again
1144
    // to avoid to notify every row remove
1145
0
    if ( nOldRowCount == nRowCount )
1146
0
        return;
1147
1148
0
    commitBrowseBoxEvent(
1149
0
        AccessibleEventId::CHILD,
1150
0
        Any(),
1151
0
        Any(getAccessibleHeaderBar( AccessibleBrowseBoxObjType::RowHeaderBar))
1152
0
    );
1153
1154
    // and now append it again
1155
0
    commitBrowseBoxEvent(
1156
0
        AccessibleEventId::CHILD,
1157
0
        Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)),
1158
0
        Any()
1159
0
    );
1160
1161
    // notify a table model change
1162
0
    commitTableEvent(
1163
0
        AccessibleEventId::TABLE_MODEL_CHANGED,
1164
0
        Any( AccessibleTableModelChange(ROWS_REMOVED,
1165
0
            0,
1166
0
            nOldRowCount,
1167
0
            -1,
1168
0
            -1)
1169
0
        ),
1170
0
        Any()
1171
0
    );
1172
0
}
1173
1174
void BrowseBox::RowInserted( sal_Int32 nRow, sal_Int32 nNumRows, bool bDoPaint, bool bKeepSelection )
1175
0
{
1176
1177
0
    if (nRow < 0)
1178
0
        nRow = 0;
1179
0
    else if (nRow > nRowCount) // maximal = nRowCount
1180
0
        nRow = nRowCount;
1181
1182
0
    if ( nNumRows <= 0 )
1183
0
        return;
1184
1185
    // adjust total row count
1186
0
    bool bLastRow = nRow >= nRowCount;
1187
0
    nRowCount += nNumRows;
1188
1189
0
    DoHideCursor();
1190
1191
    // must we paint the new rows?
1192
0
    sal_Int32 nOldCurRow = nCurRow;
1193
0
    Size aSz = pDataWin->GetOutputSizePixel();
1194
0
    if ( bDoPaint && nRow >= nTopRow &&
1195
0
         nRow <= nTopRow + aSz.Height() / GetDataRowHeight() )
1196
0
    {
1197
0
        tools::Long nY = (nRow-nTopRow) * GetDataRowHeight();
1198
0
        if ( !bLastRow )
1199
0
        {
1200
            // scroll down the rows behind the new row
1201
0
            pDataWin->GetOutDev()->SetClipRegion();
1202
0
            if( pDataWin->GetBackground().IsScrollable() )
1203
0
            {
1204
0
                pDataWin->Scroll( 0, GetDataRowHeight() * nNumRows,
1205
0
                                tools::Rectangle( Point( 0, nY ),
1206
0
                                        Size( aSz.Width(), aSz.Height() - nY ) ),
1207
0
                                SCROLL_FLAGS );
1208
0
            }
1209
0
            else
1210
0
                pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
1211
0
        }
1212
0
        else
1213
            // scroll would cause a repaint, so we must explicitly invalidate
1214
0
            pDataWin->Invalidate( tools::Rectangle( Point( 0, nY ),
1215
0
                         Size( aSz.Width(), nNumRows * GetDataRowHeight() ) ) );
1216
0
    }
1217
1218
    // correct top row if necessary
1219
0
    if ( nRow < nTopRow )
1220
0
        nTopRow += nNumRows;
1221
1222
    // adjust the selection
1223
0
    if ( bMultiSelection )
1224
0
        uRow.pSel->Insert( nRow, nNumRows );
1225
0
    else if ( uRow.nSel != BROWSER_ENDOFSELECTION && nRow <= uRow.nSel )
1226
0
        uRow.nSel += nNumRows;
1227
1228
    // adjust the cursor
1229
0
    if ( nCurRow == BROWSER_ENDOFSELECTION )
1230
0
        GoToRow( 0, false, bKeepSelection );
1231
0
    else if ( nRow <= nCurRow )
1232
0
    {
1233
0
        nCurRow += nNumRows;
1234
0
        GoToRow( nCurRow, false, bKeepSelection );
1235
0
    }
1236
1237
    // adjust the vertical scrollbar
1238
0
    if ( bDoPaint )
1239
0
    {
1240
0
        UpdateScrollbars();
1241
0
        AutoSizeLastColumn();
1242
0
    }
1243
1244
0
    DoShowCursor();
1245
    // notify accessible that rows were inserted
1246
0
    if ( isAccessibleAlive() )
1247
0
    {
1248
0
        commitTableEvent(
1249
0
            AccessibleEventId::TABLE_MODEL_CHANGED,
1250
0
            Any( AccessibleTableModelChange(
1251
0
                        ROWS_INSERTED,
1252
0
                        nRow,
1253
0
                        nRow + nNumRows,
1254
0
                        -1,
1255
0
                        -1
1256
0
                    )
1257
0
            ),
1258
0
            Any()
1259
0
        );
1260
1261
0
        for (tools::Long i = nRow+1 ; i <= nRowCount ; ++i)
1262
0
        {
1263
0
            commitHeaderBarEvent(
1264
0
                AccessibleEventId::CHILD,
1265
0
                Any( CreateAccessibleRowHeader( i ) ),
1266
0
                Any(),
1267
0
                false
1268
0
            );
1269
0
        }
1270
0
    }
1271
1272
0
    if ( nCurRow != nOldCurRow )
1273
0
        CursorMoved();
1274
1275
0
    DBG_ASSERT(nRowCount > 0,"BrowseBox: nRowCount <= 0");
1276
0
    DBG_ASSERT(nCurRow >= 0,"BrowseBox: nCurRow < 0");
1277
0
    DBG_ASSERT(nCurRow < nRowCount,"nCurRow >= nRowCount");
1278
0
}
1279
1280
1281
void BrowseBox::RowRemoved( sal_Int32 nRow, sal_Int32 nNumRows, bool bDoPaint )
1282
0
{
1283
1284
0
    if ( nRow < 0 )
1285
0
        nRow = 0;
1286
0
    else if ( nRow >= nRowCount )
1287
0
        nRow = nRowCount - 1;
1288
1289
0
    if ( nNumRows <= 0 )
1290
0
        return;
1291
1292
0
    if ( nRowCount <= 0 )
1293
0
        return;
1294
1295
0
    if ( bDoPaint )
1296
0
    {
1297
        // hide cursor and selection
1298
0
        SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1299
0
        ToggleSelection();
1300
0
        DoHideCursor();
1301
0
    }
1302
1303
    // adjust total row count
1304
0
    nRowCount -= nNumRows;
1305
0
    if (nRowCount < 0) nRowCount = 0;
1306
0
    sal_Int32 nOldCurRow = nCurRow;
1307
1308
    // adjust the selection
1309
0
    if ( bMultiSelection )
1310
        // uRow.pSel->Remove( nRow, nNumRows );
1311
0
        for ( tools::Long i = 0; i < nNumRows; i++ )
1312
0
            uRow.pSel->Remove( nRow );
1313
0
    else if ( nRow < uRow.nSel && uRow.nSel >= nNumRows )
1314
0
        uRow.nSel -= nNumRows;
1315
0
    else if ( nRow <= uRow.nSel )
1316
0
        uRow.nSel = BROWSER_ENDOFSELECTION;
1317
1318
    // adjust the cursor
1319
0
    if ( nRowCount == 0 )   // don't compare nRowCount with nNumRows as nNumRows already was subtracted from nRowCount
1320
0
        nCurRow = BROWSER_ENDOFSELECTION;
1321
0
    else if ( nRow < nCurRow )
1322
0
    {
1323
0
        nCurRow -= std::min( nCurRow - nRow, nNumRows );
1324
        // with the above nCurRow points a) to the first row after the removed block or b) to the same line
1325
        // as before, but moved up nNumRows
1326
        // case a) needs an additional correction if the last n lines were deleted, as 'the first row after the
1327
        // removed block' is an invalid position then
1328
        // FS - 09/28/99 - 68429
1329
0
        if (nCurRow == nRowCount)
1330
0
            --nCurRow;
1331
0
    }
1332
0
    else if( nRow == nCurRow && nCurRow == nRowCount )
1333
0
        nCurRow = nRowCount-1;
1334
1335
    // is the deleted row visible?
1336
0
    Size aSz = pDataWin->GetOutputSizePixel();
1337
0
    if ( nRow >= nTopRow &&
1338
0
         nRow <= nTopRow + aSz.Height() / GetDataRowHeight() )
1339
0
    {
1340
0
        if ( bDoPaint )
1341
0
        {
1342
            // scroll up the rows behind the deleted row
1343
            // if there are Rows behind
1344
0
            if (nRow < nRowCount)
1345
0
            {
1346
0
                tools::Long nY = (nRow-nTopRow) * GetDataRowHeight();
1347
0
                pDataWin->GetOutDev()->SetClipRegion();
1348
0
                if( pDataWin->GetBackground().IsScrollable() )
1349
0
                {
1350
0
                    pDataWin->Scroll( 0, - static_cast<short>(GetDataRowHeight()) * nNumRows,
1351
0
                        tools::Rectangle( Point( 0, nY ), Size( aSz.Width(),
1352
0
                            aSz.Height() - nY + nNumRows*GetDataRowHeight() ) ),
1353
0
                            SCROLL_FLAGS );
1354
0
                }
1355
0
                else
1356
0
                    pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
1357
0
            }
1358
0
            else
1359
0
            {
1360
                // Repaint the Rect of the deleted row
1361
0
                tools::Rectangle aRect(
1362
0
                        Point( 0, (nRow-nTopRow)*GetDataRowHeight() ),
1363
0
                        Size( pDataWin->GetSizePixel().Width(),
1364
0
                              nNumRows * GetDataRowHeight() ) );
1365
0
                pDataWin->Invalidate( aRect );
1366
0
            }
1367
0
        }
1368
0
    }
1369
    // is the deleted row above of the visible area?
1370
0
    else if ( nRow < nTopRow )
1371
0
        nTopRow = nTopRow >= nNumRows ? nTopRow-nNumRows : 0;
1372
1373
0
    if ( bDoPaint )
1374
0
    {
1375
        // reshow cursor and selection
1376
0
        ToggleSelection();
1377
0
        SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1378
0
        DoShowCursor();
1379
1380
        // adjust the vertical scrollbar
1381
0
        UpdateScrollbars();
1382
0
        AutoSizeLastColumn();
1383
0
    }
1384
1385
0
    if ( isAccessibleAlive() )
1386
0
    {
1387
0
        if ( nRowCount == 0 )
1388
0
        {
1389
            // all columns should be removed, so we remove the column header bar and append it again
1390
            // to avoid to notify every column remove
1391
0
            commitBrowseBoxEvent(
1392
0
                AccessibleEventId::CHILD,
1393
0
                Any(),
1394
0
                Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar))
1395
0
            );
1396
1397
            // and now append it again
1398
0
            commitBrowseBoxEvent(
1399
0
                AccessibleEventId::CHILD,
1400
0
                Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)),
1401
0
                Any()
1402
0
            );
1403
0
            commitBrowseBoxEvent(
1404
0
                AccessibleEventId::CHILD,
1405
0
                Any(),
1406
0
                Any(getAccessibleTable())
1407
0
            );
1408
1409
            // and now append it again
1410
0
            commitBrowseBoxEvent(
1411
0
                AccessibleEventId::CHILD,
1412
0
                Any(getAccessibleTable()),
1413
0
                Any()
1414
0
            );
1415
0
        }
1416
0
        else
1417
0
        {
1418
0
            commitTableEvent(
1419
0
                AccessibleEventId::TABLE_MODEL_CHANGED,
1420
0
                Any( AccessibleTableModelChange(
1421
0
                            ROWS_REMOVED,
1422
0
                            nRow,
1423
0
                            nRow + nNumRows,
1424
0
                            -1,
1425
0
                            -1
1426
0
                            )
1427
0
                ),
1428
0
                Any()
1429
0
            );
1430
1431
0
            for (tools::Long i = nRow+1 ; i <= (nRow+nNumRows) ; ++i)
1432
0
            {
1433
0
                commitHeaderBarEvent(
1434
0
                    AccessibleEventId::CHILD,
1435
0
                    Any(),
1436
0
                    Any( CreateAccessibleRowHeader( i ) ),
1437
0
                    false
1438
0
                );
1439
0
            }
1440
0
        }
1441
0
    }
1442
1443
0
    if ( nOldCurRow != nCurRow )
1444
0
        CursorMoved();
1445
1446
0
    DBG_ASSERT(nRowCount >= 0,"BrowseBox: nRowCount < 0");
1447
0
    DBG_ASSERT(nCurRow >= 0 || nRowCount == 0,"BrowseBox: nCurRow < 0 && nRowCount != 0");
1448
0
    DBG_ASSERT(nCurRow < nRowCount,"nCurRow >= nRowCount");
1449
0
}
1450
1451
1452
bool BrowseBox::GoToRow( sal_Int32 nRow)
1453
0
{
1454
0
    return GoToRow(nRow, false);
1455
0
}
1456
1457
1458
bool BrowseBox::GoToRow( sal_Int32 nRow, bool bRowColMove, bool bKeepSelection )
1459
0
{
1460
0
    sal_Int32 nOldCurRow = nCurRow;
1461
1462
    // nothing to do?
1463
0
    if ( nRow == nCurRow && ( bMultiSelection || uRow.nSel == nRow ) )
1464
0
        return true;
1465
1466
    // out of range?
1467
0
    if ( nRow < 0 || nRow >= nRowCount )
1468
0
        return false;
1469
1470
    // not allowed?
1471
0
    if ( !bRowColMove && !IsCursorMoveAllowed( nRow, nCurColId ) )
1472
0
        return false;
1473
1474
    // compute the last visible row
1475
0
    Size aSz( pDataWin->GetSizePixel() );
1476
0
    sal_uInt16 nVisibleRows = sal_uInt16( aSz.Height() / GetDataRowHeight() - 1 );
1477
0
    sal_Int32 nLastRow = nTopRow + nVisibleRows;
1478
1479
    // suspend Updates
1480
0
    pDataWin->EnterUpdateLock();
1481
1482
    // remove old highlight, if necessary
1483
0
    if ( !bMultiSelection && !bKeepSelection )
1484
0
        ToggleSelection();
1485
0
    DoHideCursor();
1486
1487
    // must we scroll?
1488
0
    bool bWasVisible = bSelectionIsVisible;
1489
0
    if (! bMultiSelection)
1490
0
    {
1491
0
        if( !bKeepSelection )
1492
0
            bSelectionIsVisible = false;
1493
0
    }
1494
0
    if ( nRow < nTopRow )
1495
0
        ScrollRows( nRow - nTopRow );
1496
0
    else if ( nRow > nLastRow )
1497
0
        ScrollRows( nRow - nLastRow );
1498
0
    bSelectionIsVisible = bWasVisible;
1499
1500
    // adjust cursor (selection) and thumb
1501
0
    if ( GetUpdateMode() )
1502
0
        pVScroll->SetThumbPos( nTopRow );
1503
1504
    // relative positioning (because nCurRow might have changed in the meantime)!
1505
0
    if (nCurRow != BROWSER_ENDOFSELECTION )
1506
0
        nCurRow = nCurRow + (nRow - nOldCurRow);
1507
1508
    // make sure that the current position is valid
1509
0
    if (nCurRow == BROWSER_ENDOFSELECTION && nRowCount > 0)
1510
0
        nCurRow = 0;
1511
0
    else if ( nCurRow >= nRowCount )
1512
0
        nCurRow = nRowCount - 1;
1513
0
    aSelRange = Range( nCurRow, nCurRow );
1514
1515
    // display new highlight if necessary
1516
0
    if ( !bMultiSelection && !bKeepSelection )
1517
0
        uRow.nSel = nRow;
1518
1519
    // resume Updates
1520
0
    pDataWin->LeaveUpdateLock();
1521
1522
    // Cursor+Highlight
1523
0
    if ( !bMultiSelection && !bKeepSelection)
1524
0
        ToggleSelection();
1525
0
    DoShowCursor();
1526
0
    if ( !bRowColMove  && nOldCurRow != nCurRow )
1527
0
        CursorMoved();
1528
1529
0
    if ( !bMultiSelection && !bKeepSelection )
1530
0
    {
1531
0
        if ( !bSelecting )
1532
0
            Select();
1533
0
        else
1534
0
            bSelect = true;
1535
0
    }
1536
0
    return true;
1537
0
}
1538
1539
1540
bool BrowseBox::GoToColumnId( sal_uInt16 nColId)
1541
0
{
1542
0
    return GoToColumnId(nColId, true);
1543
0
}
1544
1545
1546
bool BrowseBox::GoToColumnId( sal_uInt16 nColId, bool bMakeVisible, bool bRowColMove)
1547
0
{
1548
0
    if (!bColumnCursor)
1549
0
        return false;
1550
1551
    // allowed?
1552
0
    if (!bRowColMove && !IsCursorMoveAllowed( nCurRow, nColId ) )
1553
0
        return false;
1554
1555
0
    if ( nColId != nCurColId || (bMakeVisible && !IsFieldVisible(nCurRow, nColId, true)))
1556
0
    {
1557
0
        sal_uInt16 nNewPos = GetColumnPos(nColId);
1558
0
        BrowserColumn* pColumn = (nNewPos < mvCols.size()) ? mvCols[ nNewPos ].get() : nullptr;
1559
0
        DBG_ASSERT( pColumn, "no column object - invalid id?" );
1560
0
        if ( !pColumn )
1561
0
            return false;
1562
1563
0
        DoHideCursor();
1564
0
        nCurColId = nColId;
1565
1566
0
        bool bScrolled = false;
1567
1568
0
        sal_uInt16 nFirstPos = nFirstCol;
1569
0
        sal_uInt16 nWidth = static_cast<sal_uInt16>(pColumn->Width());
1570
0
        sal_uInt16 nLastPos = GetColumnAtXPosPixel(
1571
0
                            pDataWin->GetSizePixel().Width()-nWidth );
1572
0
        sal_uInt16 nFrozen = FrozenColCount();
1573
0
        if ( bMakeVisible && nLastPos &&
1574
0
             nNewPos >= nFrozen && ( nNewPos < nFirstPos || nNewPos > nLastPos ) )
1575
0
        {
1576
0
            if ( nNewPos < nFirstPos )
1577
0
                ScrollColumns( nNewPos-nFirstPos );
1578
0
            else if ( nNewPos > nLastPos )
1579
0
                ScrollColumns( nNewPos-nLastPos );
1580
0
            bScrolled = true;
1581
0
        }
1582
1583
0
        DoShowCursor();
1584
0
        if (!bRowColMove)
1585
0
        {
1586
            //try to move to nCurRow, nColId
1587
0
            CursorMoveAttempt aAttempt(nCurRow, nColId, bScrolled);
1588
            //Detect if we are already in a call to BrowseBox::GoToColumnId
1589
            //but the attempt is impossible and we are simply recursing
1590
            //into BrowseBox::GoToColumnId with the same impossible to
1591
            //fulfill conditions
1592
0
            if (m_aGotoStack.empty() || aAttempt != m_aGotoStack.top())
1593
0
            {
1594
0
                m_aGotoStack.push(aAttempt);
1595
0
                CursorMoved();
1596
0
                m_aGotoStack.pop();
1597
0
            }
1598
0
        }
1599
0
        return true;
1600
0
    }
1601
0
    return true;
1602
0
}
1603
1604
1605
bool BrowseBox::GoToRowColumnId( sal_Int32 nRow, sal_uInt16 nColId )
1606
0
{
1607
1608
    // out of range?
1609
0
    if ( nRow < 0 || nRow >= nRowCount )
1610
0
        return false;
1611
1612
0
    if (!bColumnCursor)
1613
0
        return false;
1614
1615
    // nothing to do ?
1616
0
    if ( nRow == nCurRow && ( bMultiSelection || uRow.nSel == nRow ) &&
1617
0
         nColId == nCurColId && IsFieldVisible(nCurRow, nColId, true))
1618
0
        return true;
1619
1620
    // allowed?
1621
0
    if (!IsCursorMoveAllowed(nRow, nColId))
1622
0
        return false;
1623
1624
0
    DoHideCursor();
1625
0
    bool bMoved = GoToRow(nRow, true) && GoToColumnId(nColId, true, true);
1626
0
    DoShowCursor();
1627
1628
0
    if (bMoved)
1629
0
        CursorMoved();
1630
1631
0
    return bMoved;
1632
0
}
1633
1634
1635
void BrowseBox::SetNoSelection()
1636
0
{
1637
1638
    // is there no selection
1639
0
    if ( ( !pColSel || !pColSel->GetSelectCount() ) &&
1640
0
         ( ( !bMultiSelection && uRow.nSel == BROWSER_ENDOFSELECTION ) ||
1641
0
           ( bMultiSelection && !uRow.pSel->GetSelectCount() ) ) )
1642
        // nothing to do
1643
0
        return;
1644
1645
0
    SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1646
0
    ToggleSelection();
1647
1648
    // unselect all
1649
0
    if ( bMultiSelection )
1650
0
        uRow.pSel->SelectAll(false);
1651
0
    else
1652
0
        uRow.nSel = BROWSER_ENDOFSELECTION;
1653
0
    if ( pColSel )
1654
0
        pColSel->SelectAll(false);
1655
0
    if ( !bSelecting )
1656
0
        Select();
1657
0
    else
1658
0
        bSelect = true;
1659
1660
    // restore screen
1661
0
    SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1662
1663
0
    if ( isAccessibleAlive() )
1664
0
    {
1665
0
        commitTableEvent(
1666
0
            AccessibleEventId::SELECTION_CHANGED,
1667
0
            Any(),
1668
0
            Any()
1669
0
        );
1670
0
    }
1671
0
}
1672
1673
1674
void BrowseBox::SelectAll()
1675
0
{
1676
1677
0
    if ( !bMultiSelection )
1678
0
        return;
1679
1680
0
    SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1681
0
    ToggleSelection();
1682
1683
    // select all rows
1684
0
    if ( pColSel )
1685
0
        pColSel->SelectAll(false);
1686
0
    uRow.pSel->SelectAll();
1687
1688
    // don't highlight handle column
1689
0
    BrowserColumn *pFirstCol = mvCols[ 0 ].get();
1690
0
    tools::Long nOfsX = pFirstCol->GetId() ? 0 : pFirstCol->Width();
1691
1692
    // highlight the row selection
1693
0
    if ( !bHideSelect )
1694
0
    {
1695
0
        tools::Rectangle aHighlightRect;
1696
0
        sal_uInt16 nVisibleRows =
1697
0
            static_cast<sal_uInt16>(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1698
0
        for ( sal_Int32 nRow = std::max<sal_Int32>( nTopRow, uRow.pSel->FirstSelected() );
1699
0
              nRow != BROWSER_ENDOFSELECTION && nRow < nTopRow + nVisibleRows;
1700
0
              nRow = uRow.pSel->NextSelected() )
1701
0
            aHighlightRect.Union( tools::Rectangle(
1702
0
                Point( nOfsX, (nRow-nTopRow)*GetDataRowHeight() ),
1703
0
                Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) ) );
1704
0
        pDataWin->Invalidate( aHighlightRect );
1705
0
    }
1706
1707
0
    if ( !bSelecting )
1708
0
        Select();
1709
0
    else
1710
0
        bSelect = true;
1711
1712
    // restore screen
1713
0
    SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1714
1715
0
    if ( !isAccessibleAlive() )
1716
0
        return;
1717
1718
0
    commitTableEvent(
1719
0
        AccessibleEventId::SELECTION_CHANGED,
1720
0
        Any(),
1721
0
        Any()
1722
0
    );
1723
0
    commitHeaderBarEvent(
1724
0
        AccessibleEventId::SELECTION_CHANGED,
1725
0
        Any(),
1726
0
        Any(),
1727
0
        true
1728
0
    ); // column header event
1729
1730
0
    commitHeaderBarEvent(
1731
0
        AccessibleEventId::SELECTION_CHANGED,
1732
0
        Any(),
1733
0
        Any(),
1734
0
        false
1735
0
    ); // row header event
1736
0
}
1737
1738
1739
void BrowseBox::SelectRow( sal_Int32 nRow, bool _bSelect, bool bExpand )
1740
0
{
1741
1742
0
    if ( !bMultiSelection )
1743
0
    {
1744
        // deselecting is impossible, selecting via cursor
1745
0
        if ( _bSelect )
1746
0
            GoToRow(nRow, false);
1747
0
        return;
1748
0
    }
1749
1750
0
    SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1751
1752
    // remove old selection?
1753
0
    if ( !bExpand || !bMultiSelection )
1754
0
    {
1755
0
        ToggleSelection();
1756
0
        if ( bMultiSelection )
1757
0
            uRow.pSel->SelectAll(false);
1758
0
        else
1759
0
            uRow.nSel = BROWSER_ENDOFSELECTION;
1760
0
        if ( pColSel )
1761
0
            pColSel->SelectAll(false);
1762
0
    }
1763
1764
    // set new selection
1765
0
    if  (   !bHideSelect
1766
0
        &&  (   (   bMultiSelection
1767
0
                &&  uRow.pSel->GetTotalRange().Max() >= nRow
1768
0
                &&  uRow.pSel->Select( nRow, _bSelect )
1769
0
                )
1770
0
            ||  (   !bMultiSelection
1771
0
                &&  ( uRow.nSel = nRow ) != BROWSER_ENDOFSELECTION )
1772
0
                )
1773
0
            )
1774
0
    {
1775
        // don't highlight handle column
1776
0
        BrowserColumn *pFirstCol = mvCols[ 0 ].get();
1777
0
        tools::Long nOfsX = pFirstCol->GetId() ? 0 : pFirstCol->Width();
1778
1779
        // highlight only newly selected part
1780
0
        tools::Rectangle aRect(
1781
0
            Point( nOfsX, (nRow-nTopRow)*GetDataRowHeight() ),
1782
0
            Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) );
1783
0
        pDataWin->Invalidate( aRect );
1784
0
    }
1785
1786
0
    if ( !bSelecting )
1787
0
        Select();
1788
0
    else
1789
0
        bSelect = true;
1790
1791
    // restore screen
1792
0
    SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1793
1794
0
    if ( !isAccessibleAlive() )
1795
0
        return;
1796
1797
0
    commitTableEvent(
1798
0
        AccessibleEventId::SELECTION_CHANGED,
1799
0
        Any(),
1800
0
        Any()
1801
0
    );
1802
0
    commitHeaderBarEvent(
1803
0
        AccessibleEventId::SELECTION_CHANGED,
1804
0
        Any(),
1805
0
        Any(),
1806
0
        false
1807
0
    ); // row header event
1808
0
}
1809
1810
1811
sal_Int32 BrowseBox::GetSelectRowCount() const
1812
0
{
1813
1814
0
    return bMultiSelection ? uRow.pSel->GetSelectCount() :
1815
0
           uRow.nSel == BROWSER_ENDOFSELECTION ? 0 : 1;
1816
0
}
1817
1818
1819
void BrowseBox::SelectColumnPos( sal_uInt16 nNewColPos, bool _bSelect, bool bMakeVisible )
1820
0
{
1821
1822
0
    if ( !bColumnCursor || nNewColPos == BROWSER_INVALIDID )
1823
0
        return;
1824
1825
0
    if ( !bMultiSelection )
1826
0
    {
1827
0
        if ( _bSelect )
1828
0
            GoToColumnId( mvCols[ nNewColPos ]->GetId(), bMakeVisible );
1829
0
        return;
1830
0
    }
1831
0
    else
1832
0
    {
1833
0
        if ( !GoToColumnId( mvCols[ nNewColPos ]->GetId(), bMakeVisible ) )
1834
0
            return;
1835
0
    }
1836
1837
0
    SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1838
0
    ToggleSelection();
1839
0
    if ( bMultiSelection )
1840
0
        uRow.pSel->SelectAll(false);
1841
0
    else
1842
0
        uRow.nSel = BROWSER_ENDOFSELECTION;
1843
0
    pColSel->SelectAll(false);
1844
1845
0
    if ( pColSel->Select( nNewColPos, _bSelect ) )
1846
0
    {
1847
        // GoToColumnId( mvCols->GetObject(nNewColPos)->GetId(), bMakeVisible );
1848
1849
        // only highlight painted areas
1850
0
        pDataWin->Update();
1851
0
        tools::Rectangle aFieldRectPix( GetFieldRectPixel( nCurRow, nCurColId, false ) );
1852
0
        tools::Rectangle aRect(
1853
0
            Point( aFieldRectPix.Left() - MIN_COLUMNWIDTH, 0 ),
1854
0
            Size( mvCols[ nNewColPos ]->Width(),
1855
0
                  pDataWin->GetOutputSizePixel().Height() ) );
1856
0
        pDataWin->Invalidate( aRect );
1857
0
        if ( !bSelecting )
1858
0
            Select();
1859
0
        else
1860
0
            bSelect = true;
1861
1862
0
        if ( isAccessibleAlive() )
1863
0
        {
1864
0
            commitTableEvent(
1865
0
                AccessibleEventId::SELECTION_CHANGED,
1866
0
                Any(),
1867
0
                Any()
1868
0
            );
1869
0
            commitHeaderBarEvent(
1870
0
                AccessibleEventId::SELECTION_CHANGED,
1871
0
                Any(),
1872
0
                Any(),
1873
0
                true
1874
0
            ); // column header event
1875
0
        }
1876
0
    }
1877
1878
    // restore screen
1879
0
    SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1880
0
}
1881
1882
1883
sal_uInt16 BrowseBox::GetSelectColumnCount() const
1884
0
{
1885
1886
    // while bAutoSelect (==!pColSel), 1 if any rows (yes rows!) else none
1887
0
    return pColSel ? static_cast<sal_uInt16>(pColSel->GetSelectCount()) :
1888
0
           nCurRow >= 0 ? 1 : 0;
1889
0
}
1890
1891
1892
sal_Int32 BrowseBox::FirstSelectedColumn( ) const
1893
0
{
1894
0
    return pColSel ? pColSel->FirstSelected() : BROWSER_ENDOFSELECTION;
1895
0
}
1896
1897
1898
sal_Int32 BrowseBox::FirstSelectedRow()
1899
0
{
1900
1901
0
    return bMultiSelection ? uRow.pSel->FirstSelected() : uRow.nSel;
1902
0
}
1903
1904
1905
sal_Int32 BrowseBox::NextSelectedRow()
1906
0
{
1907
1908
0
    return bMultiSelection ? uRow.pSel->NextSelected() : BROWSER_ENDOFSELECTION;
1909
0
}
1910
1911
1912
sal_Int32 BrowseBox::LastSelectedRow()
1913
0
{
1914
1915
0
    return bMultiSelection ? uRow.pSel->LastSelected() : uRow.nSel;
1916
0
}
1917
1918
1919
bool BrowseBox::IsRowSelected( sal_Int32 nRow ) const
1920
0
{
1921
1922
0
    return bMultiSelection ? uRow.pSel->IsSelected(nRow) : nRow == uRow.nSel;
1923
0
}
1924
1925
1926
bool BrowseBox::IsColumnSelected( sal_uInt16 nColumnId ) const
1927
0
{
1928
1929
0
    return pColSel ? pColSel->IsSelected( GetColumnPos(nColumnId) ) :
1930
0
                     nCurColId == nColumnId;
1931
0
}
1932
1933
1934
void BrowseBox::MakeFieldVisible
1935
(
1936
    sal_Int32   nRow,       // line number of the field (starting with 0)
1937
    sal_uInt16  nColId     // column ID of the field
1938
)
1939
1940
/*  [Description]
1941
1942
    Makes visible the field described in 'nRow' and 'nColId' by scrolling
1943
    accordingly.
1944
1945
*/
1946
1947
0
{
1948
0
    if (!pDataWin)
1949
0
        return;
1950
1951
0
    Size aTestSize = pDataWin->GetSizePixel();
1952
1953
0
    if ( !bBootstrapped || aTestSize.IsEmpty() )
1954
0
        return;
1955
1956
    // is it visible already?
1957
0
    bool bVisible = IsFieldVisible( nRow, nColId, true/*bComplete*/ );
1958
0
    if ( bVisible )
1959
0
        return;
1960
1961
    // calculate column position, field rectangle and painting area
1962
0
    sal_uInt16 nColPos = GetColumnPos( nColId );
1963
0
    tools::Rectangle aFieldRect = GetFieldRectPixel( nRow, nColId, false );
1964
0
    tools::Rectangle aDataRect( Point(0, 0), pDataWin->GetSizePixel() );
1965
1966
    // positioned outside on the left?
1967
0
    if ( nColPos >= FrozenColCount() && nColPos < nFirstCol )
1968
        // => scroll to the right
1969
0
        ScrollColumns( nColPos - nFirstCol );
1970
1971
    // while outside on the right
1972
0
    while ( aDataRect.Right() < aFieldRect.Right() )
1973
0
    {
1974
        // => scroll to the left
1975
0
        if ( ScrollColumns( 1 ) != 1 )
1976
            // no more need to scroll
1977
0
            break;
1978
0
        aFieldRect = GetFieldRectPixel( nRow, nColId, false );
1979
0
    }
1980
1981
    // positioned outside above?
1982
0
    if ( nRow < nTopRow )
1983
        // scroll further to the bottom
1984
0
        ScrollRows( nRow - nTopRow );
1985
1986
    // positioned outside below?
1987
0
    sal_Int32 nBottomRow = nTopRow + GetVisibleRows();
1988
    // decrement nBottomRow to make it the number of the last visible line
1989
    // (count starts with 0!).
1990
    // Example: BrowseBox contains exactly one entry. nBottomRow := 0 + 1 - 1
1991
0
    if( nBottomRow )
1992
0
        nBottomRow--;
1993
1994
0
    if ( nRow > nBottomRow )
1995
        // scroll further to the top
1996
0
        ScrollRows( nRow - nBottomRow );
1997
0
}
1998
1999
2000
bool BrowseBox::IsFieldVisible( sal_Int32 nRow, sal_uInt16 nColumnId,
2001
                                bool bCompletely ) const
2002
0
{
2003
2004
    // hidden by frozen column?
2005
0
    sal_uInt16 nColPos = GetColumnPos( nColumnId );
2006
0
    if ( nColPos >= FrozenColCount() && nColPos < nFirstCol )
2007
0
        return false;
2008
2009
0
    tools::Rectangle aRect( ImplFieldRectPixel( nRow, nColumnId ) );
2010
0
    if ( aRect.IsEmpty() )
2011
0
        return false;
2012
2013
    // get the visible area
2014
0
    tools::Rectangle aOutRect( Point(0, 0), pDataWin->GetOutputSizePixel() );
2015
2016
0
    if ( bCompletely )
2017
        // test if the field is completely visible
2018
0
        return aOutRect.Contains( aRect );
2019
0
    else
2020
        // test if the field is partly of completely visible
2021
0
        return !aOutRect.Intersection( aRect ).IsEmpty();
2022
0
}
2023
2024
2025
tools::Rectangle BrowseBox::GetFieldRectPixel( sal_Int32 nRow, sal_uInt16 nColumnId,
2026
                                        bool bRelToBrowser) const
2027
0
{
2028
2029
    // get the rectangle relative to DataWin
2030
0
    tools::Rectangle aRect( ImplFieldRectPixel( nRow, nColumnId ) );
2031
0
    if ( aRect.IsEmpty() )
2032
0
        return aRect;
2033
2034
    // adjust relative to BrowseBox's output area
2035
0
    Point aTopLeft( aRect.TopLeft() );
2036
0
    if ( bRelToBrowser )
2037
0
    {
2038
0
        aTopLeft = pDataWin->OutputToScreenPixel( aTopLeft );
2039
0
        aTopLeft = ScreenToOutputPixel( aTopLeft );
2040
0
    }
2041
2042
0
    return tools::Rectangle( aTopLeft, aRect.GetSize() );
2043
0
}
2044
2045
2046
tools::Rectangle BrowseBox::GetRowRectPixel( sal_Int32 nRow  ) const
2047
0
{
2048
2049
    // get the rectangle relative to DataWin
2050
0
    tools::Rectangle aRect;
2051
0
    if ( nTopRow > nRow )
2052
        // row is above visible area
2053
0
        return aRect;
2054
0
    aRect = tools::Rectangle(
2055
0
        Point( 0, GetDataRowHeight() * (nRow-nTopRow) ),
2056
0
        Size( pDataWin->GetOutputSizePixel().Width(), GetDataRowHeight() ) );
2057
0
    if ( aRect.Top() > pDataWin->GetOutputSizePixel().Height() )
2058
        // row is below visible area
2059
0
        return aRect;
2060
2061
    // adjust relative to BrowseBox's output area
2062
0
    Point aTopLeft( aRect.TopLeft() );
2063
0
    aTopLeft = pDataWin->OutputToScreenPixel( aTopLeft );
2064
0
    aTopLeft = ScreenToOutputPixel( aTopLeft );
2065
2066
0
    return tools::Rectangle( aTopLeft, aRect.GetSize() );
2067
0
}
2068
2069
2070
tools::Rectangle BrowseBox::ImplFieldRectPixel( sal_Int32 nRow, sal_uInt16 nColumnId ) const
2071
0
{
2072
2073
    // compute the X-coordinate relative to DataWin by accumulation
2074
0
    tools::Long nColX = 0;
2075
0
    sal_uInt16 nFrozenCols = FrozenColCount();
2076
0
    size_t nCol;
2077
0
    for ( nCol = 0;
2078
0
          nCol < mvCols.size() && mvCols[ nCol ]->GetId() != nColumnId;
2079
0
          ++nCol )
2080
0
        if ( mvCols[ nCol ]->IsFrozen() || nCol >= nFirstCol )
2081
0
            nColX += mvCols[ nCol ]->Width();
2082
2083
0
    if ( nCol >= mvCols.size() || ( nCol >= nFrozenCols && nCol < nFirstCol ) )
2084
0
        return tools::Rectangle();
2085
2086
    // compute the Y-coordinate relative to DataWin
2087
0
    tools::Long nRowY = GetDataRowHeight();
2088
0
    if ( nRow != BROWSER_ENDOFSELECTION ) // #105497# OJ
2089
0
        nRowY = ( nRow - nTopRow ) * GetDataRowHeight();
2090
2091
    // assemble the Rectangle relative to DataWin
2092
0
    return tools::Rectangle(
2093
0
        Point( nColX + MIN_COLUMNWIDTH, nRowY ),
2094
0
        Size( (mvCols[nCol]->Width() == LONG_MAX
2095
0
               ? LONG_MAX - (nColX + MIN_COLUMNWIDTH) : mvCols[ nCol ]->Width() - 2*MIN_COLUMNWIDTH),
2096
0
              GetDataRowHeight() - 1 ) );
2097
0
}
2098
2099
2100
sal_Int32 BrowseBox::GetRowAtYPosPixel( tools::Long nY, bool bRelToBrowser ) const
2101
0
{
2102
2103
    // compute the Y-coordinate
2104
0
    if ( bRelToBrowser )
2105
0
    {
2106
0
        Point aDataTopLeft = pDataWin->OutputToScreenPixel( Point(0, 0) );
2107
0
        Point aTopLeft = OutputToScreenPixel( Point(0, 0) );
2108
0
        nY -= aDataTopLeft.Y() - aTopLeft.Y();
2109
0
    }
2110
2111
    // no row there (e.g. in the header)
2112
0
    if ( nY < 0 || nY >= pDataWin->GetOutputSizePixel().Height() )
2113
0
        return -1;
2114
2115
0
    return nY / GetDataRowHeight() + nTopRow;
2116
0
}
2117
2118
2119
tools::Rectangle BrowseBox::GetFieldRect( sal_uInt16 nColumnId ) const
2120
0
{
2121
2122
0
    return GetFieldRectPixel( nCurRow, nColumnId );
2123
0
}
2124
2125
2126
sal_uInt16 BrowseBox::GetColumnAtXPosPixel( tools::Long nX ) const
2127
0
{
2128
2129
    // accumulate the widths of the visible columns
2130
0
    tools::Long nColX = 0;
2131
0
    for ( size_t nCol = 0; nCol < mvCols.size(); ++nCol )
2132
0
    {
2133
0
        BrowserColumn *pCol = mvCols[ nCol ].get();
2134
0
        if ( pCol->IsFrozen() || nCol >= nFirstCol )
2135
0
            nColX += pCol->Width();
2136
2137
0
        if ( nColX > nX )
2138
0
            return nCol;
2139
0
    }
2140
2141
0
    return BROWSER_INVALIDID;
2142
0
}
2143
2144
bool BrowseBox::ReserveControlArea(sal_uInt16 nWidth)
2145
0
{
2146
0
    if (nWidth != nControlAreaWidth)
2147
0
    {
2148
0
        OSL_ENSURE(nWidth,"Control area of 0 is not allowed, Use USHRT_MAX instead!");
2149
0
        nControlAreaWidth = nWidth;
2150
0
        UpdateScrollbars();
2151
0
        return true;
2152
0
    }
2153
0
    return false;
2154
0
}
2155
2156
tools::Rectangle BrowseBox::GetControlArea() const
2157
0
{
2158
0
    auto nHeight = aHScroll->GetSizePixel().Height();
2159
0
    auto nEndRight = aHScroll->GetPosPixel().X();
2160
2161
0
    return tools::Rectangle(
2162
0
        Point( 0, GetOutputSizePixel().Height() - nHeight ),
2163
0
        Size( nEndRight, nHeight ) );
2164
0
}
2165
2166
void BrowseBox::SetMode( BrowserMode nMode )
2167
0
{
2168
2169
0
    pDataWin->bAutoHScroll = BrowserMode::AUTO_HSCROLL == ( nMode & BrowserMode::AUTO_HSCROLL );
2170
0
    pDataWin->bAutoVScroll = BrowserMode::AUTO_VSCROLL == ( nMode & BrowserMode::AUTO_VSCROLL );
2171
0
    pDataWin->bNoHScroll   = BrowserMode::NO_HSCROLL   == ( nMode & BrowserMode::NO_HSCROLL );
2172
0
    pDataWin->bNoVScroll   = BrowserMode::NO_VSCROLL   == ( nMode & BrowserMode::NO_VSCROLL );
2173
2174
0
    DBG_ASSERT( !( pDataWin->bAutoHScroll && pDataWin->bNoHScroll ),
2175
0
        "BrowseBox::SetMode: AutoHScroll *and* NoHScroll?" );
2176
0
    DBG_ASSERT( !( pDataWin->bAutoVScroll && pDataWin->bNoVScroll ),
2177
0
        "BrowseBox::SetMode: AutoVScroll *and* NoVScroll?" );
2178
0
    if ( pDataWin->bAutoHScroll )
2179
0
        pDataWin->bNoHScroll = false;
2180
0
    if ( pDataWin->bAutoVScroll )
2181
0
        pDataWin->bNoVScroll = false;
2182
2183
0
    if ( pDataWin->bNoHScroll )
2184
0
        aHScroll->Hide();
2185
2186
0
    nControlAreaWidth = USHRT_MAX;
2187
2188
0
    tools::Long nOldRowSel = bMultiSelection ? uRow.pSel->FirstSelected() : uRow.nSel;
2189
0
    MultiSelection *pOldRowSel = bMultiSelection ? uRow.pSel : nullptr;
2190
2191
0
    pVScroll.disposeAndClear();
2192
2193
0
    bMultiSelection = bool( nMode & BrowserMode::MULTISELECTION );
2194
0
    bColumnCursor = bool( nMode & BrowserMode::COLUMNSELECTION );
2195
0
    bKeepHighlight = bool( nMode & BrowserMode::KEEPHIGHLIGHT );
2196
2197
0
    bHideSelect = ((nMode & BrowserMode::HIDESELECT) == BrowserMode::HIDESELECT);
2198
    // default: do not hide the cursor at all (untaken scrolling and such)
2199
0
    bHideCursor = TRISTATE_FALSE;
2200
2201
0
    if ( BrowserMode::HIDECURSOR == ( nMode & BrowserMode::HIDECURSOR ) )
2202
0
    {
2203
0
        bHideCursor = TRISTATE_TRUE;
2204
0
    }
2205
2206
0
    m_bFocusOnlyCursor = ((nMode & BrowserMode::CURSOR_WO_FOCUS) == BrowserMode::NONE);
2207
2208
0
    bHLines = ( nMode & BrowserMode::HLINES ) == BrowserMode::HLINES;
2209
0
    bVLines = ( nMode & BrowserMode::VLINES ) == BrowserMode::VLINES;
2210
2211
0
    pVScroll = VclPtr<ScrollAdaptor>::Create(this, false);
2212
0
    pVScroll->SetLineSize( 1 );
2213
0
    pVScroll->SetPageSize(1);
2214
0
    pVScroll->SetScrollHdl( LINK( this, BrowseBox, VertScrollHdl ) );
2215
2216
0
    pDataWin->bAutoSizeLastCol =
2217
0
            BrowserMode::AUTOSIZE_LASTCOL == ( nMode & BrowserMode::AUTOSIZE_LASTCOL );
2218
2219
    // create a headerbar. what happens, if a headerbar has to be created and
2220
    // there already are columns?
2221
0
    if ( BrowserMode::HEADERBAR_NEW == ( nMode & BrowserMode::HEADERBAR_NEW ) )
2222
0
    {
2223
0
        if (!pDataWin->pHeaderBar)
2224
0
            pDataWin->pHeaderBar = CreateHeaderBar( this );
2225
0
    }
2226
0
    else
2227
0
    {
2228
0
        pDataWin->pHeaderBar.disposeAndClear();
2229
0
    }
2230
2231
0
    if ( bColumnCursor )
2232
0
    {
2233
0
        if (!pColSel)
2234
0
            pColSel.reset(new MultiSelection);
2235
0
        pColSel->SetTotalRange( Range( 0, mvCols.size()-1 ) );
2236
0
    }
2237
0
    else
2238
0
    {
2239
0
        pColSel.reset();
2240
0
    }
2241
2242
0
    if ( bMultiSelection )
2243
0
    {
2244
0
        if ( pOldRowSel )
2245
0
            uRow.pSel = pOldRowSel;
2246
0
        else
2247
0
            uRow.pSel = new MultiSelection;
2248
0
    }
2249
0
    else
2250
0
    {
2251
0
        uRow.nSel = nOldRowSel;
2252
0
        delete pOldRowSel;
2253
0
    }
2254
2255
0
    if ( bBootstrapped )
2256
0
    {
2257
0
        StateChanged( StateChangedType::InitShow );
2258
0
        if ( bMultiSelection && !pOldRowSel &&
2259
0
             nOldRowSel != BROWSER_ENDOFSELECTION )
2260
0
            uRow.pSel->Select( nOldRowSel );
2261
0
    }
2262
2263
0
    if ( pDataWin )
2264
0
        pDataWin->Invalidate();
2265
2266
    // no cursor on handle column
2267
0
    if ( nCurColId == HandleColumnId )
2268
0
        nCurColId = GetColumnId( 1 );
2269
2270
0
    m_nCurrentMode = nMode;
2271
0
}
2272
2273
2274
void BrowseBox::VisibleRowsChanged( sal_Int32, sal_uInt16 )
2275
0
{
2276
2277
    // old behavior: automatically correct NumRows:
2278
0
    if ( nRowCount < GetRowCount() )
2279
0
    {
2280
0
        RowInserted(nRowCount,GetRowCount() - nRowCount, false);
2281
0
    }
2282
0
    else if ( nRowCount > GetRowCount() )
2283
0
    {
2284
0
        RowRemoved(GetRowCount(), nRowCount - GetRowCount(), false);
2285
0
    }
2286
0
}
2287
2288
2289
bool BrowseBox::IsCursorMoveAllowed( sal_Int32, sal_uInt16 ) const
2290
2291
/*  [Description]
2292
2293
    This virtual method is always called before the cursor is moved directly.
2294
    By means of 'return false', we avoid doing this if e.g. a record
2295
    contradicts any rules.
2296
2297
    This method is not called, if the cursor movement results from removing or
2298
    deleting a row/column (thus, in cases where only a "cursor correction" happens).
2299
2300
    The base implementation currently always returns true.
2301
*/
2302
2303
0
{
2304
0
    return true;
2305
0
}
2306
2307
2308
tools::Long BrowseBox::GetDataRowHeight() const
2309
0
{
2310
0
    return CalcZoom(m_nDataRowHeight ? m_nDataRowHeight : ImpGetDataRowHeight());
2311
0
}
2312
2313
2314
VclPtr<BrowserHeader> BrowseBox::CreateHeaderBar( BrowseBox* pParent )
2315
0
{
2316
0
    VclPtr<BrowserHeader> pNewBar = VclPtr<BrowserHeader>::Create( pParent );
2317
0
    pNewBar->SetStartDragHdl( LINK( this, BrowseBox, StartDragHdl ) );
2318
0
    return pNewBar;
2319
0
}
2320
2321
void BrowseBox::SetHeaderBar( BrowserHeader* pHeaderBar )
2322
0
{
2323
0
    pDataWin->pHeaderBar.disposeAndClear();
2324
0
    pDataWin->pHeaderBar = pHeaderBar;
2325
0
    pDataWin->pHeaderBar->SetStartDragHdl( LINK( this, BrowseBox, StartDragHdl ) );
2326
0
}
2327
2328
tools::Long BrowseBox::GetTitleHeight() const
2329
0
{
2330
0
    tools::Long nHeight;
2331
    // ask the header bar for the text height (if possible), as the header bar's font is adjusted with
2332
    // our (and the header's) zoom factor
2333
0
    HeaderBar* pHeaderBar = pDataWin->pHeaderBar;
2334
0
    if ( pHeaderBar )
2335
0
        nHeight = pHeaderBar->GetTextHeight();
2336
0
    else
2337
0
        nHeight = GetTextHeight();
2338
2339
0
    return nTitleLines ? nTitleLines * nHeight + 4 : 0;
2340
0
}
2341
2342
tools::Long BrowseBox::CalcReverseZoom(tools::Long nVal) const
2343
0
{
2344
0
    if (IsZoom())
2345
0
    {
2346
0
        const Fraction& rZoom = GetZoom();
2347
0
        double n = static_cast<double>(nVal);
2348
0
        n *= static_cast<double>(rZoom.GetDenominator());
2349
0
        if (!rZoom.GetNumerator())
2350
0
            throw o3tl::divide_by_zero();
2351
0
        n /= static_cast<double>(rZoom.GetNumerator());
2352
0
        nVal = n>0 ? static_cast<tools::Long>(n + 0.5) : -static_cast<tools::Long>(-n + 0.5);
2353
0
    }
2354
2355
0
    return nVal;
2356
0
}
2357
2358
void BrowseBox::CursorMoved()
2359
0
{
2360
    // before implementing more here, please adjust the EditBrowseBox
2361
2362
0
    if ( isAccessibleAlive() && HasFocus() )
2363
0
        commitTableEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
2364
0
                         Any(css::uno::Reference<css::accessibility::XAccessible>(
2365
0
                             CreateAccessibleCell(GetCurRow(), GetColumnPos(GetCurColumnId())))),
2366
0
                         Any());
2367
0
}
2368
2369
void BrowseBox::LoseFocus()
2370
0
{
2371
0
    SAL_INFO("svtools", "BrowseBox::LoseFocus " << this );
2372
2373
0
    if ( bHasFocus )
2374
0
    {
2375
0
        SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
2376
0
        DoHideCursor();
2377
2378
0
        if ( !bKeepHighlight )
2379
0
        {
2380
0
            ToggleSelection();
2381
0
            bSelectionIsVisible = false;
2382
0
        }
2383
2384
0
        bHasFocus = false;
2385
0
    }
2386
0
    Control::LoseFocus();
2387
0
}
2388
2389
2390
void BrowseBox::GetFocus()
2391
0
{
2392
0
    SAL_INFO("svtools", "BrowseBox::GetFocus " << this );
2393
2394
0
    if ( !bHasFocus )
2395
0
    {
2396
0
        if ( !bSelectionIsVisible )
2397
0
        {
2398
0
            bSelectionIsVisible = true;
2399
0
            if ( bBootstrapped )
2400
0
                ToggleSelection();
2401
0
        }
2402
2403
0
        bHasFocus = true;
2404
0
        DoShowCursor();
2405
0
    }
2406
0
    Control::GetFocus();
2407
0
}
2408
2409
2410
sal_uInt16 BrowseBox::GetVisibleRows() const
2411
0
{
2412
0
    return static_cast<sal_uInt16>((pDataWin->GetOutputSizePixel().Height() - 1 )/ GetDataRowHeight() + 1);
2413
0
}
2414
2415
BrowserDataWin& BrowseBox::GetDataWindow() const
2416
0
{
2417
0
    return *pDataWin;
2418
0
}
2419
2420
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */