Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/vcl/source/treelist/treelist.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 <vcl/toolkit/treelist.hxx>
21
#include <vcl/toolkit/treelistentry.hxx>
22
#include <vcl/toolkit/viewdataentry.hxx>
23
#include <tools/debug.hxx>
24
#include <osl/diagnose.h>
25
26
#include <cassert>
27
#include <memory>
28
#include <unordered_map>
29
#include <utility>
30
31
32
typedef std::unordered_map<SvTreeListEntry*, std::unique_ptr<SvViewDataEntry>> SvDataTable;
33
34
struct SvListView::Impl
35
{
36
    SvListView & m_rThis;
37
38
    SvDataTable m_DataTable;  // Mapping SvTreeListEntry -> ViewData
39
40
    sal_uInt32  m_nVisibleCount;
41
    sal_uInt32  m_nSelectionCount;
42
    bool        m_bVisPositionsValid;
43
44
    explicit Impl(SvListView & rThis)
45
0
        : m_rThis(rThis)
46
0
        , m_nVisibleCount(0)
47
0
        , m_nSelectionCount(0)
48
0
        , m_bVisPositionsValid(false)
49
0
    {}
50
51
    void InitTable();
52
    void RemoveViewData( SvTreeListEntry* pParent );
53
54
    void ActionMoving(SvTreeListEntry* pEntry);
55
    void ActionMoved();
56
    void ActionInserted(SvTreeListEntry* pEntry);
57
    void ActionInsertedTree(SvTreeListEntry* pEntry);
58
    void ActionRemoving(SvTreeListEntry* pEntry);
59
};
60
61
62
SvTreeList::SvTreeList(SvListView& listView) :
63
0
    mrOwnerListView(listView),
64
0
    mbEnableInvalidate(true)
65
0
{
66
0
    nEntryCount = 0;
67
0
    bAbsPositionsValid = false;
68
0
    pRootItem.reset(new SvTreeListEntry);
69
0
    eSortMode = SvSortMode::None;
70
0
}
71
72
SvTreeList::~SvTreeList()
73
0
{
74
0
}
75
76
void SvTreeList::Broadcast(
77
    SvListAction nActionId,
78
    SvTreeListEntry* pEntry1,
79
    SvTreeListEntry* pEntry2,
80
    sal_uInt32 nPos
81
)
82
0
{
83
0
    mrOwnerListView.ModelNotification(nActionId, pEntry1, pEntry2, nPos);
84
0
}
85
86
// an entry is visible if all parents are expanded
87
bool SvTreeList::IsEntryVisible( const SvListView* pView, SvTreeListEntry* pEntry ) const
88
0
{
89
0
    assert(pView && pEntry && "IsVisible:Invalid Params");
90
0
    bool bRetVal = false;
91
0
    do
92
0
    {
93
0
        if ( pEntry == pRootItem.get() )
94
0
        {
95
0
            bRetVal = true;
96
0
            break;
97
0
        }
98
0
        pEntry = pEntry->pParent;
99
0
    }  while( pView->IsExpanded( pEntry ) );
100
0
    return bRetVal;
101
0
}
102
103
sal_uInt16 SvTreeList::GetDepth( const SvTreeListEntry* pEntry ) const
104
0
{
105
0
    DBG_ASSERT(pEntry && pEntry!=pRootItem.get(),"GetDepth:Bad Entry");
106
0
    sal_uInt16 nDepth = 0;
107
0
    while( pEntry && pEntry->pParent != pRootItem.get() )
108
0
    {
109
0
        nDepth++;
110
0
        pEntry = pEntry->pParent;
111
0
    }
112
0
    return nDepth;
113
0
}
114
115
bool SvTreeList::IsAtRootDepth( const SvTreeListEntry* pEntry ) const
116
0
{
117
0
    return pEntry->pParent == pRootItem.get();
118
0
}
119
120
void SvTreeList::Clear()
121
0
{
122
0
    Broadcast( SvListAction::CLEARING );
123
0
    pRootItem->ClearChildren();
124
0
    nEntryCount = 0;
125
0
    Broadcast( SvListAction::CLEARED );
126
0
}
127
128
bool SvTreeList::IsChild(const SvTreeListEntry* pParent, const SvTreeListEntry* pChild) const
129
0
{
130
0
    if ( !pParent )
131
0
        pParent = pRootItem.get();
132
133
0
    if (pParent->m_Children.empty())
134
0
        return false;
135
136
0
    for (auto const& it : pParent->m_Children)
137
0
    {
138
0
        const SvTreeListEntry* pThis = it.get();
139
0
        if (pThis == pChild)
140
0
            return true;
141
0
        else
142
0
        {
143
0
            bool bIsChild = IsChild(pThis, pChild);
144
0
            if (bIsChild)
145
0
                return true;
146
0
        }
147
0
    }
148
0
    return false;
149
0
}
150
151
namespace {
152
153
class FindByPointer
154
{
155
    const SvTreeListEntry* mpEntry;
156
public:
157
0
    explicit FindByPointer(const SvTreeListEntry* p) : mpEntry(p) {}
158
159
    bool operator() (std::unique_ptr<SvTreeListEntry> const& rpEntry) const
160
0
    {
161
0
        return mpEntry == rpEntry.get();
162
0
    }
163
};
164
165
sal_uInt32 findEntryPosition(const SvTreeListEntries& rDst, const SvTreeListEntry* pEntry)
166
0
{
167
0
    SvTreeListEntries::const_iterator itPos = std::find_if(rDst.begin(), rDst.end(), FindByPointer(pEntry));
168
0
    if (itPos == rDst.end())
169
0
        return static_cast<sal_uInt32>(~0);
170
171
0
    return static_cast<sal_uInt32>(std::distance(rDst.begin(), itPos));
172
0
}
173
174
}
175
176
sal_uInt32 SvTreeList::Move(SvTreeListEntry* pSrcEntry,SvTreeListEntry* pTargetParent,sal_uInt32 nListPos)
177
0
{
178
    // pDest may be 0!
179
0
    assert(pSrcEntry && "Entry?");
180
0
    if ( !pTargetParent )
181
0
        pTargetParent = pRootItem.get();
182
0
    DBG_ASSERT(pSrcEntry!=pTargetParent,"Move:Source=Target");
183
184
0
    Broadcast( SvListAction::MOVING, pSrcEntry, pTargetParent, nListPos );
185
186
0
    if ( pSrcEntry == pTargetParent )
187
        // You can't move an entry onto itself as the parent. Just return its
188
        // position and bail out.
189
0
        return pSrcEntry->GetChildListPos();
190
191
0
    bAbsPositionsValid = false;
192
193
0
    SvTreeListEntries& rDst = pTargetParent->m_Children;
194
0
    SvTreeListEntries& rSrc = pSrcEntry->pParent->m_Children;
195
196
0
    bool bSameParent = pTargetParent == pSrcEntry->pParent;
197
198
    // Find the position of the entry being moved in the source container.
199
0
    SvTreeListEntries::iterator itSrcPos = rSrc.begin(), itEnd = rSrc.end();
200
0
    for (; itSrcPos != itEnd; ++itSrcPos)
201
0
    {
202
0
        const SvTreeListEntry* p = (*itSrcPos).get();
203
0
        if (p == pSrcEntry)
204
            // Found
205
0
            break;
206
0
    }
207
208
0
    if (itSrcPos == itEnd)
209
0
    {
210
0
        OSL_FAIL("Source entry not found! This should never happen.");
211
0
        return pSrcEntry->GetChildListPos();
212
0
    }
213
214
0
    if (bSameParent)
215
0
    {
216
        // Moving within the same parent.
217
218
0
        size_t nSrcPos = std::distance(rSrc.begin(), itSrcPos);
219
0
        if (nSrcPos == nListPos)
220
            // Nothing to move here.
221
0
            return pSrcEntry->GetChildListPos();
222
223
0
        if (nSrcPos < nListPos)
224
            // Destination position shifts left after removing the original.
225
0
            --nListPos;
226
227
        // Release the original.
228
0
        std::unique_ptr<SvTreeListEntry> pOriginal(std::move(*itSrcPos));
229
0
        assert(pOriginal);
230
0
        rSrc.erase(itSrcPos);
231
232
        // Determine the insertion position.
233
0
        SvTreeListEntries::iterator itDstPos = rSrc.end();
234
0
        if (nListPos < rSrc.size())
235
0
        {
236
0
            itDstPos = rSrc.begin();
237
0
            std::advance(itDstPos, nListPos);
238
0
        }
239
0
        rSrc.insert(itDstPos, std::move(pOriginal));
240
0
    }
241
0
    else
242
0
    {
243
        // Moving from one parent to another.
244
0
        SvTreeListEntries::iterator itDstPos = rDst.end();
245
0
        if (nListPos < rDst.size())
246
0
        {
247
0
            itDstPos = rDst.begin();
248
0
            std::advance(itDstPos, nListPos);
249
0
        }
250
0
        std::unique_ptr<SvTreeListEntry> pOriginal(std::move(*itSrcPos));
251
0
        assert(pOriginal);
252
0
        rSrc.erase(itSrcPos);
253
0
        rDst.insert(itDstPos, std::move(pOriginal));
254
0
    }
255
256
    // move parent (do this only now, because we need the parent for
257
    // deleting the old child list!)
258
0
    pSrcEntry->pParent = pTargetParent;
259
260
    // correct list position in target list
261
0
    SetListPositions(rDst);
262
0
    if (!bSameParent)
263
0
        SetListPositions(rSrc);
264
265
0
    sal_uInt32 nRetVal = findEntryPosition(rDst, pSrcEntry);
266
0
    OSL_ENSURE(nRetVal == pSrcEntry->GetChildListPos(), "ListPos not valid");
267
0
    Broadcast( SvListAction::MOVED,pSrcEntry,pTargetParent,nRetVal);
268
0
    return nRetVal;
269
0
}
270
271
sal_uInt32 SvTreeList::Copy(SvTreeListEntry* pSrcEntry,SvTreeListEntry* pTargetParent,sal_uInt32 nListPos)
272
0
{
273
    // pDest may be 0!
274
0
    DBG_ASSERT(pSrcEntry,"Entry?");
275
0
    if ( !pTargetParent )
276
0
        pTargetParent = pRootItem.get();
277
278
0
    bAbsPositionsValid = false;
279
280
0
    sal_uInt32 nCloneCount = 0;
281
0
    SvTreeListEntry* pClonedEntry = Clone( pSrcEntry, nCloneCount );
282
0
    nEntryCount += nCloneCount;
283
284
0
    SvTreeListEntries& rDst = pTargetParent->m_Children;
285
286
0
    pClonedEntry->pParent = pTargetParent;      // move parent
287
288
0
    if (nListPos < rDst.size())
289
0
    {
290
0
        SvTreeListEntries::iterator itPos = rDst.begin(); // insertion position.
291
0
        std::advance(itPos, nListPos);
292
0
        rDst.insert(itPos, std::unique_ptr<SvTreeListEntry>(pClonedEntry));
293
0
    }
294
0
    else
295
0
        rDst.push_back(std::unique_ptr<SvTreeListEntry>(pClonedEntry));
296
297
0
    SetListPositions(rDst); // correct list position in target list
298
299
0
    Broadcast( SvListAction::INSERTED_TREE, pClonedEntry );
300
0
    sal_uInt32 nRetVal = findEntryPosition(rDst, pClonedEntry);
301
0
    return nRetVal;
302
0
}
303
304
void SvTreeList::Move( SvTreeListEntry* pSrcEntry, SvTreeListEntry* pDstEntry )
305
0
{
306
0
    SvTreeListEntry* pParent;
307
0
    sal_uInt32 nPos;
308
309
0
    if ( !pDstEntry )
310
0
    {
311
0
        pParent = pRootItem.get();
312
0
        nPos = 0;
313
0
    }
314
0
    else
315
0
    {
316
0
        pParent = pDstEntry->pParent;
317
0
        nPos = pDstEntry->GetChildListPos();
318
0
        nPos++;  // (On screen:) insert _below_ pDstEntry
319
0
    }
320
0
    Move( pSrcEntry, pParent, nPos );
321
0
}
322
323
void SvTreeList::InsertTree(SvTreeListEntry* pSrcEntry,
324
    SvTreeListEntry* pTargetParent,sal_uInt32 nListPos)
325
0
{
326
0
    DBG_ASSERT(pSrcEntry,"InsertTree:Entry?");
327
0
    if ( !pSrcEntry )
328
0
        return;
329
330
0
    if ( !pTargetParent )
331
0
        pTargetParent = pRootItem.get();
332
333
    // take sorting into account
334
0
    GetInsertionPos( pSrcEntry, pTargetParent, nListPos );
335
336
0
    bAbsPositionsValid = false;
337
338
0
    pSrcEntry->pParent = pTargetParent; // move parent
339
0
    SvTreeListEntries& rDst = pTargetParent->m_Children;
340
341
0
    if (nListPos < rDst.size())
342
0
    {
343
0
        SvTreeListEntries::iterator itPos = rDst.begin();
344
0
        std::advance(itPos, nListPos);
345
0
        rDst.insert(itPos, std::unique_ptr<SvTreeListEntry>(pSrcEntry));
346
0
    }
347
0
    else
348
0
        rDst.push_back(std::unique_ptr<SvTreeListEntry>(pSrcEntry));
349
350
0
    SetListPositions(rDst); // correct list position in target list
351
0
    nEntryCount += GetChildCount( pSrcEntry );
352
0
    nEntryCount++; // the parent is new, too
353
354
0
    Broadcast(SvListAction::INSERTED_TREE, pSrcEntry );
355
0
}
356
357
SvTreeListEntry* SvTreeList::CloneEntry( SvTreeListEntry* pSource ) const
358
0
{
359
0
    if( aCloneLink.IsSet() )
360
0
        return aCloneLink.Call( pSource );
361
0
    SvTreeListEntry* pEntry = new SvTreeListEntry;
362
0
    pEntry->Clone(pSource);
363
0
    return pEntry;
364
0
}
365
366
SvTreeListEntry* SvTreeList::Clone( SvTreeListEntry* pEntry, sal_uInt32& nCloneCount ) const
367
0
{
368
0
    SvTreeListEntry* pClonedEntry = CloneEntry( pEntry );
369
0
    nCloneCount = 1;
370
0
    if (!pEntry->m_Children.empty())
371
        // Clone the child entries.
372
0
        CloneChildren(pClonedEntry->m_Children, nCloneCount, pEntry->m_Children, *pClonedEntry);
373
374
0
    return pClonedEntry;
375
0
}
376
377
void SvTreeList::CloneChildren(
378
        SvTreeListEntries& rDst, sal_uInt32& rCloneCount, SvTreeListEntries& rSrc, SvTreeListEntry& rNewParent) const
379
0
{
380
0
    SvTreeListEntries aClone;
381
0
    for (auto const& elem : rSrc)
382
0
    {
383
0
        SvTreeListEntry& rEntry = *elem;
384
0
        std::unique_ptr<SvTreeListEntry> pNewEntry(CloneEntry(&rEntry));
385
0
        ++rCloneCount;
386
0
        pNewEntry->pParent = &rNewParent;
387
0
        if (!rEntry.m_Children.empty())
388
            // Clone entries recursively.
389
0
            CloneChildren(pNewEntry->m_Children, rCloneCount, rEntry.m_Children, *pNewEntry);
390
391
0
        aClone.push_back(std::move(pNewEntry));
392
0
    }
393
394
0
    rDst.swap(aClone);
395
0
}
396
397
sal_uInt32 SvTreeList::GetChildCount( const SvTreeListEntry* pParent ) const
398
0
{
399
0
    if ( !pParent )
400
0
        return GetEntryCount();
401
402
0
    if (pParent->m_Children.empty())
403
0
        return 0;
404
405
0
    sal_uInt32 nCount = 0;
406
0
    sal_uInt16 nRefDepth = GetDepth( pParent );
407
0
    sal_uInt16 nActDepth = nRefDepth;
408
0
    do
409
0
    {
410
0
        pParent = Next(const_cast<SvTreeListEntry*>(pParent), &nActDepth);
411
0
        nCount++;
412
0
    } while( pParent && nRefDepth < nActDepth );
413
414
0
    assert(nCount > 0 && "given do...while");
415
0
    return nCount - 1;
416
0
}
417
418
sal_uInt32 SvTreeList::GetVisibleChildCount(const SvListView* pView, SvTreeListEntry* pParent) const
419
0
{
420
0
    assert(pView && "GetVisChildCount:No View");
421
0
    if ( !pParent )
422
0
        pParent = pRootItem.get();
423
424
0
    if (!pParent || !pView->IsExpanded(pParent) || pParent->m_Children.empty())
425
0
        return 0;
426
427
0
    sal_uInt32 nCount = 0;
428
0
    sal_uInt16 nRefDepth = GetDepth( pParent );
429
0
    sal_uInt16 nActDepth = nRefDepth;
430
0
    do
431
0
    {
432
0
        pParent = NextVisible( pView, pParent, &nActDepth );
433
0
        nCount++;
434
0
    } while( pParent && nRefDepth < nActDepth );
435
436
0
    assert(nCount > 0 && "given do...while");
437
0
    return nCount - 1;
438
0
}
439
440
sal_uInt32 SvTreeList::GetChildSelectionCount(const SvListView* pView,SvTreeListEntry* pParent) const
441
0
{
442
0
    assert(pView && "GetChildSelCount:No View");
443
0
    if ( !pParent )
444
0
        pParent = pRootItem.get();
445
446
0
    if (!pParent || pParent->m_Children.empty())
447
0
        return 0;
448
449
0
    sal_uInt32 nCount = 0;
450
0
    sal_uInt16 nRefDepth = GetDepth( pParent );
451
0
    sal_uInt16 nActDepth = nRefDepth;
452
0
    do
453
0
    {
454
0
        pParent = Next( pParent, &nActDepth );
455
0
        if( pParent && pView->IsSelected( pParent ) && nRefDepth < nActDepth)
456
0
            nCount++;
457
0
    } while( pParent && nRefDepth < nActDepth );
458
459
0
    return nCount;
460
0
}
461
462
SvTreeListEntry* SvTreeList::First() const
463
0
{
464
0
    if ( nEntryCount )
465
0
        return pRootItem->m_Children[0].get();
466
0
    else
467
0
        return nullptr;
468
0
}
469
470
SvTreeListEntry* SvTreeList::Next( SvTreeListEntry* pActEntry, sal_uInt16* pDepth ) const
471
0
{
472
0
    DBG_ASSERT( pActEntry && pActEntry->pParent, "SvTreeList::Next: invalid entry/parent!" );
473
0
    if ( !pActEntry || !pActEntry->pParent )
474
0
        return nullptr;
475
476
0
    sal_uInt16 nDepth = 0;
477
0
    bool bWithDepth = false;
478
0
    if ( pDepth )
479
0
    {
480
0
        nDepth = *pDepth;
481
0
        bWithDepth = true;
482
0
    }
483
484
    // Get the list where the current entry belongs to (from its parent).
485
0
    SvTreeListEntries* pActualList = &pActEntry->pParent->m_Children;
486
0
    sal_uInt32 nActualPos = pActEntry->GetChildListPos();
487
488
0
    if (!pActEntry->m_Children.empty())
489
0
    {
490
        // The current entry has children. Get its first child entry.
491
0
        nDepth++;
492
0
        pActEntry = pActEntry->m_Children[0].get();
493
0
        if ( bWithDepth )
494
0
            *pDepth = nDepth;
495
0
        return pActEntry;
496
0
    }
497
498
0
    if (pActualList->size() > (nActualPos+1))
499
0
    {
500
        // Get the next sibling of the current entry.
501
0
        pActEntry = (*pActualList)[nActualPos+1].get();
502
0
        if ( bWithDepth )
503
0
            *pDepth = nDepth;
504
0
        return pActEntry;
505
0
    }
506
507
    // Move up level(s) until we find the level where the next sibling exists.
508
0
    SvTreeListEntry* pParent = pActEntry->pParent;
509
0
    nDepth--;
510
0
    while( pParent != pRootItem.get() && pParent != nullptr )
511
0
    {
512
0
        DBG_ASSERT(pParent!=nullptr,"TreeData corrupt!");
513
0
        pActualList = &pParent->pParent->m_Children;
514
0
        nActualPos = pParent->GetChildListPos();
515
0
        if (pActualList->size() > (nActualPos+1))
516
0
        {
517
0
            pActEntry = (*pActualList)[nActualPos+1].get();
518
0
            if ( bWithDepth )
519
0
                *pDepth = nDepth;
520
0
            return pActEntry;
521
0
        }
522
0
        pParent = pParent->pParent;
523
0
        nDepth--;
524
0
    }
525
0
    return nullptr;
526
0
}
527
528
SvTreeListEntry* SvTreeList::Prev( SvTreeListEntry* pActEntry ) const
529
0
{
530
0
    assert(pActEntry && "Entry?");
531
532
0
    SvTreeListEntries* pActualList = &pActEntry->pParent->m_Children;
533
0
    sal_uInt32 nActualPos = pActEntry->GetChildListPos();
534
535
0
    if ( nActualPos > 0 )
536
0
    {
537
0
        pActEntry = (*pActualList)[nActualPos-1].get();
538
0
        while (!pActEntry->m_Children.empty())
539
0
        {
540
0
            pActualList = &pActEntry->m_Children;
541
0
            pActEntry = pActualList->back().get();
542
0
        }
543
0
        return pActEntry;
544
0
    }
545
0
    if ( pActEntry->pParent == pRootItem.get() )
546
0
        return nullptr;
547
548
0
    pActEntry = pActEntry->pParent;
549
550
0
    if ( pActEntry )
551
0
    {
552
0
        return pActEntry;
553
0
    }
554
0
    return nullptr;
555
0
}
556
557
SvTreeListEntry* SvTreeList::Last() const
558
0
{
559
0
    SvTreeListEntries* pActList = &pRootItem->m_Children;
560
0
    SvTreeListEntry* pEntry = nullptr;
561
0
    while (!pActList->empty())
562
0
    {
563
0
        pEntry = pActList->back().get();
564
0
        pActList = &pEntry->m_Children;
565
0
    }
566
0
    return pEntry;
567
0
}
568
569
sal_uInt32 SvTreeList::GetVisiblePos( const SvListView* pView, SvTreeListEntry const * pEntry ) const
570
0
{
571
0
    assert(pView && "View?");
572
0
    DBG_ASSERT(pEntry,"Entry?");
573
574
0
    if (!pView->m_pImpl->m_bVisPositionsValid)
575
0
    {
576
        // to make GetVisibleCount refresh the positions
577
0
        const_cast<SvListView*>(pView)->m_pImpl->m_nVisibleCount = 0;
578
0
        GetVisibleCount( const_cast<SvListView*>(pView) );
579
0
    }
580
0
    const SvViewDataEntry* pViewData = pView->GetViewData( pEntry );
581
0
    if (!pViewData)
582
0
        return 0;
583
0
    return pViewData->nVisPos;
584
0
}
585
586
sal_uInt32 SvTreeList::GetVisibleCount( SvListView* pView ) const
587
0
{
588
0
    assert(pView && "GetVisCount:No View");
589
0
    if( !pView->HasViewData() )
590
0
        return 0;
591
0
    if (pView->m_pImpl->m_nVisibleCount)
592
0
        return pView->m_pImpl->m_nVisibleCount;
593
594
0
    sal_uInt32 nPos = 0;
595
0
    SvTreeListEntry* pEntry = First();  // first entry is always visible
596
0
    while ( pEntry )
597
0
    {
598
0
        if (SvViewDataEntry* pViewData = pView->GetViewData( pEntry ))
599
0
            pViewData->nVisPos = nPos;
600
0
        nPos++;
601
0
        pEntry = NextVisible( pView, pEntry );
602
0
    }
603
#ifdef DBG_UTIL
604
    if( nPos > 10000000 )
605
    {
606
        OSL_FAIL("nVisibleCount bad");
607
    }
608
#endif
609
0
    pView->m_pImpl->m_nVisibleCount = nPos;
610
0
    pView->m_pImpl->m_bVisPositionsValid = true;
611
0
    return nPos;
612
0
}
613
614
615
// For performance reasons, this function assumes that the passed entry is
616
// already visible.
617
SvTreeListEntry* SvTreeList::NextVisible(const SvListView* pView,SvTreeListEntry* pActEntry,sal_uInt16* pActDepth) const
618
0
{
619
0
    if ( !pActEntry )
620
0
        return nullptr;
621
622
0
    assert(pView && "NextVisible:No View");
623
624
0
    sal_uInt16 nDepth = 0;
625
0
    bool bWithDepth = false;
626
0
    if ( pActDepth )
627
0
    {
628
0
        nDepth = *pActDepth;
629
0
        bWithDepth = true;
630
0
    }
631
632
0
    SvTreeListEntries* pActualList = &pActEntry->pParent->m_Children;
633
0
    sal_uInt32 nActualPos = pActEntry->GetChildListPos();
634
635
0
    if ( pView->IsExpanded(pActEntry) )
636
0
    {
637
0
        OSL_ENSURE(!pActEntry->m_Children.empty(), "Pass entry is supposed to have child entries.");
638
639
0
        nDepth++;
640
0
        pActEntry = pActEntry->m_Children[0].get();
641
0
        if ( bWithDepth )
642
0
            *pActDepth = nDepth;
643
0
        return pActEntry;
644
0
    }
645
646
0
    nActualPos++;
647
0
    if ( pActualList->size() > nActualPos  )
648
0
    {
649
0
        pActEntry = (*pActualList)[nActualPos].get();
650
0
        if ( bWithDepth )
651
0
            *pActDepth = nDepth;
652
0
        return pActEntry;
653
0
    }
654
655
0
    SvTreeListEntry* pParent = pActEntry->pParent;
656
0
    nDepth--;
657
0
    while( pParent != pRootItem.get() )
658
0
    {
659
0
        pActualList = &pParent->pParent->m_Children;
660
0
        nActualPos = pParent->GetChildListPos();
661
0
        nActualPos++;
662
0
        if ( pActualList->size() > nActualPos )
663
0
        {
664
0
            pActEntry = (*pActualList)[nActualPos].get();
665
0
            if ( bWithDepth )
666
0
                *pActDepth = nDepth;
667
0
            return pActEntry;
668
0
        }
669
0
        pParent = pParent->pParent;
670
0
        nDepth--;
671
0
    }
672
0
    return nullptr;
673
0
}
674
675
676
// For performance reasons, this function assumes that the passed entry is
677
// already visible.
678
679
SvTreeListEntry* SvTreeList::PrevVisible(const SvListView* pView, SvTreeListEntry* pActEntry) const
680
0
{
681
0
    assert(pView && pActEntry && "PrevVis:View/Entry?");
682
683
0
    SvTreeListEntries* pActualList = &pActEntry->pParent->m_Children;
684
0
    sal_uInt32 nActualPos = pActEntry->GetChildListPos();
685
686
0
    if ( nActualPos > 0 )
687
0
    {
688
0
        pActEntry = (*pActualList)[nActualPos-1].get();
689
0
        while( pView->IsExpanded(pActEntry) )
690
0
        {
691
0
            pActualList = &pActEntry->m_Children;
692
0
            pActEntry = pActualList->back().get();
693
0
        }
694
0
        return pActEntry;
695
0
    }
696
697
0
    if ( pActEntry->pParent == pRootItem.get() )
698
0
        return nullptr;
699
700
0
    pActEntry = pActEntry->pParent;
701
0
    if ( pActEntry )
702
0
    {
703
0
        return pActEntry;
704
0
    }
705
0
    return nullptr;
706
0
}
707
708
SvTreeListEntry* SvTreeList::LastVisible( const SvListView* pView) const
709
0
{
710
0
    DBG_ASSERT(pView,"LastVis:No View");
711
0
    SvTreeListEntry* pEntry = Last();
712
0
    while( pEntry && !IsEntryVisible( pView, pEntry ) )
713
0
        pEntry = PrevVisible( pView, pEntry );
714
0
    return pEntry;
715
0
}
716
717
SvTreeListEntry* SvTreeList::NextVisible(const SvListView* pView,SvTreeListEntry* pEntry,sal_uInt16& nDelta) const
718
0
{
719
0
    assert(pView && pEntry && "NextVis:Wrong Prms!");
720
0
    DBG_ASSERT(IsEntryVisible(pView,pEntry), "NextVis:Wrong Vis");
721
722
0
    sal_uInt32 nVisPos = GetVisiblePos( pView, pEntry );
723
    // nDelta entries existent?
724
    // example: 0,1,2,3,4,5,6,7,8,9 nVisPos=5 nDelta=7
725
    //           nNewDelta = 10-nVisPos-1 == 4
726
0
    if (nVisPos+nDelta >= pView->m_pImpl->m_nVisibleCount)
727
0
    {
728
0
        nDelta = static_cast<sal_uInt16>(pView->m_pImpl->m_nVisibleCount-nVisPos);
729
0
        nDelta--;
730
0
    }
731
0
    sal_uInt16 nDeltaTmp = nDelta;
732
0
    while( nDeltaTmp )
733
0
    {
734
0
        pEntry = NextVisible( pView, pEntry );
735
0
        nDeltaTmp--;
736
0
        DBG_ASSERT(pEntry,"Entry?");
737
0
    }
738
0
    return pEntry;
739
0
}
740
741
SvTreeListEntry* SvTreeList::PrevVisible( const SvListView* pView, SvTreeListEntry* pEntry, sal_uInt16& nDelta ) const
742
0
{
743
0
    DBG_ASSERT(pView&&pEntry&&IsEntryVisible(pView,pEntry),"PrevVis:Parms/!Vis");
744
745
0
    sal_uInt32 nVisPos = GetVisiblePos( pView, pEntry );
746
    // nDelta entries existent?
747
    // example: 0,1,2,3,4,5,6,7,8,9 nVisPos=8 nDelta=20
748
    //           nNewDelta = nNewVisPos
749
0
    if (  nDelta > nVisPos )
750
0
        nDelta = static_cast<sal_uInt16>(nVisPos);
751
0
    sal_uInt16 nDeltaTmp = nDelta;
752
0
    while( nDeltaTmp )
753
0
    {
754
0
        pEntry = PrevVisible( pView, pEntry );
755
0
        nDeltaTmp--;
756
0
        DBG_ASSERT(pEntry,"Entry?");
757
0
    }
758
0
    return pEntry;
759
0
}
760
761
SvTreeListEntry* SvTreeList::FirstSelected( const SvListView* pView) const
762
0
{
763
0
    DBG_ASSERT(pView,"FirstSel:No View");
764
0
    if( !pView )
765
0
        return nullptr;
766
0
    SvTreeListEntry* pActSelEntry = First();
767
0
    while( pActSelEntry && !pView->IsSelected(pActSelEntry) )
768
0
        pActSelEntry = NextVisible( pView, pActSelEntry );
769
0
    return pActSelEntry;
770
0
}
771
772
773
SvTreeListEntry* SvTreeList::FirstChild( SvTreeListEntry* pParent ) const
774
0
{
775
0
    if ( !pParent )
776
0
        pParent = pRootItem.get();
777
0
    SvTreeListEntry* pResult;
778
0
    if (!pParent->m_Children.empty())
779
0
        pResult = pParent->m_Children[0].get();
780
0
    else
781
0
        pResult = nullptr;
782
0
    return pResult;
783
0
}
784
785
SvTreeListEntry* SvTreeList::NextSelected( const SvListView* pView, SvTreeListEntry* pEntry ) const
786
0
{
787
0
    assert(pView && pEntry && "NextSel:View/Entry?");
788
0
    pEntry = Next( pEntry );
789
0
    while( pEntry && !pView->IsSelected(pEntry) )
790
0
        pEntry = Next( pEntry );
791
0
    return pEntry;
792
0
}
793
794
sal_uInt32 SvTreeList::Insert( SvTreeListEntry* pEntry,SvTreeListEntry* pParent,sal_uInt32 nPos )
795
0
{
796
0
    assert(pEntry && "Entry?");
797
798
0
    if ( !pParent )
799
0
        pParent = pRootItem.get();
800
801
0
    SvTreeListEntries& rList = pParent->m_Children;
802
803
    // take sorting into account
804
0
    GetInsertionPos( pEntry, pParent, nPos );
805
806
0
    bAbsPositionsValid = false;
807
0
    pEntry->pParent = pParent;
808
809
0
    if (nPos < rList.size())
810
0
    {
811
0
        SvTreeListEntries::iterator itPos = rList.begin();
812
0
        std::advance(itPos, nPos);
813
0
        rList.insert(itPos, std::unique_ptr<SvTreeListEntry>(pEntry));
814
0
    }
815
0
    else
816
0
        rList.push_back(std::unique_ptr<SvTreeListEntry>(pEntry));
817
818
0
    nEntryCount++;
819
0
    if (nPos != TREELIST_APPEND && (nPos != (rList.size()-1)))
820
0
        SetListPositions(rList);
821
0
    else
822
0
        pEntry->nListPos = rList.size()-1;
823
824
0
    Broadcast( SvListAction::INSERTED, pEntry );
825
0
    return nPos; // pEntry->nListPos;
826
0
}
827
828
sal_uInt32 SvTreeList::GetAbsPos( const SvTreeListEntry* pEntry) const
829
0
{
830
0
    if ( !bAbsPositionsValid )
831
0
        const_cast<SvTreeList*>(this)->SetAbsolutePositions();
832
0
    return pEntry->nAbsPos;
833
0
}
834
835
sal_uInt32 SvTreeList::GetRelPos( const SvTreeListEntry* pChild )
836
0
{
837
0
    return pChild->GetChildListPos();
838
0
}
839
840
void SvTreeList::SetAbsolutePositions()
841
0
{
842
0
    sal_uInt32 nPos = 0;
843
0
    SvTreeListEntry* pEntry = First();
844
0
    while ( pEntry )
845
0
    {
846
0
        pEntry->nAbsPos = nPos;
847
0
        nPos++;
848
0
        pEntry = Next( pEntry );
849
0
    }
850
0
    bAbsPositionsValid = true;
851
0
}
852
853
void SvListView::ExpandListEntry( SvTreeListEntry* pEntry )
854
0
{
855
0
    assert(pEntry && "Expand:View/Entry?");
856
0
    SvViewDataEntry* pViewData = GetViewData(pEntry);
857
0
    if (!pViewData)
858
0
        return;
859
860
0
    if (pViewData->IsExpanded())
861
0
        return;
862
863
0
    DBG_ASSERT(!pEntry->m_Children.empty(), "SvTreeList::Expand: We expected to have child entries.");
864
865
0
    pViewData->SetExpanded(true);
866
0
    SvTreeListEntry* pParent = pEntry->pParent;
867
    // if parent is visible, invalidate status data
868
0
    if ( IsExpanded( pParent ) )
869
0
    {
870
0
        m_pImpl->m_bVisPositionsValid = false;
871
0
        m_pImpl->m_nVisibleCount = 0;
872
0
    }
873
0
}
874
875
void SvListView::CollapseListEntry( SvTreeListEntry* pEntry )
876
0
{
877
0
    assert(pEntry && "Collapse:View/Entry?");
878
0
    SvViewDataEntry* pViewData = GetViewData( pEntry );
879
0
    if (!pViewData)
880
0
        return;
881
882
0
    if (!pViewData->IsExpanded())
883
0
        return;
884
885
0
    DBG_ASSERT(!pEntry->m_Children.empty(), "SvTreeList::Collapse: We expected to have child entries.");
886
887
0
    pViewData->SetExpanded(false);
888
889
0
    SvTreeListEntry* pParent = pEntry->pParent;
890
0
    if ( IsExpanded(pParent) )
891
0
    {
892
0
        m_pImpl->m_nVisibleCount = 0;
893
0
        m_pImpl->m_bVisPositionsValid = false;
894
0
    }
895
0
}
896
897
bool SvListView::SelectListEntry( SvTreeListEntry* pEntry, bool bSelect )
898
0
{
899
0
    DBG_ASSERT(pEntry,"Select:View/Entry?");
900
901
0
    SvViewDataEntry* pViewData = GetViewData( pEntry );
902
0
    if (!pViewData)
903
0
        return false;
904
905
0
    if ( bSelect )
906
0
    {
907
0
        if ( pViewData->IsSelected() || !pViewData->IsSelectable() )
908
0
            return false;
909
0
        else
910
0
        {
911
0
            pViewData->SetSelected(true);
912
0
            m_pImpl->m_nSelectionCount++;
913
0
        }
914
0
    }
915
0
    else
916
0
    {
917
0
        if ( !pViewData->IsSelected() )
918
0
            return false;
919
0
        else
920
0
        {
921
0
            pViewData->SetSelected(false);
922
0
            m_pImpl->m_nSelectionCount--;
923
0
        }
924
0
    }
925
0
    return true;
926
0
}
927
928
bool SvTreeList::Remove( const SvTreeListEntry* pEntry )
929
0
{
930
0
    assert(pEntry && "Cannot remove root, use clear");
931
932
0
    if( !pEntry->pParent )
933
0
    {
934
0
        OSL_FAIL("Removing entry not in model!");
935
        // Under certain circumstances (which?), the explorer deletes entries
936
        // from the view that it hasn't inserted into the view. We don't want
937
        // to crash, so we catch this case here.
938
0
        return false;
939
0
    }
940
941
0
    Broadcast(SvListAction::REMOVING, const_cast<SvTreeListEntry*>(pEntry));
942
0
    sal_uInt32 nRemoved = 1 + GetChildCount(pEntry);
943
0
    bAbsPositionsValid = false;
944
945
0
    SvTreeListEntry* pParent = pEntry->pParent;
946
0
    SvTreeListEntries& rList = pParent->m_Children;
947
0
    bool bLastEntry = false;
948
949
    // Since we need the live instance of SvTreeListEntry for broadcasting,
950
    // we first need to pop it from the container, broadcast it, then delete
951
    // the instance manually at the end.
952
953
0
    std::unique_ptr<SvTreeListEntry> pEntryDeleter;
954
0
    if ( pEntry->HasChildListPos() )
955
0
    {
956
0
        size_t nListPos = pEntry->GetChildListPos();
957
0
        bLastEntry = (nListPos == (rList.size()-1));
958
0
        SvTreeListEntries::iterator it = rList.begin();
959
0
        std::advance(it, nListPos);
960
0
        pEntryDeleter = std::move(*it);
961
0
        rList.erase(it);
962
0
    }
963
0
    else
964
0
    {
965
0
        SvTreeListEntries::iterator it =
966
0
            std::find_if(rList.begin(), rList.end(), FindByPointer(pEntry));
967
0
        if (it != rList.end())
968
0
        {
969
0
            pEntryDeleter = std::move(*it);
970
0
            rList.erase(it);
971
0
        }
972
0
    }
973
974
0
    if (!rList.empty() && !bLastEntry)
975
0
        SetListPositions(rList);
976
977
0
    nEntryCount -= nRemoved;
978
0
    Broadcast(SvListAction::REMOVED, const_cast<SvTreeListEntry*>(pEntry));
979
980
0
    return true;
981
0
}
982
983
SvTreeListEntry* SvTreeList::GetEntryAtAbsPos( sal_uInt32 nAbsPos ) const
984
0
{
985
0
    SvTreeListEntry* pEntry = First();
986
0
    while ( nAbsPos && pEntry )
987
0
    {
988
0
        pEntry = Next( pEntry );
989
0
        nAbsPos--;
990
0
    }
991
0
    return pEntry;
992
0
}
993
994
SvTreeListEntry* SvTreeList::GetEntryAtVisPos( const SvListView* pView, sal_uInt32 nVisPos ) const
995
0
{
996
0
    DBG_ASSERT(pView,"GetEntryAtVisPos:No View");
997
0
    SvTreeListEntry* pEntry = First();
998
0
    while ( nVisPos && pEntry )
999
0
    {
1000
0
        pEntry = NextVisible( pView, pEntry );
1001
0
        nVisPos--;
1002
0
    }
1003
0
    return pEntry;
1004
0
}
1005
1006
void SvTreeList::SetListPositions( SvTreeListEntries& rEntries )
1007
0
{
1008
0
    if (rEntries.empty())
1009
0
        return;
1010
1011
0
    SvTreeListEntry& rFirst = *rEntries.front();
1012
0
    if (rFirst.pParent)
1013
0
        rFirst.pParent->InvalidateChildrensListPositions();
1014
0
}
1015
1016
void SvTreeList::EnableInvalidate( bool bEnable )
1017
0
{
1018
0
    mbEnableInvalidate = bEnable;
1019
0
}
1020
1021
void SvTreeList::InvalidateEntry( SvTreeListEntry* pEntry )
1022
0
{
1023
0
    if (!mbEnableInvalidate)
1024
0
        return;
1025
1026
0
    Broadcast( SvListAction::INVALIDATE_ENTRY, pEntry );
1027
0
}
1028
1029
SvListView::SvListView()
1030
0
    : m_pImpl(new Impl(*this))
1031
0
{
1032
0
    pModel.reset(new SvTreeList(*this));
1033
0
    m_pImpl->InitTable();
1034
0
}
1035
1036
void SvListView::dispose()
1037
0
{
1038
0
    pModel.reset();
1039
0
}
1040
1041
SvListView::~SvListView()
1042
0
{
1043
0
    m_pImpl->m_DataTable.clear();
1044
0
}
1045
1046
sal_uInt32 SvListView::GetSelectionCount() const
1047
0
{ return m_pImpl->m_nSelectionCount; }
1048
1049
bool SvListView::HasViewData() const
1050
0
{ return m_pImpl->m_DataTable.size() > 1; }  // There's always a ROOT
1051
1052
1053
void SvListView::Impl::InitTable()
1054
0
{
1055
0
    DBG_ASSERT(m_rThis.pModel,"InitTable:No Model");
1056
0
    DBG_ASSERT(!m_nSelectionCount && !m_nVisibleCount && !m_bVisPositionsValid,
1057
0
            "InitTable: Not cleared!");
1058
1059
0
    if (!m_DataTable.empty())
1060
0
    {
1061
0
        DBG_ASSERT(m_DataTable.size() == 1, "InitTable: TableCount != 1");
1062
        // Delete the view data allocated to the Clear in the root.
1063
        // Attention: The model belonging to the root entry (and thus the entry
1064
        // itself) might already be deleted.
1065
0
        m_DataTable.clear();
1066
0
    }
1067
1068
0
    SvTreeListEntry* pEntry;
1069
1070
    // insert root entry
1071
0
    pEntry = m_rThis.pModel->pRootItem.get();
1072
0
    std::unique_ptr<SvViewDataEntry> pViewData(new SvViewDataEntry);
1073
0
    pViewData->SetExpanded(true);
1074
0
    m_DataTable.insert(std::make_pair(pEntry, std::move(pViewData)));
1075
    // now all the other entries
1076
0
    pEntry = m_rThis.pModel->First();
1077
0
    while( pEntry )
1078
0
    {
1079
0
        pViewData = std::make_unique<SvViewDataEntry>();
1080
0
        m_rThis.InitViewData( pViewData.get(), pEntry );
1081
0
        m_DataTable.insert(std::make_pair(pEntry, std::move(pViewData)));
1082
0
        pEntry = m_rThis.pModel->Next( pEntry );
1083
0
    }
1084
0
}
1085
1086
void SvListView::Clear()
1087
0
{
1088
0
    m_pImpl->m_DataTable.clear();
1089
0
    m_pImpl->m_nSelectionCount = 0;
1090
0
    m_pImpl->m_nVisibleCount = 0;
1091
0
    m_pImpl->m_bVisPositionsValid = false;
1092
0
    if( pModel )
1093
0
    {
1094
        // insert root entry
1095
0
        SvTreeListEntry* pEntry = pModel->pRootItem.get();
1096
0
        std::unique_ptr<SvViewDataEntry> pViewData(new SvViewDataEntry);
1097
0
        pViewData->SetExpanded(true);
1098
0
        m_pImpl->m_DataTable.insert(std::make_pair(pEntry, std::move(pViewData)));
1099
0
    }
1100
0
}
1101
1102
void SvListView::ModelHasCleared()
1103
0
{
1104
0
}
1105
1106
void SvListView::ModelHasInserted( SvTreeListEntry* )
1107
0
{
1108
0
}
1109
1110
void SvListView::ModelHasInsertedTree( SvTreeListEntry* )
1111
0
{
1112
0
}
1113
1114
void SvListView::ModelIsMoving( SvTreeListEntry* /*  pSource */ )
1115
0
{
1116
0
}
1117
1118
1119
void SvListView::ModelHasMoved( SvTreeListEntry* )
1120
0
{
1121
0
}
1122
1123
void SvListView::ModelIsRemoving( SvTreeListEntry* )
1124
0
{
1125
0
}
1126
1127
void SvListView::ModelHasRemoved( SvTreeListEntry* )
1128
0
{
1129
    //WARNING WARNING WARNING
1130
    //The supplied pointer should have been deleted
1131
    //before this call. Be careful not to use it!!!
1132
0
}
1133
1134
void SvListView::ModelHasEntryInvalidated( SvTreeListEntry*)
1135
0
{
1136
0
}
1137
1138
void SvListView::Impl::ActionMoving( SvTreeListEntry* pEntry )
1139
0
{
1140
0
    SvTreeListEntry* pParent = pEntry->pParent;
1141
0
    assert(pParent && "Model not consistent");
1142
0
    if (pParent != m_rThis.pModel->pRootItem.get() && pParent->m_Children.size() == 1)
1143
0
    {
1144
0
        const auto iter = m_DataTable.find(pParent);
1145
0
        assert(iter != m_DataTable.end());
1146
0
        SvViewDataEntry* pViewData = iter->second.get();
1147
0
        pViewData->SetExpanded(false);
1148
0
    }
1149
    // preliminary
1150
0
    m_nVisibleCount = 0;
1151
0
    m_bVisPositionsValid = false;
1152
0
}
1153
1154
void SvListView::Impl::ActionMoved()
1155
0
{
1156
0
    m_nVisibleCount = 0;
1157
0
    m_bVisPositionsValid = false;
1158
0
}
1159
1160
void SvListView::Impl::ActionInserted( SvTreeListEntry* pEntry )
1161
0
{
1162
0
    DBG_ASSERT(pEntry,"Insert:No Entry");
1163
0
    std::unique_ptr<SvViewDataEntry> pData(new SvViewDataEntry());
1164
0
    m_rThis.InitViewData( pData.get(), pEntry );
1165
0
    std::pair<SvDataTable::iterator, bool> aSuccess =
1166
0
        m_DataTable.insert(std::make_pair(pEntry, std::move(pData)));
1167
0
    DBG_ASSERT(aSuccess.second,"Entry already in View");
1168
0
    if (m_nVisibleCount && m_rThis.pModel->IsEntryVisible(&m_rThis, pEntry))
1169
0
    {
1170
0
        m_nVisibleCount = 0;
1171
0
        m_bVisPositionsValid = false;
1172
0
    }
1173
0
}
1174
1175
void SvListView::Impl::ActionInsertedTree( SvTreeListEntry* pEntry )
1176
0
{
1177
0
    if (m_rThis.pModel->IsEntryVisible(&m_rThis, pEntry))
1178
0
    {
1179
0
        m_nVisibleCount = 0;
1180
0
        m_bVisPositionsValid = false;
1181
0
    }
1182
    // iterate over entry and its children
1183
0
    SvTreeListEntry* pCurEntry = pEntry;
1184
0
    sal_uInt16 nRefDepth = m_rThis.pModel->GetDepth( pCurEntry );
1185
0
    while( pCurEntry )
1186
0
    {
1187
0
        DBG_ASSERT(m_DataTable.find(pCurEntry) != m_DataTable.end(),"Entry already in Table");
1188
0
        std::unique_ptr<SvViewDataEntry> pViewData(new SvViewDataEntry());
1189
0
        m_rThis.InitViewData( pViewData.get(), pEntry );
1190
0
        m_DataTable.insert(std::make_pair(pCurEntry, std::move(pViewData)));
1191
0
        pCurEntry = m_rThis.pModel->Next( pCurEntry );
1192
0
        if ( pCurEntry && m_rThis.pModel->GetDepth(pCurEntry) <= nRefDepth)
1193
0
            pCurEntry = nullptr;
1194
0
    }
1195
0
}
1196
1197
void SvListView::Impl::RemoveViewData( SvTreeListEntry* pParent )
1198
0
{
1199
0
    for (auto const& it : pParent->m_Children)
1200
0
    {
1201
0
        SvTreeListEntry& rEntry = *it;
1202
0
        m_DataTable.erase(&rEntry);
1203
0
        if (rEntry.HasChildren())
1204
0
            RemoveViewData(&rEntry);
1205
0
    }
1206
0
}
1207
1208
1209
void SvListView::Impl::ActionRemoving( SvTreeListEntry* pEntry )
1210
0
{
1211
0
    assert(pEntry && "Remove:No Entry");
1212
0
    const auto iter = m_DataTable.find(pEntry);
1213
0
    assert(iter != m_DataTable.end());
1214
0
    SvViewDataEntry* pViewData = iter->second.get();
1215
0
    sal_uInt32 nSelRemoved = 0;
1216
0
    if ( pViewData->IsSelected() )
1217
0
        nSelRemoved = 1 + m_rThis.pModel->GetChildSelectionCount(&m_rThis, pEntry);
1218
0
    m_nSelectionCount -= nSelRemoved;
1219
0
    sal_uInt32 nVisibleRemoved = 0;
1220
0
    if (m_rThis.pModel->IsEntryVisible(&m_rThis, pEntry))
1221
0
        nVisibleRemoved = 1 + m_rThis.pModel->GetVisibleChildCount(&m_rThis, pEntry);
1222
0
    if( m_nVisibleCount )
1223
0
    {
1224
#ifdef DBG_UTIL
1225
        if (m_nVisibleCount < nVisibleRemoved)
1226
        {
1227
            OSL_FAIL("nVisibleRemoved bad");
1228
        }
1229
#endif
1230
0
        m_nVisibleCount -= nVisibleRemoved;
1231
0
    }
1232
0
    m_bVisPositionsValid = false;
1233
1234
0
    m_DataTable.erase(pEntry);
1235
0
    RemoveViewData( pEntry );
1236
1237
0
    SvTreeListEntry* pCurEntry = pEntry->pParent;
1238
0
    if (pCurEntry && pCurEntry != m_rThis.pModel->pRootItem.get() && pCurEntry->m_Children.size() == 1)
1239
0
    {
1240
0
        SvDataTable::iterator itr = m_DataTable.find(pCurEntry);
1241
0
        assert(itr != m_DataTable.end() && "Entry not in Table");
1242
0
        pViewData = itr->second.get();
1243
0
        pViewData->SetExpanded(false);
1244
0
    }
1245
0
}
1246
1247
void SvListView::ModelNotification( SvListAction nActionId, SvTreeListEntry* pEntry1,
1248
                        SvTreeListEntry* /*pEntry2*/, sal_uInt32 /*nPos*/ )
1249
0
{
1250
1251
0
    switch( nActionId )
1252
0
    {
1253
0
        case SvListAction::INSERTED:
1254
0
            m_pImpl->ActionInserted( pEntry1 );
1255
0
            ModelHasInserted( pEntry1 );
1256
0
            break;
1257
0
        case SvListAction::INSERTED_TREE:
1258
0
            m_pImpl->ActionInsertedTree( pEntry1 );
1259
0
            ModelHasInsertedTree( pEntry1 );
1260
0
            break;
1261
0
        case SvListAction::REMOVING:
1262
0
            ModelIsRemoving( pEntry1 );
1263
0
            m_pImpl->ActionRemoving( pEntry1 );
1264
0
            break;
1265
0
        case SvListAction::REMOVED:
1266
0
            ModelHasRemoved( pEntry1 );
1267
0
            break;
1268
0
        case SvListAction::MOVING:
1269
0
            ModelIsMoving( pEntry1 );
1270
0
            m_pImpl->ActionMoving( pEntry1 );
1271
0
            break;
1272
0
        case SvListAction::MOVED:
1273
0
            m_pImpl->ActionMoved();
1274
0
            ModelHasMoved( pEntry1 );
1275
0
            break;
1276
0
        case SvListAction::CLEARING:
1277
0
            Clear();
1278
0
            ModelHasCleared(); // sic! for compatibility reasons!
1279
0
            break;
1280
0
        case SvListAction::CLEARED:
1281
0
            break;
1282
0
        case SvListAction::INVALIDATE_ENTRY:
1283
            // no action for the base class
1284
0
            ModelHasEntryInvalidated( pEntry1 );
1285
0
            break;
1286
0
        case SvListAction::RESORTED:
1287
0
            m_pImpl->m_bVisPositionsValid = false;
1288
0
            break;
1289
0
        case SvListAction::RESORTING:
1290
0
            break;
1291
0
        default:
1292
0
            OSL_FAIL("unknown ActionId");
1293
0
    }
1294
0
}
1295
1296
void SvListView::InitViewData( SvViewDataEntry*, SvTreeListEntry* )
1297
0
{
1298
0
}
1299
1300
bool SvListView::IsExpanded( SvTreeListEntry* pEntry ) const
1301
0
{
1302
0
    DBG_ASSERT(pEntry,"IsExpanded:No Entry");
1303
0
    SvDataTable::const_iterator itr = m_pImpl->m_DataTable.find(pEntry);
1304
0
    if (itr == m_pImpl->m_DataTable.end())
1305
0
        return false;
1306
0
    return itr->second->IsExpanded();
1307
0
}
1308
1309
bool SvListView::IsAllExpanded( SvTreeListEntry* pEntry ) const
1310
0
{
1311
0
    DBG_ASSERT(pEntry,"IsAllExpanded:No Entry");
1312
0
    if (!IsExpanded(pEntry))
1313
0
        return false;
1314
0
    const SvTreeListEntries& rChildren = pEntry->GetChildEntries();
1315
0
    for (auto& rChild : rChildren)
1316
0
    {
1317
0
        if (rChild->HasChildren() || rChild->HasChildrenOnDemand())
1318
0
        {
1319
0
            if (!IsAllExpanded(rChild.get()))
1320
0
                return false;
1321
0
        }
1322
0
    }
1323
0
    return true;
1324
0
}
1325
1326
bool SvListView::IsSelected(const SvTreeListEntry* pEntry) const
1327
0
{
1328
0
    DBG_ASSERT(pEntry,"IsExpanded:No Entry");
1329
0
    SvDataTable::const_iterator itr = m_pImpl->m_DataTable.find(const_cast<SvTreeListEntry*>(pEntry));
1330
0
    if (itr == m_pImpl->m_DataTable.end())
1331
0
        return false;
1332
0
    return itr->second->IsSelected();
1333
0
}
1334
1335
void SvListView::SetEntryFocus( SvTreeListEntry* pEntry, bool bFocus )
1336
0
{
1337
0
    DBG_ASSERT(pEntry,"SetEntryFocus:No Entry");
1338
0
    SvDataTable::iterator itr = m_pImpl->m_DataTable.find(pEntry);
1339
0
    assert(itr != m_pImpl->m_DataTable.end() && "Entry not in Table");
1340
0
    itr->second->SetFocus(bFocus);
1341
0
}
1342
1343
const SvViewDataEntry* SvListView::GetViewData( const SvTreeListEntry* pEntry ) const
1344
0
{
1345
0
    SvDataTable::const_iterator itr =
1346
0
        m_pImpl->m_DataTable.find(const_cast<SvTreeListEntry*>(pEntry));
1347
0
    assert(itr != m_pImpl->m_DataTable.end() && "Entry not in model or wrong view");
1348
0
    if (itr == m_pImpl->m_DataTable.end())
1349
0
        return nullptr;
1350
0
    return itr->second.get();
1351
0
}
1352
1353
SvViewDataEntry* SvListView::GetViewData( SvTreeListEntry* pEntry )
1354
0
{
1355
0
    return const_cast<SvViewDataEntry*>(std::as_const(*this).GetViewData(pEntry));
1356
0
}
1357
1358
sal_Int32 SvTreeList::Compare(const SvTreeListEntry* pLeft, const SvTreeListEntry* pRight) const
1359
0
{
1360
0
    if( aCompareLink.IsSet())
1361
0
    {
1362
0
        SvSortData aSortData;
1363
0
        aSortData.pLeft = pLeft;
1364
0
        aSortData.pRight = pRight;
1365
0
        return aCompareLink.Call( aSortData );
1366
0
    }
1367
0
    return 0;
1368
0
}
1369
1370
void SvTreeList::Resort()
1371
0
{
1372
0
    Broadcast( SvListAction::RESORTING );
1373
0
    bAbsPositionsValid = false;
1374
0
    ResortChildren( pRootItem.get() );
1375
0
    Broadcast( SvListAction::RESORTED );
1376
0
}
1377
1378
namespace {
1379
1380
class SortComparator
1381
{
1382
    SvTreeList& mrList;
1383
public:
1384
1385
0
    explicit SortComparator( SvTreeList& rList ) : mrList(rList) {}
1386
1387
    bool operator() (std::unique_ptr<SvTreeListEntry> const& rpLeft,
1388
                     std::unique_ptr<SvTreeListEntry> const& rpRight) const
1389
0
    {
1390
0
        int nCompare = mrList.Compare(rpLeft.get(), rpRight.get());
1391
0
        if (nCompare != 0 && mrList.GetSortMode() == SvSortMode::Descending)
1392
0
        {
1393
0
            if( nCompare < 0 )
1394
0
                nCompare = 1;
1395
0
            else
1396
0
                nCompare = -1;
1397
0
        }
1398
0
        return nCompare < 0;
1399
0
    }
1400
};
1401
1402
}
1403
1404
void SvTreeList::ResortChildren( SvTreeListEntry* pParent )
1405
0
{
1406
0
    assert(pParent && "Parent not set");
1407
1408
0
    if (pParent->m_Children.empty())
1409
0
        return;
1410
1411
0
    SortComparator aComp(*this);
1412
0
    std::sort(pParent->m_Children.begin(), pParent->m_Children.end(), aComp);
1413
1414
    // Recursively sort child entries.
1415
0
    for (auto const& it : pParent->m_Children)
1416
0
    {
1417
0
        SvTreeListEntry& r = *it;
1418
0
        ResortChildren(&r);
1419
0
    }
1420
1421
0
    SetListPositions(pParent->m_Children); // correct list position in target list
1422
0
}
1423
1424
void SvTreeList::GetInsertionPos( SvTreeListEntry const * pEntry, SvTreeListEntry* pParent,
1425
    sal_uInt32& rPos )
1426
0
{
1427
0
    DBG_ASSERT(pEntry,"No Entry");
1428
1429
0
    if( eSortMode == SvSortMode::None )
1430
0
        return;
1431
1432
0
    rPos = TREELIST_ENTRY_NOTFOUND;
1433
0
    const SvTreeListEntries& rChildList = GetChildList(pParent);
1434
1435
0
    if (rChildList.empty())
1436
0
        return;
1437
1438
0
    tools::Long i = 0;
1439
0
    tools::Long j = rChildList.size()-1;
1440
0
    tools::Long k;
1441
0
    sal_Int32 nCompare = 1;
1442
1443
0
    do
1444
0
    {
1445
0
        k = (i+j)/2;
1446
0
        const SvTreeListEntry* pTempEntry = rChildList[k].get();
1447
0
        nCompare = Compare( pEntry, pTempEntry );
1448
0
        if (nCompare != 0 && eSortMode == SvSortMode::Descending)
1449
0
        {
1450
0
            if( nCompare < 0 )
1451
0
                nCompare = 1;
1452
0
            else
1453
0
                nCompare = -1;
1454
0
        }
1455
0
        if( nCompare > 0 )
1456
0
            i = k + 1;
1457
0
        else
1458
0
            j = k - 1;
1459
0
    } while( (nCompare != 0) && (i <= j) );
1460
1461
0
    if( nCompare != 0 )
1462
0
    {
1463
0
        if (i > static_cast<tools::Long>(rChildList.size()-1)) // not found, end of list
1464
0
            rPos = TREELIST_ENTRY_NOTFOUND;
1465
0
        else
1466
0
            rPos = i;              // not found, middle of list
1467
0
    }
1468
0
    else
1469
0
        rPos = k;
1470
0
}
1471
1472
SvTreeListEntry* SvTreeList::GetEntry( SvTreeListEntry* pParent, sal_uInt32 nPos ) const
1473
0
{   if ( !pParent )
1474
0
        pParent = pRootItem.get();
1475
0
    SvTreeListEntry* pRet = nullptr;
1476
0
    if (nPos < pParent->m_Children.size())
1477
0
        pRet = pParent->m_Children[nPos].get();
1478
0
    return pRet;
1479
0
}
1480
1481
SvTreeListEntry* SvTreeList::GetEntry( sal_uInt32 nRootPos ) const
1482
0
{
1483
0
    SvTreeListEntry* pRet = nullptr;
1484
0
    if (nEntryCount && nRootPos < pRootItem->m_Children.size())
1485
0
        pRet = pRootItem->m_Children[nRootPos].get();
1486
0
    return pRet;
1487
0
}
1488
1489
const SvTreeListEntries& SvTreeList::GetChildList( SvTreeListEntry* pParent ) const
1490
0
{
1491
0
    if ( !pParent )
1492
0
        pParent = pRootItem.get();
1493
0
    return pParent->m_Children;
1494
0
}
1495
1496
SvTreeListEntries& SvTreeList::GetChildList( SvTreeListEntry* pParent )
1497
0
{
1498
0
    if ( !pParent )
1499
0
        pParent = pRootItem.get();
1500
0
    return pParent->m_Children;
1501
0
}
1502
1503
const SvTreeListEntry* SvTreeList::GetParent( const SvTreeListEntry* pEntry ) const
1504
0
{
1505
0
    const SvTreeListEntry* pParent = pEntry->pParent;
1506
0
    if (pParent == pRootItem.get())
1507
0
        pParent = nullptr;
1508
0
    return pParent;
1509
0
}
1510
1511
SvTreeListEntry* SvTreeList::GetParent( SvTreeListEntry* pEntry )
1512
0
{
1513
0
    SvTreeListEntry* pParent = pEntry->pParent;
1514
0
    if (pParent == pRootItem.get())
1515
0
        pParent = nullptr;
1516
0
    return pParent;
1517
0
}
1518
1519
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */