1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
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>
33 #include <vcl/toolkit/treelistbox.hxx>
34 #include <vcl/toolkit/svlbitm.hxx>
35 #include <tools/wintypes.hxx>
36 #include <bitmaps.hlst>
37 #include <svimpbox.hxx>
38 #include <comphelper/processfactory.hxx>
39 #include <comphelper/string.hxx>
40 #include <i18nlangtag/languagetag.hxx>
41 #include <tools/debug.hxx>
43 #include <vcl/toolkit/treelistentry.hxx>
44 #include <vcl/toolkit/viewdataentry.hxx>
46 // #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors
47 Image
* SvImpLBox::s_pDefCollapsed
= nullptr;
48 Image
* SvImpLBox::s_pDefExpanded
= nullptr;
49 oslInterlockedCount
SvImpLBox::s_nImageRefCount
= 0;
51 SvImpLBox::SvImpLBox( SvTreeListBox
* pLBView
, SvTreeList
* pLBTree
, WinBits nWinStyle
)
52 : m_aHorSBar(VclPtr
<ScrollBar
>::Create(pLBView
, WB_DRAG
| WB_HSCROLL
))
53 , m_aScrBarBox(VclPtr
<ScrollBarBox
>::Create(pLBView
))
54 , m_aFctSet(this, pLBView
)
55 , mbForceMakeVisible (false)
56 , m_aVerSBar(VclPtr
<ScrollBar
>::Create(pLBView
, WB_DRAG
| WB_VSCROLL
))
58 , mbNoAutoCurEntry(false)
59 , m_aSelEng(pLBView
, nullptr)
60 , m_nNextVerVisSize(0)
62 osl_atomic_increment(&s_nImageRefCount
);
65 m_aSelEng
.SetFunctionSet( static_cast<FunctionSet
*>(&m_aFctSet
) );
66 m_aSelEng
.ExpandSelectionOnMouseMove( false );
67 SetStyle( nWinStyle
);
68 SetSelectionMode( SelectionMode::Single
);
69 SetDragDropMode( DragDropMode::NONE
);
71 m_aVerSBar
->SetScrollHdl( LINK( this, SvImpLBox
, ScrollUpDownHdl
) );
72 m_aHorSBar
->SetScrollHdl( LINK( this, SvImpLBox
, ScrollLeftRightHdl
) );
73 m_aHorSBar
->SetEndScrollHdl( LINK( this, SvImpLBox
, EndScrollHdl
) );
74 m_aVerSBar
->SetEndScrollHdl( LINK( this, SvImpLBox
, EndScrollHdl
) );
75 m_aVerSBar
->SetRange( Range(0,0) );
77 m_aHorSBar
->SetRange( Range(0,0) );
78 m_aHorSBar
->SetPageSize( 24 ); // pixels
79 m_aHorSBar
->SetLineSize( 8 ); // pixels
81 m_nHorSBarHeight
= static_cast<short>(m_aHorSBar
->GetSizePixel().Height());
82 m_nVerSBarWidth
= static_cast<short>(m_aVerSBar
->GetSizePixel().Width());
84 m_pStartEntry
= nullptr;
87 m_nVisibleCount
= 0; // number of rows of data in control
88 m_nNodeBmpTabDistance
= NODE_BMP_TABDIST_NOTVALID
;
91 // button animation in listbox
92 m_pActiveButton
= nullptr;
93 m_pActiveEntry
= nullptr;
94 m_pActiveTab
= nullptr;
96 m_nFlags
= LBoxFlags::NONE
;
98 m_aEditIdle
.SetPriority( TaskPriority::LOWEST
);
99 m_aEditIdle
.SetInvokeHandler( LINK(this,SvImpLBox
,EditTimerCall
) );
102 m_pMostRightEntry
= nullptr;
103 m_nCurUserEvent
= nullptr;
105 m_bUpdateMode
= true;
106 m_bInVScrollHdl
= false;
107 m_nFlags
|= LBoxFlags::Filling
;
109 m_bSubLstOpLR
= false;
112 SvImpLBox::~SvImpLBox()
117 if ( osl_atomic_decrement(&s_nImageRefCount
) == 0 )
119 delete s_pDefCollapsed
;
120 s_pDefCollapsed
= nullptr;
121 delete s_pDefExpanded
;
122 s_pDefExpanded
= nullptr;
124 m_aVerSBar
.disposeAndClear();
125 m_aHorSBar
.disposeAndClear();
126 m_aScrBarBox
.disposeAndClear();
129 void SvImpLBox::UpdateStringSorter()
131 const css::lang::Locale
& rNewLocale
= Application::GetSettings().GetLanguageTag().getLocale();
133 if( m_pStringSorter
)
135 // different Locale from the older one, drop it and force recreate
136 const css::lang::Locale
&aLocale
= m_pStringSorter
->getLocale();
137 if( aLocale
.Language
!= rNewLocale
.Language
||
138 aLocale
.Country
!= rNewLocale
.Country
||
139 aLocale
.Variant
!= rNewLocale
.Variant
)
140 m_pStringSorter
.reset();
143 if( !m_pStringSorter
)
145 m_pStringSorter
.reset(new comphelper::string::NaturalStringSorter(
146 ::comphelper::getProcessComponentContext(),
151 short SvImpLBox::UpdateContextBmpWidthVector( SvTreeListEntry
const * pEntry
, short nWidth
)
153 DBG_ASSERT( m_pView
->pModel
, "View and Model aren't valid!" );
155 sal_uInt16 nDepth
= m_pView
->pModel
->GetDepth( pEntry
);
156 // initialize vector if necessary
157 std::vector
< short >::size_type nSize
= m_aContextBmpWidthVector
.size();
158 while ( nDepth
> nSize
)
160 m_aContextBmpWidthVector
.resize( nSize
+ 1 );
161 m_aContextBmpWidthVector
.at( nSize
) = nWidth
;
164 if( m_aContextBmpWidthVector
.size() == nDepth
)
166 m_aContextBmpWidthVector
.resize( nDepth
+ 1 );
167 m_aContextBmpWidthVector
.at( nDepth
) = 0;
169 short nContextBmpWidth
= m_aContextBmpWidthVector
[ nDepth
];
170 if( nContextBmpWidth
< nWidth
)
172 m_aContextBmpWidthVector
.at( nDepth
) = nWidth
;
176 return nContextBmpWidth
;
179 void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry
* pEntry
)
181 DBG_ASSERT( pEntry
, "Moved Entry is invalid!" );
183 SvLBoxContextBmp
* pBmpItem
= static_cast< SvLBoxContextBmp
* >( pEntry
->GetFirstItem(SvLBoxItemType::ContextBmp
) );
184 short nExpWidth
= static_cast<short>(pBmpItem
->GetBitmap1().GetSizePixel().Width());
185 short nColWidth
= static_cast<short>(pBmpItem
->GetBitmap2().GetSizePixel().Width());
186 short nMax
= std::max(nExpWidth
, nColWidth
);
187 UpdateContextBmpWidthVector( pEntry
, nMax
);
189 if( pEntry
->HasChildren() ) // recursive call, whether expanded or not
191 SvTreeListEntry
* pChild
= m_pView
->FirstChild( pEntry
);
192 DBG_ASSERT( pChild
, "The first child is invalid!" );
195 UpdateContextBmpWidthVectorFromMovedEntry( pChild
);
196 pChild
= m_pView
->Next( pChild
);
201 void SvImpLBox::UpdateContextBmpWidthMax( SvTreeListEntry
const * pEntry
)
203 sal_uInt16 nDepth
= m_pView
->pModel
->GetDepth( pEntry
);
204 if( m_aContextBmpWidthVector
.empty() )
206 short nWidth
= m_aContextBmpWidthVector
[ nDepth
];
207 if( nWidth
!= m_pView
->nContextBmpWidthMax
) {
208 m_pView
->nContextBmpWidthMax
= nWidth
;
209 m_nFlags
|= LBoxFlags::IgnoreChangedTabs
;
211 m_nFlags
&= ~LBoxFlags::IgnoreChangedTabs
;
215 void SvImpLBox::SetStyle( WinBits i_nWinStyle
)
217 m_nStyle
= i_nWinStyle
;
218 if ( ( m_nStyle
& WB_SIMPLEMODE
) && ( m_aSelEng
.GetSelectionMode() == SelectionMode::Multiple
) )
219 m_aSelEng
.AddAlways( true );
222 void SvImpLBox::SetNoAutoCurEntry( bool b
)
224 mbNoAutoCurEntry
= b
;
227 // don't touch the model any more
228 void SvImpLBox::Clear()
231 m_pStartEntry
= nullptr;
234 m_pActiveButton
= nullptr;
235 m_pActiveEntry
= nullptr;
236 m_pActiveTab
= nullptr;
239 m_pMostRightEntry
= nullptr;
241 // don't touch the cursor any more
244 if( m_pView
->HasFocus() )
245 m_pView
->HideFocus();
249 m_aVerSBar
->SetThumbPos( 0 );
250 Range
aRange( 0, 0 );
251 m_aVerSBar
->SetRange( aRange
);
252 m_aOutputSize
= m_pView
->Control::GetOutputSizePixel();
254 m_aHorSBar
->SetThumbPos( 0 );
255 MapMode
aMapMode( m_pView
->GetMapMode());
256 aMapMode
.SetOrigin( Point(0,0) );
257 m_pView
->Control::SetMapMode( aMapMode
);
258 m_aHorSBar
->SetRange( aRange
);
259 m_aHorSBar
->SetSizePixel(Size(m_aOutputSize
.Width(),m_nHorSBarHeight
));
260 m_pView
->SetClipRegion();
261 if( GetUpdateMode() )
262 m_pView
->Invalidate( GetVisibleArea() );
263 m_nFlags
|= LBoxFlags::Filling
;
264 if( !m_aHorSBar
->IsVisible() && !m_aVerSBar
->IsVisible() )
265 m_aScrBarBox
->Hide();
267 m_aContextBmpWidthVector
.clear();
269 CallEventListeners( VclEventId::ListboxItemRemoved
);
272 // *********************************************************************
273 // Paint, navigate, scroll
274 // *********************************************************************
276 IMPL_LINK_NOARG(SvImpLBox
, EndScrollHdl
, ScrollBar
*, void)
278 if( m_nFlags
& LBoxFlags::EndScrollSetVisSize
)
280 m_aVerSBar
->SetVisibleSize( m_nNextVerVisSize
);
281 m_nFlags
&= ~LBoxFlags::EndScrollSetVisSize
;
285 // handler for vertical scrollbar
287 IMPL_LINK( SvImpLBox
, ScrollUpDownHdl
, ScrollBar
*, pScrollBar
, void )
289 DBG_ASSERT(!m_bInVScrollHdl
,"Scroll handler out-paces itself!");
290 tools::Long nDelta
= pScrollBar
->GetDelta();
294 m_nFlags
&= ~LBoxFlags::Filling
;
296 m_bInVScrollHdl
= true;
298 if( m_pView
->IsEditingActive() )
300 m_pView
->EndEditing( true ); // Cancel
301 m_pView
->PaintImmediately();
309 PageDown( static_cast<sal_uInt16
>(nDelta
) );
317 PageUp( static_cast<sal_uInt16
>(nDelta
) );
319 m_bInVScrollHdl
= false;
323 void SvImpLBox::CursorDown()
328 SvTreeListEntry
* pNextFirstToDraw
= m_pView
->NextVisible(m_pStartEntry
);
329 if( pNextFirstToDraw
)
331 m_nFlags
&= ~LBoxFlags::Filling
;
333 m_pView
->PaintImmediately();
334 m_pStartEntry
= pNextFirstToDraw
;
335 tools::Rectangle
aArea( GetVisibleArea() );
336 m_pView
->Scroll( 0, -(m_pView
->GetEntryHeight()), aArea
, ScrollFlags::NoChildren
);
337 m_pView
->PaintImmediately();
339 m_pView
->NotifyScrolled();
343 void SvImpLBox::CursorUp()
348 SvTreeListEntry
* pPrevFirstToDraw
= m_pView
->PrevVisible(m_pStartEntry
);
349 if( !pPrevFirstToDraw
)
352 m_nFlags
&= ~LBoxFlags::Filling
;
353 tools::Long nEntryHeight
= m_pView
->GetEntryHeight();
355 m_pView
->PaintImmediately();
356 m_pStartEntry
= pPrevFirstToDraw
;
357 tools::Rectangle
aArea( GetVisibleArea() );
358 aArea
.AdjustBottom( -nEntryHeight
);
359 m_pView
->Scroll( 0, nEntryHeight
, aArea
, ScrollFlags::NoChildren
);
360 m_pView
->PaintImmediately();
362 m_pView
->NotifyScrolled();
365 void SvImpLBox::PageDown( sal_uInt16 nDelta
)
367 sal_uInt16 nRealDelta
= nDelta
;
375 SvTreeListEntry
* pNext
= m_pView
->NextVisible(m_pStartEntry
, nRealDelta
);
376 if( pNext
== m_pStartEntry
)
381 m_nFlags
&= ~LBoxFlags::Filling
;
382 m_pStartEntry
= pNext
;
384 if( nRealDelta
>= m_nVisibleCount
)
386 m_pView
->Invalidate( GetVisibleArea() );
387 m_pView
->PaintImmediately();
391 tools::Rectangle
aArea( GetVisibleArea() );
392 tools::Long nScroll
= m_pView
->GetEntryHeight() * static_cast<tools::Long
>(nRealDelta
);
394 m_pView
->PaintImmediately();
395 m_pView
->Scroll( 0, nScroll
, aArea
, ScrollFlags::NoChildren
);
396 m_pView
->PaintImmediately();
397 m_pView
->NotifyScrolled();
403 void SvImpLBox::PageUp( sal_uInt16 nDelta
)
405 sal_uInt16 nRealDelta
= nDelta
;
412 SvTreeListEntry
* pPrev
= m_pView
->PrevVisible(m_pStartEntry
, nRealDelta
);
413 if( pPrev
== m_pStartEntry
)
416 m_nFlags
&= ~LBoxFlags::Filling
;
419 m_pStartEntry
= pPrev
;
420 if( nRealDelta
>= m_nVisibleCount
)
422 m_pView
->Invalidate( GetVisibleArea() );
423 m_pView
->PaintImmediately();
427 tools::Long nEntryHeight
= m_pView
->GetEntryHeight();
428 tools::Rectangle
aArea( GetVisibleArea() );
429 m_pView
->PaintImmediately();
430 m_pView
->Scroll( 0, nEntryHeight
*nRealDelta
, aArea
, ScrollFlags::NoChildren
);
431 m_pView
->PaintImmediately();
432 m_pView
->NotifyScrolled();
438 void SvImpLBox::KeyUp( bool bPageUp
)
440 if( !m_aVerSBar
->IsVisible() )
445 nDelta
= m_aVerSBar
->GetPageSize();
449 tools::Long nThumbPos
= m_aVerSBar
->GetThumbPos();
451 if( nThumbPos
< nDelta
)
457 m_nFlags
&= ~LBoxFlags::Filling
;
459 m_aVerSBar
->SetThumbPos( nThumbPos
- nDelta
);
461 PageUp( static_cast<short>(nDelta
) );
467 void SvImpLBox::KeyDown( bool bPageDown
)
469 if( !m_aVerSBar
->IsVisible() )
474 nDelta
= m_aVerSBar
->GetPageSize();
478 tools::Long nThumbPos
= m_aVerSBar
->GetThumbPos();
479 tools::Long nVisibleSize
= m_aVerSBar
->GetVisibleSize();
480 tools::Long nRange
= m_aVerSBar
->GetRange().Len();
482 tools::Long nTmp
= nThumbPos
+nVisibleSize
;
483 while( (nDelta
> 0) && (nTmp
+nDelta
) >= nRange
)
489 m_nFlags
&= ~LBoxFlags::Filling
;
491 m_aVerSBar
->SetThumbPos( nThumbPos
+nDelta
);
493 PageDown( static_cast<short>(nDelta
) );
499 void SvImpLBox::InvalidateEntriesFrom( tools::Long nY
) const
501 if( !(m_nFlags
& LBoxFlags::InPaint
))
503 tools::Rectangle
aRect( GetVisibleArea() );
505 m_pView
->Invalidate( aRect
);
509 void SvImpLBox::InvalidateEntry( tools::Long nY
) const
511 if( m_nFlags
& LBoxFlags::InPaint
)
514 tools::Rectangle
aRect( GetVisibleArea() );
515 tools::Long nMaxBottom
= aRect
.Bottom();
517 aRect
.SetBottom( nY
); aRect
.AdjustBottom(m_pView
->GetEntryHeight() );
518 if( aRect
.Top() > nMaxBottom
)
520 if( aRect
.Bottom() > nMaxBottom
)
521 aRect
.SetBottom( nMaxBottom
);
522 if (m_pView
->SupportsDoubleBuffering())
523 // Perform full paint when flicker is to be avoided explicitly.
524 m_pView
->Invalidate();
526 m_pView
->Invalidate(aRect
);
529 void SvImpLBox::InvalidateEntry( SvTreeListEntry
* pEntry
)
531 if( GetUpdateMode() )
533 tools::Long nPrev
= m_nMostRight
;
534 SetMostRight( pEntry
);
535 if( nPrev
< m_nMostRight
)
538 if( !(m_nFlags
& LBoxFlags::InPaint
))
540 bool bHasFocusRect
= false;
541 if( pEntry
==m_pCursor
&& m_pView
->HasFocus() )
543 bHasFocusRect
= true;
546 InvalidateEntry( GetEntryLine( pEntry
) );
553 void SvImpLBox::RecalcFocusRect()
555 if( m_pView
->HasFocus() && m_pCursor
)
557 m_pView
->HideFocus();
558 tools::Long nY
= GetEntryLine( m_pCursor
);
559 tools::Rectangle aRect
= m_pView
->GetFocusRect( m_pCursor
, nY
);
560 vcl::Region
aOldClip( m_pView
->GetClipRegion());
561 vcl::Region
aClipRegion( GetClipRegionRect() );
562 m_pView
->SetClipRegion( aClipRegion
);
563 m_pView
->ShowFocus( aRect
);
564 m_pView
->SetClipRegion( aOldClip
);
569 // Sets cursor. When using SingleSelection, the selection is adjusted.
570 void SvImpLBox::SetCursor( SvTreeListEntry
* pEntry
, bool bForceNoSelect
)
572 SvViewDataEntry
* pViewDataNewCur
= nullptr;
574 pViewDataNewCur
= m_pView
->GetViewDataEntry(pEntry
);
576 pEntry
== m_pCursor
&&
578 pViewDataNewCur
->HasFocus() &&
579 pViewDataNewCur
->IsSelected())
584 // if this cursor is not selectable, find first visible that is and use it
585 while( pEntry
&& pViewDataNewCur
&& !pViewDataNewCur
->IsSelectable() )
587 pEntry
= m_pView
->NextVisible(pEntry
);
588 pViewDataNewCur
= pEntry
? m_pView
->GetViewDataEntry(pEntry
) : nullptr;
591 SvTreeListEntry
* pOldCursor
= m_pCursor
;
592 if( m_pCursor
&& pEntry
!= m_pCursor
)
594 m_pView
->SetEntryFocus( m_pCursor
, false );
595 if( m_bSimpleTravel
)
596 m_pView
->Select( m_pCursor
, false );
597 m_pView
->HideFocus();
603 pViewDataNewCur
->SetFocus( true );
604 if(!bForceNoSelect
&& m_bSimpleTravel
&& !(m_nFlags
& LBoxFlags::DeselectAll
) && GetUpdateMode())
606 m_pView
->Select( m_pCursor
);
607 CallEventListeners( VclEventId::ListboxTreeFocus
, m_pCursor
);
609 // multiple selection: select in cursor move if we're not in
610 // Add mode (Ctrl-F8)
611 else if( GetUpdateMode() &&
612 m_pView
->GetSelectionMode() == SelectionMode::Multiple
&&
613 !(m_nFlags
& LBoxFlags::DeselectAll
) && !m_aSelEng
.IsAddMode() &&
616 m_pView
->Select( m_pCursor
);
617 CallEventListeners( VclEventId::ListboxTreeFocus
, m_pCursor
);
622 if (bForceNoSelect
&& GetUpdateMode())
624 CallEventListeners( VclEventId::ListboxTreeFocus
, m_pCursor
);
630 DBG_ASSERT(m_aSelEng
.GetSelectionMode() != SelectionMode::Single
,"Mode?");
631 SetAnchorSelection( pOldCursor
, m_pCursor
);
634 m_nFlags
&= ~LBoxFlags::DeselectAll
;
636 m_pView
->OnCurrentEntryChanged();
639 void SvImpLBox::ShowCursor( bool bShow
)
641 if( !bShow
|| !m_pCursor
|| !m_pView
->HasFocus() )
643 vcl::Region
aOldClip( m_pView
->GetClipRegion());
644 vcl::Region
aClipRegion( GetClipRegionRect() );
645 m_pView
->SetClipRegion( aClipRegion
);
646 m_pView
->HideFocus();
647 m_pView
->SetClipRegion( aOldClip
);
651 tools::Long nY
= GetEntryLine( m_pCursor
);
652 tools::Rectangle aRect
= m_pView
->GetFocusRect( m_pCursor
, nY
);
653 vcl::Region
aOldClip( m_pView
->GetClipRegion());
654 vcl::Region
aClipRegion( GetClipRegionRect() );
655 m_pView
->SetClipRegion( aClipRegion
);
656 m_pView
->ShowFocus( aRect
);
657 m_pView
->SetClipRegion( aOldClip
);
662 void SvImpLBox::UpdateAll( bool bInvalidateCompleteView
)
665 m_aVerSBar
->SetRange( Range(0, m_pView
->GetVisibleCount()-1 ) );
669 if( m_bSimpleTravel
&& m_pCursor
&& m_pView
->HasFocus() )
670 m_pView
->Select( m_pCursor
);
672 if( bInvalidateCompleteView
)
673 m_pView
->Invalidate();
675 m_pView
->Invalidate( GetVisibleArea() );
678 IMPL_LINK( SvImpLBox
, ScrollLeftRightHdl
, ScrollBar
*, pScrollBar
, void )
680 tools::Long nDelta
= pScrollBar
->GetDelta();
683 if( m_pView
->IsEditingActive() )
685 m_pView
->EndEditing( true ); // Cancel
686 m_pView
->PaintImmediately();
688 m_pView
->nFocusWidth
= -1;
689 KeyLeftRight( nDelta
);
693 void SvImpLBox::KeyLeftRight( tools::Long nDelta
)
695 if( !(m_nFlags
& LBoxFlags::InResize
) )
696 m_pView
->PaintImmediately();
697 m_nFlags
&= ~LBoxFlags::Filling
;
700 // calculate new origin
701 tools::Long nPos
= m_aHorSBar
->GetThumbPos();
702 Point
aOrigin( -nPos
, 0 );
704 MapMode
aMapMode( m_pView
->GetMapMode() );
705 aMapMode
.SetOrigin( aOrigin
);
706 m_pView
->SetMapMode( aMapMode
);
708 if( !(m_nFlags
& LBoxFlags::InResize
) )
710 tools::Rectangle
aRect( GetVisibleArea() );
711 m_pView
->Scroll( -nDelta
, 0, aRect
, ScrollFlags::NoChildren
);
714 m_pView
->Invalidate();
717 m_pView
->NotifyScrolled();
721 // returns the last entry if position is just past the last entry
722 SvTreeListEntry
* SvImpLBox::GetClickedEntry( const Point
& rPoint
) const
724 DBG_ASSERT( m_pView
->GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" );
725 if ( !m_pView
->GetModel() )
726 // this is quite impossible. Nevertheless, stack traces from the crash reporter
727 // suggest it isn't. Okay, make it safe, and wait for somebody to reproduce it
729 // #122359# / 2005-05-23 / frank.schoenheit@sun.com
731 if( m_pView
->GetEntryCount() == 0 || !m_pStartEntry
|| !m_pView
->GetEntryHeight())
734 sal_uInt16 nClickedEntry
= static_cast<sal_uInt16
>(rPoint
.Y() / m_pView
->GetEntryHeight() );
735 sal_uInt16 nTemp
= nClickedEntry
;
736 SvTreeListEntry
* pEntry
= m_pView
->NextVisible(m_pStartEntry
, nTemp
);
741 // checks if the entry was hit "the right way"
742 // (Focusrect+ ContextBitmap at TreeListBox)
744 bool SvImpLBox::EntryReallyHit(SvTreeListEntry
* pEntry
, const Point
& rPosPixel
, tools::Long nLine
)
747 // we are not too exact when it comes to "special" entries
748 // (with CheckButtons etc.)
749 if( pEntry
->ItemCount() >= 3 )
752 tools::Rectangle
aRect( m_pView
->GetFocusRect( pEntry
, nLine
));
753 aRect
.SetRight( GetOutputSize().Width() - m_pView
->GetMapMode().GetOrigin().X() );
755 SvLBoxContextBmp
* pBmp
= static_cast<SvLBoxContextBmp
*>(pEntry
->GetFirstItem(SvLBoxItemType::ContextBmp
));
756 aRect
.AdjustLeft( -pBmp
->GetWidth(m_pView
,pEntry
) );
757 aRect
.AdjustLeft( -4 ); // a little tolerance
759 Point
aPos( rPosPixel
);
760 aPos
-= m_pView
->GetMapMode().GetOrigin();
761 bRet
= aRect
.IsInside( aPos
);
766 // returns 0 if position is just past the last entry
767 SvTreeListEntry
* SvImpLBox::GetEntry( const Point
& rPoint
) const
769 if( (m_pView
->GetEntryCount() == 0) || !m_pStartEntry
||
770 (rPoint
.Y() > m_aOutputSize
.Height())
771 || !m_pView
->GetEntryHeight())
774 sal_uInt16 nClickedEntry
= static_cast<sal_uInt16
>(rPoint
.Y() / m_pView
->GetEntryHeight() );
775 sal_uInt16 nTemp
= nClickedEntry
;
776 SvTreeListEntry
* pEntry
= m_pView
->NextVisible(m_pStartEntry
, nTemp
);
777 if( nTemp
!= nClickedEntry
)
783 SvTreeListEntry
* SvImpLBox::MakePointVisible(const Point
& rPoint
)
787 tools::Long nY
= rPoint
.Y();
788 SvTreeListEntry
* pEntry
= nullptr;
789 tools::Long nMax
= m_aOutputSize
.Height();
790 if( nY
< 0 || nY
>= nMax
) // aOutputSize.Height() )
793 pEntry
= m_pView
->PrevVisible(m_pCursor
);
795 pEntry
= m_pView
->NextVisible(m_pCursor
);
797 if( pEntry
&& pEntry
!= m_pCursor
)
798 m_pView
->SetEntryFocus( m_pCursor
, false );
807 pEntry
= GetClickedEntry( rPoint
);
810 sal_uInt16 nSteps
= 0xFFFF;
811 // TODO: LastVisible is not yet implemented!
812 pEntry
= m_pView
->NextVisible(m_pStartEntry
, nSteps
);
816 if( pEntry
!= m_pCursor
&&
817 m_aSelEng
.GetSelectionMode() == SelectionMode::Single
819 m_pView
->Select( m_pCursor
, false );
825 tools::Rectangle
SvImpLBox::GetClipRegionRect() const
827 Point
aOrigin( m_pView
->GetMapMode().GetOrigin() );
828 aOrigin
.setX( aOrigin
.X() * -1 ); // conversion document coordinates
829 tools::Rectangle
aClipRect( aOrigin
, m_aOutputSize
);
830 aClipRect
.AdjustBottom( 1 );
835 void SvImpLBox::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
837 if (!m_pView
->GetVisibleCount())
840 m_nFlags
|= LBoxFlags::InPaint
;
842 if (m_nFlags
& LBoxFlags::Filling
)
844 SvTreeListEntry
* pFirst
= m_pView
->First();
845 if (pFirst
!= m_pStartEntry
)
848 m_pStartEntry
= m_pView
->First();
849 m_aVerSBar
->SetThumbPos( 0 );
852 m_nCurUserEvent
= Application::PostUserEvent(LINK(this, SvImpLBox
, MyUserEvent
),
853 reinterpret_cast<void*>(1));
860 m_pStartEntry
= m_pView
->First();
863 if (m_nNodeBmpTabDistance
== NODE_BMP_TABDIST_NOTVALID
)
864 SetNodeBmpTabDistance();
866 tools::Long nRectHeight
= rRect
.GetHeight();
867 tools::Long nEntryHeight
= m_pView
->GetEntryHeight();
869 // calculate area for the entries we want to draw
870 sal_uInt16 nStartLine
= static_cast<sal_uInt16
>(rRect
.Top() / nEntryHeight
);
871 sal_uInt16 nCount
= static_cast<sal_uInt16
>(nRectHeight
/ nEntryHeight
);
872 nCount
+= 2; // don't miss a row
874 tools::Long nY
= nStartLine
* nEntryHeight
;
875 SvTreeListEntry
* pEntry
= m_pStartEntry
;
876 while (nStartLine
&& pEntry
)
878 pEntry
= m_pView
->NextVisible(pEntry
);
882 if (!m_pCursor
&& !mbNoAutoCurEntry
)
884 // do not select if multiselection or explicit set
885 bool bNotSelect
= (m_aSelEng
.GetSelectionMode() == SelectionMode::Multiple
) || ((m_nStyle
& WB_NOINITIALSELECTION
) == WB_NOINITIALSELECTION
);
886 SetCursor(m_pStartEntry
, bNotSelect
);
889 for(sal_uInt16 n
=0; n
< nCount
&& pEntry
; n
++)
892 m_pView
->PaintEntry1(*pEntry
, nY
, rRenderContext
);
894 pEntry
= m_pView
->NextVisible(pEntry
);
897 if (m_nStyle
& (WB_HASLINES
| WB_HASLINESATROOT
))
898 DrawNet(rRenderContext
);
900 m_nFlags
&= ~LBoxFlags::DeselectAll
;
901 m_nFlags
&= ~LBoxFlags::InPaint
;
904 void SvImpLBox::MakeVisible( SvTreeListEntry
* pEntry
, bool bMoveToTop
)
909 bool bInView
= IsEntryInView( pEntry
);
911 if( bInView
&& (!bMoveToTop
|| m_pStartEntry
== pEntry
) )
912 return; // is already visible
914 if( m_pStartEntry
|| mbForceMakeVisible
)
915 m_nFlags
&= ~LBoxFlags::Filling
;
918 if( !m_pView
->IsEntryVisible(pEntry
) ) // Parent(s) collapsed?
920 SvTreeListEntry
* pParent
= m_pView
->GetParent( pEntry
);
923 if( !m_pView
->IsExpanded( pParent
) )
925 bool bRet
= m_pView
->Expand( pParent
);
926 DBG_ASSERT(bRet
,"Not expanded!");
928 pParent
= m_pView
->GetParent( pParent
);
930 // do the parent's children fit into the view or do we have to scroll?
931 if( IsEntryInView( pEntry
) && !bMoveToTop
)
932 return; // no need to scroll
936 m_pStartEntry
= pEntry
;
939 m_aVerSBar
->SetThumbPos( static_cast<tools::Long
>(m_pView
->GetVisiblePos( m_pStartEntry
)) );
941 m_pView
->Invalidate();
944 void SvImpLBox::ScrollToAbsPos( tools::Long nPos
)
946 if( m_pView
->GetVisibleCount() == 0 )
948 tools::Long nLastEntryPos
= m_pView
->GetAbsPos( m_pView
->Last() );
952 else if( nPos
> nLastEntryPos
)
953 nPos
= nLastEntryPos
;
955 SvTreeListEntry
* pEntry
= m_pView
->GetEntryAtAbsPos( nPos
);
956 if( !pEntry
|| pEntry
== m_pStartEntry
)
959 if( m_pStartEntry
|| mbForceMakeVisible
)
960 m_nFlags
&= ~LBoxFlags::Filling
;
962 if( m_pView
->IsEntryVisible(pEntry
) )
964 m_pStartEntry
= pEntry
;
966 m_aVerSBar
->SetThumbPos( nPos
);
969 m_pView
->Invalidate();
973 void SvImpLBox::DrawNet(vcl::RenderContext
& rRenderContext
)
975 if (m_pView
->GetVisibleCount() < 2 && !m_pStartEntry
->HasChildrenOnDemand() &&
976 !m_pStartEntry
->HasChildren())
981 // for platforms that don't have nets, DrawNativeControl does nothing and returns true
982 // so that SvImpLBox::DrawNet() doesn't draw anything either
983 if (rRenderContext
.IsNativeControlSupported(ControlType::ListNet
, ControlPart::Entire
))
985 ImplControlValue aControlValue
;
986 if (rRenderContext
.DrawNativeControl(ControlType::ListNet
, ControlPart::Entire
,
987 tools::Rectangle(), ControlState::ENABLED
, aControlValue
, OUString()))
993 tools::Long nEntryHeight
= m_pView
->GetEntryHeight();
994 tools::Long nEntryHeightDIV2
= nEntryHeight
/ 2;
995 if( nEntryHeightDIV2
&& !(nEntryHeight
& 0x0001))
998 SvTreeListEntry
* pChild
;
999 SvTreeListEntry
* pEntry
= m_pStartEntry
;
1001 SvLBoxTab
* pFirstDynamicTab
= m_pView
->GetFirstDynamicTab();
1002 while (m_pTree
->GetDepth( pEntry
) > 0)
1004 pEntry
= m_pView
->GetParent(pEntry
);
1006 sal_uInt16 nOffs
= static_cast<sal_uInt16
>(m_pView
->GetVisiblePos(m_pStartEntry
) - m_pView
->GetVisiblePos(pEntry
));
1008 nY
-= (nOffs
* nEntryHeight
);
1010 DBG_ASSERT(pFirstDynamicTab
,"No Tree!");
1012 rRenderContext
.Push(PushFlags::LINECOLOR
);
1014 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1015 Color aCol
= rStyleSettings
.GetFaceColor();
1017 if (aCol
.IsRGBEqual(rRenderContext
.GetBackground().GetColor()))
1018 aCol
= rStyleSettings
.GetShadowColor();
1019 rRenderContext
.SetLineColor(aCol
);
1021 sal_uInt16 nDistance
;
1022 sal_uLong nMax
= m_nVisibleCount
+ nOffs
+ 1;
1024 const Image
& rExpandedNodeBitmap
= GetExpandedNodeBmp();
1026 for (sal_uLong n
=0; n
< nMax
&& pEntry
; n
++)
1028 if (m_pView
->IsExpanded(pEntry
))
1030 // draw vertical line
1031 aPos1
.setX(m_pView
->GetTabPos(pEntry
, pFirstDynamicTab
) + m_nNodeBmpTabDistance
+
1032 rExpandedNodeBitmap
.GetSizePixel().Width() / 2);
1033 aPos1
.setY(nY
+ nEntryHeight
);
1034 pChild
= m_pView
->FirstChild(pEntry
);
1035 assert(pChild
&& "Child?");
1036 pChild
= pChild
->LastSibling();
1037 nDistance
= static_cast<sal_uInt16
>(m_pView
->GetVisiblePos(pChild
) -
1038 m_pView
->GetVisiblePos(pEntry
));
1040 aPos2
.AdjustY((nDistance
* nEntryHeight
) - (nEntryHeightDIV2
+ 2));
1041 rRenderContext
.DrawLine(aPos1
, aPos2
);
1043 // visible in control?
1044 if (n
>= nOffs
&& !m_pTree
->IsAtRootDepth(pEntry
))
1046 // draw horizontal line
1047 aPos1
.setX(m_pView
->GetTabPos(m_pView
->GetParent(pEntry
), pFirstDynamicTab
)
1048 + m_nNodeBmpTabDistance
1049 + rExpandedNodeBitmap
.GetSizePixel().Width() / 2);
1050 aPos1
.setY(nY
+ nEntryHeightDIV2
);
1052 aPos2
.AdjustX(m_pView
->GetIndent() / 2);
1053 rRenderContext
.DrawLine(aPos1
, aPos2
);
1056 pEntry
= m_pView
->NextVisible(pEntry
);
1059 rRenderContext
.Pop();
1062 void SvImpLBox::PositionScrollBars( Size
& rSize
, sal_uInt16 nMask
)
1064 tools::Long nOverlap
= 0;
1066 Size
aVerSize( m_nVerSBarWidth
, rSize
.Height() );
1067 Size
aHorSize( rSize
.Width(), m_nHorSBarHeight
);
1069 if( nMask
& 0x0001 )
1070 aHorSize
.AdjustWidth( -m_nVerSBarWidth
);
1071 if( nMask
& 0x0002 )
1072 aVerSize
.AdjustHeight( -m_nHorSBarHeight
);
1074 aVerSize
.AdjustHeight(2 * nOverlap
);
1075 Point
aVerPos( rSize
.Width() - aVerSize
.Width() + nOverlap
, -nOverlap
);
1076 m_aVerSBar
->SetPosSizePixel( aVerPos
, aVerSize
);
1078 aHorSize
.AdjustWidth(2 * nOverlap
);
1079 Point
aHorPos( -nOverlap
, rSize
.Height() - aHorSize
.Height() + nOverlap
);
1081 m_aHorSBar
->SetPosSizePixel( aHorPos
, aHorSize
);
1083 if( nMask
& 0x0001 )
1084 rSize
.setWidth( aVerPos
.X() );
1085 if( nMask
& 0x0002 )
1086 rSize
.setHeight( aHorPos
.Y() );
1088 if( (nMask
& (0x0001|0x0002)) == (0x0001|0x0002) )
1089 m_aScrBarBox
->Show();
1091 m_aScrBarBox
->Hide();
1094 void SvImpLBox::AdjustScrollBars( Size
& rSize
)
1096 tools::Long nEntryHeight
= m_pView
->GetEntryHeight();
1100 sal_uInt16 nResult
= 0;
1102 Size
aOSize( m_pView
->Control::GetOutputSizePixel() );
1104 const WinBits nWindowStyle
= m_pView
->GetStyle();
1105 bool bVerSBar
= ( nWindowStyle
& WB_VSCROLL
) != 0;
1106 bool bHorBar
= false;
1107 tools::Long nMaxRight
= aOSize
.Width(); //GetOutputSize().Width();
1108 Point
aOrigin( m_pView
->GetMapMode().GetOrigin() );
1109 aOrigin
.setX( aOrigin
.X() * -1 );
1110 nMaxRight
+= aOrigin
.X() - 1;
1111 tools::Long nVis
= m_nMostRight
- aOrigin
.X();
1112 if( (nWindowStyle
& (WB_AUTOHSCROLL
|WB_HSCROLL
)) &&
1113 (nVis
< m_nMostRight
|| nMaxRight
< m_nMostRight
) )
1118 // number of entries that are not collapsed
1119 sal_uLong nTotalCount
= m_pView
->GetVisibleCount();
1121 // number of entries visible within the view
1122 m_nVisibleCount
= aOSize
.Height() / nEntryHeight
;
1124 // do we need a vertical scrollbar?
1125 if( bVerSBar
|| nTotalCount
> m_nVisibleCount
)
1128 nMaxRight
-= m_nVerSBarWidth
;
1131 if( (nWindowStyle
& (WB_AUTOHSCROLL
|WB_HSCROLL
)) &&
1132 (nVis
< m_nMostRight
|| nMaxRight
< m_nMostRight
) )
1137 // do we need a horizontal scrollbar?
1141 // the number of entries visible within the view has to be recalculated
1142 // because the horizontal scrollbar is now visible.
1143 m_nVisibleCount
= (aOSize
.Height() - m_nHorSBarHeight
) / nEntryHeight
;
1144 // we might actually need a vertical scrollbar now
1145 if( !(nResult
& 0x0001) &&
1146 ((nTotalCount
> m_nVisibleCount
) || bVerSBar
) )
1152 PositionScrollBars( aOSize
, nResult
);
1154 // adapt Range, VisibleRange etc.
1156 // refresh output size, in case we have to scroll
1157 tools::Rectangle aRect
;
1158 aRect
.SetSize( aOSize
);
1159 m_aSelEng
.SetVisibleArea( aRect
);
1161 // vertical scrollbar
1162 tools::Long nTemp
= static_cast<tools::Long
>(m_nVisibleCount
);
1164 if( nTemp
!= m_aVerSBar
->GetVisibleSize() )
1166 if( !m_bInVScrollHdl
)
1168 m_aVerSBar
->SetPageSize( nTemp
- 1 );
1169 m_aVerSBar
->SetVisibleSize( nTemp
);
1173 m_nFlags
|= LBoxFlags::EndScrollSetVisSize
;
1174 m_nNextVerVisSize
= nTemp
;
1178 // horizontal scrollbar
1179 nTemp
= m_aHorSBar
->GetThumbPos();
1180 m_aHorSBar
->SetVisibleSize( aOSize
.Width() );
1181 tools::Long nNewThumbPos
= m_aHorSBar
->GetThumbPos();
1182 Range
aRange( m_aHorSBar
->GetRange() );
1183 if( aRange
.Max() < m_nMostRight
+25 )
1185 aRange
.Max() = m_nMostRight
+25;
1186 m_aHorSBar
->SetRange( aRange
);
1189 if( nTemp
!= nNewThumbPos
)
1191 nTemp
= nNewThumbPos
- nTemp
;
1192 if( m_pView
->IsEditingActive() )
1194 m_pView
->EndEditing( true ); // Cancel
1195 m_pView
->PaintImmediately();
1197 m_pView
->nFocusWidth
= -1;
1198 KeyLeftRight( nTemp
);
1201 if( nResult
& 0x0001 )
1206 if( nResult
& 0x0002 )
1215 void SvImpLBox::InitScrollBarBox()
1217 m_aScrBarBox
->SetSizePixel( Size(m_nVerSBarWidth
, m_nHorSBarHeight
) );
1218 Size
aSize( m_pView
->Control::GetOutputSizePixel() );
1219 m_aScrBarBox
->SetPosPixel( Point(aSize
.Width()-m_nVerSBarWidth
, aSize
.Height()-m_nHorSBarHeight
));
1222 void SvImpLBox::Resize()
1224 m_aOutputSize
= m_pView
->Control::GetOutputSizePixel();
1225 if( m_aOutputSize
.IsEmpty() )
1227 m_nFlags
|= LBoxFlags::InResize
;
1230 if( m_pView
->GetEntryHeight())
1232 AdjustScrollBars( m_aOutputSize
);
1235 // HACK, as in floating and docked windows the scrollbars might not be drawn
1236 // correctly/not be drawn at all after resizing!
1237 if( m_aHorSBar
->IsVisible())
1238 m_aHorSBar
->Invalidate();
1239 if( m_aVerSBar
->IsVisible())
1240 m_aVerSBar
->Invalidate();
1241 m_nFlags
&= ~LBoxFlags::InResize
;
1244 void SvImpLBox::FillView()
1246 if( !m_pStartEntry
)
1248 sal_uLong nVisibleViewCount
= m_pView
->GetVisibleCount();
1249 tools::Long nTempThumb
= m_aVerSBar
->GetThumbPos();
1250 if( nTempThumb
< 0 )
1252 else if( o3tl::make_unsigned(nTempThumb
) >= nVisibleViewCount
)
1253 nTempThumb
= nVisibleViewCount
== 0 ? 0 : nVisibleViewCount
- 1;
1254 m_pStartEntry
= m_pView
->GetEntryAtVisPos(nTempThumb
);
1256 if( !m_pStartEntry
)
1259 sal_uInt16 nLast
= static_cast<sal_uInt16
>(m_pView
->GetVisiblePos(m_pView
->LastVisible()));
1260 sal_uInt16 nThumb
= static_cast<sal_uInt16
>(m_pView
->GetVisiblePos( m_pStartEntry
));
1261 sal_uLong nCurDispEntries
= nLast
-nThumb
+1;
1262 if( nCurDispEntries
>= m_nVisibleCount
)
1265 ShowCursor( false );
1266 // fill window by moving the thumb up incrementally
1267 bool bFound
= false;
1268 SvTreeListEntry
* pTemp
= m_pStartEntry
;
1269 while( nCurDispEntries
< m_nVisibleCount
&& pTemp
)
1271 pTemp
= m_pView
->PrevVisible(m_pStartEntry
);
1275 m_pStartEntry
= pTemp
;
1282 m_aVerSBar
->SetThumbPos( nThumb
);
1283 ShowCursor( true ); // recalculate focus rectangle
1284 m_pView
->Invalidate();
1289 void SvImpLBox::ShowVerSBar()
1291 bool bVerBar
= ( m_pView
->GetStyle() & WB_VSCROLL
) != 0;
1294 nVis
= m_pView
->GetVisibleCount();
1295 if( bVerBar
|| (m_nVisibleCount
&& nVis
> static_cast<sal_uLong
>(m_nVisibleCount
-1)) )
1297 if( !m_aVerSBar
->IsVisible() )
1299 m_pView
->nFocusWidth
= -1;
1300 AdjustScrollBars( m_aOutputSize
);
1301 if( GetUpdateMode() )
1302 m_aVerSBar
->Invalidate();
1307 if( m_aVerSBar
->IsVisible() )
1309 m_pView
->nFocusWidth
= -1;
1310 AdjustScrollBars( m_aOutputSize
);
1314 tools::Long nMaxRight
= GetOutputSize().Width();
1315 Point
aPos( m_pView
->GetMapMode().GetOrigin() );
1316 aPos
.setX( aPos
.X() * -1 ); // convert document coordinates
1317 nMaxRight
= nMaxRight
+ aPos
.X() - 1;
1318 if( nMaxRight
< m_nMostRight
)
1320 if( !m_aHorSBar
->IsVisible() )
1322 m_pView
->nFocusWidth
= -1;
1323 AdjustScrollBars( m_aOutputSize
);
1324 if( GetUpdateMode() )
1325 m_aHorSBar
->Invalidate();
1329 Range
aRange( m_aHorSBar
->GetRange() );
1330 if( aRange
.Max() < m_nMostRight
+25 )
1332 aRange
.Max() = m_nMostRight
+25;
1333 m_aHorSBar
->SetRange( aRange
);
1337 m_pView
->nFocusWidth
= -1;
1338 AdjustScrollBars( m_aOutputSize
);
1344 if( m_aHorSBar
->IsVisible() )
1346 m_pView
->nFocusWidth
= -1;
1347 AdjustScrollBars( m_aOutputSize
);
1353 void SvImpLBox::SyncVerThumb()
1357 tools::Long nEntryPos
= m_pView
->GetVisiblePos( m_pStartEntry
);
1358 m_aVerSBar
->SetThumbPos( nEntryPos
);
1361 m_aVerSBar
->SetThumbPos( 0 );
1364 bool SvImpLBox::IsEntryInView( SvTreeListEntry
* pEntry
) const
1367 if( !m_pView
->IsEntryVisible(pEntry
) )
1369 tools::Long nY
= GetEntryLine( pEntry
);
1372 tools::Long nMax
= m_nVisibleCount
* m_pView
->GetEntryHeight();
1377 tools::Long
SvImpLBox::GetEntryLine(const SvTreeListEntry
* pEntry
) const
1380 return -1; // invisible position
1382 tools::Long nFirstVisPos
= m_pView
->GetVisiblePos( m_pStartEntry
);
1383 tools::Long nEntryVisPos
= m_pView
->GetVisiblePos( pEntry
);
1384 nFirstVisPos
= nEntryVisPos
- nFirstVisPos
;
1385 nFirstVisPos
*= m_pView
->GetEntryHeight();
1386 return nFirstVisPos
;
1389 void SvImpLBox::SetEntryHeight()
1391 SetNodeBmpWidth( GetExpandedNodeBmp() );
1392 SetNodeBmpWidth( GetCollapsedNodeBmp() );
1393 if(!m_pView
->HasViewData()) // are we within the Clear?
1395 Size aSize
= m_pView
->Control::GetOutputSizePixel();
1396 AdjustScrollBars( aSize
);
1401 if( GetUpdateMode() )
1402 m_pView
->Invalidate();
1407 // ***********************************************************************
1408 // Callback Functions
1409 // ***********************************************************************
1411 void SvImpLBox::EntryExpanded( SvTreeListEntry
* pEntry
)
1413 // SelAllDestrAnch( false, true ); //DeselectAll();
1414 if( !GetUpdateMode() )
1417 ShowCursor( false );
1418 tools::Long nY
= GetEntryLine( pEntry
);
1419 if( IsLineVisible(nY
) )
1421 InvalidateEntriesFrom( nY
);
1422 FindMostRight( pEntry
);
1424 m_aVerSBar
->SetRange( Range(0, m_pView
->GetVisibleCount()-1 ) );
1425 // if we expanded before the thumb, the thumb's position has to be
1432 void SvImpLBox::EntryCollapsed( SvTreeListEntry
* pEntry
)
1434 if( !m_pView
->IsEntryVisible( pEntry
) )
1437 ShowCursor( false );
1439 if( !m_pMostRightEntry
|| m_pTree
->IsChild( pEntry
,m_pMostRightEntry
) )
1446 tools::Long nOldThumbPos
= m_aVerSBar
->GetThumbPos();
1447 sal_uLong nVisList
= m_pView
->GetVisibleCount();
1448 m_aVerSBar
->SetRange( Range(0, nVisList
-1) );
1449 tools::Long nNewThumbPos
= m_aVerSBar
->GetThumbPos();
1450 if( nNewThumbPos
!= nOldThumbPos
)
1452 m_pStartEntry
= m_pView
->First();
1453 sal_uInt16 nDistance
= static_cast<sal_uInt16
>(nNewThumbPos
);
1455 m_pStartEntry
= m_pView
->NextVisible(m_pStartEntry
, nDistance
);
1456 if( GetUpdateMode() )
1457 m_pView
->Invalidate();
1463 // has the cursor been collapsed?
1464 if( m_pTree
->IsChild( pEntry
, m_pCursor
) )
1465 SetCursor( pEntry
);
1466 if( GetUpdateMode() )
1469 if( GetUpdateMode() && m_pCursor
)
1470 m_pView
->Select( m_pCursor
);
1473 void SvImpLBox::CollapsingEntry( SvTreeListEntry
* pEntry
)
1475 if( !m_pView
->IsEntryVisible( pEntry
) || !m_pStartEntry
)
1478 SelAllDestrAnch( false ); // deselect all
1480 // is the collapsed cursor visible?
1481 tools::Long nY
= GetEntryLine( pEntry
);
1482 if( IsLineVisible(nY
) )
1484 if( GetUpdateMode() )
1485 InvalidateEntriesFrom( nY
);
1489 if( m_pTree
->IsChild(pEntry
, m_pStartEntry
) )
1491 m_pStartEntry
= pEntry
;
1492 if( GetUpdateMode() )
1493 m_pView
->Invalidate();
1499 void SvImpLBox::SetNodeBmpWidth( const Image
& rBmp
)
1501 const Size
aSize( rBmp
.GetSizePixel() );
1502 m_nNodeBmpWidth
= aSize
.Width();
1505 void SvImpLBox::SetNodeBmpTabDistance()
1507 m_nNodeBmpTabDistance
= -m_pView
->GetIndent();
1508 if( m_pView
->nContextBmpWidthMax
)
1510 // only if the first dynamic tab is centered (we currently assume that)
1511 Size aSize
= GetExpandedNodeBmp().GetSizePixel();
1512 m_nNodeBmpTabDistance
-= aSize
.Width() / 2;
1517 // corrects the cursor when using SingleSelection
1519 void SvImpLBox::EntrySelected( SvTreeListEntry
* pEntry
, bool bSelect
)
1521 if( m_nFlags
& LBoxFlags::IgnoreSelect
)
1524 m_nFlags
&= ~LBoxFlags::DeselectAll
;
1526 m_aSelEng
.GetSelectionMode() == SelectionMode::Single
&&
1527 pEntry
!= m_pCursor
)
1529 SetCursor( pEntry
);
1530 DBG_ASSERT(m_pView
->GetSelectionCount()==1,"selection count?");
1533 if( GetUpdateMode() && m_pView
->IsEntryVisible(pEntry
) )
1535 tools::Long nY
= GetEntryLine( pEntry
);
1536 if( IsLineVisible( nY
) )
1539 InvalidateEntry(pEntry
);
1546 void SvImpLBox::RemovingEntry( SvTreeListEntry
* pEntry
)
1548 CallEventListeners( VclEventId::ListboxItemRemoved
, pEntry
);
1552 if( !m_pView
->IsEntryVisible( pEntry
) )
1554 // if parent is collapsed => bye!
1555 m_nFlags
|= LBoxFlags::RemovedEntryInvisible
;
1559 if( pEntry
== m_pMostRightEntry
|| (
1560 pEntry
->HasChildren() && m_pView
->IsExpanded(pEntry
) &&
1561 m_pTree
->IsChild(pEntry
, m_pMostRightEntry
)))
1563 m_nFlags
|= LBoxFlags::RemovedRecalcMostRight
;
1566 SvTreeListEntry
* pOldStartEntry
= m_pStartEntry
;
1568 SvTreeListEntry
* pParent
= m_pView
->GetModel()->GetParent(pEntry
);
1570 if (pParent
&& m_pView
->GetModel()->GetChildList(pParent
).size() == 1)
1572 DBG_ASSERT( m_pView
->IsExpanded( pParent
), "Parent not expanded");
1573 pParent
->SetFlags( pParent
->GetFlags() | SvTLEntryFlags::NO_NODEBMP
);
1574 InvalidateEntry( pParent
);
1577 if( m_pCursor
&& m_pTree
->IsChild( pEntry
, m_pCursor
) )
1579 if( m_pStartEntry
&& m_pTree
->IsChild(pEntry
,m_pStartEntry
) )
1580 m_pStartEntry
= pEntry
;
1582 SvTreeListEntry
* pTemp
;
1583 if( m_pCursor
&& m_pCursor
== pEntry
)
1585 if( m_bSimpleTravel
)
1586 m_pView
->Select( m_pCursor
, false );
1587 ShowCursor( false ); // focus rectangle gone
1588 // NextSibling, because we also delete the children of the cursor
1589 pTemp
= m_pCursor
->NextSibling();
1591 pTemp
= m_pView
->PrevVisible(m_pCursor
);
1593 SetCursor( pTemp
, true );
1595 if( m_pStartEntry
&& m_pStartEntry
== pEntry
)
1597 pTemp
= m_pStartEntry
->NextSibling();
1599 pTemp
= m_pView
->PrevVisible(m_pStartEntry
);
1600 m_pStartEntry
= pTemp
;
1602 if( GetUpdateMode())
1604 // if it is the last one, we have to invalidate it, so the lines are
1605 // drawn correctly (in this case they're deleted)
1606 if( m_pStartEntry
&& (m_pStartEntry
!= pOldStartEntry
|| pEntry
== m_pView
->GetModel()->Last()) )
1608 m_aVerSBar
->SetThumbPos( m_pView
->GetVisiblePos( m_pStartEntry
));
1609 m_pView
->Invalidate( GetVisibleArea() );
1612 InvalidateEntriesFrom( GetEntryLine( pEntry
) );
1616 void SvImpLBox::EntryRemoved()
1618 if( m_nFlags
& LBoxFlags::RemovedEntryInvisible
)
1620 m_nFlags
&= ~LBoxFlags::RemovedEntryInvisible
;
1623 if( !m_pStartEntry
)
1624 m_pStartEntry
= m_pTree
->First();
1626 SetCursor( m_pStartEntry
, true );
1628 if( m_pCursor
&& (m_bSimpleTravel
|| !m_pView
->GetSelectionCount() ))
1629 m_pView
->Select( m_pCursor
);
1631 if( GetUpdateMode())
1633 if( m_nFlags
& LBoxFlags::RemovedRecalcMostRight
)
1635 m_aVerSBar
->SetRange( Range(0, m_pView
->GetVisibleCount()-1 ) );
1638 // if something above the thumb was deleted
1639 m_aVerSBar
->SetThumbPos( m_pView
->GetVisiblePos( m_pStartEntry
) );
1642 if( m_pCursor
&& m_pView
->HasFocus() && !m_pView
->IsSelected(m_pCursor
) )
1644 if( m_pView
->GetSelectionCount() )
1646 // is a neighboring entry selected?
1647 SvTreeListEntry
* pNextCursor
= m_pView
->PrevVisible( m_pCursor
);
1648 if( !pNextCursor
|| !m_pView
->IsSelected( pNextCursor
))
1649 pNextCursor
= m_pView
->NextVisible( m_pCursor
);
1650 if( !pNextCursor
|| !m_pView
->IsSelected( pNextCursor
))
1651 // no neighbor selected: use first selected
1652 pNextCursor
= m_pView
->FirstSelected();
1653 SetCursor( pNextCursor
);
1654 MakeVisible( m_pCursor
);
1657 m_pView
->Select( m_pCursor
);
1661 m_nFlags
&= ~LBoxFlags::RemovedRecalcMostRight
;
1665 void SvImpLBox::MovingEntry( SvTreeListEntry
* pEntry
)
1667 bool bDeselAll(m_nFlags
& LBoxFlags::DeselectAll
);
1668 SelAllDestrAnch( false ); // DeselectAll();
1670 m_nFlags
&= ~LBoxFlags::DeselectAll
;
1672 if( pEntry
== m_pCursor
)
1673 ShowCursor( false );
1674 if( IsEntryInView( pEntry
) )
1675 m_pView
->Invalidate();
1676 if( pEntry
!= m_pStartEntry
)
1679 SvTreeListEntry
* pNew
= nullptr;
1680 if( !pEntry
->HasChildren() )
1682 pNew
= m_pView
->NextVisible(m_pStartEntry
);
1684 pNew
= m_pView
->PrevVisible(m_pStartEntry
);
1688 pNew
= pEntry
->NextSibling();
1690 pNew
= pEntry
->PrevSibling();
1692 m_pStartEntry
= pNew
;
1695 void SvImpLBox::EntryMoved( SvTreeListEntry
* pEntry
)
1697 UpdateContextBmpWidthVectorFromMovedEntry( pEntry
);
1699 if ( !m_pStartEntry
)
1700 // this might happen if the only entry in the view is moved to its very same position
1702 m_pStartEntry
= m_pView
->First();
1704 m_aVerSBar
->SetRange( Range(0, m_pView
->GetVisibleCount()-1));
1705 sal_uInt16 nFirstPos
= static_cast<sal_uInt16
>(m_pTree
->GetAbsPos( m_pStartEntry
));
1706 sal_uInt16 nNewPos
= static_cast<sal_uInt16
>(m_pTree
->GetAbsPos( pEntry
));
1708 if( nNewPos
< nFirstPos
) // HACK!
1709 m_pStartEntry
= pEntry
;
1711 if( pEntry
== m_pCursor
)
1713 if( m_pView
->IsEntryVisible( m_pCursor
) )
1717 SvTreeListEntry
* pParent
= pEntry
;
1719 pParent
= m_pTree
->GetParent( pParent
);
1721 while( !m_pView
->IsEntryVisible( pParent
) );
1722 SetCursor( pParent
);
1725 if( IsEntryInView( pEntry
) )
1726 m_pView
->Invalidate();
1730 void SvImpLBox::EntryInserted( SvTreeListEntry
* pEntry
)
1732 if( !GetUpdateMode() )
1735 SvTreeListEntry
* pParent
= m_pTree
->GetParent(pEntry
);
1736 if (pParent
&& m_pTree
->GetChildList(pParent
).size() == 1)
1738 m_pTree
->InvalidateEntry( pParent
);
1740 if( !m_pView
->IsEntryVisible( pEntry
) )
1742 bool bDeselAll(m_nFlags
& LBoxFlags::DeselectAll
);
1744 SelAllDestrAnch( false );
1747 // nFlags &= (~LBoxFlags::DeselectAll);
1748 // ShowCursor( false ); // if cursor is moved lower
1749 tools::Long nY
= GetEntryLine( pEntry
);
1750 bool bEntryVisible
= IsLineVisible( nY
);
1753 ShowCursor( false ); // if cursor is moved lower
1754 nY
-= m_pView
->GetEntryHeight(); // because of lines
1755 InvalidateEntriesFrom( nY
);
1757 else if( m_pStartEntry
&& nY
< GetEntryLine(m_pStartEntry
) )
1759 // Check if the view is filled completely. If not, then adjust
1760 // pStartEntry and the Cursor (automatic scrolling).
1761 sal_uInt16 nLast
= static_cast<sal_uInt16
>(m_pView
->GetVisiblePos(m_pView
->LastVisible()));
1762 sal_uInt16 nThumb
= static_cast<sal_uInt16
>(m_pView
->GetVisiblePos( m_pStartEntry
));
1763 sal_uInt16 nCurDispEntries
= nLast
-nThumb
+1;
1764 if( nCurDispEntries
< m_nVisibleCount
)
1766 // set at the next paint event
1767 m_pStartEntry
= nullptr;
1768 SetCursor( nullptr );
1769 m_pView
->Invalidate();
1772 else if( !m_pStartEntry
)
1773 m_pView
->Invalidate();
1775 SetMostRight( pEntry
);
1776 m_aVerSBar
->SetRange( Range(0, m_pView
->GetVisibleCount()-1));
1777 SyncVerThumb(); // if something was inserted before the thumb
1780 if( m_pStartEntry
!= m_pView
->First() && (m_nFlags
& LBoxFlags::Filling
) )
1781 m_pView
->PaintImmediately();
1785 // ********************************************************************
1787 // ********************************************************************
1790 // ****** Control the control animation
1792 bool SvImpLBox::ButtonDownCheckCtrl(const MouseEvent
& rMEvt
, SvTreeListEntry
* pEntry
)
1794 SvLBoxItem
* pItem
= m_pView
->GetItem(pEntry
,rMEvt
.GetPosPixel().X(),&m_pActiveTab
);
1795 if (pItem
&& pItem
->GetType() == SvLBoxItemType::Button
)
1797 m_pActiveButton
= static_cast<SvLBoxButton
*>(pItem
);
1798 m_pActiveEntry
= pEntry
;
1799 if( m_pCursor
== m_pActiveEntry
)
1800 m_pView
->HideFocus();
1801 m_pView
->CaptureMouse();
1802 m_pActiveButton
->SetStateHilighted( true );
1803 InvalidateEntry(m_pActiveEntry
);
1807 m_pActiveButton
= nullptr;
1811 bool SvImpLBox::MouseMoveCheckCtrl(const MouseEvent
& rMEvt
, SvTreeListEntry
const * pEntry
)
1813 if( m_pActiveButton
)
1815 tools::Long nMouseX
= rMEvt
.GetPosPixel().X();
1816 if( pEntry
== m_pActiveEntry
&&
1817 m_pView
->GetItem(m_pActiveEntry
, nMouseX
) == m_pActiveButton
)
1819 if( !m_pActiveButton
->IsStateHilighted() )
1821 m_pActiveButton
->SetStateHilighted(true );
1822 InvalidateEntry(m_pActiveEntry
);
1827 if( m_pActiveButton
->IsStateHilighted() )
1829 m_pActiveButton
->SetStateHilighted(false );
1830 InvalidateEntry(m_pActiveEntry
);
1838 bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent
& rMEvt
)
1840 if( m_pActiveButton
)
1842 m_pView
->ReleaseMouse();
1843 SvTreeListEntry
* pEntry
= GetClickedEntry( rMEvt
.GetPosPixel() );
1844 m_pActiveButton
->SetStateHilighted( false );
1845 tools::Long nMouseX
= rMEvt
.GetPosPixel().X();
1846 if (pEntry
== m_pActiveEntry
&& m_pView
->GetItem(m_pActiveEntry
, nMouseX
) == m_pActiveButton
)
1847 m_pActiveButton
->ClickHdl(m_pActiveEntry
);
1848 InvalidateEntry(m_pActiveEntry
);
1849 if (m_pCursor
== m_pActiveEntry
)
1851 m_pActiveButton
= nullptr;
1852 m_pActiveEntry
= nullptr;
1853 m_pActiveTab
= nullptr;
1859 // ******* Control plus/minus button for expanding/collapsing
1861 // false == no expand/collapse button hit
1862 bool SvImpLBox::IsNodeButton( const Point
& rPosPixel
, const SvTreeListEntry
* pEntry
) const
1864 if( !pEntry
->HasChildren() && !pEntry
->HasChildrenOnDemand() )
1867 SvLBoxTab
* pFirstDynamicTab
= m_pView
->GetFirstDynamicTab();
1868 if( !pFirstDynamicTab
)
1871 tools::Long nMouseX
= rPosPixel
.X();
1872 // convert to document coordinates
1873 Point
aOrigin( m_pView
->GetMapMode().GetOrigin() );
1874 nMouseX
-= aOrigin
.X();
1876 tools::Long nX
= m_pView
->GetTabPos( pEntry
, pFirstDynamicTab
);
1877 nX
+= m_nNodeBmpTabDistance
;
1880 nX
+= m_nNodeBmpWidth
;
1881 return nMouseX
<= nX
;
1884 // false == hit no node button
1885 bool SvImpLBox::ButtonDownCheckExpand( const MouseEvent
& rMEvt
, SvTreeListEntry
* pEntry
)
1889 if ( m_pView
->IsEditingActive() && pEntry
== m_pView
->pEdEntry
)
1890 // inplace editing -> nothing to do
1892 else if ( IsNodeButton( rMEvt
.GetPosPixel(), pEntry
) )
1894 if ( m_pView
->IsExpanded( pEntry
) )
1896 m_pView
->EndEditing( true );
1897 m_pView
->Collapse( pEntry
);
1901 // you can expand an entry, which is in editing
1902 m_pView
->Expand( pEntry
);
1910 void SvImpLBox::MouseButtonDown( const MouseEvent
& rMEvt
)
1912 if ( !rMEvt
.IsLeft() && !rMEvt
.IsRight())
1916 Point
aPos( rMEvt
.GetPosPixel());
1918 if( aPos
.X() > m_aOutputSize
.Width() || aPos
.Y() > m_aOutputSize
.Height() )
1922 m_pCursor
= m_pStartEntry
;
1923 m_nFlags
&= ~LBoxFlags::Filling
;
1924 m_pView
->GrabFocus();
1925 //fdo#82270 Grabbing focus can invalidate the entries, re-fetch
1926 SvTreeListEntry
* pEntry
= GetEntry(aPos
);
1927 // the entry can still be invalid!
1928 if( !pEntry
|| !m_pView
->GetViewData( pEntry
))
1931 tools::Long nY
= GetEntryLine( pEntry
);
1933 if( ButtonDownCheckExpand( rMEvt
, pEntry
) )
1936 if( !EntryReallyHit(pEntry
,aPos
,nY
))
1939 SvLBoxItem
* pXItem
= m_pView
->GetItem( pEntry
, aPos
.X() );
1942 SvLBoxTab
* pXTab
= m_pView
->GetTab( pEntry
, pXItem
);
1943 if ( !rMEvt
.IsMod1() && !rMEvt
.IsMod2() && rMEvt
.IsLeft() && pXTab
->IsEditable()
1944 && pEntry
== m_pView
->FirstSelected() && nullptr == m_pView
->NextSelected( pEntry
) )
1945 // #i8234# FirstSelected() and NextSelected() ensures, that inplace editing is only triggered, when only one entry is selected
1946 m_nFlags
|= LBoxFlags::StartEditTimer
;
1947 if ( !m_pView
->IsSelected( pEntry
) )
1948 m_nFlags
&= ~LBoxFlags::StartEditTimer
;
1952 if( (rMEvt
.GetClicks() % 2) == 0)
1954 m_nFlags
&= ~LBoxFlags::StartEditTimer
;
1955 m_pView
->pHdlEntry
= pEntry
;
1956 if( !m_pView
->DoubleClickHdl() )
1958 // Handler signals nothing to be done anymore, bail out, 'this' may
1959 // even be dead and destroyed.
1964 // if the entry was deleted within the handler
1965 pEntry
= GetClickedEntry( aPos
);
1968 if( pEntry
!= m_pView
->pHdlEntry
)
1970 // select anew & bye
1971 if( !m_bSimpleTravel
&& !m_aSelEng
.IsAlwaysAdding())
1972 SelAllDestrAnch( false ); // DeselectAll();
1973 SetCursor( pEntry
);
1977 if( pEntry
->HasChildren() || pEntry
->HasChildrenOnDemand() )
1979 if( m_pView
->IsExpanded(pEntry
) )
1980 m_pView
->Collapse( pEntry
);
1982 m_pView
->Expand( pEntry
);
1983 if( pEntry
== m_pCursor
) // only if Entryitem was clicked
1984 // (Nodebutton is not an Entryitem!)
1985 m_pView
->Select( m_pCursor
);
1992 // CheckButton? (TreeListBox: Check + Info)
1993 if( ButtonDownCheckCtrl(rMEvt
, pEntry
) )
1997 if ( m_aSelEng
.GetSelectionMode() != SelectionMode::NONE
1998 && !rMEvt
.IsRight() ) // tdf#128824
1999 m_aSelEng
.SelMouseButtonDown( rMEvt
);
2002 void SvImpLBox::MouseButtonUp( const MouseEvent
& rMEvt
)
2004 if ( !ButtonUpCheckCtrl( rMEvt
) && ( m_aSelEng
.GetSelectionMode() != SelectionMode::NONE
) )
2005 m_aSelEng
.SelMouseButtonUp( rMEvt
);
2006 if( m_nFlags
& LBoxFlags::StartEditTimer
)
2008 m_nFlags
&= ~LBoxFlags::StartEditTimer
;
2009 m_aEditClickPos
= rMEvt
.GetPosPixel();
2010 m_aEditIdle
.Start();
2013 if (m_pView
->mbActivateOnSingleClick
)
2015 Point
aPos(rMEvt
.GetPosPixel());
2016 SvTreeListEntry
* pEntry
= GetEntry(aPos
);
2017 // tdf#143245 ActivateOnSingleClick only
2018 // if the 'up' is at the active entry
2019 // typically selected by the 'down'
2020 if (!pEntry
|| pEntry
!= m_pCursor
)
2022 m_pView
->DoubleClickHdl();
2026 void SvImpLBox::MouseMove( const MouseEvent
& rMEvt
)
2028 Point aPos
= rMEvt
.GetPosPixel();
2029 SvTreeListEntry
* pEntry
= GetClickedEntry(aPos
);
2030 if ( !MouseMoveCheckCtrl( rMEvt
, pEntry
) && ( m_aSelEng
.GetSelectionMode() != SelectionMode::NONE
) )
2032 m_aSelEng
.SelMouseMove(rMEvt
);
2033 if (m_pView
->mbHoverSelection
)
2035 if (aPos
.X() < 0 || aPos
.Y() < 0 || aPos
.X() > m_aOutputSize
.Width() || aPos
.Y() > m_aOutputSize
.Height())
2038 pEntry
= GetEntry(aPos
);
2040 m_pView
->SelectAll(false);
2041 else if (!m_pView
->IsSelected(pEntry
) && IsSelectable(pEntry
))
2042 m_pView
->Select(pEntry
);
2047 void SvImpLBox::ExpandAll()
2049 sal_uInt16 nRefDepth
= m_pTree
->GetDepth(m_pCursor
);
2050 SvTreeListEntry
* pCur
= m_pTree
->Next(m_pCursor
);
2051 while (pCur
&& m_pTree
->GetDepth(pCur
) > nRefDepth
)
2053 if (pCur
->HasChildren() && !m_pView
->IsExpanded(pCur
))
2054 m_pView
->Expand(pCur
);
2055 pCur
= m_pTree
->Next(pCur
);
2059 void SvImpLBox::CollapseTo(SvTreeListEntry
* pParentToCollapse
)
2061 // collapse all parents until we get to the given parent to collapse
2062 if (!pParentToCollapse
)
2065 sal_uInt16 nRefDepth
;
2066 // special case explorer: if the root only has a single
2067 // entry, don't collapse the root entry
2068 if (m_pTree
->GetChildList(nullptr).size() < 2)
2071 pParentToCollapse
= m_pCursor
;
2072 while (m_pTree
->GetParent(pParentToCollapse
)
2073 && m_pTree
->GetDepth(m_pTree
->GetParent(pParentToCollapse
)) > 0)
2075 pParentToCollapse
= m_pTree
->GetParent(pParentToCollapse
);
2079 nRefDepth
= m_pTree
->GetDepth(pParentToCollapse
);
2081 if (m_pView
->IsExpanded(pParentToCollapse
))
2082 m_pView
->Collapse(pParentToCollapse
);
2083 SvTreeListEntry
* pCur
= m_pTree
->Next(pParentToCollapse
);
2084 while (pCur
&& m_pTree
->GetDepth(pCur
) > nRefDepth
)
2086 if (pCur
->HasChildren() && m_pView
->IsExpanded(pCur
))
2087 m_pView
->Collapse(pCur
);
2088 pCur
= m_pTree
->Next(pCur
);
2092 bool SvImpLBox::KeyInput( const KeyEvent
& rKEvt
)
2095 const vcl::KeyCode
& rKeyCode
= rKEvt
.GetKeyCode();
2097 if( rKeyCode
.IsMod2() )
2098 return false; // don't evaluate Alt key
2100 m_nFlags
&= ~LBoxFlags::Filling
;
2103 m_pCursor
= m_pStartEntry
;
2107 bool bKeyUsed
= true;
2109 sal_uInt16 nDelta
= static_cast<sal_uInt16
>(m_aVerSBar
->GetPageSize());
2110 sal_uInt16 aCode
= rKeyCode
.GetCode();
2112 bool bShift
= rKeyCode
.IsShift();
2113 bool bMod1
= rKeyCode
.IsMod1();
2115 SvTreeListEntry
* pNewCursor
;
2120 if( !IsEntryInView( m_pCursor
) )
2121 MakeVisible( m_pCursor
);
2123 pNewCursor
= m_pCursor
;
2126 pNewCursor
= m_pView
->PrevVisible(pNewCursor
);
2127 } while( pNewCursor
&& !IsSelectable(pNewCursor
) );
2129 // if there is no next entry, take the current one
2130 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
2133 pNewCursor
= m_pCursor
;
2135 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
2136 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
2137 if( !IsEntryInView( pNewCursor
) )
2142 if( !IsEntryInView( m_pCursor
) )
2143 MakeVisible( m_pCursor
);
2145 pNewCursor
= m_pCursor
;
2148 pNewCursor
= m_pView
->NextVisible(pNewCursor
);
2149 } while( pNewCursor
&& !IsSelectable(pNewCursor
) );
2151 // if there is no next entry, take the current one
2152 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
2154 // 06.09.20001 - 83416 - frank.schoenheit@sun.com
2155 if ( !pNewCursor
&& m_pCursor
)
2156 pNewCursor
= m_pCursor
;
2160 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
2161 if( IsEntryInView( pNewCursor
) )
2162 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
2166 m_pView
->Select( m_pCursor
, false );
2168 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
2172 KeyDown( false ); // because scrollbar range might still
2180 // only try to expand if sublist is expandable,
2181 // otherwise ignore the key press
2182 if( IsExpandable() && !m_pView
->IsExpanded( m_pCursor
) )
2183 m_pView
->Expand( m_pCursor
);
2185 else if (m_aHorSBar
->IsVisible())
2187 tools::Long nThumb
= m_aHorSBar
->GetThumbPos();
2188 nThumb
+= m_aHorSBar
->GetLineSize();
2189 tools::Long nOldThumb
= m_aHorSBar
->GetThumbPos();
2190 m_aHorSBar
->SetThumbPos( nThumb
);
2192 nThumb
-= m_aHorSBar
->GetThumbPos();
2196 KeyLeftRight( nThumb
);
2206 if (m_aHorSBar
->IsVisible())
2208 tools::Long nThumb
= m_aHorSBar
->GetThumbPos();
2209 nThumb
-= m_aHorSBar
->GetLineSize();
2210 tools::Long nOldThumb
= m_aHorSBar
->GetThumbPos();
2211 m_aHorSBar
->SetThumbPos( nThumb
);
2213 nThumb
-= m_aHorSBar
->GetThumbPos();
2216 KeyLeftRight( -nThumb
);
2218 else if( m_bSubLstOpLR
)
2220 if( IsExpandable() && m_pView
->IsExpanded( m_pCursor
) )
2221 m_pView
->Collapse( m_pCursor
);
2224 pNewCursor
= m_pView
->GetParent( m_pCursor
);
2226 SetCursor( pNewCursor
);
2230 else if( m_bSubLstOpLR
)
2232 if( IsExpandable() && m_pView
->IsExpanded( m_pCursor
) )
2233 m_pView
->Collapse( m_pCursor
);
2236 pNewCursor
= m_pView
->GetParent( m_pCursor
);
2238 SetCursor( pNewCursor
);
2249 pNewCursor
= m_pView
->PrevVisible(m_pCursor
, nDelta
);
2251 while( nDelta
&& pNewCursor
&& !IsSelectable(pNewCursor
) )
2253 pNewCursor
= m_pView
->NextVisible(pNewCursor
);
2259 DBG_ASSERT(pNewCursor
&& pNewCursor
!=m_pCursor
, "Cursor?");
2260 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
2261 if( IsEntryInView( pNewCursor
) )
2262 SetCursor( pNewCursor
);
2265 SetCursor( pNewCursor
);
2277 pNewCursor
= m_pView
->NextVisible(m_pCursor
, nDelta
);
2279 while( nDelta
&& pNewCursor
&& !IsSelectable(pNewCursor
) )
2281 pNewCursor
= m_pView
->PrevVisible(pNewCursor
);
2285 if( nDelta
&& pNewCursor
)
2287 DBG_ASSERT(pNewCursor
&& pNewCursor
!=m_pCursor
, "Cursor?");
2288 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
2289 if( IsEntryInView( pNewCursor
) )
2290 SetCursor( pNewCursor
);
2293 SetCursor( pNewCursor
);
2298 KeyDown( false ); // see also: KEY_DOWN
2305 if ( m_pView
->GetSelectionMode() != SelectionMode::NONE
)
2309 if ( m_pView
->GetSelectionMode() == SelectionMode::Multiple
&& !bShift
)
2311 m_pView
->Select( m_pCursor
, !m_pView
->IsSelected( m_pCursor
) );
2313 else if ( !bShift
/*&& !bMod1*/ )
2315 if ( m_aSelEng
.IsAddMode() )
2318 m_pView
->Select( m_pCursor
, !m_pView
->IsSelected( m_pCursor
) );
2320 else if ( !m_pView
->IsSelected( m_pCursor
) )
2322 SelAllDestrAnch( false );
2323 m_pView
->Select( m_pCursor
);
2336 bKeyUsed
= !m_pView
->DoubleClickHdl();
2340 if( !bShift
&& !bMod1
)
2342 m_aEditClickPos
= Point( -1, -1 );
2343 EditTimerCall( nullptr );
2350 if( bShift
&& m_pView
->GetSelectionMode()==SelectionMode::Multiple
&&
2351 !(m_nStyle
& WB_SIMPLEMODE
))
2353 if( m_aSelEng
.IsAlwaysAdding() )
2354 m_aSelEng
.AddAlways( false );
2356 m_aSelEng
.AddAlways( true );
2363 if (!m_pView
->IsExpanded(m_pCursor
))
2364 m_pView
->Expand(m_pCursor
);
2371 SelAllDestrAnch( true );
2377 if (m_pView
->IsExpanded(m_pCursor
))
2378 m_pView
->Collapse(m_pCursor
);
2380 CollapseTo(m_pTree
->GetRootLevelParent(m_pCursor
));
2386 // only try to expand/collapse if sublist is expandable,
2387 // otherwise ignore the key press
2388 if( IsExpandable() )
2390 if (!m_pView
->IsAllExpanded(m_pCursor
))
2392 m_pView
->Expand(m_pCursor
);
2396 CollapseTo(m_pCursor
);
2405 SelAllDestrAnch( true );
2412 SelAllDestrAnch( false );
2418 pNewCursor
= m_pView
->GetModel()->First();
2420 while( pNewCursor
&& !IsSelectable(pNewCursor
) )
2422 pNewCursor
= m_pView
->NextVisible(pNewCursor
);
2425 if( pNewCursor
&& pNewCursor
!= m_pCursor
)
2427 // SelAllDestrAnch( false );
2428 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
2429 SetCursor( pNewCursor
);
2430 if( !IsEntryInView( pNewCursor
) )
2431 MakeVisible( pNewCursor
);
2438 pNewCursor
= m_pView
->GetModel()->Last();
2440 while( pNewCursor
&& !IsSelectable(pNewCursor
) )
2442 pNewCursor
= m_pView
->PrevVisible(pNewCursor
);
2445 if( pNewCursor
&& pNewCursor
!= m_pCursor
)
2447 // SelAllDestrAnch( false );
2448 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
2449 SetCursor( pNewCursor
);
2450 if( !IsEntryInView( pNewCursor
) )
2451 MakeVisible( pNewCursor
);
2461 // must not be handled because this quits dialogs and does other magic things...
2462 // if there are other single keys which should not be handled, they can be added here
2467 // is there any reason why we should eat the events here? The only place where this is called
2468 // is from SvTreeListBox::KeyInput. If we set bKeyUsed to true here, then the key input
2469 // is just silenced. However, we want SvLBox::KeyInput to get a chance, to do the QuickSelection
2471 // (The old code here which intentionally set bKeyUsed to sal_True said this was because of "quick search"
2472 // handling, but actually there was no quick search handling anymore. We just re-implemented it.)
2473 // #i31275# / 2009-06-16 / frank.schoenheit@sun.com
2480 void SvImpLBox::GetFocus()
2484 m_pView
->SetEntryFocus( m_pCursor
, true );
2486 // auskommentiert wg. deselectall
2487 // if( bSimpleTravel && !pView->IsSelected(pCursor) )
2488 // pView->Select( pCursor, true );
2490 if( m_nStyle
& WB_HIDESELECTION
)
2492 SvTreeListEntry
* pEntry
= m_pView
->FirstSelected();
2495 InvalidateEntry( pEntry
);
2496 pEntry
= m_pView
->NextSelected( pEntry
);
2501 void SvImpLBox::LoseFocus()
2505 m_pView
->SetEntryFocus( m_pCursor
,false );
2506 ShowCursor( false );
2508 if( m_nStyle
& WB_HIDESELECTION
)
2510 SvTreeListEntry
* pEntry
= m_pView
? m_pView
->FirstSelected() : nullptr;
2513 InvalidateEntry( pEntry
);
2514 pEntry
= m_pView
->NextSelected( pEntry
);
2520 // ********************************************************************
2522 // ********************************************************************
2524 void SvImpLBox::SelectEntry( SvTreeListEntry
* pEntry
, bool bSelect
)
2526 m_pView
->Select( pEntry
, bSelect
);
2529 ImpLBSelEng::ImpLBSelEng( SvImpLBox
* pImpl
, SvTreeListBox
* pV
)
2535 ImpLBSelEng::~ImpLBSelEng()
2539 void ImpLBSelEng::BeginDrag()
2544 void ImpLBSelEng::CreateAnchor()
2546 pImp
->m_pAnchor
= pImp
->m_pCursor
;
2549 void ImpLBSelEng::DestroyAnchor()
2551 pImp
->m_pAnchor
= nullptr;
2554 void ImpLBSelEng::SetCursorAtPoint(const Point
& rPoint
, bool bDontSelectAtCursor
)
2556 SvTreeListEntry
* pNewCursor
= pImp
->MakePointVisible( rPoint
);
2559 // at SimpleTravel, the SetCursor is selected and the select handler is
2561 //if( !bDontSelectAtCursor && !pImp->bSimpleTravel )
2562 // pImp->SelectEntry( pNewCursor, true );
2563 pImp
->SetCursor( pNewCursor
, bDontSelectAtCursor
);
2567 bool ImpLBSelEng::IsSelectionAtPoint( const Point
& rPoint
)
2569 SvTreeListEntry
* pEntry
= pImp
->MakePointVisible( rPoint
);
2571 return pView
->IsSelected(pEntry
);
2575 void ImpLBSelEng::DeselectAtPoint( const Point
& rPoint
)
2577 SvTreeListEntry
* pEntry
= pImp
->MakePointVisible( rPoint
);
2580 pImp
->SelectEntry( pEntry
, false );
2583 void ImpLBSelEng::DeselectAll()
2585 pImp
->SelAllDestrAnch( false, false ); // don't reset SelectionEngine!
2586 pImp
->m_nFlags
&= ~LBoxFlags::DeselectAll
;
2589 // ***********************************************************************
2591 // ***********************************************************************
2593 void SvImpLBox::SetAnchorSelection(SvTreeListEntry
* pOldCursor
,SvTreeListEntry
* pNewCursor
)
2595 SvTreeListEntry
* pEntry
;
2596 sal_uLong nAnchorVisPos
= m_pView
->GetVisiblePos( m_pAnchor
);
2597 sal_uLong nOldVisPos
= m_pView
->GetVisiblePos( pOldCursor
);
2598 sal_uLong nNewVisPos
= m_pView
->GetVisiblePos( pNewCursor
);
2600 if( nOldVisPos
> nAnchorVisPos
||
2601 ( nAnchorVisPos
==nOldVisPos
&& nNewVisPos
> nAnchorVisPos
) )
2603 if( nNewVisPos
> nOldVisPos
)
2605 pEntry
= pOldCursor
;
2606 while( pEntry
&& pEntry
!= pNewCursor
)
2608 m_pView
->Select( pEntry
);
2609 pEntry
= m_pView
->NextVisible(pEntry
);
2612 m_pView
->Select( pEntry
);
2616 if( nNewVisPos
< nAnchorVisPos
)
2619 while( pEntry
&& pEntry
!= pOldCursor
)
2621 m_pView
->Select( pEntry
, false );
2622 pEntry
= m_pView
->NextVisible(pEntry
);
2625 m_pView
->Select( pEntry
, false );
2627 pEntry
= pNewCursor
;
2628 while( pEntry
&& pEntry
!= m_pAnchor
)
2630 m_pView
->Select( pEntry
);
2631 pEntry
= m_pView
->NextVisible(pEntry
);
2634 m_pView
->Select( pEntry
);
2638 if( nNewVisPos
< nOldVisPos
)
2640 pEntry
= m_pView
->NextVisible(pNewCursor
);
2641 while( pEntry
&& pEntry
!= pOldCursor
)
2643 m_pView
->Select( pEntry
, false );
2644 pEntry
= m_pView
->NextVisible(pEntry
);
2647 m_pView
->Select( pEntry
, false );
2653 if( nNewVisPos
< nOldVisPos
) // enlarge selection
2655 pEntry
= pNewCursor
;
2656 while( pEntry
&& pEntry
!= pOldCursor
)
2658 m_pView
->Select( pEntry
);
2659 pEntry
= m_pView
->NextVisible(pEntry
);
2662 m_pView
->Select( pEntry
);
2666 if( nNewVisPos
> nAnchorVisPos
)
2668 pEntry
= pOldCursor
;
2669 while( pEntry
&& pEntry
!= m_pAnchor
)
2671 m_pView
->Select( pEntry
, false );
2672 pEntry
= m_pView
->NextVisible(pEntry
);
2675 m_pView
->Select( pEntry
, false );
2677 while( pEntry
&& pEntry
!= pNewCursor
)
2679 m_pView
->Select( pEntry
);
2680 pEntry
= m_pView
->NextVisible(pEntry
);
2683 m_pView
->Select( pEntry
);
2687 if( nNewVisPos
> nOldVisPos
)
2689 pEntry
= pOldCursor
;
2690 while( pEntry
&& pEntry
!= pNewCursor
)
2692 m_pView
->Select( pEntry
, false );
2693 pEntry
= m_pView
->NextVisible(pEntry
);
2700 void SvImpLBox::SelAllDestrAnch(
2701 bool bSelect
, bool bDestroyAnchor
, bool bSingleSelToo
)
2703 SvTreeListEntry
* pEntry
;
2704 m_nFlags
&= ~LBoxFlags::DeselectAll
;
2705 if( bSelect
&& m_bSimpleTravel
)
2707 if( m_pCursor
&& !m_pView
->IsSelected( m_pCursor
))
2709 m_pView
->Select( m_pCursor
);
2713 if( !bSelect
&& m_pView
->GetSelectionCount() == 0 )
2715 if( m_bSimpleTravel
&& ( !GetUpdateMode() || !m_pCursor
) )
2716 m_nFlags
|= LBoxFlags::DeselectAll
;
2719 if( bSelect
&& m_pView
->GetSelectionCount() == m_pView
->GetEntryCount())
2721 if( !bSingleSelToo
&& m_bSimpleTravel
)
2724 if( !bSelect
&& m_pView
->GetSelectionCount()==1 && m_pCursor
&&
2725 m_pView
->IsSelected( m_pCursor
))
2727 m_pView
->Select( m_pCursor
, false );
2728 if( bDestroyAnchor
)
2729 DestroyAnchor(); // delete anchor & reset SelectionEngine
2731 m_pAnchor
= nullptr; // always delete internal anchor
2735 if( m_bSimpleTravel
&& !m_pCursor
&& !GetUpdateMode() )
2736 m_nFlags
|= LBoxFlags::DeselectAll
;
2738 ShowCursor( false );
2739 bool bUpdate
= GetUpdateMode();
2741 m_nFlags
|= LBoxFlags::IgnoreSelect
; // EntryInserted should not do anything
2742 pEntry
= m_pTree
->First();
2745 if( m_pView
->Select( pEntry
, bSelect
) )
2747 if( bUpdate
&& m_pView
->IsEntryVisible(pEntry
) )
2749 tools::Long nY
= GetEntryLine( pEntry
);
2750 if( IsLineVisible( nY
) )
2751 InvalidateEntry(pEntry
);
2754 pEntry
= m_pTree
->Next( pEntry
);
2756 m_nFlags
&= ~LBoxFlags::IgnoreSelect
;
2758 if( bDestroyAnchor
)
2759 DestroyAnchor(); // delete anchor & reset SelectionEngine
2761 m_pAnchor
= nullptr; // always delete internal anchor
2765 void SvImpLBox::SetSelectionMode( SelectionMode eSelMode
)
2767 m_aSelEng
.SetSelectionMode( eSelMode
);
2768 if( eSelMode
== SelectionMode::Single
)
2769 m_bSimpleTravel
= true;
2771 m_bSimpleTravel
= false;
2772 if( (m_nStyle
& WB_SIMPLEMODE
) && (eSelMode
== SelectionMode::Multiple
) )
2773 m_aSelEng
.AddAlways( true );
2776 // ***********************************************************************
2778 // ***********************************************************************
2780 void SvImpLBox::SetDragDropMode( DragDropMode eDDMode
)
2782 if( eDDMode
!= DragDropMode::NONE
)
2784 m_aSelEng
.ExpandSelectionOnMouseMove( false );
2785 m_aSelEng
.EnableDrag( true );
2789 m_aSelEng
.ExpandSelectionOnMouseMove();
2790 m_aSelEng
.EnableDrag( false );
2794 void SvImpLBox::BeginDrag()
2796 m_nFlags
&= ~LBoxFlags::Filling
;
2797 m_pView
->StartDrag( 0, m_aSelEng
.GetMousePosPixel() );
2800 void SvImpLBox::PaintDDCursor(SvTreeListEntry
* pEntry
, bool bShow
)
2805 SvViewDataEntry
* pViewData
= m_pView
->GetViewData(pEntry
);
2806 pViewData
->SetDragTarget(bShow
);
2808 // in MacOS we need to draw directly (as we are synchronous) or no invalidation happens
2809 m_pView
->PaintEntry1(*pEntry
, GetEntryLine(pEntry
), *m_pView
);
2811 InvalidateEntry(pEntry
);
2816 void SvImpLBox::Command( const CommandEvent
& rCEvt
)
2818 CommandEventId nCommand
= rCEvt
.GetCommand();
2820 if( nCommand
== CommandEventId::ContextMenu
)
2823 // scroll mouse event?
2824 if (nCommand
== CommandEventId::Wheel
||
2825 nCommand
== CommandEventId::StartAutoScroll
||
2826 nCommand
== CommandEventId::AutoScroll
||
2827 nCommand
== CommandEventId::Gesture
)
2829 if (m_pView
->HandleScrollCommand(rCEvt
, m_aHorSBar
.get(), m_aVerSBar
.get()))
2833 const Point
& rPos
= rCEvt
.GetMousePosPixel();
2834 if( rPos
.X() < m_aOutputSize
.Width() && rPos
.Y() < m_aOutputSize
.Height() )
2835 m_aSelEng
.Command( rCEvt
);
2838 tools::Rectangle
SvImpLBox::GetVisibleArea() const
2840 Point
aPos( m_pView
->GetMapMode().GetOrigin() );
2841 aPos
.setX( aPos
.X() * -1 );
2842 tools::Rectangle
aRect( aPos
, m_aOutputSize
);
2846 void SvImpLBox::Invalidate()
2848 m_pView
->SetClipRegion();
2851 void SvImpLBox::SetCurEntry( SvTreeListEntry
* pEntry
)
2853 if ( ( m_aSelEng
.GetSelectionMode() != SelectionMode::Single
)
2854 && ( m_aSelEng
.GetSelectionMode() != SelectionMode::NONE
)
2856 SelAllDestrAnch( false );
2858 MakeVisible( pEntry
);
2859 SetCursor( pEntry
);
2860 if ( pEntry
&& ( m_aSelEng
.GetSelectionMode() != SelectionMode::NONE
) )
2861 m_pView
->Select( pEntry
);
2864 IMPL_LINK_NOARG(SvImpLBox
, EditTimerCall
, Timer
*, void)
2866 if( !m_pView
->IsInplaceEditingEnabled() )
2869 bool bIsMouseTriggered
= m_aEditClickPos
.X() >= 0;
2870 if ( bIsMouseTriggered
)
2872 Point aCurrentMousePos
= m_pView
->GetPointerPosPixel();
2873 if ( ( std::abs( aCurrentMousePos
.X() - m_aEditClickPos
.X() ) > 5 )
2874 || ( std::abs( aCurrentMousePos
.Y() - m_aEditClickPos
.Y() ) > 5 )
2881 SvTreeListEntry
* pEntry
= GetCurEntry();
2884 ShowCursor( false );
2885 m_pView
->ImplEditEntry( pEntry
);
2890 bool SvImpLBox::RequestHelp( const HelpEvent
& rHEvt
)
2892 if( rHEvt
.GetMode() & HelpEventMode::QUICK
)
2894 Point
aPos( m_pView
->ScreenToOutputPixel( rHEvt
.GetMousePosPixel() ));
2895 if( !GetVisibleArea().IsInside( aPos
))
2898 SvTreeListEntry
* pEntry
= GetEntry( aPos
);
2901 // recalculate text rectangle
2903 SvLBoxItem
* pItem
= m_pView
->GetItem( pEntry
, aPos
.X(), &pTab
);
2904 if (!pItem
|| pItem
->GetType() != SvLBoxItemType::String
)
2907 aPos
= GetEntryPosition( pEntry
);
2908 aPos
.setX( m_pView
->GetTabPos( pEntry
, pTab
) ); //pTab->GetPos();
2909 Size
aSize(pItem
->GetWidth(m_pView
, pEntry
), pItem
->GetHeight(m_pView
, pEntry
));
2910 SvLBoxTab
* pNextTab
= NextTab( pTab
);
2911 bool bItemClipped
= false;
2912 // is the item cut off by its right neighbor?
2913 if( pNextTab
&& m_pView
->GetTabPos(pEntry
,pNextTab
) < aPos
.X()+aSize
.Width() )
2915 aSize
.setWidth( pNextTab
->GetPos() - pTab
->GetPos() );
2916 bItemClipped
= true;
2918 tools::Rectangle
aItemRect( aPos
, aSize
);
2920 tools::Rectangle
aViewRect( GetVisibleArea() );
2922 if( bItemClipped
|| !aViewRect
.IsInside( aItemRect
) )
2924 // clip the right edge of the item at the edge of the view
2925 //if( aItemRect.Right() > aViewRect.Right() )
2926 // aItemRect.Right() = aViewRect.Right();
2928 Point aPt
= m_pView
->OutputToScreenPixel( aItemRect
.TopLeft() );
2929 aItemRect
.SetLeft( aPt
.X() );
2930 aItemRect
.SetTop( aPt
.Y() );
2931 aPt
= m_pView
->OutputToScreenPixel( aItemRect
.BottomRight() );
2932 aItemRect
.SetRight( aPt
.X() );
2933 aItemRect
.SetBottom( aPt
.Y() );
2935 Help::ShowQuickHelp( m_pView
, aItemRect
,
2936 static_cast<SvLBoxString
*>(pItem
)->GetText(), QuickHelpFlags::Left
| QuickHelpFlags::VCenter
);
2944 SvLBoxTab
* SvImpLBox::NextTab( SvLBoxTab
const * pTab
)
2946 sal_uInt16 nTabCount
= m_pView
->TabCount();
2947 if( nTabCount
<= 1 )
2949 for( int nTab
=0; nTab
< (nTabCount
-1); nTab
++)
2951 if( m_pView
->aTabs
[nTab
].get() == pTab
)
2952 return m_pView
->aTabs
[nTab
+1].get();
2957 void SvImpLBox::SetUpdateMode( bool bMode
)
2959 if( m_bUpdateMode
!= bMode
)
2961 m_bUpdateMode
= bMode
;
2967 bool SvImpLBox::SetMostRight( SvTreeListEntry
* pEntry
)
2969 if( m_pView
->nTreeFlags
& SvTreeFlags::RECALCTABS
)
2971 m_nFlags
|= LBoxFlags::IgnoreChangedTabs
;
2973 m_nFlags
&= ~LBoxFlags::IgnoreChangedTabs
;
2976 sal_uInt16 nLastTab
= m_pView
->aTabs
.size() - 1;
2977 sal_uInt16 nLastItem
= pEntry
->ItemCount() - 1;
2978 if( !m_pView
->aTabs
.empty() && nLastItem
!= USHRT_MAX
)
2980 if( nLastItem
< nLastTab
)
2981 nLastTab
= nLastItem
;
2983 SvLBoxTab
* pTab
= m_pView
->aTabs
[ nLastTab
].get();
2984 SvLBoxItem
& rItem
= pEntry
->GetItem( nLastTab
);
2986 tools::Long nTabPos
= m_pView
->GetTabPos( pEntry
, pTab
);
2988 tools::Long nMaxRight
= GetOutputSize().Width();
2989 Point
aPos( m_pView
->GetMapMode().GetOrigin() );
2990 aPos
.setX( aPos
.X() * -1 ); // conversion document coordinates
2991 nMaxRight
= nMaxRight
+ aPos
.X() - 1;
2993 tools::Long nNextTab
= nTabPos
< nMaxRight
? nMaxRight
: nMaxRight
+ 50;
2994 tools::Long nTabWidth
= nNextTab
- nTabPos
+ 1;
2995 auto nItemSize
= rItem
.GetWidth(m_pView
,pEntry
);
2996 tools::Long nOffset
= pTab
->CalcOffset( nItemSize
, nTabWidth
);
2998 tools::Long nRight
= nTabPos
+ nOffset
+ nItemSize
;
2999 if( nRight
> m_nMostRight
)
3001 m_nMostRight
= nRight
;
3002 m_pMostRightEntry
= pEntry
;
3009 void SvImpLBox::FindMostRight()
3012 m_pMostRightEntry
= nullptr;
3013 if( !m_pView
->GetModel() )
3016 SvTreeListEntry
* pEntry
= m_pView
->FirstVisible();
3019 SetMostRight( pEntry
);
3020 pEntry
= m_pView
->NextVisible( pEntry
);
3024 void SvImpLBox::FindMostRight( SvTreeListEntry
* pParent
)
3029 FindMostRight_Impl( pParent
);
3032 void SvImpLBox::FindMostRight_Impl( SvTreeListEntry
* pParent
)
3034 SvTreeListEntries
& rList
= m_pTree
->GetChildList( pParent
);
3036 size_t nCount
= rList
.size();
3037 for( size_t nCur
= 0; nCur
< nCount
; nCur
++ )
3039 SvTreeListEntry
* pChild
= rList
[nCur
].get();
3040 SetMostRight( pChild
);
3041 if( pChild
->HasChildren() && m_pView
->IsExpanded( pChild
))
3042 FindMostRight_Impl( pChild
);
3046 void SvImpLBox::NotifyTabsChanged()
3048 if( GetUpdateMode() && !(m_nFlags
& LBoxFlags::IgnoreChangedTabs
) &&
3049 m_nCurUserEvent
== nullptr )
3051 m_nCurUserEvent
= Application::PostUserEvent(LINK(this,SvImpLBox
,MyUserEvent
));
3055 bool SvImpLBox::IsExpandable() const
3057 return m_pCursor
->HasChildren() || m_pCursor
->HasChildrenOnDemand();
3060 IMPL_LINK(SvImpLBox
, MyUserEvent
, void*, pArg
, void )
3062 m_nCurUserEvent
= nullptr;
3065 m_pView
->Invalidate();
3066 m_pView
->PaintImmediately();
3072 m_pView
->Invalidate( GetVisibleArea() );
3077 void SvImpLBox::StopUserEvent()
3079 if( m_nCurUserEvent
!= nullptr )
3081 Application::RemoveUserEvent( m_nCurUserEvent
);
3082 m_nCurUserEvent
= nullptr;
3086 void SvImpLBox::implInitDefaultNodeImages()
3088 if ( s_pDefCollapsed
)
3089 // assume that all or nothing is initialized
3092 s_pDefCollapsed
= new Image(StockImage::Yes
, RID_BMP_TREENODE_COLLAPSED
);
3093 s_pDefExpanded
= new Image(StockImage::Yes
, RID_BMP_TREENODE_EXPANDED
);
3097 const Image
& SvImpLBox::GetDefaultExpandedNodeImage( )
3099 implInitDefaultNodeImages();
3100 return *s_pDefExpanded
;
3104 const Image
& SvImpLBox::GetDefaultCollapsedNodeImage( )
3106 implInitDefaultNodeImages();
3107 return *s_pDefCollapsed
;
3111 void SvImpLBox::CallEventListeners( VclEventId nEvent
, void* pData
)
3114 m_pView
->CallImplEventListeners( nEvent
, pData
);
3118 bool SvImpLBox::IsSelectable( const SvTreeListEntry
* pEntry
)
3122 SvViewDataEntry
* pViewDataNewCur
= m_pView
->GetViewDataEntry(pEntry
);
3123 return (pViewDataNewCur
== nullptr) || pViewDataNewCur
->IsSelectable();
3131 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */