Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/treelist/svimpbox.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 <sal/config.h>
21
22
#include <o3tl/safeint.hxx>
23
#include <vcl/svapp.hxx>
24
#include <vcl/salnativewidgets.hxx>
25
#include <vcl/help.hxx>
26
#include <vcl/settings.hxx>
27
#include <vcl/commandevent.hxx>
28
29
#include <cstdlib>
30
#include <memory>
31
#include <stack>
32
33
#include <vcl/toolkit/treelistbox.hxx>
34
#include <vcl/toolkit/svlbitm.hxx>
35
#include <vcl/wintypes.hxx>
36
#include <SvLBoxButton.hxx>
37
#include <bitmaps.hlst>
38
#include <svimpbox.hxx>
39
#include <comphelper/processfactory.hxx>
40
#include <comphelper/string.hxx>
41
#include <i18nlangtag/languagetag.hxx>
42
#include <tools/debug.hxx>
43
44
#include <vcl/toolkit/treelistentry.hxx>
45
#include <vcl/toolkit/viewdataentry.hxx>
46
47
// #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors
48
Image*  SvImpLBox::s_pDefCollapsed      = nullptr;
49
Image*  SvImpLBox::s_pDefExpanded       = nullptr;
50
oslInterlockedCount SvImpLBox::s_nImageRefCount   = 0;
51
52
SvImpLBox::SvImpLBox(SvTreeListBox& rView, SvTreeList& rTree, WinBits nWinStyle)
53
0
    : m_rTree(rTree)
54
0
    , m_aScrBarBox(VclPtr<ScrollBarBox>::Create(&rView))
55
0
    , m_aFctSet(*this, rView)
56
0
    , mbForceMakeVisible (false)
57
0
    , m_aEditIdle("SvImpLBox m_aEditIdle")
58
0
    , m_rView(rView)
59
0
    , m_aHorSBar(VclPtr<ScrollBar>::Create(&rView, WB_DRAG | WB_HSCROLL))
60
0
    , m_aVerSBar(VclPtr<ScrollBar>::Create(&rView, WB_DRAG | WB_VSCROLL))
61
0
    , m_aOutputSize(0, 0)
62
0
    , mbNoAutoCurEntry(false)
63
0
    , m_aSelEng(&rView, nullptr)
64
0
    , m_nNextVerVisSize(0)
65
0
{
66
0
    osl_atomic_increment(&s_nImageRefCount);
67
0
    m_aSelEng.SetFunctionSet( static_cast<FunctionSet*>(&m_aFctSet) );
68
0
    m_aSelEng.ExpandSelectionOnMouseMove( false );
69
0
    SetStyle( nWinStyle );
70
0
    SetSelectionMode( SelectionMode::Single );
71
0
    SetDragDropMode( DragDropMode::NONE );
72
73
0
    m_aVerSBar->SetScrollHdl( LINK( this, SvImpLBox, ScrollUpDownHdl ) );
74
0
    m_aHorSBar->SetScrollHdl( LINK( this, SvImpLBox, ScrollLeftRightHdl ) );
75
0
    m_aHorSBar->SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) );
76
0
    m_aVerSBar->SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) );
77
0
    m_aVerSBar->SetRange( Range(0,0) );
78
0
    m_aVerSBar->Hide();
79
0
    m_aHorSBar->SetRange( Range(0,0) );
80
0
    m_aHorSBar->SetPageSize( 24 ); // pixels
81
0
    m_aHorSBar->SetLineSize( 8 ); // pixels
82
83
0
    m_nHorSBarHeight = static_cast<short>(m_aHorSBar->GetSizePixel().Height());
84
0
    m_nVerSBarWidth = static_cast<short>(m_aVerSBar->GetSizePixel().Width());
85
86
0
    m_pStartEntry = nullptr;
87
0
    m_pCursor             = nullptr;
88
0
    m_pCursorOld          = nullptr;
89
0
    m_pAnchor             = nullptr;
90
0
    m_nVisibleCount       = 0;    // number of rows of data in control
91
0
    m_nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID;
92
0
    m_nNodeBmpWidth       = 0;
93
94
    // button animation in listbox
95
0
    m_pActiveButton = nullptr;
96
0
    m_pActiveEntry = nullptr;
97
98
0
    m_nFlags = LBoxFlags::NONE;
99
100
0
    m_aEditIdle.SetPriority( TaskPriority::LOWEST );
101
0
    m_aEditIdle.SetInvokeHandler( LINK(this,SvImpLBox,EditTimerCall) );
102
103
0
    m_nMostRight = -1;
104
0
    m_pMostRightEntry = nullptr;
105
0
    m_nCurUserEvent = nullptr;
106
107
0
    m_bUpdateMode = true;
108
0
    m_bInVScrollHdl = false;
109
0
    m_nFlags |= LBoxFlags::Filling;
110
111
0
    m_bSubLstOpLR = false;
112
0
}
113
114
SvImpLBox::~SvImpLBox()
115
0
{
116
0
    m_aEditIdle.Stop();
117
0
    StopUserEvent();
118
119
0
    if ( osl_atomic_decrement(&s_nImageRefCount) == 0 )
120
0
    {
121
0
        delete s_pDefCollapsed;
122
0
        s_pDefCollapsed = nullptr;
123
0
        delete s_pDefExpanded;
124
0
        s_pDefExpanded = nullptr;
125
0
    }
126
0
    m_aVerSBar.disposeAndClear();
127
0
    m_aHorSBar.disposeAndClear();
128
0
    m_aScrBarBox.disposeAndClear();
129
0
}
130
131
void SvImpLBox::UpdateStringSorter()
132
0
{
133
0
    const css::lang::Locale& rNewLocale = Application::GetSettings().GetLanguageTag().getLocale();
134
135
0
    if( m_pStringSorter )
136
0
    {
137
        // different Locale from the older one, drop it and force recreate
138
0
        const css::lang::Locale &aLocale = m_pStringSorter->getLocale();
139
0
        if( aLocale.Language != rNewLocale.Language ||
140
0
            aLocale.Country != rNewLocale.Country ||
141
0
            aLocale.Variant != rNewLocale.Variant )
142
0
            m_pStringSorter.reset();
143
0
    }
144
145
0
    if( !m_pStringSorter )
146
0
    {
147
0
        m_pStringSorter.reset(new comphelper::string::NaturalStringSorter(
148
0
                              ::comphelper::getProcessComponentContext(),
149
0
                              rNewLocale));
150
0
    }
151
0
}
152
153
short SvImpLBox::UpdateContextBmpWidthVector( SvTreeListEntry const * pEntry, short nWidth )
154
0
{
155
0
    DBG_ASSERT(m_rView.m_pModel, "View and Model aren't valid!");
156
157
0
    sal_uInt16 nDepth = m_rView.m_pModel->GetDepth(pEntry);
158
    // initialize vector if necessary
159
0
    std::vector< short >::size_type nSize = m_aContextBmpWidthVector.size();
160
0
    while ( nDepth > nSize )
161
0
    {
162
0
        m_aContextBmpWidthVector.resize( nSize + 1 );
163
0
        m_aContextBmpWidthVector.at( nSize ) = nWidth;
164
0
        ++nSize;
165
0
    }
166
0
    if( m_aContextBmpWidthVector.size() == nDepth )
167
0
    {
168
0
        m_aContextBmpWidthVector.resize( nDepth + 1 );
169
0
        m_aContextBmpWidthVector.at( nDepth ) = 0;
170
0
    }
171
0
    short nContextBmpWidth = m_aContextBmpWidthVector[ nDepth ];
172
0
    if( nContextBmpWidth < nWidth )
173
0
    {
174
0
        m_aContextBmpWidthVector.at( nDepth ) = nWidth;
175
0
        return nWidth;
176
0
    }
177
0
    else
178
0
        return nContextBmpWidth;
179
0
}
180
181
void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry* pEntry )
182
0
{
183
0
    assert(pEntry && "Moved Entry is invalid!");
184
185
0
    SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem(SvLBoxItemType::ContextBmp) );
186
0
    short nExpWidth = static_cast<short>(pBmpItem->GetBitmap1().GetSizePixel().Width());
187
0
    short nColWidth = static_cast<short>(pBmpItem->GetBitmap2().GetSizePixel().Width());
188
0
    short nMax = std::max(nExpWidth, nColWidth);
189
0
    UpdateContextBmpWidthVector( pEntry, nMax );
190
191
0
    if( pEntry->HasChildren() ) // recursive call, whether expanded or not
192
0
    {
193
0
        SvTreeListEntry* pChild = m_rView.FirstChild(pEntry);
194
0
        DBG_ASSERT( pChild, "The first child is invalid!" );
195
0
        do
196
0
        {
197
0
            UpdateContextBmpWidthVectorFromMovedEntry( pChild );
198
0
            pChild = m_rView.Next(pChild);
199
0
        } while ( pChild );
200
0
    }
201
0
}
202
203
void SvImpLBox::UpdateContextBmpWidthMax( SvTreeListEntry const * pEntry )
204
0
{
205
0
    sal_uInt16 nDepth = m_rView.m_pModel->GetDepth(pEntry);
206
0
    if( m_aContextBmpWidthVector.empty() )
207
0
        return;
208
0
    short nWidth = m_aContextBmpWidthVector[ nDepth ];
209
0
    if (nWidth != m_rView.m_nContextBmpWidthMax)
210
0
    {
211
0
        m_rView.m_nContextBmpWidthMax = nWidth;
212
0
        m_nFlags |= LBoxFlags::IgnoreChangedTabs;
213
0
        m_rView.SetTabs();
214
0
        m_nFlags &= ~LBoxFlags::IgnoreChangedTabs;
215
0
    }
216
0
}
217
218
void SvImpLBox::SetStyle( WinBits i_nWinStyle )
219
0
{
220
0
    m_nStyle = i_nWinStyle;
221
0
    if ( ( m_nStyle & WB_SIMPLEMODE) && ( m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) )
222
0
        m_aSelEng.AddAlways( true );
223
0
}
224
225
void SvImpLBox::SetNoAutoCurEntry( bool b )
226
0
{
227
0
    mbNoAutoCurEntry = b;
228
0
}
229
230
// don't touch the model any more
231
void SvImpLBox::Clear()
232
0
{
233
0
    StopUserEvent();
234
0
    m_pStartEntry = nullptr;
235
0
    m_pAnchor = nullptr;
236
237
0
    m_pActiveButton = nullptr;
238
0
    m_pActiveEntry = nullptr;
239
240
0
    m_nMostRight = -1;
241
0
    m_pMostRightEntry = nullptr;
242
243
    // don't touch the cursor any more
244
0
    if( m_pCursor )
245
0
    {
246
0
        if (m_rView.HasFocus())
247
0
            m_rView.HideFocus();
248
0
        m_pCursor = nullptr;
249
0
    }
250
0
    m_pCursorOld = nullptr;
251
0
    m_aVerSBar->Hide();
252
0
    m_aVerSBar->SetThumbPos( 0 );
253
0
    Range aRange( 0, 0 );
254
0
    m_aVerSBar->SetRange( aRange );
255
0
    m_aOutputSize = m_rView.Control::GetOutputSizePixel();
256
0
    m_aHorSBar->Hide();
257
0
    m_aHorSBar->SetThumbPos( 0 );
258
0
    MapMode aMapMode(m_rView.GetMapMode());
259
0
    aMapMode.SetOrigin( Point(0,0) );
260
0
    m_rView.Control::SetMapMode(aMapMode);
261
0
    m_aHorSBar->SetRange( aRange );
262
0
    m_aHorSBar->SetSizePixel(Size(m_aOutputSize.Width(),m_nHorSBarHeight));
263
0
    m_rView.GetOutDev()->SetClipRegion();
264
0
    if( GetUpdateMode() )
265
0
        m_rView.Invalidate(GetVisibleArea());
266
0
    m_nFlags |= LBoxFlags::Filling;
267
0
    if( !m_aHorSBar->IsVisible() && !m_aVerSBar->IsVisible() )
268
0
        m_aScrBarBox->Hide();
269
270
0
    m_aContextBmpWidthVector.clear();
271
272
0
    CallEventListeners( VclEventId::ListboxItemRemoved );
273
0
}
274
275
// *********************************************************************
276
// Paint, navigate, scroll
277
// *********************************************************************
278
279
IMPL_LINK_NOARG(SvImpLBox, EndScrollHdl, ScrollBar*, void)
280
0
{
281
0
    if( m_nFlags & LBoxFlags::EndScrollSetVisSize )
282
0
    {
283
0
        m_aVerSBar->SetVisibleSize( m_nNextVerVisSize );
284
0
        m_nFlags &= ~LBoxFlags::EndScrollSetVisSize;
285
0
    }
286
0
}
287
288
// handler for vertical scrollbar
289
290
IMPL_LINK( SvImpLBox, ScrollUpDownHdl, ScrollBar *, pScrollBar, void )
291
0
{
292
0
    DBG_ASSERT(!m_bInVScrollHdl,"Scroll handler out-paces itself!");
293
0
    tools::Long nDelta = pScrollBar->GetDelta();
294
0
    if( !nDelta )
295
0
        return;
296
297
    // when only one row don't skip lines
298
0
    if (pScrollBar->GetPageSize() == 1)
299
0
        nDelta = nDelta > 0 ? 1 : -1;
300
301
0
    m_nFlags &= ~LBoxFlags::Filling;
302
303
0
    m_bInVScrollHdl = true;
304
305
0
    if (m_rView.IsEditingActive())
306
0
    {
307
0
        m_rView.EndEditing(true); // Cancel
308
0
        m_rView.PaintImmediately();
309
0
    }
310
311
0
    if( nDelta > 0 )
312
0
    {
313
0
        if( nDelta == 1 && pScrollBar->GetPageSize() > 1)
314
0
            CursorDown();
315
0
        else
316
0
            PageDown( static_cast<sal_uInt16>(nDelta) );
317
0
    }
318
0
    else
319
0
    {
320
0
        nDelta *= -1;
321
0
        if( nDelta == 1 && pScrollBar->GetPageSize() > 1)
322
0
            CursorUp();
323
0
        else
324
0
            PageUp( static_cast<sal_uInt16>(nDelta) );
325
0
    }
326
0
    m_bInVScrollHdl = false;
327
0
}
328
329
330
void SvImpLBox::CursorDown()
331
0
{
332
0
    if (!m_pStartEntry)
333
0
        return;
334
335
0
    SvTreeListEntry* pNextFirstToDraw = m_rView.NextVisible(m_pStartEntry);
336
0
    if( pNextFirstToDraw )
337
0
    {
338
0
        m_nFlags &= ~LBoxFlags::Filling;
339
0
        ShowCursor( false );
340
0
        m_rView.PaintImmediately();
341
0
        m_pStartEntry = pNextFirstToDraw;
342
0
        tools::Rectangle aArea( GetVisibleArea() );
343
0
        m_rView.Scroll(0, -(m_rView.GetEntryHeight()), aArea, ScrollFlags::NoChildren);
344
0
        m_rView.PaintImmediately();
345
0
        ShowCursor( true );
346
0
        m_rView.NotifyScrolled();
347
0
    }
348
0
}
349
350
void SvImpLBox::CursorUp()
351
0
{
352
0
    if (!m_pStartEntry)
353
0
        return;
354
355
0
    SvTreeListEntry* pPrevFirstToDraw = m_rView.PrevVisible(m_pStartEntry);
356
0
    if( !pPrevFirstToDraw )
357
0
        return;
358
359
0
    m_nFlags &= ~LBoxFlags::Filling;
360
0
    tools::Long nEntryHeight = m_rView.GetEntryHeight();
361
0
    ShowCursor( false );
362
0
    m_rView.PaintImmediately();
363
0
    m_pStartEntry = pPrevFirstToDraw;
364
0
    tools::Rectangle aArea( GetVisibleArea() );
365
0
    if (aArea.GetHeight() > nEntryHeight)
366
0
        aArea.AdjustBottom(-nEntryHeight);
367
0
    m_rView.Scroll(0, nEntryHeight, aArea, ScrollFlags::NoChildren);
368
0
    m_rView.PaintImmediately();
369
0
    ShowCursor( true );
370
0
    m_rView.NotifyScrolled();
371
0
}
372
373
void SvImpLBox::PageDown( sal_uInt16 nDelta )
374
0
{
375
0
    sal_uInt16 nRealDelta = nDelta;
376
377
0
    if( !nDelta )
378
0
        return;
379
380
0
    if (!m_pStartEntry)
381
0
        return;
382
383
0
    SvTreeListEntry* pNext = m_rView.NextVisible(m_pStartEntry, nRealDelta);
384
0
    if( pNext == m_pStartEntry )
385
0
        return;
386
387
0
    ShowCursor( false );
388
389
0
    m_nFlags &= ~LBoxFlags::Filling;
390
0
    m_rView.PaintImmediately();
391
0
    m_pStartEntry = pNext;
392
393
0
    if( nRealDelta >= m_nVisibleCount )
394
0
    {
395
0
        m_rView.Invalidate(GetVisibleArea());
396
0
        m_rView.PaintImmediately();
397
0
    }
398
0
    else
399
0
    {
400
0
        tools::Rectangle aArea( GetVisibleArea() );
401
0
        tools::Long nScroll = m_rView.GetEntryHeight() * static_cast<tools::Long>(nRealDelta);
402
0
        nScroll = -nScroll;
403
0
        m_rView.PaintImmediately();
404
0
        m_rView.Scroll(0, nScroll, aArea, ScrollFlags::NoChildren);
405
0
        m_rView.PaintImmediately();
406
0
    }
407
408
0
    ShowCursor( true );
409
0
    m_rView.NotifyScrolled();
410
0
}
411
412
void SvImpLBox::PageUp( sal_uInt16 nDelta )
413
0
{
414
0
    sal_uInt16 nRealDelta = nDelta;
415
0
    if( !nDelta )
416
0
        return;
417
418
0
    if (!m_pStartEntry)
419
0
        return;
420
421
0
    SvTreeListEntry* pPrev = m_rView.PrevVisible(m_pStartEntry, nRealDelta);
422
0
    if( pPrev == m_pStartEntry )
423
0
        return;
424
425
0
    m_nFlags &= ~LBoxFlags::Filling;
426
0
    ShowCursor( false );
427
428
0
    m_rView.PaintImmediately();
429
0
    m_pStartEntry = pPrev;
430
0
    if( nRealDelta >= m_nVisibleCount )
431
0
    {
432
0
        m_rView.Invalidate(GetVisibleArea());
433
0
        m_rView.PaintImmediately();
434
0
    }
435
0
    else
436
0
    {
437
0
        tools::Long nEntryHeight = m_rView.GetEntryHeight();
438
0
        tools::Rectangle aArea( GetVisibleArea() );
439
0
        m_rView.PaintImmediately();
440
0
        m_rView.Scroll(0, nEntryHeight * nRealDelta, aArea, ScrollFlags::NoChildren);
441
0
        m_rView.PaintImmediately();
442
0
    }
443
444
0
    ShowCursor( true );
445
0
    m_rView.NotifyScrolled();
446
0
}
447
448
void SvImpLBox::KeyUp( bool bPageUp )
449
0
{
450
0
    if( !m_aVerSBar->IsVisible() )
451
0
        return;
452
453
0
    tools::Long nDelta;
454
0
    if( bPageUp )
455
0
        nDelta = m_aVerSBar->GetPageSize();
456
0
    else
457
0
        nDelta = 1;
458
459
0
    tools::Long nThumbPos = m_aVerSBar->GetThumbPos();
460
461
0
    if( nThumbPos < nDelta )
462
0
        nDelta = nThumbPos;
463
464
0
    if( nDelta <= 0 )
465
0
        return;
466
467
0
    m_nFlags &= ~LBoxFlags::Filling;
468
469
0
    m_aVerSBar->SetThumbPos( nThumbPos - nDelta );
470
0
    if( bPageUp )
471
0
        PageUp( static_cast<short>(nDelta) );
472
0
    else
473
0
        CursorUp();
474
0
}
475
476
477
void SvImpLBox::KeyDown( bool bPageDown )
478
0
{
479
0
    if( !m_aVerSBar->IsVisible() )
480
0
        return;
481
482
0
    tools::Long nDelta;
483
0
    if( bPageDown )
484
0
        nDelta = m_aVerSBar->GetPageSize();
485
0
    else
486
0
        nDelta = 1;
487
488
0
    tools::Long nThumbPos = m_aVerSBar->GetThumbPos();
489
0
    tools::Long nVisibleSize = m_aVerSBar->GetVisibleSize();
490
0
    tools::Long nRange = m_aVerSBar->GetRange().Len();
491
492
0
    tools::Long nTmp = nThumbPos+nVisibleSize;
493
0
    while( (nDelta > 0) && (nTmp+nDelta) >= nRange )
494
0
        nDelta--;
495
496
0
    if( nDelta <= 0 )
497
0
        return;
498
499
0
    m_nFlags &= ~LBoxFlags::Filling;
500
501
0
    m_aVerSBar->SetThumbPos( nThumbPos+nDelta );
502
0
    if( bPageDown )
503
0
        PageDown( static_cast<short>(nDelta) );
504
0
    else
505
0
        CursorDown();
506
0
}
507
508
509
void SvImpLBox::InvalidateEntriesFrom( tools::Long nY ) const
510
0
{
511
0
    if( !(m_nFlags & LBoxFlags::InPaint ))
512
0
    {
513
0
        tools::Rectangle aRect( GetVisibleArea() );
514
0
        aRect.SetTop( nY );
515
0
        m_rView.Invalidate(aRect);
516
0
    }
517
0
}
518
519
void SvImpLBox::InvalidateEntry( tools::Long nY ) const
520
0
{
521
0
    if( m_nFlags & LBoxFlags::InPaint )
522
0
        return;
523
524
0
    tools::Rectangle aRect( GetVisibleArea() );
525
0
    tools::Long nMaxBottom = aRect.Bottom();
526
0
    aRect.SetTop( nY );
527
0
    aRect.SetBottom(nY);
528
0
    aRect.AdjustBottom(m_rView.GetEntryHeight());
529
0
    if( aRect.Top() > nMaxBottom )
530
0
        return;
531
0
    if( aRect.Bottom() > nMaxBottom )
532
0
        aRect.SetBottom( nMaxBottom );
533
0
    if (m_rView.SupportsDoubleBuffering())
534
        // Perform full paint when flicker is to be avoided explicitly.
535
0
        m_rView.Invalidate();
536
0
    else
537
0
        m_rView.Invalidate(aRect);
538
0
}
539
540
void SvImpLBox::InvalidateEntry( SvTreeListEntry* pEntry )
541
0
{
542
0
    if( GetUpdateMode() )
543
0
    {
544
0
        tools::Long nPrev = m_nMostRight;
545
0
        SetMostRight( pEntry );
546
0
        if( nPrev < m_nMostRight )
547
0
            ShowVerSBar();
548
0
    }
549
0
    if( !(m_nFlags & LBoxFlags::InPaint ))
550
0
    {
551
0
        bool bHasFocusRect = false;
552
0
        if (pEntry == m_pCursor && m_rView.HasFocus())
553
0
        {
554
0
            bHasFocusRect = true;
555
0
            ShowCursor( false );
556
0
        }
557
0
        InvalidateEntry( GetEntryLine( pEntry ) );
558
0
        if( bHasFocusRect )
559
0
            ShowCursor( true );
560
0
    }
561
0
}
562
563
564
void SvImpLBox::RecalcFocusRect()
565
0
{
566
0
    if (m_rView.HasFocus() && m_pCursor)
567
0
    {
568
0
        m_rView.HideFocus();
569
0
        tools::Long nY = GetEntryLine( m_pCursor );
570
0
        tools::Rectangle aRect = m_rView.GetFocusRect(m_pCursor, nY);
571
0
        vcl::Region aOldClip(m_rView.GetOutDev()->GetClipRegion());
572
0
        vcl::Region aClipRegion( GetClipRegionRect() );
573
0
        m_rView.GetOutDev()->SetClipRegion(aClipRegion);
574
0
        m_rView.ShowFocus(aRect);
575
0
        m_rView.GetOutDev()->SetClipRegion(aOldClip);
576
0
    }
577
0
}
578
579
580
//  Sets cursor. When using SingleSelection, the selection is adjusted.
581
void SvImpLBox::SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect )
582
0
{
583
0
    SvViewDataEntry* pViewDataNewCur = nullptr;
584
0
    if( pEntry )
585
0
        pViewDataNewCur = &m_rView.GetViewDataEntry(*pEntry);
586
0
    if( pEntry &&
587
0
        pEntry == m_pCursor &&
588
0
        pViewDataNewCur &&
589
0
        pViewDataNewCur->HasFocus() &&
590
0
        pViewDataNewCur->IsSelected())
591
0
    {
592
0
        return;
593
0
    }
594
595
    // if this cursor is not selectable, find first visible that is and use it
596
0
    while( pEntry && pViewDataNewCur && !pViewDataNewCur->IsSelectable() )
597
0
    {
598
0
        pEntry = m_rView.NextVisible(pEntry);
599
0
        pViewDataNewCur = pEntry ? &m_rView.GetViewDataEntry(*pEntry) : nullptr;
600
0
    }
601
602
0
    SvTreeListEntry* pOldCursor = m_pCursor;
603
0
    if( m_pCursor && pEntry != m_pCursor )
604
0
    {
605
0
        m_rView.SetEntryFocus(m_pCursor, false);
606
0
        if( m_bSimpleTravel )
607
0
            m_rView.Select(m_pCursor, false);
608
0
        m_rView.HideFocus();
609
0
    }
610
0
    m_pCursor = pEntry;
611
0
    if( m_pCursor )
612
0
    {
613
0
        if (pViewDataNewCur)
614
0
            pViewDataNewCur->SetFocus( true );
615
0
        if(!bForceNoSelect && m_bSimpleTravel && !(m_nFlags & LBoxFlags::DeselectAll) && GetUpdateMode())
616
0
        {
617
0
            m_rView.Select(m_pCursor);
618
0
            CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor );
619
0
        }
620
        // multiple selection: select in cursor move if we're not in
621
        // Add mode (Ctrl-F8)
622
0
        else if (GetUpdateMode() && m_rView.GetSelectionMode() == SelectionMode::Multiple
623
0
                 && !(m_nFlags & LBoxFlags::DeselectAll) && !m_aSelEng.IsAddMode()
624
0
                 && !bForceNoSelect)
625
0
        {
626
0
            m_rView.Select(m_pCursor);
627
0
            CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor );
628
0
        }
629
0
        else
630
0
        {
631
0
            ShowCursor( true );
632
0
            if (bForceNoSelect && GetUpdateMode())
633
0
            {
634
0
                CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor);
635
0
            }
636
0
        }
637
638
0
        if( m_pAnchor )
639
0
        {
640
0
            DBG_ASSERT(m_aSelEng.GetSelectionMode() != SelectionMode::Single,"Mode?");
641
0
            SetAnchorSelection( pOldCursor, m_pCursor );
642
0
        }
643
0
    }
644
0
    m_nFlags &= ~LBoxFlags::DeselectAll;
645
646
0
    m_rView.OnCurrentEntryChanged();
647
0
}
648
649
void SvImpLBox::ShowCursor( bool bShow )
650
0
{
651
0
    if (!bShow || !m_pCursor || !m_rView.HasFocus())
652
0
    {
653
0
        vcl::Region aOldClip(m_rView.GetOutDev()->GetClipRegion());
654
0
        vcl::Region aClipRegion( GetClipRegionRect() );
655
0
        m_rView.GetOutDev()->SetClipRegion(aClipRegion);
656
0
        m_rView.HideFocus();
657
0
        m_rView.GetOutDev()->SetClipRegion(aOldClip);
658
0
    }
659
0
    else
660
0
    {
661
0
        tools::Long nY = GetEntryLine( m_pCursor );
662
0
        tools::Rectangle aRect = m_rView.GetFocusRect(m_pCursor, nY);
663
0
        vcl::Region aOldClip(m_rView.GetOutDev()->GetClipRegion());
664
0
        vcl::Region aClipRegion( GetClipRegionRect() );
665
0
        m_rView.GetOutDev()->SetClipRegion(aClipRegion);
666
0
        m_rView.ShowFocus(aRect);
667
0
        m_rView.GetOutDev()->SetClipRegion(aOldClip);
668
0
    }
669
0
}
670
671
672
void SvImpLBox::UpdateAll()
673
0
{
674
0
    FindMostRight();
675
0
    m_aVerSBar->SetRange(Range(0, static_cast<tools::Long>(m_rView.GetVisibleCount()) - 1));
676
0
    SyncVerThumb();
677
0
    FillView();
678
0
    ShowVerSBar();
679
0
    if (m_bSimpleTravel && m_pCursor && m_rView.HasFocus())
680
0
        m_rView.Select(m_pCursor);
681
0
    ShowCursor( true );
682
0
    m_rView.Invalidate(GetVisibleArea());
683
0
}
684
685
IMPL_LINK( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar, void )
686
0
{
687
0
    tools::Long nDelta = pScrollBar->GetDelta();
688
0
    if( nDelta )
689
0
    {
690
0
        if (m_rView.IsEditingActive())
691
0
        {
692
0
            m_rView.EndEditing(true); // Cancel
693
0
            m_rView.PaintImmediately();
694
0
        }
695
0
        m_rView.m_nFocusWidth = -1;
696
0
        KeyLeftRight( nDelta );
697
0
    }
698
0
}
699
700
void SvImpLBox::KeyLeftRight( tools::Long nDelta )
701
0
{
702
0
    if( !(m_nFlags & LBoxFlags::InResize) )
703
0
        m_rView.PaintImmediately();
704
0
    m_nFlags &= ~LBoxFlags::Filling;
705
0
    ShowCursor( false );
706
707
    // calculate new origin
708
0
    tools::Long nPos = m_aHorSBar->GetThumbPos();
709
0
    Point aOrigin( -nPos, 0 );
710
711
0
    MapMode aMapMode(m_rView.GetMapMode());
712
0
    aMapMode.SetOrigin( aOrigin );
713
0
    m_rView.SetMapMode(aMapMode);
714
715
0
    if( !(m_nFlags & LBoxFlags::InResize) )
716
0
    {
717
0
        tools::Rectangle aRect( GetVisibleArea() );
718
0
        m_rView.Scroll(-nDelta, 0, aRect, ScrollFlags::NoChildren);
719
0
    }
720
0
    else
721
0
        m_rView.Invalidate();
722
0
    RecalcFocusRect();
723
0
    ShowCursor( true );
724
0
    m_rView.NotifyScrolled();
725
0
}
726
727
728
// returns the last entry if position is just past the last entry
729
SvTreeListEntry* SvImpLBox::GetClickedEntry( const Point& rPoint ) const
730
0
{
731
0
    DBG_ASSERT(m_rView.GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!");
732
0
    if (!m_rView.GetModel())
733
        // this is quite impossible. Nevertheless, stack traces from the crash reporter
734
        // suggest it isn't. Okay, make it safe, and wait for somebody to reproduce it
735
        // reliably :-\ ...
736
        // #122359# / 2005-05-23 / frank.schoenheit@sun.com
737
0
        return nullptr;
738
0
    if (m_rView.GetEntryCount() == 0 || !m_pStartEntry || !m_rView.GetEntryHeight())
739
0
        return nullptr;
740
741
0
    sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_rView.GetEntryHeight());
742
0
    sal_uInt16 nTemp = nClickedEntry;
743
0
    SvTreeListEntry* pEntry = m_rView.NextVisible(m_pStartEntry, nTemp);
744
0
    return pEntry;
745
0
}
746
747
748
//  checks if the entry was hit "the right way"
749
//  (Focusrect+ ContextBitmap at TreeListBox)
750
751
bool SvImpLBox::EntryReallyHit(SvTreeListEntry& rEntry, const Point& rPosPixel, tools::Long nLine)
752
0
{
753
0
    bool bRet;
754
    // we are not too exact when it comes to "special" entries
755
    // (with CheckButtons etc.)
756
0
    if (rEntry.ItemCount() >= 3)
757
0
        return true;
758
759
0
    tools::Rectangle aRect(m_rView.GetFocusRect(&rEntry, nLine));
760
0
    aRect.SetRight(GetOutputSize().Width() - m_rView.GetMapMode().GetOrigin().X());
761
762
0
    SvLBoxContextBmp* pBmp
763
0
        = static_cast<SvLBoxContextBmp*>(rEntry.GetFirstItem(SvLBoxItemType::ContextBmp));
764
0
    aRect.AdjustLeft(-pBmp->GetWidth(m_rView, rEntry));
765
0
    aRect.AdjustLeft( -4 ); // a little tolerance
766
767
0
    Point aPos( rPosPixel );
768
0
    aPos -= m_rView.GetMapMode().GetOrigin();
769
0
    bRet = aRect.Contains( aPos );
770
0
    return bRet;
771
0
}
772
773
774
// returns 0 if position is just past the last entry
775
SvTreeListEntry* SvImpLBox::GetEntry( const Point& rPoint ) const
776
0
{
777
0
    if ((m_rView.GetEntryCount() == 0) || !m_pStartEntry || (rPoint.Y() > m_aOutputSize.Height())
778
0
        || !m_rView.GetEntryHeight())
779
0
        return nullptr;
780
781
0
    sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_rView.GetEntryHeight());
782
0
    sal_uInt16 nTemp = nClickedEntry;
783
0
    SvTreeListEntry* pEntry = m_rView.NextVisible(m_pStartEntry, nTemp);
784
0
    if( nTemp != nClickedEntry )
785
0
        pEntry = nullptr;
786
0
    return pEntry;
787
0
}
788
789
790
SvTreeListEntry* SvImpLBox::MakePointVisible(const Point& rPoint)
791
0
{
792
0
    if( !m_pCursor )
793
0
        return nullptr;
794
0
    tools::Long nY = rPoint.Y();
795
0
    SvTreeListEntry* pEntry = nullptr;
796
0
    tools::Long nMax = m_aOutputSize.Height();
797
0
    if( nY < 0 || nY >= nMax ) // aOutputSize.Height() )
798
0
    {
799
0
        if( nY < 0 )
800
0
            pEntry = m_rView.PrevVisible(m_pCursor);
801
0
        else
802
0
            pEntry = m_rView.NextVisible(m_pCursor);
803
804
0
        if( pEntry && pEntry != m_pCursor )
805
0
            m_rView.SetEntryFocus(m_pCursor, false);
806
807
0
        if( nY < 0 )
808
0
            KeyUp( false );
809
0
        else
810
0
            KeyDown( false );
811
0
    }
812
0
    else
813
0
    {
814
0
        pEntry = GetClickedEntry( rPoint );
815
0
        if( !pEntry )
816
0
        {
817
0
            sal_uInt16 nSteps = 0xFFFF;
818
            // TODO: LastVisible is not yet implemented!
819
0
            pEntry = m_rView.NextVisible(m_pStartEntry, nSteps);
820
0
        }
821
0
        if( pEntry )
822
0
        {
823
0
            if( pEntry != m_pCursor &&
824
0
                 m_aSelEng.GetSelectionMode() == SelectionMode::Single
825
0
            )
826
0
                m_rView.Select(m_pCursor, false);
827
0
        }
828
0
    }
829
0
    return pEntry;
830
0
}
831
832
tools::Rectangle SvImpLBox::GetClipRegionRect() const
833
0
{
834
0
    Point aOrigin(m_rView.GetMapMode().GetOrigin());
835
0
    aOrigin.setX( aOrigin.X() * -1 ); // conversion document coordinates
836
0
    tools::Rectangle aClipRect( aOrigin, m_aOutputSize );
837
0
    aClipRect.AdjustBottom( 1 );
838
0
    return aClipRect;
839
0
}
840
841
842
void SvImpLBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
843
0
{
844
0
    if (!m_rView.GetVisibleCount())
845
0
        return;
846
847
0
    m_nFlags |= LBoxFlags::InPaint;
848
849
0
    if (m_nFlags & LBoxFlags::Filling)
850
0
    {
851
0
        SvTreeListEntry* pFirst = m_rView.First();
852
0
        if (pFirst != m_pStartEntry)
853
0
        {
854
0
            ShowCursor(false);
855
0
            m_pStartEntry = m_rView.First();
856
0
            m_aVerSBar->SetThumbPos( 0 );
857
0
            StopUserEvent();
858
0
            ShowCursor(true);
859
0
            m_nCurUserEvent = Application::PostUserEvent(LINK(this, SvImpLBox, MyUserEvent),
860
0
                                                       reinterpret_cast<void*>(1));
861
0
            return;
862
0
        }
863
0
    }
864
865
0
    if (!m_pStartEntry)
866
0
    {
867
0
        m_pStartEntry = m_rView.First();
868
0
    }
869
870
0
    if (m_nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID)
871
0
        SetNodeBmpTabDistance();
872
873
0
    tools::Long nRectHeight = rRect.GetHeight();
874
0
    tools::Long nEntryHeight = m_rView.GetEntryHeight();
875
876
0
    assert(nEntryHeight);
877
0
    if (!nEntryHeight)
878
0
        return;
879
880
    // calculate area for the entries we want to draw
881
0
    sal_uInt16 nStartLine = static_cast<sal_uInt16>(rRect.Top() / nEntryHeight);
882
0
    sal_uInt16 nCount = static_cast<sal_uInt16>(nRectHeight / nEntryHeight);
883
0
    nCount += 2; // don't miss a row
884
885
0
    tools::Long nY = nStartLine * nEntryHeight;
886
0
    SvTreeListEntry* pEntry = m_pStartEntry;
887
0
    while (nStartLine && pEntry)
888
0
    {
889
0
        pEntry = m_rView.NextVisible(pEntry);
890
0
        nStartLine--;
891
0
    }
892
893
0
    if (!m_pCursor && !mbNoAutoCurEntry)
894
0
    {
895
        // do not select if multiselection or explicit set
896
0
        bool bNotSelect = (m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) || ((m_nStyle & WB_NOINITIALSELECTION) == WB_NOINITIALSELECTION);
897
0
        SetCursor(m_pStartEntry, bNotSelect);
898
0
    }
899
900
0
    for(sal_uInt16 n=0; n< nCount && pEntry; n++)
901
0
    {
902
        /*long nMaxRight=*/
903
0
        m_rView.PaintEntry1(*pEntry, nY, rRenderContext);
904
0
        nY += nEntryHeight;
905
0
        pEntry = m_rView.NextVisible(pEntry);
906
0
    }
907
908
0
    if (m_nStyle & (WB_HASLINES | WB_HASLINESATROOT))
909
0
        DrawNet(rRenderContext);
910
911
0
    m_nFlags &= ~LBoxFlags::DeselectAll;
912
0
    m_nFlags &= ~LBoxFlags::InPaint;
913
0
}
914
915
void SvImpLBox::MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop )
916
0
{
917
0
    if( !pEntry )
918
0
        return;
919
920
0
    bool bInView = IsEntryInView( pEntry );
921
922
0
    if( bInView && (!bMoveToTop || m_pStartEntry == pEntry) )
923
0
        return;  // is already visible
924
925
0
    if( m_pStartEntry || mbForceMakeVisible )
926
0
        m_nFlags &= ~LBoxFlags::Filling;
927
0
    if( !bInView )
928
0
    {
929
0
        if (!m_rView.IsEntryVisible(pEntry)) // Parent(s) collapsed?
930
0
        {
931
0
            SvTreeListEntry* pParent = m_rView.GetParent(pEntry);
932
0
            while( pParent )
933
0
            {
934
0
                if (!m_rView.IsExpanded(pParent))
935
0
                {
936
0
                    bool bRet = m_rView.Expand(*pParent);
937
0
                    DBG_ASSERT(bRet,"Not expanded!");
938
0
                }
939
0
                pParent = m_rView.GetParent(pParent);
940
0
            }
941
            // do the parent's children fit into the view or do we have to scroll?
942
0
            if( IsEntryInView( pEntry ) && !bMoveToTop )
943
0
                return;  // no need to scroll
944
0
        }
945
0
    }
946
947
0
    m_pStartEntry = pEntry;
948
0
    ShowCursor( false );
949
0
    FillView();
950
0
    m_aVerSBar->SetThumbPos(static_cast<tools::Long>(m_rView.GetVisiblePos(m_pStartEntry)));
951
0
    ShowCursor( true );
952
0
    m_rView.NotifyScrolled();
953
0
    m_rView.Invalidate();
954
0
}
955
956
void SvImpLBox::ScrollToAbsPos( tools::Long nPos )
957
0
{
958
0
    if (m_rView.GetVisibleCount() == 0)
959
0
        return;
960
0
    tools::Long nLastEntryPos = m_rView.GetAbsPos(m_rView.Last());
961
962
0
    if( nPos < 0 )
963
0
        nPos = 0;
964
0
    else if( nPos > nLastEntryPos )
965
0
        nPos = nLastEntryPos;
966
967
0
    SvTreeListEntry* pEntry = m_rView.GetEntryAtAbsPos(nPos);
968
0
    if( !pEntry || pEntry == m_pStartEntry )
969
0
        return;
970
971
0
    if( m_pStartEntry || mbForceMakeVisible )
972
0
        m_nFlags &= ~LBoxFlags::Filling;
973
974
0
    if (m_rView.IsEntryVisible(pEntry))
975
0
    {
976
0
        m_pStartEntry = pEntry;
977
0
        ShowCursor( false );
978
0
        m_aVerSBar->SetThumbPos( nPos );
979
0
        ShowCursor( true );
980
0
        if (GetUpdateMode())
981
0
            m_rView.Invalidate();
982
0
    }
983
0
}
984
985
void SvImpLBox::DrawNet(vcl::RenderContext& rRenderContext)
986
0
{
987
0
    if (m_rView.GetVisibleCount() < 2 && !m_pStartEntry->HasChildrenOnDemand()
988
0
        && !m_pStartEntry->HasChildren())
989
0
    {
990
0
        return;
991
0
    }
992
993
    // for platforms that don't have nets, DrawNativeControl does nothing and returns true
994
    // so that SvImpLBox::DrawNet() doesn't draw anything either
995
0
    if (rRenderContext.IsNativeControlSupported(ControlType::ListNet, ControlPart::Entire))
996
0
    {
997
0
        ImplControlValue aControlValue;
998
0
        if (rRenderContext.DrawNativeControl(ControlType::ListNet, ControlPart::Entire,
999
0
                                             tools::Rectangle(), ControlState::ENABLED, aControlValue, OUString()))
1000
0
        {
1001
0
            return;
1002
0
        }
1003
0
    }
1004
1005
0
    tools::Long nEntryHeight = m_rView.GetEntryHeight();
1006
0
    tools::Long nEntryHeightDIV2 = nEntryHeight / 2;
1007
0
    if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001))
1008
0
        nEntryHeightDIV2--;
1009
1010
0
    SvTreeListEntry* pChild;
1011
0
    SvTreeListEntry* pEntry = m_pStartEntry;
1012
1013
0
    SvLBoxTab* pFirstDynamicTab = m_rView.GetFirstDynamicTab();
1014
0
    while (m_rTree.GetDepth(pEntry) > 0)
1015
0
    {
1016
0
        pEntry = m_rView.GetParent(pEntry);
1017
0
    }
1018
0
    sal_uInt16 nOffs = static_cast<sal_uInt16>(m_rView.GetVisiblePos(m_pStartEntry)
1019
0
                                               - m_rView.GetVisiblePos(pEntry));
1020
0
    tools::Long nY = 0;
1021
0
    nY -= (nOffs * nEntryHeight);
1022
1023
0
    DBG_ASSERT(pFirstDynamicTab,"No Tree!");
1024
1025
0
    auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::LINECOLOR);
1026
1027
0
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1028
1029
    // Set color to draw the vertical and horizontal lines
1030
0
    rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
1031
1032
0
    Point aPos1, aPos2;
1033
0
    sal_uInt16 nDistance;
1034
0
    sal_uLong nMax = m_nVisibleCount + nOffs + 1;
1035
1036
0
    const Image& rExpandedNodeBitmap = GetExpandedNodeBmp();
1037
1038
0
    for (sal_uLong n=0; n< nMax && pEntry; n++)
1039
0
    {
1040
0
        if (m_rView.IsExpanded(pEntry))
1041
0
        {
1042
            // draw vertical line
1043
0
            aPos1.setX(m_rView.GetTabPos(pEntry, pFirstDynamicTab) + m_nNodeBmpTabDistance
1044
0
                       + rExpandedNodeBitmap.GetSizePixel().Width() / 2);
1045
0
            aPos1.setY(nY + nEntryHeight);
1046
0
            pChild = m_rView.FirstChild(pEntry);
1047
0
            assert(pChild && "Child?");
1048
0
            pChild = pChild->LastSibling();
1049
0
            nDistance = static_cast<sal_uInt16>(m_rView.GetVisiblePos(pChild)
1050
0
                                                - m_rView.GetVisiblePos(pEntry));
1051
0
            aPos2 = aPos1;
1052
0
            aPos2.AdjustY((nDistance * nEntryHeight) - (nEntryHeightDIV2 + 2));
1053
0
            rRenderContext.DrawLine(aPos1, aPos2);
1054
0
        }
1055
        // visible in control?
1056
0
        if (n >= nOffs && !m_rTree.IsAtRootDepth(pEntry))
1057
0
        {
1058
            // draw horizontal line
1059
0
            aPos1.setX(m_rView.GetTabPos(m_rView.GetParent(pEntry), pFirstDynamicTab)
1060
0
                       + m_nNodeBmpTabDistance + rExpandedNodeBitmap.GetSizePixel().Width() / 2);
1061
0
            aPos1.setY(nY + nEntryHeightDIV2);
1062
0
            aPos2 = aPos1;
1063
0
            aPos2.AdjustX(m_rView.GetIndent() / 2);
1064
0
            rRenderContext.DrawLine(aPos1, aPos2);
1065
0
        }
1066
0
        nY += nEntryHeight;
1067
0
        pEntry = m_rView.NextVisible(pEntry);
1068
0
    }
1069
0
}
1070
1071
void SvImpLBox::PositionScrollBars(Size& rSize, ScrollBarMask eMask)
1072
0
{
1073
0
    Size aVerSize( m_nVerSBarWidth, rSize.Height() );
1074
0
    Size aHorSize( rSize.Width(), m_nHorSBarHeight );
1075
1076
0
    if (eMask & ScrollBarMask::Vertical)
1077
0
        aHorSize.AdjustWidth( -m_nVerSBarWidth );
1078
0
    if (eMask & ScrollBarMask::Horizontal)
1079
0
        aVerSize.AdjustHeight( -m_nHorSBarHeight );
1080
1081
0
    Point aVerPos(rSize.Width() - aVerSize.Width(), 0);
1082
0
    m_aVerSBar->SetPosSizePixel( aVerPos, aVerSize );
1083
1084
0
    Point aHorPos(0, rSize.Height() - aHorSize.Height());
1085
1086
0
    m_aHorSBar->SetPosSizePixel( aHorPos, aHorSize );
1087
1088
0
    if (eMask & ScrollBarMask::Vertical)
1089
0
        rSize.setWidth( aVerPos.X() );
1090
0
    if (eMask & ScrollBarMask::Horizontal)
1091
0
        rSize.setHeight( aHorPos.Y() );
1092
1093
0
    if (eMask == (ScrollBarMask::Horizontal | ScrollBarMask::Vertical))
1094
0
        m_aScrBarBox->Show();
1095
0
    else
1096
0
        m_aScrBarBox->Hide();
1097
0
}
1098
1099
void SvImpLBox::AdjustScrollBars( Size& rSize )
1100
0
{
1101
0
    tools::Long nEntryHeight = m_rView.GetEntryHeight();
1102
0
    if( !nEntryHeight )
1103
0
        return;
1104
1105
0
    ScrollBarMask eResult = ScrollBarMask::None;
1106
1107
0
    Size aOSize(m_rView.Control::GetOutputSizePixel());
1108
1109
0
    const WinBits nWindowStyle = m_rView.GetStyle();
1110
0
    bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0;
1111
0
    bool bHorBar = false;
1112
0
    tools::Long nMaxRight = aOSize.Width();
1113
0
    Point aOrigin(m_rView.GetMapMode().GetOrigin());
1114
0
    aOrigin.setX( aOrigin.X() * -1 );
1115
0
    nMaxRight += aOrigin.X() - 1;
1116
0
    tools::Long nVis = m_nMostRight - aOrigin.X();
1117
0
    if( (nWindowStyle & (WB_AUTOHSCROLL|WB_HSCROLL)) &&
1118
0
        (nVis < m_nMostRight || nMaxRight < m_nMostRight) )
1119
0
    {
1120
0
        bHorBar = true;
1121
0
    }
1122
1123
    // number of entries that are not collapsed
1124
0
    sal_uLong nTotalCount = m_rView.GetVisibleCount();
1125
1126
    // number of entries visible within the view
1127
0
    m_nVisibleCount = o3tl::make_unsigned(aOSize.Height() / nEntryHeight);
1128
1129
    // do we need a vertical scrollbar?
1130
0
    if( bVerSBar || nTotalCount > m_nVisibleCount )
1131
0
    {
1132
0
        eResult |= ScrollBarMask::Vertical;
1133
0
        nMaxRight -= m_nVerSBarWidth;
1134
0
        if( !bHorBar )
1135
0
        {
1136
0
            if( (nWindowStyle & (WB_AUTOHSCROLL|WB_HSCROLL)) &&
1137
0
                (nVis < m_nMostRight || nMaxRight < m_nMostRight) )
1138
0
                bHorBar = true;
1139
0
        }
1140
0
    }
1141
1142
    // do we need a horizontal scrollbar?
1143
0
    if( bHorBar )
1144
0
    {
1145
0
        eResult |= ScrollBarMask::Horizontal;
1146
        // the number of entries visible within the view has to be recalculated
1147
        // because the horizontal scrollbar is now visible.
1148
0
        m_nVisibleCount = o3tl::make_unsigned(std::max<tools::Long>(0, aOSize.Height() - m_nHorSBarHeight) / nEntryHeight);
1149
        // we might actually need a vertical scrollbar now
1150
0
        if (nTotalCount > m_nVisibleCount)
1151
0
        {
1152
0
            eResult |= ScrollBarMask::Vertical;
1153
0
        }
1154
0
    }
1155
1156
0
    PositionScrollBars(aOSize, eResult);
1157
1158
    // adapt Range, VisibleRange etc.
1159
1160
    // refresh output size, in case we have to scroll
1161
0
    tools::Rectangle aRect;
1162
0
    aRect.SetSize( aOSize );
1163
0
    m_aSelEng.SetVisibleArea( aRect );
1164
1165
    // vertical scrollbar
1166
0
    tools::Long nTemp = static_cast<tools::Long>(m_nVisibleCount);
1167
0
    nTemp--;
1168
0
    if( nTemp != m_aVerSBar->GetVisibleSize() )
1169
0
    {
1170
0
        if( !m_bInVScrollHdl )
1171
0
        {
1172
0
            m_aVerSBar->SetPageSize( nTemp - 1 );
1173
0
            m_aVerSBar->SetVisibleSize( nTemp );
1174
0
        }
1175
0
        else
1176
0
        {
1177
0
            m_nFlags |= LBoxFlags::EndScrollSetVisSize;
1178
0
            m_nNextVerVisSize = nTemp;
1179
0
        }
1180
0
    }
1181
1182
    // horizontal scrollbar
1183
0
    nTemp = m_aHorSBar->GetThumbPos();
1184
0
    m_aHorSBar->SetVisibleSize( aOSize.Width() );
1185
0
    tools::Long nNewThumbPos = m_aHorSBar->GetThumbPos();
1186
0
    Range aRange( m_aHorSBar->GetRange() );
1187
0
    if( aRange.Max() < m_nMostRight+25 )
1188
0
    {
1189
0
        aRange.Max() = m_nMostRight+25;
1190
0
        m_aHorSBar->SetRange( aRange );
1191
0
    }
1192
1193
0
    if( nTemp != nNewThumbPos )
1194
0
    {
1195
0
        nTemp = nNewThumbPos - nTemp;
1196
0
        if (m_rView.IsEditingActive())
1197
0
        {
1198
0
            m_rView.EndEditing(true); // Cancel
1199
0
            m_rView.PaintImmediately();
1200
0
        }
1201
0
        m_rView.m_nFocusWidth = -1;
1202
0
        KeyLeftRight( nTemp );
1203
0
    }
1204
1205
0
    if (eResult & ScrollBarMask::Vertical)
1206
0
        m_aVerSBar->Show();
1207
0
    else
1208
0
        m_aVerSBar->Hide();
1209
1210
0
    if (eResult & ScrollBarMask::Horizontal)
1211
0
        m_aHorSBar->Show();
1212
0
    else
1213
0
    {
1214
0
        m_aHorSBar->Hide();
1215
0
    }
1216
0
    rSize = aOSize;
1217
0
}
1218
1219
void SvImpLBox::InitScrollBarBox()
1220
0
{
1221
0
    m_aScrBarBox->SetSizePixel( Size(m_nVerSBarWidth, m_nHorSBarHeight) );
1222
0
    Size aSize(m_rView.Control::GetOutputSizePixel());
1223
0
    m_aScrBarBox->SetPosPixel( Point(aSize.Width()-m_nVerSBarWidth, aSize.Height()-m_nHorSBarHeight));
1224
0
}
1225
1226
void SvImpLBox::Resize()
1227
0
{
1228
0
    m_aOutputSize = m_rView.Control::GetOutputSizePixel();
1229
0
    if( m_aOutputSize.IsEmpty() )
1230
0
        return;
1231
0
    m_nFlags |= LBoxFlags::InResize;
1232
0
    InitScrollBarBox();
1233
1234
0
    if (m_rView.GetEntryHeight())
1235
0
    {
1236
0
        AdjustScrollBars( m_aOutputSize );
1237
0
        UpdateAll();
1238
0
    }
1239
    // HACK, as in floating and docked windows the scrollbars might not be drawn
1240
    // correctly/not be drawn at all after resizing!
1241
0
    if( m_aHorSBar->IsVisible())
1242
0
        m_aHorSBar->Invalidate();
1243
0
    if( m_aVerSBar->IsVisible())
1244
0
        m_aVerSBar->Invalidate();
1245
0
    m_nFlags &= ~LBoxFlags::InResize;
1246
0
}
1247
1248
void SvImpLBox::FillView()
1249
0
{
1250
0
    if( !m_pStartEntry )
1251
0
    {
1252
0
        sal_uLong nVisibleViewCount = m_rView.GetVisibleCount();
1253
0
        tools::Long nTempThumb = m_aVerSBar->GetThumbPos();
1254
0
        if( nTempThumb < 0 )
1255
0
            nTempThumb = 0;
1256
0
        else if( o3tl::make_unsigned(nTempThumb) >= nVisibleViewCount )
1257
0
            nTempThumb = nVisibleViewCount == 0 ? 0 : nVisibleViewCount - 1;
1258
0
        m_pStartEntry = m_rView.GetEntryAtVisPos(nTempThumb);
1259
0
    }
1260
0
    if( !m_pStartEntry )
1261
0
        return;
1262
1263
0
    sal_uInt16 nLast = static_cast<sal_uInt16>(m_rView.GetVisiblePos(m_rView.LastVisible()));
1264
0
    sal_uInt16 nThumb = static_cast<sal_uInt16>(m_rView.GetVisiblePos(m_pStartEntry));
1265
0
    sal_uLong nCurDispEntries = nLast-nThumb+1;
1266
0
    if( nCurDispEntries >=  m_nVisibleCount )
1267
0
        return;
1268
1269
0
    ShowCursor( false );
1270
    // fill window by moving the thumb up incrementally
1271
0
    bool bFound = false;
1272
0
    SvTreeListEntry* pTemp = m_pStartEntry;
1273
0
    while( nCurDispEntries < m_nVisibleCount && pTemp )
1274
0
    {
1275
0
        pTemp = m_rView.PrevVisible(m_pStartEntry);
1276
0
        if( pTemp )
1277
0
        {
1278
0
            nThumb--;
1279
0
            m_pStartEntry = pTemp;
1280
0
            nCurDispEntries++;
1281
0
            bFound = true;
1282
0
        }
1283
0
    }
1284
0
    if( bFound )
1285
0
    {
1286
0
        m_aVerSBar->SetThumbPos( nThumb );
1287
0
        ShowCursor( true ); // recalculate focus rectangle
1288
0
        m_rView.Invalidate();
1289
0
    }
1290
0
}
1291
1292
1293
void SvImpLBox::ShowVerSBar()
1294
0
{
1295
0
    bool bVerBar = (m_rView.GetStyle() & WB_VSCROLL) != 0;
1296
0
    sal_uLong nVis = 0;
1297
0
    if( !bVerBar )
1298
0
        nVis = m_rView.GetVisibleCount();
1299
0
    if( bVerBar || (m_nVisibleCount && nVis > static_cast<sal_uLong>(m_nVisibleCount-1)) )
1300
0
    {
1301
0
        if( !m_aVerSBar->IsVisible() )
1302
0
        {
1303
0
            m_rView.m_nFocusWidth = -1;
1304
0
            AdjustScrollBars( m_aOutputSize );
1305
0
            if( GetUpdateMode() )
1306
0
                m_aVerSBar->Invalidate();
1307
0
        }
1308
0
    }
1309
0
    else
1310
0
    {
1311
0
        if( m_aVerSBar->IsVisible() )
1312
0
        {
1313
0
            m_rView.m_nFocusWidth = -1;
1314
0
            AdjustScrollBars( m_aOutputSize );
1315
0
        }
1316
0
    }
1317
1318
0
    tools::Long nMaxRight = GetOutputSize().Width();
1319
0
    Point aPos(m_rView.GetMapMode().GetOrigin());
1320
0
    aPos.setX( aPos.X() * -1 ); // convert document coordinates
1321
0
    nMaxRight = nMaxRight + aPos.X() - 1;
1322
0
    if( nMaxRight < m_nMostRight  )
1323
0
    {
1324
0
        if( !m_aHorSBar->IsVisible() )
1325
0
        {
1326
0
            m_rView.m_nFocusWidth = -1;
1327
0
            AdjustScrollBars( m_aOutputSize );
1328
0
            if( GetUpdateMode() )
1329
0
                m_aHorSBar->Invalidate();
1330
0
        }
1331
0
        else
1332
0
        {
1333
0
            Range aRange( m_aHorSBar->GetRange() );
1334
0
            if( aRange.Max() < m_nMostRight+25 )
1335
0
            {
1336
0
                aRange.Max() = m_nMostRight+25;
1337
0
                m_aHorSBar->SetRange( aRange );
1338
0
            }
1339
0
            else
1340
0
            {
1341
0
                m_rView.m_nFocusWidth = -1;
1342
0
                AdjustScrollBars( m_aOutputSize );
1343
0
            }
1344
0
        }
1345
0
    }
1346
0
    else
1347
0
    {
1348
0
        if( m_aHorSBar->IsVisible() )
1349
0
        {
1350
0
            m_rView.m_nFocusWidth = -1;
1351
0
            AdjustScrollBars( m_aOutputSize );
1352
0
        }
1353
0
    }
1354
0
}
1355
1356
1357
void SvImpLBox::SyncVerThumb()
1358
0
{
1359
0
    if( m_pStartEntry )
1360
0
    {
1361
0
        tools::Long nEntryPos = m_rView.GetVisiblePos(m_pStartEntry);
1362
0
        m_aVerSBar->SetThumbPos( nEntryPos );
1363
0
    }
1364
0
    else
1365
0
        m_aVerSBar->SetThumbPos( 0 );
1366
0
}
1367
1368
bool SvImpLBox::IsEntryInView( SvTreeListEntry* pEntry ) const
1369
0
{
1370
    // parent collapsed
1371
0
    if (!m_rView.IsEntryVisible(pEntry))
1372
0
        return false;
1373
0
    tools::Long nY = GetEntryLine( pEntry );
1374
0
    if( nY < 0 )
1375
0
        return false;
1376
0
    tools::Long nMax = m_nVisibleCount * m_rView.GetEntryHeight();
1377
0
    return nY < nMax;
1378
0
}
1379
1380
1381
tools::Long SvImpLBox::GetEntryLine(const SvTreeListEntry* pEntry) const
1382
0
{
1383
0
    if(!m_pStartEntry )
1384
0
        return -1; // invisible position
1385
1386
0
    tools::Long nFirstVisPos = m_rView.GetVisiblePos(m_pStartEntry);
1387
0
    tools::Long nEntryVisPos = m_rView.GetVisiblePos(pEntry);
1388
0
    nFirstVisPos = nEntryVisPos - nFirstVisPos;
1389
0
    nFirstVisPos *= m_rView.GetEntryHeight();
1390
0
    return nFirstVisPos;
1391
0
}
1392
1393
void SvImpLBox::SetEntryHeight()
1394
0
{
1395
0
    SetNodeBmpWidth( GetExpandedNodeBmp() );
1396
0
    SetNodeBmpWidth( GetCollapsedNodeBmp() );
1397
0
    if (!m_rView.HasViewData()) // are we within the Clear?
1398
0
    {
1399
0
        Size aSize = m_rView.Control::GetOutputSizePixel();
1400
0
        AdjustScrollBars( aSize );
1401
0
    }
1402
0
    else
1403
0
    {
1404
0
        Resize();
1405
0
        if( GetUpdateMode() )
1406
0
            m_rView.Invalidate();
1407
0
    }
1408
0
}
1409
1410
1411
// ***********************************************************************
1412
// Callback Functions
1413
// ***********************************************************************
1414
1415
void SvImpLBox::EntryExpanded( SvTreeListEntry* pEntry )
1416
0
{
1417
    // SelAllDestrAnch( false, true ); //DeselectAll();
1418
0
    if( !GetUpdateMode() )
1419
0
        return;
1420
1421
0
    ShowCursor( false );
1422
0
    tools::Long nY = GetEntryLine( pEntry );
1423
0
    if( IsLineVisible(nY) )
1424
0
    {
1425
0
        InvalidateEntriesFrom( nY );
1426
0
        FindMostRight( pEntry );
1427
0
    }
1428
0
    m_aVerSBar->SetRange(Range(0, static_cast<tools::Long>(m_rView.GetVisibleCount()) - 1));
1429
    // if we expanded before the thumb, the thumb's position has to be
1430
    // corrected
1431
0
    SyncVerThumb();
1432
0
    ShowVerSBar();
1433
0
    ShowCursor( true );
1434
0
}
1435
1436
void SvImpLBox::EntryCollapsed( SvTreeListEntry* pEntry )
1437
0
{
1438
0
    if (!m_rView.IsEntryVisible(pEntry))
1439
0
        return;
1440
1441
0
    ShowCursor( false );
1442
1443
0
    if (!m_pMostRightEntry || m_rTree.IsChild(pEntry, m_pMostRightEntry))
1444
0
    {
1445
0
        FindMostRight();
1446
0
    }
1447
1448
0
    if( m_pStartEntry )
1449
0
    {
1450
0
        tools::Long nOldThumbPos   = m_aVerSBar->GetThumbPos();
1451
0
        tools::Long nVisList = m_rView.GetVisibleCount();
1452
0
        m_aVerSBar->SetRange( Range(0, nVisList-1) );
1453
0
        tools::Long nNewThumbPos   = m_aVerSBar->GetThumbPos();
1454
0
        if( nNewThumbPos != nOldThumbPos  )
1455
0
        {
1456
0
            m_pStartEntry = m_rView.First();
1457
0
            sal_uInt16 nDistance = static_cast<sal_uInt16>(nNewThumbPos);
1458
0
            if( nDistance )
1459
0
                m_pStartEntry = m_rView.NextVisible(m_pStartEntry, nDistance);
1460
0
            if( GetUpdateMode() )
1461
0
                m_rView.Invalidate();
1462
0
        }
1463
0
        else
1464
0
            SyncVerThumb();
1465
0
        ShowVerSBar();
1466
0
    }
1467
    // has the cursor been collapsed?
1468
0
    if (m_rTree.IsChild(pEntry, m_pCursor))
1469
0
        SetCursor( pEntry );
1470
0
    if( GetUpdateMode() )
1471
0
        ShowVerSBar();
1472
0
    ShowCursor( true );
1473
0
    if( GetUpdateMode() && m_pCursor )
1474
0
        m_rView.Select(m_pCursor);
1475
0
}
1476
1477
void SvImpLBox::CollapsingEntry( SvTreeListEntry* pEntry )
1478
0
{
1479
0
    if (!m_rView.IsEntryVisible(pEntry) || !m_pStartEntry)
1480
0
        return;
1481
1482
0
    SelAllDestrAnch( false ); // deselect all
1483
1484
    // is the collapsed cursor visible?
1485
0
    tools::Long nY = GetEntryLine( pEntry );
1486
0
    if( IsLineVisible(nY) )
1487
0
    {
1488
0
        if( GetUpdateMode() )
1489
0
            InvalidateEntriesFrom( nY );
1490
0
    }
1491
0
    else
1492
0
    {
1493
0
        if (m_rTree.IsChild(pEntry, m_pStartEntry))
1494
0
        {
1495
0
            m_pStartEntry = pEntry;
1496
0
            if( GetUpdateMode() )
1497
0
                m_rView.Invalidate();
1498
0
        }
1499
0
    }
1500
0
}
1501
1502
1503
void SvImpLBox::SetNodeBmpWidth( const Image& rBmp )
1504
0
{
1505
0
    const Size aSize( rBmp.GetSizePixel() );
1506
0
    m_nNodeBmpWidth = aSize.Width();
1507
0
}
1508
1509
void SvImpLBox::SetNodeBmpTabDistance()
1510
0
{
1511
0
    m_nNodeBmpTabDistance = -m_rView.GetIndent();
1512
0
    if (m_rView.m_nContextBmpWidthMax)
1513
0
    {
1514
        // only if the first dynamic tab is centered (we currently assume that)
1515
0
        Size aSize = GetExpandedNodeBmp().GetSizePixel();
1516
0
        m_nNodeBmpTabDistance -= aSize.Width() / 2;
1517
0
    }
1518
0
}
1519
1520
1521
// corrects the cursor when using SingleSelection
1522
1523
void SvImpLBox::EntrySelected( SvTreeListEntry* pEntry, bool bSelect )
1524
0
{
1525
0
    if( m_nFlags & LBoxFlags::IgnoreSelect )
1526
0
        return;
1527
1528
0
    m_nFlags &= ~LBoxFlags::DeselectAll;
1529
0
    if( bSelect &&
1530
0
        m_aSelEng.GetSelectionMode() == SelectionMode::Single &&
1531
0
        pEntry != m_pCursor )
1532
0
    {
1533
0
        SetCursor( pEntry );
1534
0
        DBG_ASSERT(m_rView.GetSelectionCount() == 1, "selection count?");
1535
0
    }
1536
1537
0
    if (GetUpdateMode() && m_rView.IsEntryVisible(pEntry))
1538
0
    {
1539
0
        tools::Long nY = GetEntryLine( pEntry );
1540
0
        if( IsLineVisible( nY ) )
1541
0
        {
1542
0
            ShowCursor(false);
1543
0
            InvalidateEntry(pEntry);
1544
0
            ShowCursor(true);
1545
0
        }
1546
0
    }
1547
0
}
1548
1549
1550
void SvImpLBox::RemovingEntry( SvTreeListEntry* pEntry )
1551
0
{
1552
0
    CallEventListeners( VclEventId::ListboxItemRemoved , pEntry );
1553
1554
0
    DestroyAnchor();
1555
1556
0
    if (!m_rView.IsEntryVisible(pEntry))
1557
0
    {
1558
        // if parent is collapsed => bye!
1559
0
        m_nFlags |= LBoxFlags::RemovedEntryInvisible;
1560
0
        return;
1561
0
    }
1562
1563
0
    if (pEntry == m_pMostRightEntry
1564
0
        || (pEntry->HasChildren() && m_rView.IsExpanded(pEntry)
1565
0
            && m_rTree.IsChild(pEntry, m_pMostRightEntry)))
1566
0
    {
1567
0
        m_nFlags |= LBoxFlags::RemovedRecalcMostRight;
1568
0
    }
1569
1570
0
    SvTreeListEntry* pOldStartEntry = m_pStartEntry;
1571
1572
0
    SvTreeListEntry* pParent = m_rView.GetModel()->GetParent(pEntry);
1573
1574
0
    if (pParent && m_rView.GetModel()->GetChildList(pParent).size() == 1)
1575
0
    {
1576
0
        DBG_ASSERT(m_rView.IsExpanded(pParent), "Parent not expanded");
1577
0
        pParent->SetFlags( pParent->GetFlags() | SvTLEntryFlags::NO_NODEBMP);
1578
0
        InvalidateEntry( pParent );
1579
0
    }
1580
1581
0
    if (m_pCursor && m_rTree.IsChild(pEntry, m_pCursor))
1582
0
        m_pCursor = pEntry;
1583
0
    if (m_pStartEntry && m_rTree.IsChild(pEntry, m_pStartEntry))
1584
0
        m_pStartEntry = pEntry;
1585
1586
0
    SvTreeListEntry* pTemp;
1587
0
    if( m_pCursor && m_pCursor == pEntry )
1588
0
    {
1589
0
        if( m_bSimpleTravel )
1590
0
            m_rView.Select(m_pCursor, false);
1591
0
        ShowCursor( false );    // focus rectangle gone
1592
        // NextSibling, because we also delete the children of the cursor
1593
0
        pTemp = m_pCursor->NextSibling();
1594
0
        if( !pTemp )
1595
0
            pTemp = m_rView.PrevVisible(m_pCursor);
1596
1597
0
        SetCursor( pTemp, true );
1598
0
    }
1599
0
    if( m_pStartEntry && m_pStartEntry == pEntry )
1600
0
    {
1601
0
        pTemp = m_pStartEntry->NextSibling();
1602
0
        if( !pTemp )
1603
0
            pTemp = m_rView.PrevVisible(m_pStartEntry);
1604
0
        m_pStartEntry = pTemp;
1605
0
    }
1606
0
    if( GetUpdateMode())
1607
0
    {
1608
        // if it is the last one, we have to invalidate it, so the lines are
1609
        // drawn correctly (in this case they're deleted)
1610
0
        if (m_pStartEntry
1611
0
            && (m_pStartEntry != pOldStartEntry || pEntry == m_rView.GetModel()->Last()))
1612
0
        {
1613
0
            m_aVerSBar->SetThumbPos(m_rView.GetVisiblePos(m_pStartEntry));
1614
0
            m_rView.Invalidate(GetVisibleArea());
1615
0
        }
1616
0
        else
1617
0
            InvalidateEntriesFrom( GetEntryLine( pEntry ) );
1618
0
    }
1619
0
}
1620
1621
void SvImpLBox::EntryRemoved()
1622
0
{
1623
0
    if( m_nFlags & LBoxFlags::RemovedEntryInvisible )
1624
0
    {
1625
0
        m_nFlags &= ~LBoxFlags::RemovedEntryInvisible;
1626
0
        return;
1627
0
    }
1628
0
    if( !m_pStartEntry )
1629
0
        m_pStartEntry = m_rTree.First();
1630
0
    if( !m_pCursor )
1631
0
        SetCursor( m_pStartEntry, true );
1632
1633
0
    if (m_pCursor && (m_bSimpleTravel || !m_rView.GetSelectionCount()))
1634
0
        m_rView.Select(m_pCursor);
1635
1636
0
    if( GetUpdateMode())
1637
0
    {
1638
0
        if( m_nFlags & LBoxFlags::RemovedRecalcMostRight )
1639
0
            FindMostRight();
1640
0
        m_aVerSBar->SetRange(Range(0, static_cast<tools::Long>(m_rView.GetVisibleCount()) - 1));
1641
0
        FillView();
1642
0
        if( m_pStartEntry )
1643
            // if something above the thumb was deleted
1644
0
            m_aVerSBar->SetThumbPos(m_rView.GetVisiblePos(m_pStartEntry));
1645
1646
0
        ShowVerSBar();
1647
0
        if (m_pCursor && m_rView.HasFocus() && !m_rView.IsSelected(m_pCursor))
1648
0
        {
1649
0
            if (m_rView.GetSelectionCount())
1650
0
            {
1651
                // is a neighboring entry selected?
1652
0
                SvTreeListEntry* pNextCursor = m_rView.PrevVisible(m_pCursor);
1653
0
                if (!pNextCursor || !m_rView.IsSelected(pNextCursor))
1654
0
                    pNextCursor = m_rView.NextVisible(m_pCursor);
1655
0
                if (!pNextCursor || !m_rView.IsSelected(pNextCursor))
1656
                    // no neighbor selected: use first selected
1657
0
                    pNextCursor = m_rView.FirstSelected();
1658
0
                SetCursor( pNextCursor );
1659
0
                MakeVisible( m_pCursor );
1660
0
            }
1661
0
            else
1662
0
                m_rView.Select(m_pCursor);
1663
0
        }
1664
0
        ShowCursor( true );
1665
0
    }
1666
0
    m_nFlags &= ~LBoxFlags::RemovedRecalcMostRight;
1667
0
}
1668
1669
1670
void SvImpLBox::MovingEntry( SvTreeListEntry* pEntry )
1671
0
{
1672
0
    bool bDeselAll(m_nFlags & LBoxFlags::DeselectAll);
1673
0
    SelAllDestrAnch( false );  // DeselectAll();
1674
0
    if( !bDeselAll )
1675
0
        m_nFlags &= ~LBoxFlags::DeselectAll;
1676
1677
0
    if( pEntry == m_pCursor )
1678
0
        ShowCursor( false );
1679
0
    if( IsEntryInView( pEntry ) )
1680
0
        m_rView.Invalidate();
1681
0
    if( pEntry != m_pStartEntry )
1682
0
        return;
1683
1684
0
    SvTreeListEntry* pNew = nullptr;
1685
0
    if( !pEntry->HasChildren() )
1686
0
    {
1687
0
        pNew = m_rView.NextVisible(m_pStartEntry);
1688
0
        if( !pNew )
1689
0
            pNew = m_rView.PrevVisible(m_pStartEntry);
1690
0
    }
1691
0
    else
1692
0
    {
1693
0
        pNew = pEntry->NextSibling();
1694
0
        if( !pNew )
1695
0
            pNew = pEntry->PrevSibling();
1696
0
    }
1697
0
    m_pStartEntry = pNew;
1698
0
}
1699
1700
void SvImpLBox::EntryMoved( SvTreeListEntry* pEntry )
1701
0
{
1702
0
    UpdateContextBmpWidthVectorFromMovedEntry( pEntry );
1703
1704
0
    if ( !m_pStartEntry )
1705
        // this might happen if the only entry in the view is moved to its very same position
1706
        // #i97346#
1707
0
        m_pStartEntry = m_rView.First();
1708
1709
0
    m_aVerSBar->SetRange(Range(0, static_cast<tools::Long>(m_rView.GetVisibleCount()) - 1));
1710
0
    sal_uInt16 nFirstPos = static_cast<sal_uInt16>(m_rTree.GetAbsPos(m_pStartEntry));
1711
0
    sal_uInt16 nNewPos = static_cast<sal_uInt16>(m_rTree.GetAbsPos(pEntry));
1712
0
    FindMostRight();
1713
0
    if( nNewPos < nFirstPos ) // HACK!
1714
0
        m_pStartEntry = pEntry;
1715
0
    SyncVerThumb();
1716
0
    if( pEntry == m_pCursor )
1717
0
    {
1718
0
        if (m_rView.IsEntryVisible(m_pCursor))
1719
0
            ShowCursor( true );
1720
0
        else
1721
0
        {
1722
0
            SvTreeListEntry* pParent = pEntry;
1723
0
            do {
1724
0
                pParent = m_rTree.GetParent(pParent);
1725
0
            } while (!m_rView.IsEntryVisible(pParent));
1726
0
            SetCursor( pParent );
1727
0
        }
1728
0
    }
1729
0
    if( IsEntryInView( pEntry ) )
1730
0
        m_rView.Invalidate();
1731
0
}
1732
1733
1734
void SvImpLBox::EntryInserted( SvTreeListEntry* pEntry )
1735
0
{
1736
0
    if( !GetUpdateMode() )
1737
0
        return;
1738
1739
0
    SvTreeListEntry* pParent = m_rTree.GetParent(pEntry);
1740
0
    if (pParent && m_rTree.GetChildList(pParent).size() == 1)
1741
        // draw plus sign
1742
0
        m_rTree.InvalidateEntry(*pParent);
1743
1744
0
    if (!m_rView.IsEntryVisible(pEntry))
1745
0
        return;
1746
0
    bool bDeselAll(m_nFlags & LBoxFlags::DeselectAll);
1747
0
    if( bDeselAll )
1748
0
        SelAllDestrAnch( false );
1749
0
    else
1750
0
        DestroyAnchor();
1751
    //  nFlags &= (~LBoxFlags::DeselectAll);
1752
//      ShowCursor( false ); // if cursor is moved lower
1753
0
    tools::Long nY = GetEntryLine( pEntry );
1754
0
    bool bEntryVisible = IsLineVisible( nY );
1755
0
    if( bEntryVisible )
1756
0
    {
1757
0
        ShowCursor( false ); // if cursor is moved lower
1758
0
        nY -= m_rView.GetEntryHeight(); // because of lines
1759
0
        InvalidateEntriesFrom( nY );
1760
0
    }
1761
0
    else if( m_pStartEntry && nY < GetEntryLine(m_pStartEntry) )
1762
0
    {
1763
        // Check if the view is filled completely. If not, then adjust
1764
        // pStartEntry and the Cursor (automatic scrolling).
1765
0
        sal_uInt16 nLast = static_cast<sal_uInt16>(m_rView.GetVisiblePos(m_rView.LastVisible()));
1766
0
        sal_uInt16 nThumb = static_cast<sal_uInt16>(m_rView.GetVisiblePos(m_pStartEntry));
1767
0
        sal_uInt16 nCurDispEntries = nLast-nThumb+1;
1768
0
        if( nCurDispEntries < m_nVisibleCount )
1769
0
        {
1770
            // set at the next paint event
1771
0
            m_pStartEntry = nullptr;
1772
0
            SetCursor( nullptr );
1773
0
            m_rView.Invalidate();
1774
0
        }
1775
0
    }
1776
0
    else if( !m_pStartEntry )
1777
0
        m_rView.Invalidate();
1778
1779
0
    SetMostRight( pEntry );
1780
0
    m_aVerSBar->SetRange(Range(0, static_cast<tools::Long>(m_rView.GetVisibleCount()) - 1));
1781
0
    SyncVerThumb(); // if something was inserted before the thumb
1782
0
    ShowVerSBar();
1783
0
    ShowCursor( true );
1784
0
    if (m_pStartEntry != m_rView.First() && (m_nFlags & LBoxFlags::Filling))
1785
0
        m_rView.PaintImmediately();
1786
0
}
1787
1788
1789
// ********************************************************************
1790
// Event handler
1791
// ********************************************************************
1792
1793
1794
// ****** Control the control animation
1795
1796
bool SvImpLBox::ButtonDownCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry* pEntry)
1797
0
{
1798
0
    SvLBoxItem* pItem = m_rView.GetItem(pEntry, rMEvt.GetPosPixel().X());
1799
0
    if (pItem && pItem->GetType() == SvLBoxItemType::Button)
1800
0
    {
1801
0
        m_pActiveButton = static_cast<SvLBoxButton*>(pItem);
1802
0
        m_pActiveEntry = pEntry;
1803
0
        if( m_pCursor == m_pActiveEntry )
1804
0
            m_rView.HideFocus();
1805
0
        m_rView.CaptureMouse();
1806
0
        m_pActiveButton->SetStateHilighted( true );
1807
0
        InvalidateEntry(m_pActiveEntry);
1808
0
        return true;
1809
0
    }
1810
0
    else
1811
0
        m_pActiveButton = nullptr;
1812
0
    return false;
1813
0
}
1814
1815
bool SvImpLBox::MouseMoveCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry const * pEntry)
1816
0
{
1817
0
    if( m_pActiveButton )
1818
0
    {
1819
0
        tools::Long nMouseX = rMEvt.GetPosPixel().X();
1820
0
        if (pEntry == m_pActiveEntry && m_rView.GetItem(m_pActiveEntry, nMouseX) == m_pActiveButton)
1821
0
        {
1822
0
            if( !m_pActiveButton->IsStateHilighted() )
1823
0
            {
1824
0
                m_pActiveButton->SetStateHilighted(true );
1825
0
                InvalidateEntry(m_pActiveEntry);
1826
0
            }
1827
0
        }
1828
0
        else
1829
0
        {
1830
0
            if( m_pActiveButton->IsStateHilighted() )
1831
0
            {
1832
0
                m_pActiveButton->SetStateHilighted(false );
1833
0
                InvalidateEntry(m_pActiveEntry);
1834
0
            }
1835
0
        }
1836
0
        return true;
1837
0
    }
1838
0
    return false;
1839
0
}
1840
1841
bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt )
1842
0
{
1843
0
    if( m_pActiveButton && m_pActiveButton->isEnable())
1844
0
    {
1845
0
        m_rView.ReleaseMouse();
1846
0
        SvTreeListEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() );
1847
0
        m_pActiveButton->SetStateHilighted( false );
1848
0
        tools::Long nMouseX = rMEvt.GetPosPixel().X();
1849
0
        if (pEntry == m_pActiveEntry && m_rView.GetItem(m_pActiveEntry, nMouseX) == m_pActiveButton)
1850
0
        {
1851
0
            const bool bChecked = m_pActiveButton->IsStateChecked();
1852
0
            m_pActiveButton->ClickHdl(m_pActiveEntry);
1853
0
            if (m_pActiveButton->IsStateChecked() != bChecked)
1854
0
                CallEventListeners(VclEventId::CheckboxToggle, m_pActiveEntry);
1855
0
        }
1856
0
        InvalidateEntry(m_pActiveEntry);
1857
0
        if (m_pCursor == m_pActiveEntry)
1858
0
            ShowCursor(true);
1859
0
        m_pActiveButton = nullptr;
1860
0
        m_pActiveEntry = nullptr;
1861
0
        return true;
1862
0
    }
1863
0
    return false;
1864
0
}
1865
1866
// ******* Control plus/minus button for expanding/collapsing
1867
1868
// false == no expand/collapse button hit
1869
bool SvImpLBox::IsNodeButton(const Point& rPosPixel, const SvTreeListEntry& rEntry) const
1870
0
{
1871
0
    if (!rEntry.HasChildren() && !rEntry.HasChildrenOnDemand())
1872
0
        return false;
1873
1874
0
    SvLBoxTab* pFirstDynamicTab = m_rView.GetFirstDynamicTab();
1875
0
    if( !pFirstDynamicTab )
1876
0
        return false;
1877
1878
0
    tools::Long nMouseX = rPosPixel.X();
1879
    // convert to document coordinates
1880
0
    Point aOrigin(m_rView.GetMapMode().GetOrigin());
1881
0
    nMouseX -= aOrigin.X();
1882
1883
0
    tools::Long nX = m_rView.GetTabPos(&rEntry, pFirstDynamicTab);
1884
0
    nX += m_nNodeBmpTabDistance;
1885
0
    if( nMouseX < nX )
1886
0
        return false;
1887
0
    nX += m_nNodeBmpWidth;
1888
0
    return nMouseX <= nX;
1889
0
}
1890
1891
// false == hit no node button
1892
bool SvImpLBox::ButtonDownCheckExpand(const MouseEvent& rMEvt, SvTreeListEntry& rEntry)
1893
0
{
1894
0
    bool bRet = false;
1895
1896
0
    if (m_rView.IsEditingActive() && &rEntry == m_rView.m_pEdEntry)
1897
        // inplace editing -> nothing to do
1898
0
        bRet = true;
1899
0
    else if (IsNodeButton(rMEvt.GetPosPixel(), rEntry))
1900
0
    {
1901
0
        if (m_rView.IsExpanded(&rEntry))
1902
0
        {
1903
0
            m_rView.EndEditing(true);
1904
0
            m_rView.Collapse(&rEntry);
1905
0
        }
1906
0
        else
1907
0
        {
1908
            // you can expand an entry, which is in editing
1909
0
            m_rView.Expand(rEntry);
1910
0
        }
1911
0
        bRet = true;
1912
0
    }
1913
1914
0
    return bRet;
1915
0
}
1916
1917
void SvImpLBox::MouseButtonDown( const MouseEvent& rMEvt )
1918
0
{
1919
0
    if ( !rMEvt.IsLeft() && !rMEvt.IsRight())
1920
0
        return;
1921
1922
0
    m_aEditIdle.Stop();
1923
0
    Point aPos( rMEvt.GetPosPixel());
1924
1925
0
    if( aPos.X() > m_aOutputSize.Width() || aPos.Y() > m_aOutputSize.Height() )
1926
0
        return;
1927
1928
0
    if( !m_pCursor )
1929
0
        m_pCursor = m_pStartEntry;
1930
0
    m_nFlags &= ~LBoxFlags::Filling;
1931
0
    m_rView.GrabFocus();
1932
    //fdo#82270 Grabbing focus can invalidate the entries, re-fetch
1933
0
    SvTreeListEntry* pEntry = GetEntry(aPos);
1934
    // the entry can still be invalid!
1935
0
    if (!pEntry)
1936
0
    {
1937
0
        if (!rMEvt.GetModifier() && rMEvt.IsLeft())
1938
0
            SelAllDestrAnch(false); // deselect all
1939
0
        return;
1940
0
    }
1941
1942
0
    tools::Long nY = GetEntryLine( pEntry );
1943
    // Node-Button?
1944
0
    if (ButtonDownCheckExpand(rMEvt, *pEntry))
1945
0
        return;
1946
1947
0
    if (!EntryReallyHit(*pEntry, aPos, nY))
1948
0
        return;
1949
1950
0
    SvLBoxItem* pXItem = m_rView.GetItem(pEntry, aPos.X());
1951
0
    if( pXItem )
1952
0
    {
1953
0
        SvLBoxTab* pXTab = m_rView.GetTab(*pEntry, *pXItem);
1954
0
        if (!rMEvt.IsMod1() && !rMEvt.IsMod2() && rMEvt.IsLeft() && pXTab->IsEditable()
1955
0
            && pEntry == m_rView.FirstSelected() && nullptr == m_rView.NextSelected(pEntry))
1956
            // #i8234# FirstSelected() and NextSelected() ensures, that inplace editing is only triggered, when only one entry is selected
1957
0
            m_nFlags |= LBoxFlags::StartEditTimer;
1958
0
        if (!m_rView.IsSelected(pEntry))
1959
0
            m_nFlags &= ~LBoxFlags::StartEditTimer;
1960
0
    }
1961
1962
1963
0
    if( (rMEvt.GetClicks() % 2) == 0)
1964
0
    {
1965
0
        m_nFlags &= ~LBoxFlags::StartEditTimer;
1966
0
        m_rView.m_pHdlEntry = pEntry;
1967
0
        if (!m_rView.DoubleClickHdl())
1968
0
        {
1969
            // Handler signals nothing to be done anymore, bail out, 'this' may
1970
            // even be dead and destroyed.
1971
0
            return;
1972
0
        }
1973
0
        else
1974
0
        {
1975
            // if the entry was deleted within the handler
1976
0
            pEntry = GetClickedEntry( aPos );
1977
0
            if( !pEntry )
1978
0
                return;
1979
0
            if (pEntry != m_rView.m_pHdlEntry)
1980
0
            {
1981
                // select anew & bye
1982
0
                if( !m_bSimpleTravel && !m_aSelEng.IsAlwaysAdding())
1983
0
                    SelAllDestrAnch( false ); // DeselectAll();
1984
0
                SetCursor( pEntry );
1985
1986
0
                return;
1987
0
            }
1988
0
            if( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() )
1989
0
            {
1990
0
                if (m_rView.IsExpanded(pEntry))
1991
0
                    m_rView.Collapse(pEntry);
1992
0
                else
1993
0
                    m_rView.Expand(*pEntry);
1994
0
                if( pEntry == m_pCursor )  // only if Entryitem was clicked
1995
                                          // (Nodebutton is not an Entryitem!)
1996
0
                    m_rView.Select(m_pCursor);
1997
0
                return;
1998
0
            }
1999
0
        }
2000
0
    }
2001
0
    else
2002
0
    {
2003
        // CheckButton? (TreeListBox: Check + Info)
2004
0
        if( ButtonDownCheckCtrl(rMEvt, pEntry) )
2005
0
            return;
2006
        // Inplace-Editing?
2007
0
    }
2008
0
    if ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE
2009
0
         && !rMEvt.IsRight() ) // tdf#128824
2010
0
        m_aSelEng.SelMouseButtonDown( rMEvt );
2011
0
}
2012
2013
void SvImpLBox::MouseButtonUp( const MouseEvent& rMEvt)
2014
0
{
2015
0
    if ( !ButtonUpCheckCtrl( rMEvt ) && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
2016
0
        m_aSelEng.SelMouseButtonUp( rMEvt );
2017
0
    if( m_nFlags & LBoxFlags::StartEditTimer )
2018
0
    {
2019
0
        m_nFlags &= ~LBoxFlags::StartEditTimer;
2020
0
        m_aEditClickPos = rMEvt.GetPosPixel();
2021
0
        m_aEditIdle.Start();
2022
0
    }
2023
2024
0
    if (m_rView.mbActivateOnSingleClick)
2025
0
    {
2026
0
        Point aPos(rMEvt.GetPosPixel());
2027
0
        SvTreeListEntry* pEntry = GetEntry(aPos);
2028
        // tdf#143245 ActivateOnSingleClick only
2029
        // if the 'up' is at the active entry
2030
        // typically selected by the 'down'
2031
0
        if (!pEntry || pEntry != m_pCursor)
2032
0
            return;
2033
0
        m_rView.DoubleClickHdl();
2034
0
    }
2035
0
}
2036
2037
void SvImpLBox::MouseMove( const MouseEvent& rMEvt)
2038
0
{
2039
0
    Point aPos = rMEvt.GetPosPixel();
2040
0
    SvTreeListEntry* pEntry = GetClickedEntry(aPos);
2041
0
    if ( MouseMoveCheckCtrl( rMEvt, pEntry ) || ( m_aSelEng.GetSelectionMode() == SelectionMode::NONE ) )
2042
0
        return;
2043
2044
0
    m_aSelEng.SelMouseMove(rMEvt);
2045
0
    if (m_rView.mbHoverSelection)
2046
0
    {
2047
0
        if (aPos.X() < 0 || aPos.Y() < 0 || aPos.X() > m_aOutputSize.Width() || aPos.Y() > m_aOutputSize.Height())
2048
0
            pEntry = nullptr;
2049
0
        else
2050
0
            pEntry = GetEntry(aPos);
2051
0
        if (!pEntry)
2052
0
            m_rView.SelectAll(false);
2053
0
        else if (!m_rView.IsSelected(pEntry) && IsSelectable(*pEntry))
2054
0
        {
2055
0
            m_rView.mbSelectingByHover = true;
2056
0
            m_rView.Select(pEntry);
2057
0
            m_rView.mbSelectingByHover = false;
2058
0
        }
2059
0
    }
2060
0
}
2061
2062
void SvImpLBox::ExpandAll()
2063
0
{
2064
0
    sal_uInt16 nRefDepth = m_rTree.GetDepth(m_pCursor);
2065
0
    SvTreeListEntry* pCur = m_rTree.Next(m_pCursor);
2066
0
    while (pCur && m_rTree.GetDepth(pCur) > nRefDepth)
2067
0
    {
2068
0
        if (pCur->HasChildren() && !m_rView.IsExpanded(pCur))
2069
0
            m_rView.Expand(*pCur);
2070
0
        pCur = m_rTree.Next(pCur);
2071
0
    }
2072
0
}
2073
2074
void SvImpLBox::CollapseTo(SvTreeListEntry* pParentToCollapse)
2075
0
{
2076
    // collapse all parents until we get to the given parent to collapse
2077
0
    if (!pParentToCollapse)
2078
0
        return;
2079
2080
0
    sal_uInt16 nRefDepth;
2081
    // special case explorer: if the root only has a single
2082
    // entry, don't collapse the root entry
2083
0
    if (m_rTree.GetChildList(nullptr).size() < 2)
2084
0
    {
2085
0
        nRefDepth = 1;
2086
0
        pParentToCollapse = m_pCursor;
2087
0
        while (m_rTree.GetParent(pParentToCollapse)
2088
0
               && m_rTree.GetDepth(m_rTree.GetParent(pParentToCollapse)) > 0)
2089
0
        {
2090
0
            pParentToCollapse = m_rTree.GetParent(pParentToCollapse);
2091
0
        }
2092
0
    }
2093
0
    else
2094
0
        nRefDepth = m_rTree.GetDepth(pParentToCollapse);
2095
2096
0
    if (m_rView.IsExpanded(pParentToCollapse))
2097
0
        m_rView.Collapse(pParentToCollapse);
2098
0
    SvTreeListEntry* pCur = m_rTree.Next(pParentToCollapse);
2099
0
    while (pCur && m_rTree.GetDepth(pCur) > nRefDepth)
2100
0
    {
2101
0
        if (pCur->HasChildren() && m_rView.IsExpanded(pCur))
2102
0
            m_rView.Collapse(pCur);
2103
0
        pCur = m_rTree.Next(pCur);
2104
0
    }
2105
0
}
2106
2107
bool SvImpLBox::KeyInput( const KeyEvent& rKEvt)
2108
0
{
2109
0
    m_aEditIdle.Stop();
2110
0
    const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
2111
2112
0
    if( rKeyCode.IsMod2() )
2113
0
        return false; // don't evaluate Alt key
2114
2115
0
    m_nFlags &= ~LBoxFlags::Filling;
2116
2117
0
    if( !m_pCursor )
2118
0
        m_pCursor = m_pStartEntry;
2119
0
    if( !m_pCursor )
2120
0
        return false;
2121
2122
0
    bool bKeyUsed = true;
2123
2124
0
    sal_uInt16  nDelta = static_cast<sal_uInt16>(m_aVerSBar->GetPageSize());
2125
0
    sal_uInt16  aCode = rKeyCode.GetCode();
2126
2127
0
    bool    bShift = rKeyCode.IsShift();
2128
0
    bool    bMod1 = rKeyCode.IsMod1();
2129
2130
0
    SvTreeListEntry* pNewCursor;
2131
2132
0
    switch( aCode )
2133
0
    {
2134
0
        case KEY_UP:
2135
0
            if( !IsEntryInView( m_pCursor ) )
2136
0
                MakeVisible( m_pCursor );
2137
2138
0
            pNewCursor = m_pCursor;
2139
0
            do
2140
0
            {
2141
0
                pNewCursor = m_rView.PrevVisible(pNewCursor);
2142
0
            } while (pNewCursor && !IsSelectable(*pNewCursor));
2143
2144
            // if there is no next entry, take the current one
2145
            // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
2146
            // the cursor key
2147
0
            if (!pNewCursor)
2148
0
                pNewCursor = m_pCursor;
2149
2150
0
            m_aSelEng.CursorPosChanging( bShift, bMod1 );
2151
0
            SetCursor( pNewCursor, bMod1 );     // no selection, when Ctrl is on
2152
0
            if( !IsEntryInView( pNewCursor ) )
2153
0
                KeyUp( false );
2154
0
            break;
2155
2156
0
        case KEY_DOWN:
2157
0
            if( !IsEntryInView( m_pCursor ) )
2158
0
                MakeVisible( m_pCursor );
2159
2160
0
            pNewCursor = m_pCursor;
2161
0
            do
2162
0
            {
2163
0
                pNewCursor = m_rView.NextVisible(pNewCursor);
2164
0
            } while (pNewCursor && !IsSelectable(*pNewCursor));
2165
2166
            // if there is no next entry, take the current one
2167
            // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
2168
            // the cursor key
2169
            // 06.09.20001 - 83416 - frank.schoenheit@sun.com
2170
0
            if ( !pNewCursor && m_pCursor )
2171
0
                pNewCursor = m_pCursor;
2172
2173
0
            if( pNewCursor )
2174
0
            {
2175
0
                m_aSelEng.CursorPosChanging( bShift, bMod1 );
2176
0
                if( IsEntryInView( pNewCursor ) )
2177
0
                    SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
2178
0
                else
2179
0
                {
2180
0
                    if( m_pCursor )
2181
0
                        m_rView.Select(m_pCursor, false);
2182
0
                    KeyDown( false );
2183
0
                    SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
2184
0
                }
2185
0
            }
2186
0
            else
2187
0
                KeyDown( false );   // because scrollbar range might still
2188
                                        // allow scrolling
2189
0
            break;
2190
2191
0
        case KEY_RIGHT:
2192
0
        {
2193
0
            if( m_bSubLstOpLR )
2194
0
            {
2195
                // only try to expand if sublist is expandable,
2196
                // otherwise ignore the key press
2197
0
                if (IsExpandable() && !m_rView.IsExpanded(m_pCursor))
2198
0
                    m_rView.Expand(*m_pCursor);
2199
0
            }
2200
0
            else if (m_aHorSBar->IsVisible())
2201
0
            {
2202
0
                tools::Long    nThumb = m_aHorSBar->GetThumbPos();
2203
0
                nThumb += m_aHorSBar->GetLineSize();
2204
0
                tools::Long    nOldThumb = m_aHorSBar->GetThumbPos();
2205
0
                m_aHorSBar->SetThumbPos( nThumb );
2206
0
                nThumb = nOldThumb;
2207
0
                nThumb -= m_aHorSBar->GetThumbPos();
2208
0
                nThumb *= -1;
2209
0
                if( nThumb )
2210
0
                {
2211
0
                    KeyLeftRight( nThumb );
2212
0
                }
2213
0
            }
2214
0
            else
2215
0
                bKeyUsed = false;
2216
0
            break;
2217
0
        }
2218
2219
0
        case KEY_LEFT:
2220
0
        {
2221
0
            if (m_aHorSBar->IsVisible())
2222
0
            {
2223
0
                tools::Long    nThumb = m_aHorSBar->GetThumbPos();
2224
0
                nThumb -= m_aHorSBar->GetLineSize();
2225
0
                tools::Long    nOldThumb = m_aHorSBar->GetThumbPos();
2226
0
                m_aHorSBar->SetThumbPos( nThumb );
2227
0
                nThumb = nOldThumb;
2228
0
                nThumb -= m_aHorSBar->GetThumbPos();
2229
0
                if( nThumb )
2230
0
                {
2231
0
                    KeyLeftRight( -nThumb );
2232
0
                }
2233
0
                else if( m_bSubLstOpLR )
2234
0
                {
2235
0
                    if (IsExpandable() && m_rView.IsExpanded(m_pCursor))
2236
0
                        m_rView.Collapse(m_pCursor);
2237
0
                    else
2238
0
                    {
2239
0
                        pNewCursor = m_rView.GetParent(m_pCursor);
2240
0
                        if( pNewCursor )
2241
0
                            SetCursor( pNewCursor );
2242
0
                    }
2243
0
                }
2244
0
            }
2245
0
            else if( m_bSubLstOpLR )
2246
0
            {
2247
0
                if (IsExpandable() && m_rView.IsExpanded(m_pCursor))
2248
0
                    m_rView.Collapse(m_pCursor);
2249
0
                else
2250
0
                {
2251
0
                    pNewCursor = m_rView.GetParent(m_pCursor);
2252
0
                    if( pNewCursor )
2253
0
                        SetCursor( pNewCursor );
2254
0
                }
2255
0
            }
2256
0
            else
2257
0
                bKeyUsed = false;
2258
0
            break;
2259
0
        }
2260
2261
0
        case KEY_PAGEUP:
2262
0
            if( !bMod1 )
2263
0
            {
2264
0
                pNewCursor = m_rView.PrevVisible(m_pCursor, nDelta);
2265
2266
0
                while (nDelta && pNewCursor && !IsSelectable(*pNewCursor))
2267
0
                {
2268
0
                    pNewCursor = m_rView.NextVisible(pNewCursor);
2269
0
                    nDelta--;
2270
0
                }
2271
2272
0
                if( nDelta )
2273
0
                {
2274
0
                    DBG_ASSERT(pNewCursor && pNewCursor!=m_pCursor, "Cursor?");
2275
0
                    m_aSelEng.CursorPosChanging( bShift, bMod1 );
2276
0
                    if( IsEntryInView( pNewCursor ) )
2277
0
                        SetCursor( pNewCursor );
2278
0
                    else
2279
0
                    {
2280
0
                        SetCursor( pNewCursor );
2281
0
                        KeyUp( true );
2282
0
                    }
2283
0
                }
2284
0
            }
2285
0
            else
2286
0
                bKeyUsed = false;
2287
0
            break;
2288
2289
0
        case KEY_PAGEDOWN:
2290
0
            if( !bMod1 )
2291
0
            {
2292
0
                pNewCursor = m_rView.NextVisible(m_pCursor, nDelta);
2293
2294
0
                while (nDelta && pNewCursor && !IsSelectable(*pNewCursor))
2295
0
                {
2296
0
                    pNewCursor = m_rView.PrevVisible(pNewCursor);
2297
0
                    nDelta--;
2298
0
                }
2299
2300
0
                if( nDelta && pNewCursor )
2301
0
                {
2302
0
                    DBG_ASSERT(pNewCursor && pNewCursor!=m_pCursor, "Cursor?");
2303
0
                    m_aSelEng.CursorPosChanging( bShift, bMod1 );
2304
0
                    if( IsEntryInView( pNewCursor ) )
2305
0
                        SetCursor( pNewCursor );
2306
0
                    else
2307
0
                    {
2308
0
                        SetCursor( pNewCursor );
2309
0
                        KeyDown( true );
2310
0
                    }
2311
0
                }
2312
0
                else
2313
0
                    KeyDown( false ); // see also: KEY_DOWN
2314
0
            }
2315
0
            else
2316
0
                bKeyUsed = false;
2317
0
            break;
2318
2319
0
        case KEY_SPACE:
2320
0
            if (m_rView.GetSelectionMode() != SelectionMode::NONE)
2321
0
            {
2322
0
                if ( bMod1 )
2323
0
                {
2324
0
                    if (m_rView.GetSelectionMode() == SelectionMode::Multiple && !bShift)
2325
                        // toggle selection
2326
0
                        m_rView.Select(m_pCursor, !m_rView.IsSelected(m_pCursor));
2327
0
                }
2328
0
                else if ( !bShift /*&& !bMod1*/ )
2329
0
                {
2330
0
                    if ( m_aSelEng.IsAddMode() )
2331
0
                    {
2332
                        // toggle selection
2333
0
                        m_rView.Select(m_pCursor, !m_rView.IsSelected(m_pCursor));
2334
0
                    }
2335
0
                    else if (m_rView.IsSelected(m_pCursor))
2336
0
                    {
2337
                        // trigger button
2338
0
                        SvLBoxItem* pButtonItem = m_pCursor->GetFirstItem(SvLBoxItemType::Button);
2339
0
                        if (pButtonItem)
2340
0
                        {
2341
0
                            SvLBoxButton* pButton = static_cast<SvLBoxButton*>(pButtonItem);
2342
0
                            const bool bChecked = pButton->IsStateChecked();
2343
0
                            pButton->ClickHdl(m_pCursor);
2344
0
                            InvalidateEntry(m_pCursor);
2345
0
                            if (pButton->IsStateChecked() != bChecked)
2346
0
                                CallEventListeners(VclEventId::CheckboxToggle, m_pActiveEntry);
2347
0
                        }
2348
0
                        else
2349
0
                            bKeyUsed = false;
2350
0
                    }
2351
0
                    else
2352
0
                    {
2353
0
                        SelAllDestrAnch( false );
2354
0
                        m_rView.Select(m_pCursor);
2355
0
                    }
2356
0
                }
2357
0
                else
2358
0
                    bKeyUsed = false;
2359
0
            }
2360
0
            else
2361
0
                bKeyUsed = false;
2362
0
            break;
2363
2364
0
        case KEY_RETURN:
2365
0
            bKeyUsed = !m_rView.DoubleClickHdl();
2366
0
            break;
2367
2368
0
        case KEY_F2:
2369
0
            if( !bShift && !bMod1 )
2370
0
            {
2371
0
                m_aEditClickPos = Point( -1, -1 );
2372
0
                EditTimerCall( nullptr );
2373
0
            }
2374
0
            else
2375
0
                bKeyUsed = false;
2376
0
            break;
2377
2378
0
        case KEY_F8:
2379
0
            if (bShift && m_rView.GetSelectionMode() == SelectionMode::Multiple
2380
0
                && !(m_nStyle & WB_SIMPLEMODE))
2381
0
            {
2382
0
                if( m_aSelEng.IsAlwaysAdding() )
2383
0
                    m_aSelEng.AddAlways( false );
2384
0
                else
2385
0
                    m_aSelEng.AddAlways( true );
2386
0
            }
2387
0
            else
2388
0
                bKeyUsed = false;
2389
0
            break;
2390
2391
0
        case KEY_ADD:
2392
0
            if (!m_rView.IsExpanded(m_pCursor))
2393
0
                m_rView.Expand(*m_pCursor);
2394
0
            if (bMod1)
2395
0
                ExpandAll();
2396
0
            break;
2397
2398
0
        case KEY_DIVIDE :
2399
0
        case KEY_A:
2400
0
            if( bMod1 )
2401
0
                SelAllDestrAnch( true );
2402
0
            else
2403
0
                bKeyUsed = false;
2404
0
            break;
2405
2406
0
        case KEY_SUBTRACT:
2407
0
            if (m_rView.IsExpanded(m_pCursor))
2408
0
            {
2409
0
                if (bMod1)
2410
0
                    CollapseTo(m_pCursor);
2411
0
                else
2412
0
                    m_rView.Collapse(m_pCursor);
2413
0
            }
2414
0
            break;
2415
2416
0
        case KEY_MULTIPLY:
2417
0
            if( bMod1 )
2418
0
            {
2419
                // only try to expand/collapse if sublist is expandable,
2420
                // otherwise ignore the key press
2421
0
                if( IsExpandable() )
2422
0
                {
2423
0
                    if (!m_rView.IsAllExpanded(m_pCursor))
2424
0
                    {
2425
0
                        m_rView.Expand(*m_pCursor);
2426
0
                        ExpandAll();
2427
0
                    }
2428
0
                    else
2429
0
                        CollapseTo(m_pCursor);
2430
0
                }
2431
0
            }
2432
0
            else
2433
0
                bKeyUsed = false;
2434
0
            break;
2435
2436
0
        case KEY_COMMA :
2437
0
            if( bMod1 )
2438
0
                SelAllDestrAnch( false );
2439
0
            else
2440
0
                bKeyUsed = false;
2441
0
            break;
2442
2443
0
        case KEY_HOME :
2444
0
            pNewCursor = m_rView.GetModel()->First();
2445
2446
0
            while (pNewCursor && !IsSelectable(*pNewCursor))
2447
0
            {
2448
0
                pNewCursor = m_rView.NextVisible(pNewCursor);
2449
0
            }
2450
2451
0
            if( pNewCursor && pNewCursor != m_pCursor )
2452
0
            {
2453
//              SelAllDestrAnch( false );
2454
0
                m_aSelEng.CursorPosChanging( bShift, bMod1 );
2455
0
                SetCursor( pNewCursor );
2456
0
                if( !IsEntryInView( pNewCursor ) )
2457
0
                    MakeVisible( pNewCursor );
2458
0
            }
2459
0
            else
2460
0
                bKeyUsed = false;
2461
0
            break;
2462
2463
0
        case KEY_END :
2464
0
            pNewCursor = m_rView.GetModel()->Last();
2465
2466
0
            while (pNewCursor && !IsSelectable(*pNewCursor))
2467
0
            {
2468
0
                pNewCursor = m_rView.PrevVisible(pNewCursor);
2469
0
            }
2470
2471
0
            if( pNewCursor && pNewCursor != m_pCursor)
2472
0
            {
2473
//              SelAllDestrAnch( false );
2474
0
                m_aSelEng.CursorPosChanging( bShift, bMod1 );
2475
0
                SetCursor( pNewCursor );
2476
0
                if( !IsEntryInView( pNewCursor ) )
2477
0
                    MakeVisible( pNewCursor );
2478
0
            }
2479
0
            else
2480
0
                bKeyUsed = false;
2481
0
            break;
2482
2483
0
        case KEY_ESCAPE:
2484
0
        case KEY_TAB:
2485
0
        case KEY_DELETE:
2486
0
        case KEY_BACKSPACE:
2487
            // must not be handled because this quits dialogs and does other magic things...
2488
            // if there are other single keys which should not be handled, they can be added here
2489
0
            bKeyUsed = false;
2490
0
            break;
2491
2492
0
        default:
2493
            // is there any reason why we should eat the events here? The only place where this is called
2494
            // is from SvTreeListBox::KeyInput. If we set bKeyUsed to true here, then the key input
2495
            // is just silenced. However, we want SvLBox::KeyInput to get a chance, to do the QuickSelection
2496
            // handling.
2497
            // (The old code here which intentionally set bKeyUsed to sal_True said this was because of "quick search"
2498
            // handling, but actually there was no quick search handling anymore. We just re-implemented it.)
2499
            // #i31275# / 2009-06-16 / frank.schoenheit@sun.com
2500
0
            bKeyUsed = false;
2501
0
            break;
2502
0
    }
2503
0
    return bKeyUsed;
2504
0
}
2505
2506
void SvImpLBox::GetFocus()
2507
0
{
2508
0
    if( m_pCursor )
2509
0
    {
2510
0
        m_rView.SetEntryFocus(m_pCursor, true);
2511
0
        ShowCursor( true );
2512
// auskommentiert wg. deselectall
2513
//      if( bSimpleTravel && !pView->IsSelected(pCursor) )
2514
//          pView->Select( pCursor, true );
2515
0
    }
2516
0
    if( m_nStyle & WB_HIDESELECTION )
2517
0
    {
2518
0
        SvTreeListEntry* pEntry = m_rView.FirstSelected();
2519
0
        while( pEntry )
2520
0
        {
2521
0
            InvalidateEntry( pEntry );
2522
0
            pEntry = m_rView.NextSelected(pEntry);
2523
0
        }
2524
0
    }
2525
0
}
2526
2527
void SvImpLBox::LoseFocus()
2528
0
{
2529
0
    m_aEditIdle.Stop();
2530
0
    if( m_pCursor )
2531
0
        m_rView.SetEntryFocus(m_pCursor, false);
2532
0
    ShowCursor( false );
2533
2534
0
    if( m_nStyle & WB_HIDESELECTION )
2535
0
    {
2536
0
        SvTreeListEntry* pEntry = m_rView.FirstSelected();
2537
0
        while( pEntry )
2538
0
        {
2539
0
            InvalidateEntry( pEntry );
2540
0
            pEntry = m_rView.NextSelected(pEntry);
2541
0
        }
2542
0
    }
2543
0
}
2544
2545
2546
// ********************************************************************
2547
// SelectionEngine
2548
// ********************************************************************
2549
2550
void SvImpLBox::SelectEntry( SvTreeListEntry* pEntry, bool bSelect )
2551
0
{
2552
0
    m_rView.Select(pEntry, bSelect);
2553
0
}
2554
2555
ImpLBSelEng::ImpLBSelEng(SvImpLBox& rImp, SvTreeListBox& rView)
2556
0
    : m_rImp(rImp)
2557
0
{
2558
0
    pView = &rView;
2559
0
}
2560
2561
ImpLBSelEng::~ImpLBSelEng()
2562
0
{
2563
0
}
2564
2565
0
void ImpLBSelEng::BeginDrag() { m_rImp.BeginDrag(); }
2566
2567
0
void ImpLBSelEng::CreateAnchor() { m_rImp.m_pAnchor = m_rImp.m_pCursor; }
2568
2569
0
void ImpLBSelEng::DestroyAnchor() { m_rImp.m_pAnchor = nullptr; }
2570
2571
void ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, bool bDontSelectAtCursor)
2572
0
{
2573
0
    SvTreeListEntry* pNewCursor = m_rImp.MakePointVisible(rPoint);
2574
0
    if( pNewCursor )
2575
0
    {
2576
        // at SimpleTravel, the SetCursor is selected and the select handler is
2577
        // called
2578
        //if( !bDontSelectAtCursor && !pImp->bSimpleTravel )
2579
        //  pImp->SelectEntry( pNewCursor, true );
2580
0
        m_rImp.SetCursor(pNewCursor, bDontSelectAtCursor);
2581
0
    }
2582
0
}
2583
2584
bool ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint )
2585
0
{
2586
0
    SvTreeListEntry* pEntry = m_rImp.MakePointVisible(rPoint);
2587
0
    if( pEntry )
2588
0
        return pView->IsSelected(pEntry);
2589
0
    return false;
2590
0
}
2591
2592
void ImpLBSelEng::DeselectAtPoint( const Point& rPoint )
2593
0
{
2594
0
    SvTreeListEntry* pEntry = m_rImp.MakePointVisible(rPoint);
2595
0
    if( !pEntry )
2596
0
        return;
2597
0
    m_rImp.SelectEntry(pEntry, false);
2598
0
}
2599
2600
void ImpLBSelEng::DeselectAll()
2601
0
{
2602
0
    m_rImp.SelAllDestrAnch(false, false); // don't reset SelectionEngine!
2603
0
    m_rImp.m_nFlags &= ~LBoxFlags::DeselectAll;
2604
0
}
2605
2606
// ***********************************************************************
2607
// Selection
2608
// ***********************************************************************
2609
2610
void SvImpLBox::SetAnchorSelection(SvTreeListEntry* pOldCursor,SvTreeListEntry* pNewCursor)
2611
0
{
2612
0
    SvTreeListEntry* pEntry;
2613
0
    sal_uLong nAnchorVisPos = m_rView.GetVisiblePos(m_pAnchor);
2614
0
    sal_uLong nOldVisPos = m_rView.GetVisiblePos(pOldCursor);
2615
0
    sal_uLong nNewVisPos = m_rView.GetVisiblePos(pNewCursor);
2616
2617
0
    if( nOldVisPos > nAnchorVisPos ||
2618
0
        ( nAnchorVisPos==nOldVisPos && nNewVisPos > nAnchorVisPos) )
2619
0
    {
2620
0
        if( nNewVisPos > nOldVisPos )
2621
0
        {
2622
0
            pEntry = pOldCursor;
2623
0
            while( pEntry && pEntry != pNewCursor )
2624
0
            {
2625
0
                m_rView.Select(pEntry);
2626
0
                pEntry = m_rView.NextVisible(pEntry);
2627
0
            }
2628
0
            if( pEntry )
2629
0
                m_rView.Select(pEntry);
2630
0
            return;
2631
0
        }
2632
2633
0
        if( nNewVisPos < nAnchorVisPos )
2634
0
        {
2635
0
            pEntry = m_pAnchor;
2636
0
            while( pEntry && pEntry != pOldCursor )
2637
0
            {
2638
0
                m_rView.Select(pEntry, false);
2639
0
                pEntry = m_rView.NextVisible(pEntry);
2640
0
            }
2641
0
            if( pEntry )
2642
0
                m_rView.Select(pEntry, false);
2643
2644
0
            pEntry = pNewCursor;
2645
0
            while( pEntry && pEntry != m_pAnchor )
2646
0
            {
2647
0
                m_rView.Select(pEntry);
2648
0
                pEntry = m_rView.NextVisible(pEntry);
2649
0
            }
2650
0
            if( pEntry )
2651
0
                m_rView.Select(pEntry);
2652
0
            return;
2653
0
        }
2654
2655
0
        if( nNewVisPos < nOldVisPos )
2656
0
        {
2657
0
            pEntry = m_rView.NextVisible(pNewCursor);
2658
0
            while( pEntry && pEntry != pOldCursor )
2659
0
            {
2660
0
                m_rView.Select(pEntry, false);
2661
0
                pEntry = m_rView.NextVisible(pEntry);
2662
0
            }
2663
0
            if( pEntry )
2664
0
                m_rView.Select(pEntry, false);
2665
0
            return;
2666
0
        }
2667
0
    }
2668
0
    else
2669
0
    {
2670
0
        if( nNewVisPos < nOldVisPos )  // enlarge selection
2671
0
        {
2672
0
            pEntry = pNewCursor;
2673
0
            while( pEntry && pEntry != pOldCursor )
2674
0
            {
2675
0
                m_rView.Select(pEntry);
2676
0
                pEntry = m_rView.NextVisible(pEntry);
2677
0
            }
2678
0
            if( pEntry )
2679
0
                m_rView.Select(pEntry);
2680
0
            return;
2681
0
        }
2682
2683
0
        if( nNewVisPos > nAnchorVisPos )
2684
0
        {
2685
0
            pEntry = pOldCursor;
2686
0
            while( pEntry && pEntry != m_pAnchor )
2687
0
            {
2688
0
                m_rView.Select(pEntry, false);
2689
0
                pEntry = m_rView.NextVisible(pEntry);
2690
0
            }
2691
0
            if( pEntry )
2692
0
                m_rView.Select(pEntry, false);
2693
0
            pEntry = m_pAnchor;
2694
0
            while( pEntry && pEntry != pNewCursor )
2695
0
            {
2696
0
                m_rView.Select(pEntry);
2697
0
                pEntry = m_rView.NextVisible(pEntry);
2698
0
            }
2699
0
            if( pEntry )
2700
0
                m_rView.Select(pEntry);
2701
0
            return;
2702
0
        }
2703
2704
0
        if( nNewVisPos > nOldVisPos )
2705
0
        {
2706
0
            pEntry = pOldCursor;
2707
0
            while( pEntry && pEntry != pNewCursor )
2708
0
            {
2709
0
                m_rView.Select(pEntry, false);
2710
0
                pEntry = m_rView.NextVisible(pEntry);
2711
0
            }
2712
0
            return;
2713
0
        }
2714
0
    }
2715
0
}
2716
2717
void SvImpLBox::SelAllDestrAnch(
2718
    bool bSelect, bool bDestroyAnchor, bool bSingleSelToo )
2719
0
{
2720
0
    SvTreeListEntry* pEntry;
2721
0
    m_nFlags &= ~LBoxFlags::DeselectAll;
2722
0
    if( bSelect && m_bSimpleTravel )
2723
0
    {
2724
0
        if (m_pCursor && !m_rView.IsSelected(m_pCursor))
2725
0
        {
2726
0
            m_rView.Select(m_pCursor);
2727
0
        }
2728
0
        return;
2729
0
    }
2730
0
    if (!bSelect && m_rView.GetSelectionCount() == 0)
2731
0
    {
2732
0
        if( m_bSimpleTravel && ( !GetUpdateMode() || !m_pCursor) )
2733
0
            m_nFlags |= LBoxFlags::DeselectAll;
2734
0
        return;
2735
0
    }
2736
0
    if (bSelect && m_rView.GetSelectionCount() == m_rView.GetEntryCount())
2737
0
        return;
2738
0
    if( !bSingleSelToo && m_bSimpleTravel )
2739
0
        return;
2740
2741
0
    if (!bSelect && m_rView.GetSelectionCount() == 1 && m_pCursor && m_rView.IsSelected(m_pCursor))
2742
0
    {
2743
0
        m_rView.Select(m_pCursor, false);
2744
0
        if( bDestroyAnchor )
2745
0
            DestroyAnchor(); // delete anchor & reset SelectionEngine
2746
0
        else
2747
0
            m_pAnchor = nullptr; // always delete internal anchor
2748
0
        return;
2749
0
    }
2750
2751
0
    if( m_bSimpleTravel && !m_pCursor && !GetUpdateMode() )
2752
0
        m_nFlags |= LBoxFlags::DeselectAll;
2753
2754
0
    ShowCursor( false );
2755
0
    bool bUpdate = GetUpdateMode();
2756
2757
0
    m_nFlags |= LBoxFlags::IgnoreSelect; // EntryInserted should not do anything
2758
0
    pEntry = m_rTree.First();
2759
0
    while( pEntry )
2760
0
    {
2761
0
        if (m_rView.Select(pEntry, bSelect))
2762
0
        {
2763
0
            if (bUpdate && m_rView.IsEntryVisible(pEntry))
2764
0
            {
2765
0
                tools::Long nY = GetEntryLine( pEntry );
2766
0
                if( IsLineVisible( nY ) )
2767
0
                    InvalidateEntry(pEntry);
2768
0
            }
2769
0
        }
2770
0
        pEntry = m_rTree.Next(pEntry);
2771
0
    }
2772
0
    m_nFlags &= ~LBoxFlags::IgnoreSelect;
2773
2774
0
    if( bDestroyAnchor )
2775
0
        DestroyAnchor(); // delete anchor & reset SelectionEngine
2776
0
    else
2777
0
        m_pAnchor = nullptr; // always delete internal anchor
2778
0
    ShowCursor( true );
2779
0
}
2780
2781
void SvImpLBox::SetSelectionMode( SelectionMode eSelMode  )
2782
0
{
2783
0
    m_aSelEng.SetSelectionMode( eSelMode);
2784
0
    if( eSelMode == SelectionMode::Single )
2785
0
        m_bSimpleTravel = true;
2786
0
    else
2787
0
        m_bSimpleTravel = false;
2788
0
    if( (m_nStyle & WB_SIMPLEMODE) && (eSelMode == SelectionMode::Multiple) )
2789
0
        m_aSelEng.AddAlways( true );
2790
0
}
2791
2792
// ***********************************************************************
2793
// Drag & Drop
2794
// ***********************************************************************
2795
2796
void SvImpLBox::SetDragDropMode( DragDropMode eDDMode )
2797
0
{
2798
0
    if( eDDMode != DragDropMode::NONE )
2799
0
    {
2800
0
        m_aSelEng.ExpandSelectionOnMouseMove( false );
2801
0
        m_aSelEng.EnableDrag( true );
2802
0
    }
2803
0
    else
2804
0
    {
2805
0
        m_aSelEng.ExpandSelectionOnMouseMove();
2806
0
        m_aSelEng.EnableDrag( false );
2807
0
    }
2808
0
}
2809
2810
void SvImpLBox::BeginDrag()
2811
0
{
2812
0
    m_nFlags &= ~LBoxFlags::Filling;
2813
0
    m_rView.StartDrag(0, m_aSelEng.GetMousePosPixel());
2814
0
}
2815
2816
void SvImpLBox::PaintDDCursor(SvTreeListEntry* pEntry, bool bShow)
2817
0
{
2818
0
    if (pEntry)
2819
0
    {
2820
0
        SvViewDataEntry& rViewData = m_rView.GetViewData(pEntry);
2821
0
        rViewData.SetDragTarget(bShow);
2822
#ifdef MACOSX
2823
        // in MacOS we need to draw directly (as we are synchronous) or no invalidation happens
2824
        m_rView.PaintEntry1(*pEntry, GetEntryLine(pEntry), *m_rView.GetOutDev());
2825
#else
2826
0
        InvalidateEntry(pEntry);
2827
0
#endif
2828
0
    }
2829
0
}
2830
2831
void SvImpLBox::Command( const CommandEvent& rCEvt )
2832
0
{
2833
0
    CommandEventId nCommand = rCEvt.GetCommand();
2834
2835
0
    if( nCommand == CommandEventId::ContextMenu )
2836
0
        m_aEditIdle.Stop();
2837
2838
    // scroll mouse event?
2839
0
    if (nCommand == CommandEventId::Wheel ||
2840
0
        nCommand == CommandEventId::StartAutoScroll ||
2841
0
        nCommand == CommandEventId::AutoScroll ||
2842
0
        nCommand == CommandEventId::GesturePan)
2843
0
    {
2844
0
        if (m_rView.HandleScrollCommand(rCEvt, m_aHorSBar.get(), m_aVerSBar.get()))
2845
0
            return;
2846
0
    }
2847
2848
0
    const Point& rPos = rCEvt.GetMousePosPixel();
2849
0
    if( rPos.X() < m_aOutputSize.Width() && rPos.Y() < m_aOutputSize.Height() )
2850
0
        m_aSelEng.Command( rCEvt );
2851
0
}
2852
2853
tools::Rectangle SvImpLBox::GetVisibleArea() const
2854
0
{
2855
0
    Point aPos(m_rView.GetMapMode().GetOrigin());
2856
0
    aPos.setX( aPos.X() * -1 );
2857
0
    tools::Rectangle aRect( aPos, m_aOutputSize );
2858
0
    return aRect;
2859
0
}
2860
2861
0
void SvImpLBox::Invalidate() { m_rView.GetOutDev()->SetClipRegion(); }
2862
2863
void SvImpLBox::SetCurEntry( SvTreeListEntry* pEntry )
2864
0
{
2865
0
    if  (  ( m_aSelEng.GetSelectionMode() != SelectionMode::Single )
2866
0
        && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE )
2867
0
        )
2868
0
        SelAllDestrAnch( false );
2869
0
    if ( pEntry )
2870
0
        MakeVisible( pEntry );
2871
0
    SetCursor( pEntry );
2872
0
    if ( pEntry && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) )
2873
0
        m_rView.Select(pEntry);
2874
0
}
2875
2876
IMPL_LINK_NOARG(SvImpLBox, EditTimerCall, Timer *, void)
2877
0
{
2878
0
    if (!m_rView.IsInplaceEditingEnabled())
2879
0
        return;
2880
2881
0
    bool bIsMouseTriggered = m_aEditClickPos.X() >= 0;
2882
0
    if ( bIsMouseTriggered )
2883
0
    {
2884
0
        Point aCurrentMousePos = m_rView.GetPointerPosPixel();
2885
0
        if  (   ( std::abs( aCurrentMousePos.X() - m_aEditClickPos.X() ) > 5 )
2886
0
            ||  ( std::abs( aCurrentMousePos.Y() - m_aEditClickPos.Y() ) > 5 )
2887
0
            )
2888
0
        {
2889
0
            return;
2890
0
        }
2891
0
    }
2892
2893
0
    SvTreeListEntry* pEntry = GetCurEntry();
2894
0
    if( pEntry )
2895
0
    {
2896
0
        ShowCursor( false );
2897
0
        m_rView.ImplEditEntry(pEntry);
2898
0
        ShowCursor( true );
2899
0
    }
2900
0
}
2901
2902
bool SvImpLBox::RequestHelp( const HelpEvent& rHEvt )
2903
0
{
2904
0
    if( rHEvt.GetMode() & HelpEventMode::QUICK )
2905
0
    {
2906
0
        Point aPos(m_rView.ScreenToOutputPixel(rHEvt.GetMousePosPixel()));
2907
0
        if( !GetVisibleArea().Contains( aPos ))
2908
0
            return false;
2909
2910
0
        SvTreeListEntry* pEntry = GetEntry( aPos );
2911
0
        if( pEntry )
2912
0
        {
2913
            // recalculate text rectangle
2914
0
            SvLBoxTab* pTab;
2915
0
            SvLBoxItem* pItem = m_rView.GetItem(pEntry, aPos.X(), &pTab);
2916
0
            if (!pItem || pItem->GetType() != SvLBoxItemType::String)
2917
0
                return false;
2918
2919
0
            aPos = GetEntryPosition( pEntry );
2920
0
            aPos.setX(m_rView.GetTabPos(pEntry, pTab)); //pTab->GetPos();
2921
0
            Size aSize(pItem->GetWidth(m_rView, *pEntry), pItem->GetHeight(m_rView, *pEntry));
2922
0
            SvLBoxTab* pNextTab = NextTab( pTab );
2923
0
            bool bItemClipped = false;
2924
            // is the item cut off by its right neighbor?
2925
0
            if (pNextTab && m_rView.GetTabPos(pEntry, pNextTab) < aPos.X() + aSize.Width())
2926
0
            {
2927
0
                aSize.setWidth( pNextTab->GetPos() - pTab->GetPos() );
2928
0
                bItemClipped = true;
2929
0
            }
2930
0
            tools::Rectangle aItemRect( aPos, aSize );
2931
2932
0
            tools::Rectangle aViewRect( GetVisibleArea() );
2933
2934
0
            if( bItemClipped || !aViewRect.Contains( aItemRect ) )
2935
0
            {
2936
                // clip the right edge of the item at the edge of the view
2937
                //if( aItemRect.Right() > aViewRect.Right() )
2938
                //  aItemRect.Right() = aViewRect.Right();
2939
2940
0
                Point aPt = m_rView.OutputToScreenPixel(aItemRect.TopLeft());
2941
0
                aItemRect.SetLeft( aPt.X() );
2942
0
                aItemRect.SetTop( aPt.Y() );
2943
0
                aPt = m_rView.OutputToScreenPixel(aItemRect.BottomRight());
2944
0
                aItemRect.SetRight( aPt.X() );
2945
0
                aItemRect.SetBottom( aPt.Y() );
2946
2947
0
                Help::ShowQuickHelp(&m_rView, aItemRect,
2948
0
                                    static_cast<SvLBoxString*>(pItem)->GetText(),
2949
0
                                    QuickHelpFlags::Left | QuickHelpFlags::VCenter);
2950
0
                return true;
2951
0
            }
2952
0
        }
2953
0
    }
2954
0
    return false;
2955
0
}
2956
2957
SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab const * pTab )
2958
0
{
2959
0
    sal_uInt16 nTabCount = m_rView.TabCount();
2960
0
    if( nTabCount <= 1 )
2961
0
        return nullptr;
2962
0
    for( int nTab=0; nTab < (nTabCount-1); nTab++)
2963
0
    {
2964
0
        if (m_rView.m_aTabs[nTab].get() == pTab)
2965
0
            return m_rView.m_aTabs[nTab + 1].get();
2966
0
    }
2967
0
    return nullptr;
2968
0
}
2969
2970
void SvImpLBox::SetUpdateMode( bool bMode )
2971
0
{
2972
0
    if( m_bUpdateMode != bMode )
2973
0
    {
2974
0
        m_bUpdateMode = bMode;
2975
0
        if( m_bUpdateMode )
2976
0
            UpdateAll();
2977
0
    }
2978
0
}
2979
2980
void SvImpLBox::SetMostRight( SvTreeListEntry* pEntry )
2981
0
{
2982
0
    if (m_rView.m_nTreeFlags & SvTreeFlags::RECALCTABS)
2983
0
    {
2984
0
        m_nFlags |= LBoxFlags::IgnoreChangedTabs;
2985
0
        m_rView.SetTabs();
2986
0
        m_nFlags &= ~LBoxFlags::IgnoreChangedTabs;
2987
0
    }
2988
2989
0
    sal_uInt16 nLastTab = m_rView.m_aTabs.size() - 1;
2990
0
    sal_uInt16 nLastItem = pEntry->ItemCount() - 1;
2991
0
    if (m_rView.m_aTabs.empty() || nLastItem == USHRT_MAX)
2992
0
        return;
2993
2994
0
    if( nLastItem < nLastTab )
2995
0
        nLastTab = nLastItem;
2996
2997
0
    SvLBoxTab* pTab = m_rView.m_aTabs[nLastTab].get();
2998
0
    SvLBoxItem& rItem = pEntry->GetItem( nLastTab );
2999
3000
0
    tools::Long nTabPos = m_rView.GetTabPos(pEntry, pTab);
3001
3002
0
    tools::Long nMaxRight = GetOutputSize().Width();
3003
0
    Point aPos(m_rView.GetMapMode().GetOrigin());
3004
0
    aPos.setX( aPos.X() * -1 ); // conversion document coordinates
3005
0
    nMaxRight = nMaxRight + aPos.X() - 1;
3006
3007
0
    tools::Long nNextTab = nTabPos < nMaxRight ? nMaxRight : nMaxRight + 50;
3008
0
    tools::Long nTabWidth = nNextTab - nTabPos + 1;
3009
0
    auto nItemSize = rItem.GetWidth(m_rView, *pEntry);
3010
0
    tools::Long nOffset = pTab->CalcOffset( nItemSize, nTabWidth );
3011
3012
0
    tools::Long nRight = nTabPos + nOffset + nItemSize;
3013
0
    if( nRight > m_nMostRight )
3014
0
    {
3015
0
        m_nMostRight = nRight;
3016
0
        m_pMostRightEntry = pEntry;
3017
0
    }
3018
0
}
3019
3020
void SvImpLBox::FindMostRight()
3021
0
{
3022
0
    m_nMostRight = -1;
3023
0
    m_pMostRightEntry = nullptr;
3024
0
    if (!m_rView.GetModel())
3025
0
        return;
3026
3027
0
    SvTreeListEntry* pEntry = m_rView.FirstVisible();
3028
0
    while( pEntry )
3029
0
    {
3030
0
        SetMostRight( pEntry );
3031
0
        pEntry = m_rView.NextVisible(pEntry);
3032
0
    }
3033
0
}
3034
3035
void SvImpLBox::FindMostRight( SvTreeListEntry* pParent )
3036
0
{
3037
0
    if( !pParent )
3038
0
        FindMostRight();
3039
0
    else
3040
0
        FindMostRight_Impl( pParent );
3041
0
}
3042
3043
void SvImpLBox::FindMostRight_Impl( SvTreeListEntry* pParent )
3044
0
{
3045
0
    const SvTreeListEntries& rList = m_rTree.GetChildList(pParent);
3046
3047
0
    size_t nCount = rList.size();
3048
0
    for( size_t nCur = 0; nCur < nCount; nCur++ )
3049
0
    {
3050
0
        SvTreeListEntry* pChild = rList[nCur].get();
3051
0
        SetMostRight( pChild );
3052
0
        if (pChild->HasChildren() && m_rView.IsExpanded(pChild))
3053
0
            FindMostRight_Impl( pChild );
3054
0
    }
3055
0
}
3056
3057
void SvImpLBox::NotifyTabsChanged()
3058
0
{
3059
0
    if( GetUpdateMode() && !(m_nFlags & LBoxFlags::IgnoreChangedTabs ) &&
3060
0
        m_nCurUserEvent == nullptr )
3061
0
    {
3062
0
        m_nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent));
3063
0
    }
3064
0
}
3065
3066
bool SvImpLBox::IsExpandable() const
3067
0
{
3068
0
    return m_pCursor->HasChildren() || m_pCursor->HasChildrenOnDemand();
3069
0
}
3070
3071
IMPL_LINK(SvImpLBox, MyUserEvent, void*, pArg, void )
3072
0
{
3073
0
    m_nCurUserEvent = nullptr;
3074
0
    if( !pArg )
3075
0
    {
3076
0
        m_rView.Invalidate();
3077
0
        m_rView.PaintImmediately();
3078
0
    }
3079
0
    else
3080
0
    {
3081
0
        FindMostRight();
3082
0
        ShowVerSBar();
3083
0
        m_rView.Invalidate(GetVisibleArea());
3084
0
    }
3085
0
}
3086
3087
3088
void SvImpLBox::StopUserEvent()
3089
0
{
3090
0
    if( m_nCurUserEvent != nullptr )
3091
0
    {
3092
0
        Application::RemoveUserEvent( m_nCurUserEvent );
3093
0
        m_nCurUserEvent = nullptr;
3094
0
    }
3095
0
}
3096
3097
void SvImpLBox::implInitDefaultNodeImages()
3098
0
{
3099
0
    if ( s_pDefCollapsed )
3100
        // assume that all or nothing is initialized
3101
0
        return;
3102
3103
0
    s_pDefCollapsed = new Image(StockImage::Yes, RID_BMP_TREENODE_COLLAPSED);
3104
0
    s_pDefExpanded = new Image(StockImage::Yes, RID_BMP_TREENODE_EXPANDED);
3105
0
}
3106
3107
3108
const Image& SvImpLBox::GetDefaultExpandedNodeImage( )
3109
0
{
3110
0
    implInitDefaultNodeImages();
3111
0
    return *s_pDefExpanded;
3112
0
}
3113
3114
3115
const Image& SvImpLBox::GetDefaultCollapsedNodeImage( )
3116
0
{
3117
0
    implInitDefaultNodeImages();
3118
0
    return *s_pDefCollapsed;
3119
0
}
3120
3121
3122
void SvImpLBox::CallEventListeners( VclEventId nEvent, void* pData )
3123
0
{
3124
0
    m_rView.CallEventListeners(nEvent, pData);
3125
0
}
3126
3127
bool SvImpLBox::IsSelectable(const SvTreeListEntry& rEntry) const
3128
0
{
3129
0
    SvViewDataEntry& rViewDataNewCur = m_rView.GetViewDataEntry(rEntry);
3130
0
    return rViewDataNewCur.IsSelectable();
3131
0
}
3132
3133
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */