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 <vcl/svapp.hxx>
21 #include <vcl/salnativewidgets.hxx>
22 #include <vcl/help.hxx>
23 #include <vcl/settings.hxx>
28 #include <svtools/treelistbox.hxx>
29 #include <svtools/svlbitm.hxx>
30 #include <svimpbox.hxx>
31 #include <rtl/instance.hxx>
32 #include <svtools/svtresid.hxx>
33 #include <tools/wintypes.hxx>
34 #include <svtools/svtools.hrc>
35 #include <comphelper/processfactory.hxx>
36 #include <comphelper/string.hxx>
38 #include <svtools/treelistentry.hxx>
39 #include <svtools/viewdataentry.hxx>
41 #define NODE_BMP_TABDIST_NOTVALID -2000000
42 #define FIRST_ENTRY_TAB 1
44 // #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors
45 Image
* SvImpLBox::s_pDefCollapsed
= NULL
;
46 Image
* SvImpLBox::s_pDefExpanded
= NULL
;
47 sal_Int32
SvImpLBox::s_nImageRefCount
= 0;
49 SvImpLBox::SvImpLBox( SvTreeListBox
* pLBView
, SvTreeList
* pLBTree
, WinBits nWinStyle
)
50 : aVerSBar(VclPtr
<ScrollBar
>::Create(pLBView
, WB_DRAG
| WB_VSCROLL
))
51 , aHorSBar(VclPtr
<ScrollBar
>::Create(pLBView
, WB_DRAG
| WB_HSCROLL
))
52 , aScrBarBox(VclPtr
<ScrollBarBox
>::Create(pLBView
))
54 , aSelEng(pLBView
, (FunctionSet
*)0)
55 , aFctSet(this, &aSelEng
, pLBView
)
58 , bAreChildrenTransient(true)
59 , m_pStringSorter(NULL
)
61 osl_atomic_increment(&s_nImageRefCount
);
64 aSelEng
.SetFunctionSet( (FunctionSet
*)&aFctSet
);
65 aSelEng
.ExpandSelectionOnMouseMove( false );
66 SetStyle( nWinStyle
);
67 SetSelectionMode( SINGLE_SELECTION
);
68 SetDragDropMode( DragDropMode::NONE
);
70 aVerSBar
->SetScrollHdl( LINK( this, SvImpLBox
, ScrollUpDownHdl
) );
71 aHorSBar
->SetScrollHdl( LINK( this, SvImpLBox
, ScrollLeftRightHdl
) );
72 aHorSBar
->SetEndScrollHdl( LINK( this, SvImpLBox
, EndScrollHdl
) );
73 aVerSBar
->SetEndScrollHdl( LINK( this, SvImpLBox
, EndScrollHdl
) );
74 aVerSBar
->SetRange( Range(0,0) );
76 aHorSBar
->SetRange( Range(0,0) );
77 aHorSBar
->SetPageSize( 24 ); // pixels
78 aHorSBar
->SetLineSize( 8 ); // pixels
80 nHorSBarHeight
= (short)aHorSBar
->GetSizePixel().Height();
81 nVerSBarWidth
= (short)aVerSBar
->GetSizePixel().Width();
86 nVisibleCount
= 0; // number of rows of data in control
87 nNodeBmpTabDistance
= NODE_BMP_TABDIST_NOTVALID
;
91 bAsyncBeginDrag
= false;
92 aAsyncBeginDragIdle
.SetPriority( SchedulerPriority::HIGHEST
);
93 aAsyncBeginDragIdle
.SetIdleHdl( LINK(this,SvImpLBox
,BeginDragHdl
));
94 // button animation in listbox
100 nCurTabPos
= FIRST_ENTRY_TAB
;
102 aEditIdle
.SetPriority( SchedulerPriority::LOWEST
);
103 aEditIdle
.SetIdleHdl( LINK(this,SvImpLBox
,EditTimerCall
) );
110 bInVScrollHdl
= false;
113 bSubLstOpRet
= bSubLstOpLR
= bContextMenuHandling
= bIsCellFocusEnabled
= false;
116 SvImpLBox::~SvImpLBox()
121 delete m_pStringSorter
;
122 if ( osl_atomic_decrement(&s_nImageRefCount
) == 0 )
124 DELETEZ(s_pDefCollapsed
);
125 DELETEZ(s_pDefExpanded
);
127 aVerSBar
.disposeAndClear();
128 aHorSBar
.disposeAndClear();
129 aScrBarBox
.disposeAndClear();
132 void SvImpLBox::UpdateStringSorter()
134 const ::com::sun::star::lang::Locale
& rNewLocale
= Application::GetSettings().GetLanguageTag().getLocale();
136 if( m_pStringSorter
)
138 // different Locale from the older one, drop it and force recreate
139 const ::com::sun::star::lang::Locale
&aLocale
= m_pStringSorter
->getLocale();
140 if( aLocale
.Language
!= rNewLocale
.Language
||
141 aLocale
.Country
!= rNewLocale
.Country
||
142 aLocale
.Variant
!= rNewLocale
.Variant
)
144 delete m_pStringSorter
;
145 m_pStringSorter
= NULL
;
149 if( !m_pStringSorter
)
151 m_pStringSorter
= new comphelper::string::NaturalStringSorter(
152 ::comphelper::getProcessComponentContext(),
157 // #97680# ----------------------
158 short SvImpLBox::UpdateContextBmpWidthVector( SvTreeListEntry
* pEntry
, short nWidth
)
160 DBG_ASSERT( pView
->pModel
, "View and Model aren't valid!" );
162 sal_uInt16 nDepth
= pView
->pModel
->GetDepth( pEntry
);
163 // initialize vector if necessary
164 std::vector
< short >::size_type nSize
= aContextBmpWidthVector
.size();
165 while ( nDepth
> nSize
)
167 aContextBmpWidthVector
.resize( nSize
+ 1 );
168 aContextBmpWidthVector
.at( nSize
) = nWidth
;
171 if( aContextBmpWidthVector
.size() == nDepth
)
173 aContextBmpWidthVector
.resize( nDepth
+ 1 );
174 aContextBmpWidthVector
.at( nDepth
) = 0;
176 short nContextBmpWidth
= aContextBmpWidthVector
[ nDepth
];
177 if( nContextBmpWidth
< nWidth
)
179 aContextBmpWidthVector
.at( nDepth
) = nWidth
;
183 return nContextBmpWidth
;
186 void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry
* pEntry
)
188 DBG_ASSERT( pEntry
, "Moved Entry is invalid!" );
190 SvLBoxContextBmp
* pBmpItem
= static_cast< SvLBoxContextBmp
* >( pEntry
->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP
) );
191 short nExpWidth
= (short)pBmpItem
->GetBitmap1().GetSizePixel().Width();
192 short nColWidth
= (short)pBmpItem
->GetBitmap2().GetSizePixel().Width();
193 short nMax
= std::max(nExpWidth
, nColWidth
);
194 UpdateContextBmpWidthVector( pEntry
, nMax
);
196 if( pEntry
->HasChildren() ) // recursive call, whether expanded or not
198 SvTreeListEntry
* pChild
= pView
->FirstChild( pEntry
);
199 DBG_ASSERT( pChild
, "The first child is invalid!" );
202 UpdateContextBmpWidthVectorFromMovedEntry( pChild
);
203 pChild
= pView
->Next( pChild
);
208 void SvImpLBox::UpdateContextBmpWidthMax( SvTreeListEntry
* pEntry
)
210 sal_uInt16 nDepth
= pView
->pModel
->GetDepth( pEntry
);
211 if( aContextBmpWidthVector
.size() < 1 )
213 short nWidth
= aContextBmpWidthVector
[ nDepth
];
214 if( nWidth
!= pView
->nContextBmpWidthMax
) {
215 pView
->nContextBmpWidthMax
= nWidth
;
216 nFlags
|= F_IGNORE_CHANGED_TABS
;
218 nFlags
&= ~F_IGNORE_CHANGED_TABS
;
222 void SvImpLBox::CalcCellFocusRect( SvTreeListEntry
* pEntry
, Rectangle
& rRect
)
224 if ( pEntry
&& bIsCellFocusEnabled
)
226 if ( nCurTabPos
> FIRST_ENTRY_TAB
)
228 SvLBoxItem
* pItem
= pCursor
->GetItem( nCurTabPos
);
229 rRect
.Left() = pView
->GetTab( pCursor
, pItem
)->GetPos();
231 if (pCursor
->ItemCount() > static_cast<size_t>(nCurTabPos
+1))
233 SvLBoxItem
* pNextItem
= pCursor
->GetItem( nCurTabPos
+ 1 );
234 long nRight
= pView
->GetTab( pCursor
, pNextItem
)->GetPos() - 1;
235 if ( nRight
< rRect
.Right() )
236 rRect
.Right() = nRight
;
241 void SvImpLBox::SetStyle( WinBits i_nWinStyle
)
243 m_nStyle
= i_nWinStyle
;
244 if ( ( m_nStyle
& WB_SIMPLEMODE
) && ( aSelEng
.GetSelectionMode() == MULTIPLE_SELECTION
) )
245 aSelEng
.AddAlways( true );
248 void SvImpLBox::SetExtendedWindowBits( ExtendedWinBits _nBits
)
250 nExtendedWinBits
= _nBits
;
253 // don't touch the model any more
254 void SvImpLBox::Clear()
267 // don't touch the cursor any more
270 if( pView
->HasFocus() )
275 aVerSBar
->SetThumbPos( 0 );
276 Range
aRange( 0, 0 );
277 aVerSBar
->SetRange( aRange
);
278 aOutputSize
= pView
->Control::GetOutputSizePixel();
279 nFlags
&= ~(F_VER_SBARSIZE_WITH_HBAR
| F_HOR_SBARSIZE_WITH_VBAR
);
281 aHorSBar
->SetThumbPos( 0 );
282 MapMode
aMapMode( pView
->GetMapMode());
283 aMapMode
.SetOrigin( Point(0,0) );
284 pView
->Control::SetMapMode( aMapMode
);
285 aHorSBar
->SetRange( aRange
);
286 aHorSBar
->SetSizePixel(Size(aOutputSize
.Width(),nHorSBarHeight
));
287 pView
->SetClipRegion();
288 if( GetUpdateMode() )
289 pView
->Invalidate( GetVisibleArea() );
291 if( !aHorSBar
->IsVisible() && !aVerSBar
->IsVisible() )
294 aContextBmpWidthVector
.clear();
296 CallEventListeners( VCLEVENT_LISTBOX_ITEMREMOVED
, NULL
);
299 // *********************************************************************
300 // Paint, navigate, scroll
301 // *********************************************************************
303 IMPL_LINK_NOARG(SvImpLBox
, EndScrollHdl
)
305 if( nFlags
& F_ENDSCROLL_SET_VIS_SIZE
)
307 aVerSBar
->SetVisibleSize( nNextVerVisSize
);
308 nFlags
&= ~F_ENDSCROLL_SET_VIS_SIZE
;
314 // handler for vertical scrollbar
316 IMPL_LINK( SvImpLBox
, ScrollUpDownHdl
, ScrollBar
*, pScrollBar
)
318 DBG_ASSERT(!bInVScrollHdl
,"Scroll handler out-paces itself!");
319 long nDelta
= pScrollBar
->GetDelta();
323 nFlags
&= (~F_FILLING
);
325 bInVScrollHdl
= true;
327 if( pView
->IsEditingActive() )
329 pView
->EndEditing( true ); // Cancel
339 PageDown( (sal_uInt16
) nDelta
);
347 PageUp( (sal_uInt16
) nDelta
);
349 bInVScrollHdl
= false;
354 void SvImpLBox::CursorDown()
359 SvTreeListEntry
* pNextFirstToDraw
= pView
->NextVisible(pStartEntry
);
360 if( pNextFirstToDraw
)
362 nFlags
&= (~F_FILLING
);
365 pStartEntry
= pNextFirstToDraw
;
366 Rectangle
aArea( GetVisibleArea() );
367 pView
->Scroll( 0, -(pView
->GetEntryHeight()), aArea
, SCROLL_NOCHILDREN
);
370 pView
->NotifyScrolled();
374 void SvImpLBox::CursorUp()
379 SvTreeListEntry
* pPrevFirstToDraw
= pView
->PrevVisible(pStartEntry
);
380 if( pPrevFirstToDraw
)
382 nFlags
&= (~F_FILLING
);
383 long nEntryHeight
= pView
->GetEntryHeight();
386 pStartEntry
= pPrevFirstToDraw
;
387 Rectangle
aArea( GetVisibleArea() );
388 aArea
.Bottom() -= nEntryHeight
;
389 pView
->Scroll( 0, nEntryHeight
, aArea
, SCROLL_NOCHILDREN
);
392 pView
->NotifyScrolled();
396 void SvImpLBox::PageDown( sal_uInt16 nDelta
)
398 sal_uInt16 nRealDelta
= nDelta
;
406 SvTreeListEntry
* pNext
= pView
->NextVisible(pStartEntry
, nRealDelta
);
407 if( pNext
== pStartEntry
)
412 nFlags
&= (~F_FILLING
);
416 if( nRealDelta
>= nVisibleCount
)
418 pView
->Invalidate( GetVisibleArea() );
423 long nScroll
= nRealDelta
* (-1);
424 Rectangle
aArea( GetVisibleArea() );
425 nScroll
= pView
->GetEntryHeight() * static_cast<long>(nRealDelta
);
428 pView
->Scroll( 0, nScroll
, aArea
, SCROLL_NOCHILDREN
);
430 pView
->NotifyScrolled();
436 void SvImpLBox::PageUp( sal_uInt16 nDelta
)
438 sal_uInt16 nRealDelta
= nDelta
;
445 SvTreeListEntry
* pPrev
= pView
->PrevVisible(pStartEntry
, nRealDelta
);
446 if( pPrev
== pStartEntry
)
449 nFlags
&= (~F_FILLING
);
454 if( nRealDelta
>= nVisibleCount
)
456 pView
->Invalidate( GetVisibleArea() );
461 long nEntryHeight
= pView
->GetEntryHeight();
462 Rectangle
aArea( GetVisibleArea() );
464 pView
->Scroll( 0, nEntryHeight
*nRealDelta
, aArea
, SCROLL_NOCHILDREN
);
466 pView
->NotifyScrolled();
472 void SvImpLBox::KeyUp( bool bPageUp
, bool bNotifyScroll
)
474 if( !aVerSBar
->IsVisible() )
479 nDelta
= aVerSBar
->GetPageSize();
483 long nThumbPos
= aVerSBar
->GetThumbPos();
485 if( nThumbPos
< nDelta
)
491 nFlags
&= (~F_FILLING
);
495 aVerSBar
->SetThumbPos( nThumbPos
- nDelta
);
497 PageUp( (short)nDelta
);
506 void SvImpLBox::KeyDown( bool bPageDown
, bool bNotifyScroll
)
508 if( !aVerSBar
->IsVisible() )
513 nDelta
= aVerSBar
->GetPageSize();
517 long nThumbPos
= aVerSBar
->GetThumbPos();
518 long nVisibleSize
= aVerSBar
->GetVisibleSize();
519 long nRange
= aVerSBar
->GetRange().Len();
521 long nTmp
= nThumbPos
+nVisibleSize
;
522 while( (nDelta
> 0) && (nTmp
+nDelta
) >= nRange
)
528 nFlags
&= (~F_FILLING
);
532 aVerSBar
->SetThumbPos( nThumbPos
+nDelta
);
534 PageDown( (short)nDelta
);
544 void SvImpLBox::InvalidateEntriesFrom( long nY
) const
546 if( !(nFlags
& F_IN_PAINT
))
548 Rectangle
aRect( GetVisibleArea() );
550 pView
->Invalidate( aRect
);
554 void SvImpLBox::InvalidateEntry( long nY
) const
556 if( !(nFlags
& F_IN_PAINT
))
558 Rectangle
aRect( GetVisibleArea() );
559 long nMaxBottom
= aRect
.Bottom();
561 aRect
.Bottom() = nY
; aRect
.Bottom() += pView
->GetEntryHeight();
562 if( aRect
.Top() > nMaxBottom
)
564 if( aRect
.Bottom() > nMaxBottom
)
565 aRect
.Bottom() = nMaxBottom
;
566 pView
->Invalidate( aRect
);
570 void SvImpLBox::InvalidateEntry( SvTreeListEntry
* pEntry
)
572 if( GetUpdateMode() )
574 long nPrev
= nMostRight
;
575 SetMostRight( pEntry
);
576 if( nPrev
< nMostRight
)
579 if( !(nFlags
& F_IN_PAINT
))
581 bool bHasFocusRect
= false;
582 if( pEntry
==pCursor
&& pView
->HasFocus() )
584 bHasFocusRect
= true;
587 InvalidateEntry( GetEntryLine( pEntry
) );
594 void SvImpLBox::RecalcFocusRect()
596 if( pView
->HasFocus() && pCursor
)
599 long nY
= GetEntryLine( pCursor
);
600 Rectangle aRect
= pView
->GetFocusRect( pCursor
, nY
);
601 CalcCellFocusRect( pCursor
, aRect
);
602 vcl::Region
aOldClip( pView
->GetClipRegion());
603 vcl::Region
aClipRegion( GetClipRegionRect() );
604 pView
->SetClipRegion( aClipRegion
);
605 pView
->ShowFocus( aRect
);
606 pView
->SetClipRegion( aOldClip
);
611 // Sets cursor. When using SingleSelection, the selection is adjusted.
614 void SvImpLBox::SetCursor( SvTreeListEntry
* pEntry
, bool bForceNoSelect
)
616 SvViewDataEntry
* pViewDataNewCur
= 0;
618 pViewDataNewCur
= pView
->GetViewDataEntry(pEntry
);
622 pViewDataNewCur
->HasFocus() &&
623 pViewDataNewCur
->IsSelected())
628 // if this cursor is not selectable, find first visible that is and use it
629 while( pEntry
&& pViewDataNewCur
&& !pViewDataNewCur
->IsSelectable() )
631 pEntry
= pView
->NextVisible(pEntry
);
632 pViewDataNewCur
= pEntry
? pView
->GetViewDataEntry(pEntry
) : 0;
635 SvTreeListEntry
* pOldCursor
= pCursor
;
636 if( pCursor
&& pEntry
!= pCursor
)
638 pView
->SetEntryFocus( pCursor
, false );
640 pView
->Select( pCursor
, false );
647 pViewDataNewCur
->SetFocus( true );
648 if(!bForceNoSelect
&& bSimpleTravel
&& !(nFlags
& F_DESEL_ALL
) && GetUpdateMode())
650 pView
->Select( pCursor
, true );
651 CallEventListeners( VCLEVENT_LISTBOX_TREEFOCUS
, pCursor
);
653 // multiple selection: select in cursor move if we're not in
654 // Add mode (Ctrl-F8)
655 else if( GetUpdateMode() &&
656 pView
->GetSelectionMode() == MULTIPLE_SELECTION
&&
657 !(nFlags
& F_DESEL_ALL
) && !aSelEng
.IsAddMode() &&
660 pView
->Select( pCursor
, true );
661 CallEventListeners( VCLEVENT_LISTBOX_TREEFOCUS
, pCursor
);
666 if (bForceNoSelect
&& GetUpdateMode())
668 CallEventListeners( VCLEVENT_LISTBOX_TREEFOCUS
, pCursor
);
674 DBG_ASSERT(aSelEng
.GetSelectionMode() != SINGLE_SELECTION
,"Mode?");
675 SetAnchorSelection( pOldCursor
, pCursor
);
678 nFlags
&= (~F_DESEL_ALL
);
680 pView
->OnCurrentEntryChanged();
683 void SvImpLBox::ShowCursor( bool bShow
)
685 if( !bShow
|| !pCursor
|| !pView
->HasFocus() )
687 vcl::Region
aOldClip( pView
->GetClipRegion());
688 vcl::Region
aClipRegion( GetClipRegionRect() );
689 pView
->SetClipRegion( aClipRegion
);
691 pView
->SetClipRegion( aOldClip
);
695 long nY
= GetEntryLine( pCursor
);
696 Rectangle aRect
= pView
->GetFocusRect( pCursor
, nY
);
697 CalcCellFocusRect( pCursor
, aRect
);
698 vcl::Region
aOldClip( pView
->GetClipRegion());
699 vcl::Region
aClipRegion( GetClipRegionRect() );
700 pView
->SetClipRegion( aClipRegion
);
701 pView
->ShowFocus( aRect
);
702 pView
->SetClipRegion( aOldClip
);
708 void SvImpLBox::UpdateAll(
709 bool bInvalidateCompleteView
, bool bUpdateVerScrollBar
)
711 if( bUpdateVerScrollBar
)
713 aVerSBar
->SetRange( Range(0, pView
->GetVisibleCount()-1 ) );
717 if( bSimpleTravel
&& pCursor
&& pView
->HasFocus() )
718 pView
->Select( pCursor
, true );
720 if( bInvalidateCompleteView
)
723 pView
->Invalidate( GetVisibleArea() );
726 IMPL_LINK( SvImpLBox
, ScrollLeftRightHdl
, ScrollBar
*, pScrollBar
)
728 long nDelta
= pScrollBar
->GetDelta();
731 if( pView
->IsEditingActive() )
733 pView
->EndEditing( true ); // Cancel
736 pView
->nFocusWidth
= -1;
737 KeyLeftRight( nDelta
);
742 void SvImpLBox::KeyLeftRight( long nDelta
)
744 if( !(nFlags
& F_IN_RESIZE
) )
747 nFlags
&= (~F_FILLING
);
750 // neuen Origin berechnen
751 long nPos
= aHorSBar
->GetThumbPos();
752 Point
aOrigin( -nPos
, 0 );
754 MapMode
aMapMode( pView
->GetMapMode() );
755 aMapMode
.SetOrigin( aOrigin
);
756 pView
->SetMapMode( aMapMode
);
758 if( !(nFlags
& F_IN_RESIZE
) )
760 Rectangle
aRect( GetVisibleArea() );
761 pView
->Scroll( -nDelta
, 0, aRect
, SCROLL_NOCHILDREN
);
767 pView
->NotifyScrolled();
771 // returns the last entry if position is just past the last entry
772 SvTreeListEntry
* SvImpLBox::GetClickedEntry( const Point
& rPoint
) const
774 DBG_ASSERT( pView
->GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" );
775 if ( !pView
->GetModel() )
776 // this is quite impossible. Nevertheless, stack traces from the crash reporter
777 // suggest it isn't. Okay, make it safe, and wait for somebody to reproduce it
779 // #122359# / 2005-05-23 / frank.schoenheit@sun.com
781 if( pView
->GetEntryCount() == 0 || !pStartEntry
|| !pView
->GetEntryHeight())
784 sal_uInt16 nClickedEntry
= (sal_uInt16
)(rPoint
.Y() / pView
->GetEntryHeight() );
785 sal_uInt16 nTemp
= nClickedEntry
;
786 SvTreeListEntry
* pEntry
= pView
->NextVisible(pStartEntry
, nTemp
);
791 // checks if the entry was hit "the right way"
792 // (Focusrect+ ContextBitmap bei TreeListBox)
794 bool SvImpLBox::EntryReallyHit(SvTreeListEntry
* pEntry
, const Point
& rPosPixel
, long nLine
)
797 // we are not too exact when it comes to "special" entries
798 // (with CheckButtons etc.)
799 if( pEntry
->ItemCount() >= 3 )
802 Rectangle
aRect( pView
->GetFocusRect( pEntry
, nLine
));
803 aRect
.Right() = GetOutputSize().Width() - pView
->GetMapMode().GetOrigin().X();
805 SvLBoxContextBmp
* pBmp
= static_cast<SvLBoxContextBmp
*>(pEntry
->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP
));
806 aRect
.Left() -= pBmp
->GetSize(pView
,pEntry
).Width();
807 aRect
.Left() -= 4; // a little tolerance
809 Point
aPos( rPosPixel
);
810 aPos
-= pView
->GetMapMode().GetOrigin();
811 if( aRect
.IsInside( aPos
) )
819 // returns 0 if position is just past the last entry
820 SvTreeListEntry
* SvImpLBox::GetEntry( const Point
& rPoint
) const
822 if( (pView
->GetEntryCount() == 0) || !pStartEntry
||
823 (rPoint
.Y() > aOutputSize
.Height())
824 || !pView
->GetEntryHeight())
827 sal_uInt16 nClickedEntry
= (sal_uInt16
)(rPoint
.Y() / pView
->GetEntryHeight() );
828 sal_uInt16 nTemp
= nClickedEntry
;
829 SvTreeListEntry
* pEntry
= pView
->NextVisible(pStartEntry
, nTemp
);
830 if( nTemp
!= nClickedEntry
)
836 SvTreeListEntry
* SvImpLBox::MakePointVisible(const Point
& rPoint
, bool bNotifyScroll
)
840 long nY
= rPoint
.Y();
841 SvTreeListEntry
* pEntry
= 0;
842 long nMax
= aOutputSize
.Height();
843 if( nY
< 0 || nY
>= nMax
) // aOutputSize.Height() )
846 pEntry
= pView
->PrevVisible(pCursor
);
848 pEntry
= pView
->NextVisible(pCursor
);
850 if( pEntry
&& pEntry
!= pCursor
)
851 pView
->SetEntryFocus( pCursor
, false );
854 KeyUp( false, bNotifyScroll
);
856 KeyDown( false, bNotifyScroll
);
860 pEntry
= GetClickedEntry( rPoint
);
863 sal_uInt16 nSteps
= 0xFFFF;
864 // TODO: LastVisible is not yet implemented!
865 pEntry
= pView
->NextVisible(pStartEntry
, nSteps
);
869 if( pEntry
!= pCursor
&&
870 aSelEng
.GetSelectionMode() == SINGLE_SELECTION
872 pView
->Select( pCursor
, false );
878 Rectangle
SvImpLBox::GetClipRegionRect() const
880 Point
aOrigin( pView
->GetMapMode().GetOrigin() );
881 aOrigin
.X() *= -1; // conversion document coordinates
882 Rectangle
aClipRect( aOrigin
, aOutputSize
);
883 aClipRect
.Bottom()++;
888 void SvImpLBox::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& rRect
)
890 if (!pView
->GetVisibleCount())
893 nFlags
|= F_IN_PAINT
;
895 if (nFlags
& F_FILLING
)
897 SvTreeListEntry
* pFirst
= pView
->First();
898 if (pFirst
!= pStartEntry
)
901 pStartEntry
= pView
->First();
902 aVerSBar
->SetThumbPos( 0 );
905 nCurUserEvent
= Application::PostUserEvent(LINK(this, SvImpLBox
, MyUserEvent
),
906 reinterpret_cast<void*>(1));
913 pStartEntry
= pView
->First();
916 if (nNodeBmpTabDistance
== NODE_BMP_TABDIST_NOTVALID
)
917 SetNodeBmpTabDistance();
919 long nRectHeight
= rRect
.GetHeight();
920 long nEntryHeight
= pView
->GetEntryHeight();
922 // calculate area for the entries we want to draw
923 sal_uInt16 nStartLine
= static_cast<sal_uInt16
>(rRect
.Top() / nEntryHeight
);
924 sal_uInt16 nCount
= static_cast<sal_uInt16
>(nRectHeight
/ nEntryHeight
);
925 nCount
+= 2; // don't miss a row
927 long nY
= nStartLine
* nEntryHeight
;
928 SvTreeListEntry
* pEntry
= pStartEntry
;
929 while (nStartLine
&& pEntry
)
931 pEntry
= pView
->NextVisible(pEntry
);
935 vcl::Region
aClipRegion(GetClipRegionRect());
937 // first draw the lines, then clip them!
938 rRenderContext
.SetClipRegion();
939 if (m_nStyle
& (WB_HASLINES
| WB_HASLINESATROOT
))
940 DrawNet(rRenderContext
);
942 rRenderContext
.SetClipRegion(aClipRegion
);
944 for(sal_uInt16 n
=0; n
< nCount
&& pEntry
; n
++)
947 pView
->PaintEntry1(pEntry
, nY
, rRenderContext
, SvLBoxTabFlags::ALL
, true );
949 pEntry
= pView
->NextVisible(pEntry
);
952 if (!pCursor
&& ((nExtendedWinBits
& EWB_NO_AUTO_CURENTRY
) == 0))
954 // do not select if multiselection or explicit set
955 bool bNotSelect
= (aSelEng
.GetSelectionMode() == MULTIPLE_SELECTION
) || ((m_nStyle
& WB_NOINITIALSELECTION
) == WB_NOINITIALSELECTION
);
956 SetCursor(pStartEntry
, bNotSelect
);
959 nFlags
&= (~F_DESEL_ALL
);
960 rRenderContext
.SetClipRegion();
961 if (!(nFlags
& F_PAINTED
))
965 nFlags
&= (~F_IN_PAINT
);
968 void SvImpLBox::MakeVisible( SvTreeListEntry
* pEntry
, bool bMoveToTop
)
973 bool bInView
= IsEntryInView( pEntry
);
975 if( bInView
&& (!bMoveToTop
|| pStartEntry
== pEntry
) )
976 return; // is already visible
978 if( pStartEntry
|| (m_nStyle
& WB_FORCE_MAKEVISIBLE
) )
979 nFlags
&= (~F_FILLING
);
982 if( !pView
->IsEntryVisible(pEntry
) ) // Parent(s) collapsed?
984 SvTreeListEntry
* pParent
= pView
->GetParent( pEntry
);
987 if( !pView
->IsExpanded( pParent
) )
992 pView
->Expand( pParent
);
993 DBG_ASSERT(bRet
,"Not expanded!");
995 pParent
= pView
->GetParent( pParent
);
997 // do the parent's children fit into the view or do we have to scroll?
998 if( IsEntryInView( pEntry
) && !bMoveToTop
)
999 return; // no need to scroll
1003 pStartEntry
= pEntry
;
1004 ShowCursor( false );
1006 aVerSBar
->SetThumbPos( (long)(pView
->GetVisiblePos( pStartEntry
)) );
1008 pView
->Invalidate();
1011 void SvImpLBox::ScrollToAbsPos( long nPos
)
1013 if( pView
->GetVisibleCount() == 0 )
1015 long nLastEntryPos
= pView
->GetAbsPos( pView
->Last() );
1019 else if( nPos
> nLastEntryPos
)
1020 nPos
= nLastEntryPos
;
1022 SvTreeListEntry
* pEntry
= pView
->GetEntryAtAbsPos( nPos
);
1023 if( !pEntry
|| pEntry
== pStartEntry
)
1026 if( pStartEntry
|| (m_nStyle
& WB_FORCE_MAKEVISIBLE
) )
1027 nFlags
&= (~F_FILLING
);
1029 if( pView
->IsEntryVisible(pEntry
) )
1031 pStartEntry
= pEntry
;
1032 ShowCursor( false );
1033 aVerSBar
->SetThumbPos( nPos
);
1035 if (GetUpdateMode())
1036 pView
->Invalidate();
1040 void SvImpLBox::DrawNet(vcl::RenderContext
& rRenderContext
)
1042 if (pView
->GetVisibleCount() < 2 && !pStartEntry
->HasChildrenOnDemand() &&
1043 !pStartEntry
->HasChildren())
1048 // for platforms that don't have nets, DrawNativeControl does nothing and returns true
1049 // so that SvImpLBox::DrawNet() doesn't draw anything either
1050 if (rRenderContext
.IsNativeControlSupported(CTRL_LISTNET
, PART_ENTIRE_CONTROL
))
1052 ImplControlValue aControlValue
;
1053 ControlState nState
= ControlState::ENABLED
;
1054 if (rRenderContext
.DrawNativeControl(CTRL_LISTNET
, PART_ENTIRE_CONTROL
,
1055 Rectangle(), nState
, aControlValue
, OUString()))
1062 long nEntryHeight
= pView
->GetEntryHeight();
1063 long nEntryHeightDIV2
= nEntryHeight
/ 2;
1064 if( nEntryHeightDIV2
&& !(nEntryHeight
& 0x0001))
1067 SvTreeListEntry
* pChild
;
1068 SvTreeListEntry
* pEntry
= pStartEntry
;
1070 SvLBoxTab
* pFirstDynamicTab
= pView
->GetFirstDynamicTab();
1071 while (pTree
->GetDepth( pEntry
) > 0)
1073 pEntry
= pView
->GetParent(pEntry
);
1075 sal_uInt16 nOffs
= static_cast<sal_uInt16
>(pView
->GetVisiblePos(pStartEntry
) - pView
->GetVisiblePos(pEntry
));
1077 nY
-= (nOffs
* nEntryHeight
);
1079 DBG_ASSERT(pFirstDynamicTab
,"No Tree!");
1081 rRenderContext
.Push(PushFlags::LINECOLOR
);
1083 const StyleSettings
& rStyleSettings
= rRenderContext
.GetSettings().GetStyleSettings();
1084 Color aCol
= rStyleSettings
.GetFaceColor();
1086 if (aCol
.IsRGBEqual(rRenderContext
.GetBackground().GetColor()))
1087 aCol
= rStyleSettings
.GetShadowColor();
1088 rRenderContext
.SetLineColor(aCol
);
1090 sal_uInt16 nDistance
;
1091 sal_uLong nMax
= nVisibleCount
+ nOffs
+ 1;
1093 const Image
& rExpandedNodeBitmap
= GetExpandedNodeBmp();
1095 for (sal_uLong n
=0; n
< nMax
&& pEntry
; n
++)
1097 if (pView
->IsExpanded(pEntry
))
1099 aPos1
.X() = pView
->GetTabPos(pEntry
, pFirstDynamicTab
);
1100 // if it is not a context bitmap, go a little to the right below the
1101 // first text (node bitmap, too)
1102 if (!pView
->nContextBmpWidthMax
)
1103 aPos1
.X() += rExpandedNodeBitmap
.GetSizePixel().Width() / 2;
1106 aPos1
.Y() += nEntryHeightDIV2
;
1108 pChild
= pView
->FirstChild( pEntry
);
1109 DBG_ASSERT(pChild
,"Child?");
1110 pChild
= SvTreeList::LastSibling( pChild
);
1111 nDistance
= static_cast<sal_uInt16
>(pView
->GetVisiblePos(pChild
) - pView
->GetVisiblePos(pEntry
));
1113 aPos2
.Y() += nDistance
* nEntryHeight
;
1114 rRenderContext
.DrawLine(aPos1
, aPos2
);
1116 // visible in control?
1117 if (n
>= nOffs
&& ((m_nStyle
& WB_HASLINESATROOT
) || !pTree
->IsAtRootDepth(pEntry
)))
1119 // can we recycle aPos1?
1120 if (!pView
->IsExpanded(pEntry
))
1123 aPos1
.X() = pView
->GetTabPos(pEntry
, pFirstDynamicTab
);
1124 // if it is not a context bitmap, go a little to the right below
1125 // the first text (node bitmap, too)
1126 if (!pView
->nContextBmpWidthMax
)
1127 aPos1
.X() += rExpandedNodeBitmap
.GetSizePixel().Width() / 2;
1129 aPos1
.Y() += nEntryHeightDIV2
;
1130 aPos2
.X() = aPos1
.X();
1132 aPos2
.Y() = aPos1
.Y();
1133 aPos2
.X() -= pView
->GetIndent();
1134 rRenderContext
.DrawLine(aPos1
, aPos2
);
1137 pEntry
= pView
->NextVisible(pEntry
);
1139 if (m_nStyle
& WB_HASLINESATROOT
)
1141 pEntry
= pView
->First();
1142 aPos1
.X() = pView
->GetTabPos(pEntry
, pFirstDynamicTab
);
1143 // if it is not a context bitmap, go a little to the right below the
1144 // first text (node bitmap, too)
1145 if (!pView
->nContextBmpWidthMax
)
1146 aPos1
.X() += rExpandedNodeBitmap
.GetSizePixel().Width() / 2;
1147 aPos1
.X() -= pView
->GetIndent();
1148 aPos1
.Y() = GetEntryLine( pEntry
);
1149 aPos1
.Y() += nEntryHeightDIV2
;
1150 pChild
= SvTreeList::LastSibling( pEntry
);
1151 aPos2
.X() = aPos1
.X();
1152 aPos2
.Y() = GetEntryLine( pChild
);
1153 aPos2
.Y() += nEntryHeightDIV2
;
1154 rRenderContext
.DrawLine(aPos1
, aPos2
);
1156 rRenderContext
.Pop();
1159 void SvImpLBox::PositionScrollBars( Size
& rSize
, sal_uInt16 nMask
)
1163 Size
aVerSize( nVerSBarWidth
, rSize
.Height() );
1164 Size
aHorSize( rSize
.Width(), nHorSBarHeight
);
1166 if( nMask
& 0x0001 )
1167 aHorSize
.Width() -= nVerSBarWidth
;
1168 if( nMask
& 0x0002 )
1169 aVerSize
.Height() -= nHorSBarHeight
;
1171 aVerSize
.Height() += 2 * nOverlap
;
1172 Point
aVerPos( rSize
.Width() - aVerSize
.Width() + nOverlap
, -nOverlap
);
1173 aVerSBar
->SetPosSizePixel( aVerPos
, aVerSize
);
1175 aHorSize
.Width() += 2 * nOverlap
;
1176 Point
aHorPos( -nOverlap
, rSize
.Height() - aHorSize
.Height() + nOverlap
);
1178 aHorSBar
->SetPosSizePixel( aHorPos
, aHorSize
);
1180 if( nMask
& 0x0001 )
1181 rSize
.Width() = aVerPos
.X();
1182 if( nMask
& 0x0002 )
1183 rSize
.Height() = aHorPos
.Y();
1185 if( (nMask
& (0x0001|0x0002)) == (0x0001|0x0002) )
1191 // nResult: Bit0 == VerSBar Bit1 == HorSBar
1192 sal_uInt16
SvImpLBox::AdjustScrollBars( Size
& rSize
)
1194 long nEntryHeight
= pView
->GetEntryHeight();
1198 sal_uInt16 nResult
= 0;
1200 Size
aOSize( pView
->Control::GetOutputSizePixel() );
1202 const WinBits nWindowStyle
= pView
->GetStyle();
1203 bool bVerSBar
= ( nWindowStyle
& WB_VSCROLL
) != 0;
1204 bool bHorBar
= false;
1205 long nMaxRight
= aOSize
.Width(); //GetOutputSize().Width();
1206 Point
aOrigin( pView
->GetMapMode().GetOrigin() );
1208 nMaxRight
+= aOrigin
.X() - 1;
1209 long nVis
= nMostRight
- aOrigin
.X();
1210 if( (nWindowStyle
& WB_HSCROLL
) &&
1211 (nVis
< nMostRight
|| nMaxRight
< nMostRight
) )
1216 // number of entries that are not collapsed
1217 sal_uLong nTotalCount
= pView
->GetVisibleCount();
1219 // number of entries visible within the view
1220 nVisibleCount
= aOSize
.Height() / nEntryHeight
;
1222 // do we need a vertical scrollbar?
1223 if( bVerSBar
|| nTotalCount
> nVisibleCount
)
1226 nFlags
|= F_HOR_SBARSIZE_WITH_VBAR
;
1227 nMaxRight
-= nVerSBarWidth
;
1230 if( (nWindowStyle
& WB_HSCROLL
) &&
1231 (nVis
< nMostRight
|| nMaxRight
< nMostRight
) )
1236 // do we need a horizontal scrollbar?
1240 // the number of entries visible within the view has to be recalculated
1241 // because the horizontal scrollbar is now visible.
1242 nVisibleCount
= (aOSize
.Height() - nHorSBarHeight
) / nEntryHeight
;
1243 // we might actually need a vertical scrollbar now
1244 if( !(nResult
& 0x0001) &&
1245 ((nTotalCount
> nVisibleCount
) || bVerSBar
) )
1248 nFlags
|= F_VER_SBARSIZE_WITH_HBAR
;
1252 PositionScrollBars( aOSize
, nResult
);
1254 // adapt Range, VisibleRange etc.
1256 // refresh output size, in case we have to scroll
1258 aRect
.SetSize( aOSize
);
1259 aSelEng
.SetVisibleArea( aRect
);
1261 // vertical scrollbar
1262 long nTemp
= (long)nVisibleCount
;
1264 if( nTemp
!= aVerSBar
->GetVisibleSize() )
1266 if( !bInVScrollHdl
)
1268 aVerSBar
->SetPageSize( nTemp
- 1 );
1269 aVerSBar
->SetVisibleSize( nTemp
);
1273 nFlags
|= F_ENDSCROLL_SET_VIS_SIZE
;
1274 nNextVerVisSize
= nTemp
;
1278 // horizontal scrollbar
1279 nTemp
= aHorSBar
->GetThumbPos();
1280 aHorSBar
->SetVisibleSize( aOSize
.Width() );
1281 long nNewThumbPos
= aHorSBar
->GetThumbPos();
1282 Range
aRange( aHorSBar
->GetRange() );
1283 if( aRange
.Max() < nMostRight
+25 )
1285 aRange
.Max() = nMostRight
+25;
1286 aHorSBar
->SetRange( aRange
);
1289 if( nTemp
!= nNewThumbPos
)
1291 nTemp
= nNewThumbPos
- nTemp
;
1292 if( pView
->IsEditingActive() )
1294 pView
->EndEditing( true ); // Cancel
1297 pView
->nFocusWidth
= -1;
1298 KeyLeftRight( nTemp
);
1301 if( nResult
& 0x0001 )
1306 if( nResult
& 0x0002 )
1316 void SvImpLBox::InitScrollBarBox()
1318 aScrBarBox
->SetSizePixel( Size(nVerSBarWidth
, nHorSBarHeight
) );
1319 Size
aSize( pView
->Control::GetOutputSizePixel() );
1320 aScrBarBox
->SetPosPixel( Point(aSize
.Width()-nVerSBarWidth
, aSize
.Height()-nHorSBarHeight
));
1323 void SvImpLBox::Resize()
1325 aOutputSize
= pView
->Control::GetOutputSizePixel();
1326 if( aOutputSize
.Width() <= 0 || aOutputSize
.Height() <= 0 )
1328 nFlags
|= F_IN_RESIZE
;
1331 if( pView
->GetEntryHeight())
1333 AdjustScrollBars( aOutputSize
);
1336 // HACK, as in floating and docked windows the scrollbars might not be drawn
1337 // correctly/not be drawn at all after resizing!
1338 if( aHorSBar
->IsVisible())
1339 aHorSBar
->Invalidate();
1340 if( aVerSBar
->IsVisible())
1341 aVerSBar
->Invalidate();
1342 nFlags
&= (~(F_IN_RESIZE
| F_PAINTED
));
1345 void SvImpLBox::FillView()
1349 sal_uInt16 nVisibleViewCount
= (sal_uInt16
)(pView
->GetVisibleCount());
1350 sal_uInt16 nTempThumb
= (sal_uInt16
)aVerSBar
->GetThumbPos();
1351 if( nTempThumb
>= nVisibleViewCount
)
1352 nTempThumb
= nVisibleViewCount
- 1;
1353 pStartEntry
= pView
->GetEntryAtVisPos(nTempThumb
);
1357 sal_uInt16 nLast
= (sal_uInt16
)(pView
->GetVisiblePos(pView
->LastVisible()));
1358 sal_uInt16 nThumb
= (sal_uInt16
)(pView
->GetVisiblePos( pStartEntry
));
1359 sal_uInt16 nCurDispEntries
= nLast
-nThumb
+1;
1360 if( nCurDispEntries
< nVisibleCount
)
1362 ShowCursor( false );
1363 // fill window by moving the thumb up incrementally
1364 bool bFound
= false;
1365 SvTreeListEntry
* pTemp
= pStartEntry
;
1366 while( nCurDispEntries
< nVisibleCount
&& pTemp
)
1368 pTemp
= pView
->PrevVisible(pStartEntry
);
1372 pStartEntry
= pTemp
;
1379 aVerSBar
->SetThumbPos( nThumb
);
1380 ShowCursor( true ); // recalculate focus rectangle
1381 pView
->Invalidate();
1390 void SvImpLBox::ShowVerSBar()
1392 bool bVerBar
= ( pView
->GetStyle() & WB_VSCROLL
) != 0;
1395 nVis
= pView
->GetVisibleCount();
1396 if( bVerBar
|| (nVisibleCount
&& nVis
> (sal_uLong
)(nVisibleCount
-1)) )
1398 if( !aVerSBar
->IsVisible() )
1400 pView
->nFocusWidth
= -1;
1401 AdjustScrollBars( aOutputSize
);
1402 if( GetUpdateMode() )
1408 if( aVerSBar
->IsVisible() )
1410 pView
->nFocusWidth
= -1;
1411 AdjustScrollBars( aOutputSize
);
1415 long nMaxRight
= GetOutputSize().Width();
1416 Point
aPos( pView
->GetMapMode().GetOrigin() );
1417 aPos
.X() *= -1; // convert document coordinates
1418 nMaxRight
= nMaxRight
+ aPos
.X() - 1;
1419 if( nMaxRight
< nMostRight
)
1421 if( !aHorSBar
->IsVisible() )
1423 pView
->nFocusWidth
= -1;
1424 AdjustScrollBars( aOutputSize
);
1425 if( GetUpdateMode() )
1430 Range
aRange( aHorSBar
->GetRange() );
1431 if( aRange
.Max() < nMostRight
+25 )
1433 aRange
.Max() = nMostRight
+25;
1434 aHorSBar
->SetRange( aRange
);
1438 pView
->nFocusWidth
= -1;
1439 AdjustScrollBars( aOutputSize
);
1445 if( aHorSBar
->IsVisible() )
1447 pView
->nFocusWidth
= -1;
1448 AdjustScrollBars( aOutputSize
);
1454 void SvImpLBox::SyncVerThumb()
1458 long nEntryPos
= pView
->GetVisiblePos( pStartEntry
);
1459 aVerSBar
->SetThumbPos( nEntryPos
);
1462 aVerSBar
->SetThumbPos( 0 );
1465 bool SvImpLBox::IsEntryInView( SvTreeListEntry
* pEntry
) const
1468 if( !pView
->IsEntryVisible(pEntry
) )
1470 long nY
= GetEntryLine( pEntry
);
1473 long nMax
= nVisibleCount
* pView
->GetEntryHeight();
1480 long SvImpLBox::GetEntryLine( SvTreeListEntry
* pEntry
) const
1483 return -1; // invisible position
1485 long nFirstVisPos
= pView
->GetVisiblePos( pStartEntry
);
1486 long nEntryVisPos
= pView
->GetVisiblePos( pEntry
);
1487 nFirstVisPos
= nEntryVisPos
- nFirstVisPos
;
1488 nFirstVisPos
*= pView
->GetEntryHeight();
1489 return nFirstVisPos
;
1492 void SvImpLBox::SetEntryHeight( short /* nHeight */ )
1494 SetNodeBmpYOffset( GetExpandedNodeBmp() );
1495 SetNodeBmpYOffset( GetCollapsedNodeBmp() );
1496 if(!pView
->HasViewData()) // are we within the Clear?
1498 Size aSize
= pView
->Control::GetOutputSizePixel();
1499 AdjustScrollBars( aSize
);
1504 if( GetUpdateMode() )
1505 pView
->Invalidate();
1511 // ***********************************************************************
1512 // Callback Functions
1513 // ***********************************************************************
1515 void SvImpLBox::EntryExpanded( SvTreeListEntry
* pEntry
)
1517 // SelAllDestrAnch( false, true ); //DeselectAll();
1518 if( GetUpdateMode() )
1520 ShowCursor( false );
1521 long nY
= GetEntryLine( pEntry
);
1522 if( IsLineVisible(nY
) )
1524 InvalidateEntriesFrom( nY
);
1525 FindMostRight( pEntry
, 0 );
1527 aVerSBar
->SetRange( Range(0, pView
->GetVisibleCount()-1 ) );
1528 // if we expanded before the thumb, the thumb's position has to be
1536 void SvImpLBox::EntryCollapsed( SvTreeListEntry
* pEntry
)
1538 if( !pView
->IsEntryVisible( pEntry
) )
1541 ShowCursor( false );
1543 if( !pMostRightEntry
|| pTree
->IsChild( pEntry
,pMostRightEntry
) )
1550 long nOldThumbPos
= aVerSBar
->GetThumbPos();
1551 sal_uLong nVisList
= pView
->GetVisibleCount();
1552 aVerSBar
->SetRange( Range(0, nVisList
-1) );
1553 long nNewThumbPos
= aVerSBar
->GetThumbPos();
1554 if( nNewThumbPos
!= nOldThumbPos
)
1556 pStartEntry
= pView
->First();
1557 sal_uInt16 nDistance
= (sal_uInt16
)nNewThumbPos
;
1559 pStartEntry
= pView
->NextVisible(pStartEntry
, nDistance
);
1560 if( GetUpdateMode() )
1561 pView
->Invalidate();
1567 // has the cursor been collapsed?
1568 if( pTree
->IsChild( pEntry
, pCursor
) )
1569 SetCursor( pEntry
);
1570 if( GetUpdateMode() )
1573 if( GetUpdateMode() && pCursor
)
1574 pView
->Select( pCursor
, true );
1577 void SvImpLBox::CollapsingEntry( SvTreeListEntry
* pEntry
)
1579 if( !pView
->IsEntryVisible( pEntry
) || !pStartEntry
)
1582 SelAllDestrAnch( false, true ); // deselect all
1584 // is the collapsed cursor visible?
1585 long nY
= GetEntryLine( pEntry
);
1586 if( IsLineVisible(nY
) )
1588 if( GetUpdateMode() )
1589 InvalidateEntriesFrom( nY
);
1593 if( pTree
->IsChild(pEntry
, pStartEntry
) )
1595 pStartEntry
= pEntry
;
1596 if( GetUpdateMode() )
1597 pView
->Invalidate();
1603 void SvImpLBox::SetNodeBmpYOffset( const Image
& rBmp
)
1606 nYoffsNodeBmp
= pView
->GetHeightOffset( rBmp
, aSize
);
1607 nNodeBmpWidth
= aSize
.Width();
1610 void SvImpLBox::SetNodeBmpTabDistance()
1612 nNodeBmpTabDistance
= -pView
->GetIndent();
1613 if( pView
->nContextBmpWidthMax
)
1615 // only if the first dynamic tab is centered (we currently assume that)
1616 Size aSize
= GetExpandedNodeBmp().GetSizePixel();
1617 nNodeBmpTabDistance
-= aSize
.Width() / 2;
1622 // corrects the cursor when using SingleSelection
1624 void SvImpLBox::EntrySelected( SvTreeListEntry
* pEntry
, bool bSelect
)
1626 if( nFlags
& F_IGNORE_SELECT
)
1629 nFlags
&= (~F_DESEL_ALL
);
1631 aSelEng
.GetSelectionMode() == SINGLE_SELECTION
&&
1634 SetCursor( pEntry
);
1635 DBG_ASSERT(pView
->GetSelectionCount()==1,"selection count?");
1638 if( GetUpdateMode() && pView
->IsEntryVisible(pEntry
) )
1640 long nY
= GetEntryLine( pEntry
);
1641 if( IsLineVisible( nY
) )
1644 InvalidateEntry(pEntry
);
1651 void SvImpLBox::RemovingEntry( SvTreeListEntry
* pEntry
)
1653 CallEventListeners( VCLEVENT_LISTBOX_ITEMREMOVED
, pEntry
);
1657 if( !pView
->IsEntryVisible( pEntry
) )
1659 // if parent is collapsed => bye!
1660 nFlags
|= F_REMOVED_ENTRY_INVISIBLE
;
1664 if( pEntry
== pMostRightEntry
|| (
1665 pEntry
->HasChildren() && pView
->IsExpanded(pEntry
) &&
1666 pTree
->IsChild(pEntry
, pMostRightEntry
)))
1668 nFlags
|= F_REMOVED_RECALC_MOST_RIGHT
;
1671 SvTreeListEntry
* pOldStartEntry
= pStartEntry
;
1673 SvTreeListEntry
* pParent
= pView
->GetModel()->GetParent(pEntry
);
1675 if (pParent
&& pView
->GetModel()->GetChildList(pParent
).size() == 1)
1677 DBG_ASSERT( pView
->IsExpanded( pParent
), "Parent not expanded");
1678 pParent
->SetFlags( pParent
->GetFlags() | SvTLEntryFlags::NO_NODEBMP
);
1679 InvalidateEntry( pParent
);
1682 if( pCursor
&& pTree
->IsChild( pEntry
, pCursor
) )
1684 if( pStartEntry
&& pTree
->IsChild(pEntry
,pStartEntry
) )
1685 pStartEntry
= pEntry
;
1687 SvTreeListEntry
* pTemp
;
1688 if( pCursor
&& pCursor
== pEntry
)
1691 pView
->Select( pCursor
, false );
1692 ShowCursor( false ); // focus rectangle gone
1693 // NextSibling, because we also delete the children of the cursor
1694 pTemp
= SvTreeListBox::NextSibling( pCursor
);
1696 pTemp
= pView
->PrevVisible(pCursor
);
1698 SetCursor( pTemp
, true );
1700 if( pStartEntry
&& pStartEntry
== pEntry
)
1702 pTemp
= SvTreeListBox::NextSibling( pStartEntry
);
1704 pTemp
= pView
->PrevVisible(pStartEntry
);
1705 pStartEntry
= pTemp
;
1707 if( GetUpdateMode())
1709 // if it is the last one, we have to invalidate it, so the lines are
1710 // drawn correctly (in this case they're deleted)
1711 if( pStartEntry
&& (pStartEntry
!= pOldStartEntry
|| pEntry
== pView
->GetModel()->Last()) )
1713 aVerSBar
->SetThumbPos( pView
->GetVisiblePos( pStartEntry
));
1714 pView
->Invalidate( GetVisibleArea() );
1717 InvalidateEntriesFrom( GetEntryLine( pEntry
) );
1721 void SvImpLBox::EntryRemoved()
1723 if( nFlags
& F_REMOVED_ENTRY_INVISIBLE
)
1725 nFlags
&= (~F_REMOVED_ENTRY_INVISIBLE
);
1729 pStartEntry
= pTree
->First();
1731 SetCursor( pStartEntry
, true );
1733 if( pCursor
&& (bSimpleTravel
|| !pView
->GetSelectionCount() ))
1734 pView
->Select( pCursor
, true );
1736 if( GetUpdateMode())
1738 if( nFlags
& F_REMOVED_RECALC_MOST_RIGHT
)
1740 aVerSBar
->SetRange( Range(0, pView
->GetVisibleCount()-1 ) );
1743 // if something above the thumb was deleted
1744 aVerSBar
->SetThumbPos( pView
->GetVisiblePos( pStartEntry
) );
1747 if( pCursor
&& pView
->HasFocus() && !pView
->IsSelected(pCursor
) )
1749 if( pView
->GetSelectionCount() )
1751 // is a neighboring entry selected?
1752 SvTreeListEntry
* pNextCursor
= pView
->PrevVisible( pCursor
);
1753 if( !pNextCursor
|| !pView
->IsSelected( pNextCursor
))
1754 pNextCursor
= pView
->NextVisible( pCursor
);
1755 if( !pNextCursor
|| !pView
->IsSelected( pNextCursor
))
1756 // no neighbor selected: use first selected
1757 pNextCursor
= pView
->FirstSelected();
1758 SetCursor( pNextCursor
);
1759 MakeVisible( pCursor
);
1762 pView
->Select( pCursor
, true );
1766 nFlags
&= (~F_REMOVED_RECALC_MOST_RIGHT
);
1770 void SvImpLBox::MovingEntry( SvTreeListEntry
* pEntry
)
1772 int bDeselAll
= nFlags
& F_DESEL_ALL
;
1773 SelAllDestrAnch( false, true ); // DeselectAll();
1775 nFlags
&= (~F_DESEL_ALL
);
1777 if( pEntry
== pCursor
)
1778 ShowCursor( false );
1779 if( IsEntryInView( pEntry
) )
1780 pView
->Invalidate();
1781 if( pEntry
== pStartEntry
)
1783 SvTreeListEntry
* pNew
= 0;
1784 if( !pEntry
->HasChildren() )
1786 pNew
= pView
->NextVisible(pStartEntry
);
1788 pNew
= pView
->PrevVisible(pStartEntry
);
1792 pNew
= SvTreeList::NextSibling( pEntry
);
1794 pNew
= SvTreeList::PrevSibling( pEntry
);
1800 void SvImpLBox::EntryMoved( SvTreeListEntry
* pEntry
)
1802 UpdateContextBmpWidthVectorFromMovedEntry( pEntry
);
1805 // this might happen if the only entry in the view is moved to its very same position
1807 pStartEntry
= pView
->First();
1809 aVerSBar
->SetRange( Range(0, pView
->GetVisibleCount()-1));
1810 sal_uInt16 nFirstPos
= (sal_uInt16
)pTree
->GetAbsPos( pStartEntry
);
1811 sal_uInt16 nNewPos
= (sal_uInt16
)pTree
->GetAbsPos( pEntry
);
1813 if( nNewPos
< nFirstPos
) // HACK!
1814 pStartEntry
= pEntry
;
1816 if( pEntry
== pCursor
)
1818 if( pView
->IsEntryVisible( pCursor
) )
1822 SvTreeListEntry
* pParent
= pEntry
;
1824 pParent
= pTree
->GetParent( pParent
);
1826 while( !pView
->IsEntryVisible( pParent
) );
1827 SetCursor( pParent
);
1830 if( IsEntryInView( pEntry
) )
1831 pView
->Invalidate();
1836 void SvImpLBox::EntryInserted( SvTreeListEntry
* pEntry
)
1838 if( GetUpdateMode() )
1840 SvTreeListEntry
* pParent
= pTree
->GetParent(pEntry
);
1841 if (pParent
&& pTree
->GetChildList(pParent
).size() == 1)
1843 pTree
->InvalidateEntry( pParent
);
1845 if( !pView
->IsEntryVisible( pEntry
) )
1847 int bDeselAll
= nFlags
& F_DESEL_ALL
;
1849 SelAllDestrAnch( false, true );
1852 // nFlags &= (~F_DESEL_ALL);
1853 // ShowCursor( false ); // if cursor is moved lower
1854 long nY
= GetEntryLine( pEntry
);
1855 bool bEntryVisible
= IsLineVisible( nY
);
1858 ShowCursor( false ); // if cursor is moved lower
1859 nY
-= pView
->GetEntryHeight(); // because of lines
1860 InvalidateEntriesFrom( nY
);
1862 else if( pStartEntry
&& nY
< GetEntryLine(pStartEntry
) )
1864 // Check if the view is filled completely. If not, then adjust
1865 // pStartEntry and the Cursor (automatic scrolling).
1866 sal_uInt16 nLast
= (sal_uInt16
)(pView
->GetVisiblePos(pView
->LastVisible()));
1867 sal_uInt16 nThumb
= (sal_uInt16
)(pView
->GetVisiblePos( pStartEntry
));
1868 sal_uInt16 nCurDispEntries
= nLast
-nThumb
+1;
1869 if( nCurDispEntries
< nVisibleCount
)
1871 // set at the next paint event
1874 pView
->Invalidate();
1877 else if( !pStartEntry
)
1878 pView
->Invalidate();
1880 SetMostRight( pEntry
);
1881 aVerSBar
->SetRange( Range(0, pView
->GetVisibleCount()-1));
1882 SyncVerThumb(); // if something was inserted before the thumb
1885 if( pStartEntry
!= pView
->First() && (nFlags
& F_FILLING
) )
1892 // ********************************************************************
1894 // ********************************************************************
1897 // ****** Control the control animation
1899 bool SvImpLBox::ButtonDownCheckCtrl(const MouseEvent
& rMEvt
, SvTreeListEntry
* pEntry
, long /*nY*/)
1901 SvLBoxItem
* pItem
= pView
->GetItem(pEntry
,rMEvt
.GetPosPixel().X(),&pActiveTab
);
1902 if (pItem
&& pItem
->GetType() == SV_ITEM_ID_LBOXBUTTON
)
1904 pActiveButton
= static_cast<SvLBoxButton
*>(pItem
);
1905 pActiveEntry
= pEntry
;
1906 if( pCursor
== pActiveEntry
)
1908 pView
->CaptureMouse();
1909 pActiveButton
->SetStateHilighted( true );
1910 InvalidateEntry(pActiveEntry
);
1918 bool SvImpLBox::MouseMoveCheckCtrl(const MouseEvent
& rMEvt
, SvTreeListEntry
* pEntry
)
1922 long nMouseX
= rMEvt
.GetPosPixel().X();
1923 if( pEntry
== pActiveEntry
&&
1924 pView
->GetItem(pActiveEntry
, nMouseX
) == pActiveButton
)
1926 if( !pActiveButton
->IsStateHilighted() )
1928 pActiveButton
->SetStateHilighted(true );
1929 InvalidateEntry(pActiveEntry
);
1934 if( pActiveButton
->IsStateHilighted() )
1936 pActiveButton
->SetStateHilighted(false );
1937 InvalidateEntry(pActiveEntry
);
1945 bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent
& rMEvt
)
1949 pView
->ReleaseMouse();
1950 SvTreeListEntry
* pEntry
= GetClickedEntry( rMEvt
.GetPosPixel() );
1951 pActiveButton
->SetStateHilighted( false );
1952 long nMouseX
= rMEvt
.GetPosPixel().X();
1953 if (pEntry
== pActiveEntry
&& pView
->GetItem(pActiveEntry
, nMouseX
) == pActiveButton
)
1954 pActiveButton
->ClickHdl(pView
, pActiveEntry
);
1955 InvalidateEntry(pActiveEntry
);
1956 if (pCursor
== pActiveEntry
)
1966 // ******* Control plus/minus button for expanding/collapsing
1968 // false == no expand/collapse button hit
1969 bool SvImpLBox::IsNodeButton( const Point
& rPosPixel
, SvTreeListEntry
* pEntry
) const
1971 if( !pEntry
->HasChildren() && !pEntry
->HasChildrenOnDemand() )
1974 SvLBoxTab
* pFirstDynamicTab
= pView
->GetFirstDynamicTab();
1975 if( !pFirstDynamicTab
)
1978 long nMouseX
= rPosPixel
.X();
1979 // convert to document coordinates
1980 Point
aOrigin( pView
->GetMapMode().GetOrigin() );
1981 nMouseX
-= aOrigin
.X();
1983 long nX
= pView
->GetTabPos( pEntry
, pFirstDynamicTab
);
1984 nX
+= nNodeBmpTabDistance
;
1987 nX
+= nNodeBmpWidth
;
1993 // false == hit no node button
1994 bool SvImpLBox::ButtonDownCheckExpand( const MouseEvent
& rMEvt
, SvTreeListEntry
* pEntry
, long /* nY */ )
1998 if ( pView
->IsEditingActive() && pEntry
== pView
->pEdEntry
)
1999 // inplace editing -> nothing to do
2001 else if ( IsNodeButton( rMEvt
.GetPosPixel(), pEntry
) )
2003 if ( pView
->IsExpanded( pEntry
) )
2005 pView
->EndEditing( true );
2006 pView
->Collapse( pEntry
);
2010 // you can expand an entry, which is in editing
2011 pView
->Expand( pEntry
);
2019 void SvImpLBox::MouseButtonDown( const MouseEvent
& rMEvt
)
2021 if ( !rMEvt
.IsLeft() && !rMEvt
.IsRight())
2025 Point
aPos( rMEvt
.GetPosPixel());
2027 if( aPos
.X() > aOutputSize
.Width() || aPos
.Y() > aOutputSize
.Height() )
2030 SvTreeListEntry
* pEntry
= GetEntry( aPos
);
2031 if ( pEntry
!= pCursor
)
2032 // new entry selected -> reset current tab position to first tab
2033 nCurTabPos
= FIRST_ENTRY_TAB
;
2034 nFlags
&= (~F_FILLING
);
2036 //fdo#82270 Grabbing focus can invalidate the entries, re-fetch
2037 pEntry
= GetEntry(aPos
);
2038 // the entry can still be invalid!
2039 if( !pEntry
|| !pView
->GetViewData( pEntry
))
2042 long nY
= GetEntryLine( pEntry
);
2044 if( ButtonDownCheckExpand( rMEvt
, pEntry
, nY
) )
2047 if( !EntryReallyHit(pEntry
,aPos
,nY
))
2050 SvLBoxItem
* pXItem
= pView
->GetItem( pEntry
, aPos
.X() );
2053 SvLBoxTab
* pXTab
= pView
->GetTab( pEntry
, pXItem
);
2054 if ( !rMEvt
.IsMod1() && !rMEvt
.IsMod2() && rMEvt
.IsLeft() && pXTab
->IsEditable()
2055 && pEntry
== pView
->FirstSelected() && NULL
== pView
->NextSelected( pEntry
) )
2056 // #i8234# FirstSelected() and NextSelected() ensures, that inplace editing is only triggered, when only one entry is selected
2057 nFlags
|= F_START_EDITTIMER
;
2058 if ( !pView
->IsSelected( pEntry
) )
2059 nFlags
&= ~F_START_EDITTIMER
;
2063 if( (rMEvt
.GetClicks() % 2) == 0 )
2065 nFlags
&= (~F_START_EDITTIMER
);
2066 pView
->pHdlEntry
= pEntry
;
2067 if( pView
->DoubleClickHdl() )
2069 // if the entry was deleted within the handler
2070 pEntry
= GetClickedEntry( aPos
);
2073 if( pEntry
!= pView
->pHdlEntry
)
2075 // select anew & bye
2076 if( !bSimpleTravel
&& !aSelEng
.IsAlwaysAdding())
2077 SelAllDestrAnch( false, true ); // DeselectAll();
2078 SetCursor( pEntry
);
2082 if( pEntry
->HasChildren() || pEntry
->HasChildrenOnDemand() )
2084 if( pView
->IsExpanded(pEntry
) )
2085 pView
->Collapse( pEntry
);
2087 pView
->Expand( pEntry
);
2088 if( pEntry
== pCursor
) // only if Entryitem was clicked
2089 // (Nodebutton is not an Entryitem!)
2090 pView
->Select( pCursor
, true );
2097 // CheckButton? (TreeListBox: Check + Info)
2098 if( ButtonDownCheckCtrl(rMEvt
, pEntry
, nY
) )
2102 if ( aSelEng
.GetSelectionMode() != NO_SELECTION
)
2103 aSelEng
.SelMouseButtonDown( rMEvt
);
2106 void SvImpLBox::MouseButtonUp( const MouseEvent
& rMEvt
)
2108 if ( !ButtonUpCheckCtrl( rMEvt
) && ( aSelEng
.GetSelectionMode() != NO_SELECTION
) )
2109 aSelEng
.SelMouseButtonUp( rMEvt
);
2111 if( nFlags
& F_START_EDITTIMER
)
2113 nFlags
&= (~F_START_EDITTIMER
);
2114 aEditClickPos
= rMEvt
.GetPosPixel();
2121 void SvImpLBox::MouseMove( const MouseEvent
& rMEvt
)
2123 SvTreeListEntry
* pEntry
= GetClickedEntry( rMEvt
.GetPosPixel() );
2124 if ( !MouseMoveCheckCtrl( rMEvt
, pEntry
) && ( aSelEng
.GetSelectionMode() != NO_SELECTION
) )
2125 aSelEng
.SelMouseMove( rMEvt
);
2129 bool SvImpLBox::KeyInput( const KeyEvent
& rKEvt
)
2132 const vcl::KeyCode
& rKeyCode
= rKEvt
.GetKeyCode();
2134 if( rKeyCode
.IsMod2() )
2135 return false; // don't evaluate Alt key
2137 nFlags
&= (~F_FILLING
);
2140 pCursor
= pStartEntry
;
2144 bool bKeyUsed
= true;
2146 sal_uInt16 nDelta
= (sal_uInt16
)aVerSBar
->GetPageSize();
2147 sal_uInt16 aCode
= rKeyCode
.GetCode();
2149 bool bShift
= rKeyCode
.IsShift();
2150 bool bMod1
= rKeyCode
.IsMod1();
2152 SvTreeListEntry
* pNewCursor
;
2154 const WinBits nWindowStyle
= pView
->GetStyle();
2158 if( !IsEntryInView( pCursor
) )
2159 MakeVisible( pCursor
);
2161 pNewCursor
= pCursor
;
2164 pNewCursor
= pView
->PrevVisible(pNewCursor
);
2165 } while( pNewCursor
&& !IsSelectable(pNewCursor
) );
2168 // new entry selected -> reset current tab position to first tab
2169 nCurTabPos
= FIRST_ENTRY_TAB
;
2170 // if there is no next entry, take the current one
2171 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
2173 if ( !pNewCursor
&& pCursor
)
2174 pNewCursor
= pCursor
;
2178 aSelEng
.CursorPosChanging( bShift
, bMod1
);
2179 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
2180 if( !IsEntryInView( pNewCursor
) )
2186 if( !IsEntryInView( pCursor
) )
2187 MakeVisible( pCursor
);
2189 pNewCursor
= pCursor
;
2192 pNewCursor
= pView
->NextVisible(pNewCursor
);
2193 } while( pNewCursor
&& !IsSelectable(pNewCursor
) );
2196 // new entry selected -> reset current tab position to first tab
2197 nCurTabPos
= FIRST_ENTRY_TAB
;
2199 // if there is no next entry, take the current one
2200 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
2202 // 06.09.20001 - 83416 - frank.schoenheit@sun.com
2203 if ( !pNewCursor
&& pCursor
)
2204 pNewCursor
= pCursor
;
2208 aSelEng
.CursorPosChanging( bShift
, bMod1
);
2209 if( IsEntryInView( pNewCursor
) )
2210 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
2214 pView
->Select( pCursor
, false );
2216 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
2220 KeyDown( false ); // because scrollbar range might still
2228 // only try to expand if sublist is expandable,
2229 // otherwise ignore the key press
2230 if( IsNowExpandable() )
2231 pView
->Expand( pCursor
);
2233 else if ( bIsCellFocusEnabled
&& pCursor
)
2235 if ( nCurTabPos
< ( pView
->TabCount() - 1 /*!2*/ ) )
2239 CallEventListeners( VCLEVENT_LISTBOX_SELECT
, pCursor
);
2242 else if( nWindowStyle
& WB_HSCROLL
)
2244 long nThumb
= aHorSBar
->GetThumbPos();
2245 nThumb
+= aHorSBar
->GetLineSize();
2246 long nOldThumb
= aHorSBar
->GetThumbPos();
2247 aHorSBar
->SetThumbPos( nThumb
);
2249 nThumb
-= aHorSBar
->GetThumbPos();
2253 KeyLeftRight( nThumb
);
2264 if ( bIsCellFocusEnabled
&& pCursor
)
2266 if ( nCurTabPos
> FIRST_ENTRY_TAB
)
2270 CallEventListeners( VCLEVENT_LISTBOX_SELECT
, pCursor
);
2273 else if ( nWindowStyle
& WB_HSCROLL
)
2275 long nThumb
= aHorSBar
->GetThumbPos();
2276 nThumb
-= aHorSBar
->GetLineSize();
2277 long nOldThumb
= aHorSBar
->GetThumbPos();
2278 aHorSBar
->SetThumbPos( nThumb
);
2280 nThumb
-= aHorSBar
->GetThumbPos();
2283 KeyLeftRight( -nThumb
);
2286 else if( bSubLstOpLR
)
2288 if( IsExpandable() && pView
->IsExpanded( pCursor
) )
2289 pView
->Collapse( pCursor
);
2292 pNewCursor
= pView
->GetParent( pCursor
);
2294 SetCursor( pNewCursor
);
2298 else if( bSubLstOpLR
)
2300 if( IsExpandable() && pView
->IsExpanded( pCursor
) )
2301 pView
->Collapse( pCursor
);
2304 pNewCursor
= pView
->GetParent( pCursor
);
2306 SetCursor( pNewCursor
);
2317 pNewCursor
= pView
->PrevVisible(pCursor
, nDelta
);
2319 while( nDelta
&& pNewCursor
&& !IsSelectable(pNewCursor
) )
2321 pNewCursor
= pView
->NextVisible(pNewCursor
);
2327 DBG_ASSERT(pNewCursor
&& pNewCursor
!=pCursor
, "Cursor?");
2328 aSelEng
.CursorPosChanging( bShift
, bMod1
);
2329 if( IsEntryInView( pNewCursor
) )
2330 SetCursor( pNewCursor
);
2333 SetCursor( pNewCursor
);
2345 pNewCursor
= pView
->NextVisible(pCursor
, nDelta
);
2347 while( nDelta
&& pNewCursor
&& !IsSelectable(pNewCursor
) )
2349 pNewCursor
= pView
->PrevVisible(pNewCursor
);
2353 if( nDelta
&& pNewCursor
)
2355 DBG_ASSERT(pNewCursor
&& pNewCursor
!=pCursor
, "Cursor?");
2356 aSelEng
.CursorPosChanging( bShift
, bMod1
);
2357 if( IsEntryInView( pNewCursor
) )
2358 SetCursor( pNewCursor
);
2361 SetCursor( pNewCursor
);
2366 KeyDown( false ); // see also: KEY_DOWN
2373 if ( pView
->GetSelectionMode() != NO_SELECTION
)
2377 if ( pView
->GetSelectionMode() == MULTIPLE_SELECTION
&& !bShift
)
2379 pView
->Select( pCursor
, !pView
->IsSelected( pCursor
) );
2381 else if ( !bShift
/*&& !bMod1*/ )
2383 if ( aSelEng
.IsAddMode() )
2386 pView
->Select( pCursor
, !pView
->IsSelected( pCursor
) );
2388 else if ( !pView
->IsSelected( pCursor
) )
2390 SelAllDestrAnch( false );
2391 pView
->Select( pCursor
, true );
2404 if( bSubLstOpRet
&& IsExpandable() )
2406 if( pView
->IsExpanded( pCursor
) )
2407 pView
->Collapse( pCursor
);
2409 pView
->Expand( pCursor
);
2416 if( !bShift
&& !bMod1
)
2418 aEditClickPos
= Point( -1, -1 );
2426 if( bShift
&& pView
->GetSelectionMode()==MULTIPLE_SELECTION
&&
2427 !(m_nStyle
& WB_SIMPLEMODE
))
2429 if( aSelEng
.IsAlwaysAdding() )
2430 aSelEng
.AddAlways( false );
2432 aSelEng
.AddAlways( true );
2441 if( !pView
->IsExpanded(pCursor
))
2442 pView
->Expand( pCursor
);
2445 sal_uInt16 nRefDepth
= pTree
->GetDepth( pCursor
);
2446 SvTreeListEntry
* pCur
= pTree
->Next( pCursor
);
2447 while( pCur
&& pTree
->GetDepth(pCur
) > nRefDepth
)
2449 if( pCur
->HasChildren() && !pView
->IsExpanded(pCur
))
2450 pView
->Expand( pCur
);
2451 pCur
= pTree
->Next( pCur
);
2461 SelAllDestrAnch( true );
2469 if( pView
->IsExpanded(pCursor
))
2470 pView
->Collapse( pCursor
);
2473 // collapse all parents until we get to the root
2474 SvTreeListEntry
* pParentToCollapse
= pTree
->GetRootLevelParent(pCursor
);
2475 if( pParentToCollapse
)
2477 sal_uInt16 nRefDepth
;
2478 // special case explorer: if the root only has a single
2479 // entry, don't collapse the root entry
2480 if (pTree
->GetChildList(0).size() < 2)
2483 pParentToCollapse
= pCursor
;
2484 while( pTree
->GetParent(pParentToCollapse
) &&
2485 pTree
->GetDepth( pTree
->GetParent(pParentToCollapse
)) > 0)
2487 pParentToCollapse
= pTree
->GetParent(pParentToCollapse
);
2493 if( pView
->IsExpanded(pParentToCollapse
) )
2494 pView
->Collapse( pParentToCollapse
);
2495 SvTreeListEntry
* pCur
= pTree
->Next( pParentToCollapse
);
2496 while( pCur
&& pTree
->GetDepth(pCur
) > nRefDepth
)
2498 if( pCur
->HasChildren() && pView
->IsExpanded(pCur
) )
2499 pView
->Collapse( pCur
);
2500 pCur
= pTree
->Next( pCur
);
2511 SelAllDestrAnch( true );
2518 SelAllDestrAnch( false );
2524 pNewCursor
= pView
->GetModel()->First();
2526 while( pNewCursor
&& !IsSelectable(pNewCursor
) )
2528 pNewCursor
= pView
->NextVisible(pNewCursor
);
2531 if( pNewCursor
&& pNewCursor
!= pCursor
)
2533 // SelAllDestrAnch( false );
2534 aSelEng
.CursorPosChanging( bShift
, bMod1
);
2535 SetCursor( pNewCursor
);
2536 if( !IsEntryInView( pNewCursor
) )
2537 MakeVisible( pNewCursor
);
2544 pNewCursor
= pView
->GetModel()->Last();
2546 while( pNewCursor
&& !IsSelectable(pNewCursor
) )
2548 pNewCursor
= pView
->PrevVisible(pNewCursor
);
2551 if( pNewCursor
&& pNewCursor
!= pCursor
)
2553 // SelAllDestrAnch( false );
2554 aSelEng
.CursorPosChanging( bShift
, bMod1
);
2555 SetCursor( pNewCursor
);
2556 if( !IsEntryInView( pNewCursor
) )
2557 MakeVisible( pNewCursor
);
2567 // must not be handled because this quits dialogs and does other magic things...
2568 // if there are other single keys which should not be handled, they can be added here
2573 // is there any reason why we should eat the events here? The only place where this is called
2574 // is from SvTreeListBox::KeyInput. If we set bKeyUsed to true here, then the key input
2575 // is just silenced. However, we want SvLBox::KeyInput to get a chance, to do the QuickSelection
2577 // (The old code here which intentionally set bKeyUsed to sal_True said this was because of "quick search"
2578 // handling, but actually there was no quick search handling anymore. We just re-implemented it.)
2579 // #i31275# / 2009-06-16 / frank.schoenheit@sun.com
2586 void SvImpLBox::GetFocus()
2590 pView
->SetEntryFocus( pCursor
, true );
2592 // auskommentiert wg. deselectall
2593 // if( bSimpleTravel && !pView->IsSelected(pCursor) )
2594 // pView->Select( pCursor, true );
2596 if( m_nStyle
& WB_HIDESELECTION
)
2598 SvTreeListEntry
* pEntry
= pView
->FirstSelected();
2601 InvalidateEntry( pEntry
);
2602 pEntry
= pView
->NextSelected( pEntry
);
2607 void SvImpLBox::LoseFocus()
2611 pView
->SetEntryFocus( pCursor
,false );
2612 ShowCursor( false );
2614 if( m_nStyle
& WB_HIDESELECTION
)
2616 SvTreeListEntry
* pEntry
= pView
? pView
->FirstSelected() : NULL
;
2619 InvalidateEntry( pEntry
);
2620 pEntry
= pView
->NextSelected( pEntry
);
2626 // ********************************************************************
2628 // ********************************************************************
2630 void SvImpLBox::SelectEntry( SvTreeListEntry
* pEntry
, bool bSelect
)
2632 pView
->Select( pEntry
, bSelect
);
2635 ImpLBSelEng::ImpLBSelEng( SvImpLBox
* pImpl
, SelectionEngine
* pSEng
,
2643 ImpLBSelEng::~ImpLBSelEng()
2647 void ImpLBSelEng::BeginDrag()
2652 void ImpLBSelEng::CreateAnchor()
2654 pImp
->pAnchor
= pImp
->pCursor
;
2657 void ImpLBSelEng::DestroyAnchor()
2662 bool ImpLBSelEng::SetCursorAtPoint(const Point
& rPoint
, bool bDontSelectAtCursor
)
2664 SvTreeListEntry
* pNewCursor
= pImp
->MakePointVisible( rPoint
);
2665 if( pNewCursor
!= pImp
->pCursor
)
2666 pImp
->BeginScroll();
2670 // at SimpleTravel, the SetCursor is selected and the select handler is
2672 //if( !bDontSelectAtCursor && !pImp->bSimpleTravel )
2673 // pImp->SelectEntry( pNewCursor, true );
2674 pImp
->SetCursor( pNewCursor
, bDontSelectAtCursor
);
2680 bool ImpLBSelEng::IsSelectionAtPoint( const Point
& rPoint
)
2682 SvTreeListEntry
* pEntry
= pImp
->MakePointVisible( rPoint
);
2684 return pView
->IsSelected(pEntry
);
2688 void ImpLBSelEng::DeselectAtPoint( const Point
& rPoint
)
2690 SvTreeListEntry
* pEntry
= pImp
->MakePointVisible( rPoint
);
2693 pImp
->SelectEntry( pEntry
, false );
2696 void ImpLBSelEng::DeselectAll()
2698 pImp
->SelAllDestrAnch( false, false ); // don't reset SelectionEngine!
2699 pImp
->nFlags
&= (~F_DESEL_ALL
);
2702 // ***********************************************************************
2704 // ***********************************************************************
2706 void SvImpLBox::SetAnchorSelection(SvTreeListEntry
* pOldCursor
,SvTreeListEntry
* pNewCursor
)
2708 SvTreeListEntry
* pEntry
;
2709 sal_uLong nAnchorVisPos
= pView
->GetVisiblePos( pAnchor
);
2710 sal_uLong nOldVisPos
= pView
->GetVisiblePos( pOldCursor
);
2711 sal_uLong nNewVisPos
= pView
->GetVisiblePos( pNewCursor
);
2713 if( nOldVisPos
> nAnchorVisPos
||
2714 ( nAnchorVisPos
==nOldVisPos
&& nNewVisPos
> nAnchorVisPos
) )
2716 if( nNewVisPos
> nOldVisPos
)
2718 pEntry
= pOldCursor
;
2719 while( pEntry
&& pEntry
!= pNewCursor
)
2721 pView
->Select( pEntry
, true );
2722 pEntry
= pView
->NextVisible(pEntry
);
2725 pView
->Select( pEntry
, true );
2729 if( nNewVisPos
< nAnchorVisPos
)
2732 while( pEntry
&& pEntry
!= pOldCursor
)
2734 pView
->Select( pEntry
, false );
2735 pEntry
= pView
->NextVisible(pEntry
);
2738 pView
->Select( pEntry
, false );
2740 pEntry
= pNewCursor
;
2741 while( pEntry
&& pEntry
!= pAnchor
)
2743 pView
->Select( pEntry
, true );
2744 pEntry
= pView
->NextVisible(pEntry
);
2747 pView
->Select( pEntry
, true );
2751 if( nNewVisPos
< nOldVisPos
)
2753 pEntry
= pNewCursor
;
2754 pEntry
= pView
->NextVisible(pEntry
);
2755 while( pEntry
&& pEntry
!= pOldCursor
)
2757 pView
->Select( pEntry
, false );
2758 pEntry
= pView
->NextVisible(pEntry
);
2761 pView
->Select( pEntry
, false );
2767 if( nNewVisPos
< nOldVisPos
) // enlarge selection
2769 pEntry
= pNewCursor
;
2770 while( pEntry
&& pEntry
!= pOldCursor
)
2772 pView
->Select( pEntry
, true );
2773 pEntry
= pView
->NextVisible(pEntry
);
2776 pView
->Select( pEntry
, true );
2780 if( nNewVisPos
> nAnchorVisPos
)
2782 pEntry
= pOldCursor
;
2783 while( pEntry
&& pEntry
!= pAnchor
)
2785 pView
->Select( pEntry
, false );
2786 pEntry
= pView
->NextVisible(pEntry
);
2789 pView
->Select( pEntry
, false );
2791 while( pEntry
&& pEntry
!= pNewCursor
)
2793 pView
->Select( pEntry
, true );
2794 pEntry
= pView
->NextVisible(pEntry
);
2797 pView
->Select( pEntry
, true );
2801 if( nNewVisPos
> nOldVisPos
)
2803 pEntry
= pOldCursor
;
2804 while( pEntry
&& pEntry
!= pNewCursor
)
2806 pView
->Select( pEntry
, false );
2807 pEntry
= pView
->NextVisible(pEntry
);
2814 void SvImpLBox::SelAllDestrAnch(
2815 bool bSelect
, bool bDestroyAnchor
, bool bSingleSelToo
)
2817 SvTreeListEntry
* pEntry
;
2818 nFlags
&= (~F_DESEL_ALL
);
2819 if( bSelect
&& bSimpleTravel
)
2821 if( pCursor
&& !pView
->IsSelected( pCursor
))
2823 pView
->Select( pCursor
, true );
2827 if( !bSelect
&& pView
->GetSelectionCount() == 0 )
2829 if( bSimpleTravel
&& ( !GetUpdateMode() || !pCursor
) )
2830 nFlags
|= F_DESEL_ALL
;
2833 if( bSelect
&& pView
->GetSelectionCount() == pView
->GetEntryCount())
2835 if( !bSingleSelToo
&& bSimpleTravel
)
2838 if( !bSelect
&& pView
->GetSelectionCount()==1 && pCursor
&&
2839 pView
->IsSelected( pCursor
))
2841 pView
->Select( pCursor
, false );
2842 if( bDestroyAnchor
)
2843 DestroyAnchor(); // delete anchor & reset SelectionEngine
2845 pAnchor
= 0; // always delete internal anchor
2849 if( bSimpleTravel
&& !pCursor
&& !GetUpdateMode() )
2850 nFlags
|= F_DESEL_ALL
;
2852 ShowCursor( false );
2853 bool bUpdate
= GetUpdateMode();
2855 nFlags
|= F_IGNORE_SELECT
; // EntryInserted should not do anything
2856 pEntry
= pTree
->First();
2859 if( pView
->Select( pEntry
, bSelect
) )
2861 if( bUpdate
&& pView
->IsEntryVisible(pEntry
) )
2863 long nY
= GetEntryLine( pEntry
);
2864 if( IsLineVisible( nY
) )
2865 InvalidateEntry(pEntry
);
2868 pEntry
= pTree
->Next( pEntry
);
2870 nFlags
&= ~F_IGNORE_SELECT
;
2872 if( bDestroyAnchor
)
2873 DestroyAnchor(); // delete anchor & reset SelectionEngine
2875 pAnchor
= 0; // always delete internal anchor
2879 void SvImpLBox::SetSelectionMode( SelectionMode eSelMode
)
2881 aSelEng
.SetSelectionMode( eSelMode
);
2882 if( eSelMode
== SINGLE_SELECTION
)
2883 bSimpleTravel
= true;
2885 bSimpleTravel
= false;
2886 if( (m_nStyle
& WB_SIMPLEMODE
) && (eSelMode
== MULTIPLE_SELECTION
) )
2887 aSelEng
.AddAlways( true );
2890 // ***********************************************************************
2892 // ***********************************************************************
2894 void SvImpLBox::SetDragDropMode( DragDropMode eDDMode
)
2896 if( eDDMode
!= DragDropMode::NONE
&& eDDMode
!= DragDropMode::APP_DROP
)
2898 aSelEng
.ExpandSelectionOnMouseMove( false );
2899 aSelEng
.EnableDrag( true );
2903 aSelEng
.ExpandSelectionOnMouseMove( true );
2904 aSelEng
.EnableDrag( false );
2908 void SvImpLBox::BeginDrag()
2910 nFlags
&= (~F_FILLING
);
2911 if( !bAsyncBeginDrag
)
2914 pView
->StartDrag( 0, aSelEng
.GetMousePosPixel() );
2919 aAsyncBeginDragPos
= aSelEng
.GetMousePosPixel();
2920 aAsyncBeginDragIdle
.Start();
2924 IMPL_LINK_NOARG_TYPED(SvImpLBox
, BeginDragHdl
, Idle
*, void)
2926 pView
->StartDrag( 0, aAsyncBeginDragPos
);
2929 void SvImpLBox::PaintDDCursor( SvTreeListEntry
* pInsertionPos
)
2934 nY
= GetEntryLine( pInsertionPos
);
2935 nY
+= pView
->GetEntryHeight();
2939 RasterOp eOldOp
= pView
->GetRasterOp();
2940 pView
->SetRasterOp( ROP_INVERT
);
2941 Color aOldLineColor
= pView
->GetLineColor();
2942 pView
->SetLineColor( Color( COL_BLACK
) );
2943 pView
->DrawLine( Point( 0, nY
), Point( aOutputSize
.Width(), nY
) );
2944 pView
->SetLineColor( aOldLineColor
);
2945 pView
->SetRasterOp( eOldOp
);
2948 // Delete all submenus of a PopupMenu, recursively
2949 static void lcl_DeleteSubPopups(PopupMenu
* pPopup
)
2951 for(sal_uInt16 i
= 0; i
< pPopup
->GetItemCount(); i
++)
2953 PopupMenu
* pSubPopup
= pPopup
->GetPopupMenu( pPopup
->GetItemId( i
));
2956 lcl_DeleteSubPopups(pSubPopup
);
2962 void SvImpLBox::Command( const CommandEvent
& rCEvt
)
2964 CommandEventId nCommand
= rCEvt
.GetCommand();
2966 if( nCommand
== CommandEventId::ContextMenu
)
2969 // scroll mouse event?
2970 if( ( ( nCommand
== CommandEventId::Wheel
) || ( nCommand
== CommandEventId::StartAutoScroll
) || ( nCommand
== CommandEventId::AutoScroll
) )
2971 && pView
->HandleScrollCommand( rCEvt
, aHorSBar
.get(), aVerSBar
.get() ) )
2974 if( bContextMenuHandling
&& nCommand
== CommandEventId::ContextMenu
)
2977 bool bClickedIsFreePlace
= false;
2978 std::stack
<SvTreeListEntry
*> aSelRestore
;
2980 if( rCEvt
.IsMouseEvent() )
2981 { // change selection, if mouse position doesn't fit to selection
2983 aPopupPos
= rCEvt
.GetMousePosPixel();
2985 SvTreeListEntry
* pClickedEntry
= GetEntry( aPopupPos
);
2987 { // mouse in non empty area
2988 bool bClickedIsSelected
= false;
2990 // collect the currently selected entries
2991 SvTreeListEntry
* pSelected
= pView
->FirstSelected();
2994 bClickedIsSelected
|= ( pClickedEntry
== pSelected
);
2995 pSelected
= pView
->NextSelected( pSelected
);
2998 // if the entry which the user clicked at is not selected
2999 if( !bClickedIsSelected
)
3000 { // deselect all other and select the clicked one
3001 pView
->SelectAll( false );
3002 pView
->SetCursor( pClickedEntry
);
3005 else if( aSelEng
.GetSelectionMode() == SINGLE_SELECTION
)
3007 bClickedIsFreePlace
= true;
3008 sal_Int32 nSelectedEntries
= pView
->GetSelectionCount();
3009 SvTreeListEntry
* pSelected
= pView
->FirstSelected();
3010 for(sal_uInt16 nSel
= 0; nSel
< nSelectedEntries
; nSel
++ )
3012 aSelRestore
.push(pSelected
);
3013 pSelected
= pView
->NextSelected( pSelected
);
3015 pView
->SelectAll( false );
3019 pView
->SelectAll( false );
3025 { // key event (or at least no mouse event)
3026 sal_Int32 nSelectionCount
= pView
->GetSelectionCount();
3028 if( nSelectionCount
)
3029 { // now always take first visible as base for positioning the menu
3030 SvTreeListEntry
* pSelected
= pView
->FirstSelected();
3033 if( IsEntryInView( pSelected
) )
3036 pSelected
= pView
->NextSelected( pSelected
);
3041 // no one was visible
3042 pSelected
= pView
->FirstSelected();
3043 pView
->MakeVisible( pSelected
);
3046 aPopupPos
= pView
->GetFocusRect( pSelected
, pView
->GetEntryPosition( pSelected
).Y() ).Center();
3049 aPopupPos
= Point( 0, 0 );
3052 PopupMenu
* pPopup
= pView
->CreateContextMenu();
3056 // do action for selected entry in popup menu
3057 sal_uInt16 nMenuAction
= pPopup
->Execute( pView
, aPopupPos
);
3059 pView
->ExcecuteContextMenuAction( nMenuAction
);
3060 lcl_DeleteSubPopups(pPopup
);
3064 if( bClickedIsFreePlace
)
3066 while(!aSelRestore
.empty())
3068 SvTreeListEntry
* pEntry
= aSelRestore
.top();
3069 //#i19717# the entry is maybe already deleted
3070 bool bFound
= false;
3071 for(sal_uLong nEntry
= 0; nEntry
< pView
->GetEntryCount(); nEntry
++)
3072 if(pEntry
== pView
->GetEntry(nEntry
))
3078 SetCurEntry( pEntry
);
3086 const Point
& rPos
= rCEvt
.GetMousePosPixel();
3087 if( rPos
.X() < aOutputSize
.Width() && rPos
.Y() < aOutputSize
.Height() )
3088 aSelEng
.Command( rCEvt
);
3093 void SvImpLBox::BeginScroll()
3095 if( !(nFlags
& F_IN_SCROLLING
))
3097 nFlags
|= F_IN_SCROLLING
;
3101 void SvImpLBox::EndScroll()
3103 if( nFlags
& F_IN_SCROLLING
)
3105 pView
->NotifyEndScroll();
3106 nFlags
&= (~F_IN_SCROLLING
);
3111 Rectangle
SvImpLBox::GetVisibleArea() const
3113 Point
aPos( pView
->GetMapMode().GetOrigin() );
3115 Rectangle
aRect( aPos
, aOutputSize
);
3119 void SvImpLBox::Invalidate()
3121 pView
->SetClipRegion();
3124 void SvImpLBox::SetCurEntry( SvTreeListEntry
* pEntry
)
3126 if ( ( aSelEng
.GetSelectionMode() != SINGLE_SELECTION
)
3127 && ( aSelEng
.GetSelectionMode() != NO_SELECTION
)
3129 SelAllDestrAnch( false, true, false );
3131 MakeVisible( pEntry
);
3132 SetCursor( pEntry
);
3133 if ( pEntry
&& ( aSelEng
.GetSelectionMode() != NO_SELECTION
) )
3134 pView
->Select( pEntry
, true );
3137 IMPL_LINK_NOARG_TYPED(SvImpLBox
, EditTimerCall
, Idle
*, void)
3139 if( pView
->IsInplaceEditingEnabled() )
3141 bool bIsMouseTriggered
= aEditClickPos
.X() >= 0;
3142 if ( bIsMouseTriggered
)
3144 Point aCurrentMousePos
= pView
->GetPointerPosPixel();
3145 if ( ( std::abs( aCurrentMousePos
.X() - aEditClickPos
.X() ) > 5 )
3146 || ( std::abs( aCurrentMousePos
.Y() - aEditClickPos
.Y() ) > 5 )
3153 SvTreeListEntry
* pEntry
= GetCurEntry();
3156 ShowCursor( false );
3157 pView
->ImplEditEntry( pEntry
);
3163 bool SvImpLBox::RequestHelp( const HelpEvent
& rHEvt
)
3165 if( rHEvt
.GetMode() & HelpEventMode::QUICK
)
3167 Point
aPos( pView
->ScreenToOutputPixel( rHEvt
.GetMousePosPixel() ));
3168 if( !GetVisibleArea().IsInside( aPos
))
3171 SvTreeListEntry
* pEntry
= GetEntry( aPos
);
3174 // recalculate text rectangle
3176 SvLBoxItem
* pItem
= pView
->GetItem( pEntry
, aPos
.X(), &pTab
);
3177 if (!pItem
|| pItem
->GetType() != SV_ITEM_ID_LBOXSTRING
)
3180 aPos
= GetEntryPosition( pEntry
);
3181 aPos
.X() = pView
->GetTabPos( pEntry
, pTab
); //pTab->GetPos();
3182 Size
aSize( pItem
->GetSize( pView
, pEntry
) );
3183 SvLBoxTab
* pNextTab
= NextTab( pTab
);
3184 bool bItemClipped
= false;
3185 // is the item cut off by its right neighbor?
3186 if( pNextTab
&& pView
->GetTabPos(pEntry
,pNextTab
) < aPos
.X()+aSize
.Width() )
3188 aSize
.Width() = pNextTab
->GetPos() - pTab
->GetPos();
3189 bItemClipped
= true;
3191 Rectangle
aItemRect( aPos
, aSize
);
3193 Rectangle
aViewRect( GetVisibleArea() );
3195 if( bItemClipped
|| !aViewRect
.IsInside( aItemRect
) )
3197 // clip the right edge of the item at the edge of the view
3198 //if( aItemRect.Right() > aViewRect.Right() )
3199 // aItemRect.Right() = aViewRect.Right();
3201 Point aPt
= pView
->OutputToScreenPixel( aItemRect
.TopLeft() );
3202 aItemRect
.Left() = aPt
.X();
3203 aItemRect
.Top() = aPt
.Y();
3204 aPt
= pView
->OutputToScreenPixel( aItemRect
.BottomRight() );
3205 aItemRect
.Right() = aPt
.X();
3206 aItemRect
.Bottom() = aPt
.Y();
3208 Help::ShowQuickHelp( pView
, aItemRect
,
3209 static_cast<SvLBoxString
*>(pItem
)->GetText(), QuickHelpFlags::Left
| QuickHelpFlags::VCenter
);
3217 SvLBoxTab
* SvImpLBox::NextTab( SvLBoxTab
* pTab
)
3219 sal_uInt16 nTabCount
= pView
->TabCount();
3220 if( nTabCount
<= 1 )
3222 for( sal_uInt16 nTab
=0; nTab
< (nTabCount
-1); nTab
++)
3224 if( pView
->aTabs
[nTab
]==pTab
)
3225 return (SvLBoxTab
*)(pView
->aTabs
[nTab
+1]);
3230 void SvImpLBox::EndSelection()
3233 nFlags
&= ~F_START_EDITTIMER
;
3236 void SvImpLBox::SetUpdateMode( bool bMode
)
3238 if( bUpdateMode
!= bMode
)
3240 bUpdateMode
= bMode
;
3246 bool SvImpLBox::SetMostRight( SvTreeListEntry
* pEntry
)
3248 if( pView
->nTreeFlags
& SvTreeFlags::RECALCTABS
)
3250 nFlags
|= F_IGNORE_CHANGED_TABS
;
3252 nFlags
&= ~F_IGNORE_CHANGED_TABS
;
3255 sal_uInt16 nLastTab
= pView
->aTabs
.size() - 1;
3256 sal_uInt16 nLastItem
= pEntry
->ItemCount() - 1;
3257 if( !pView
->aTabs
.empty() && nLastItem
!= USHRT_MAX
)
3259 if( nLastItem
< nLastTab
)
3260 nLastTab
= nLastItem
;
3262 SvLBoxTab
* pTab
= pView
->aTabs
[ nLastTab
];
3263 SvLBoxItem
* pItem
= pEntry
->GetItem( nLastTab
);
3265 long nTabPos
= pView
->GetTabPos( pEntry
, pTab
);
3267 long nMaxRight
= GetOutputSize().Width();
3268 Point
aPos( pView
->GetMapMode().GetOrigin() );
3269 aPos
.X() *= -1; // conversion document coordinates
3270 nMaxRight
= nMaxRight
+ aPos
.X() - 1;
3272 long nNextTab
= nTabPos
< nMaxRight
? nMaxRight
: nMaxRight
+ 50;
3273 long nTabWidth
= nNextTab
- nTabPos
+ 1;
3274 long nItemSize
= pItem
->GetSize(pView
,pEntry
).Width();
3275 long nOffset
= pTab
->CalcOffset( nItemSize
, nTabWidth
);
3277 long nRight
= nTabPos
+ nOffset
+ nItemSize
;
3278 if( nRight
> nMostRight
)
3280 nMostRight
= nRight
;
3281 pMostRightEntry
= pEntry
;
3288 void SvImpLBox::FindMostRight( SvTreeListEntry
* pEntryToIgnore
)
3291 pMostRightEntry
= 0;
3292 if( !pView
->GetModel() )
3295 SvTreeListEntry
* pEntry
= pView
->FirstVisible();
3298 if( pEntry
!= pEntryToIgnore
)
3299 SetMostRight( pEntry
);
3300 pEntry
= pView
->NextVisible( pEntry
);
3304 void SvImpLBox::FindMostRight( SvTreeListEntry
* pParent
, SvTreeListEntry
* pEntryToIgnore
)
3307 FindMostRight( pEntryToIgnore
);
3309 FindMostRight_Impl( pParent
, pEntryToIgnore
);
3312 void SvImpLBox::FindMostRight_Impl( SvTreeListEntry
* pParent
, SvTreeListEntry
* pEntryToIgnore
)
3314 SvTreeListEntries
& rList
= pTree
->GetChildList( pParent
);
3316 size_t nCount
= rList
.size();
3317 for( size_t nCur
= 0; nCur
< nCount
; nCur
++ )
3319 SvTreeListEntry
* pChild
= &rList
[nCur
];
3320 if( pChild
!= pEntryToIgnore
)
3322 SetMostRight( pChild
);
3323 if( pChild
->HasChildren() && pView
->IsExpanded( pChild
))
3324 FindMostRight_Impl( pChild
, pEntryToIgnore
);
3329 void SvImpLBox::NotifyTabsChanged()
3331 if( GetUpdateMode() && !(nFlags
& F_IGNORE_CHANGED_TABS
) &&
3332 nCurUserEvent
== 0 )
3334 nCurUserEvent
= Application::PostUserEvent(LINK(this,SvImpLBox
,MyUserEvent
),(void*)0);
3338 bool SvImpLBox::IsExpandable() const
3340 return pCursor
->HasChildren() || pCursor
->HasChildrenOnDemand();
3343 bool SvImpLBox::IsNowExpandable() const
3345 return IsExpandable() && !pView
->IsExpanded( pCursor
);
3348 IMPL_LINK(SvImpLBox
, MyUserEvent
, void*, pArg
)
3353 pView
->Invalidate();
3360 pView
->Invalidate( GetVisibleArea() );
3366 void SvImpLBox::StopUserEvent()
3368 if( nCurUserEvent
!= 0 )
3370 Application::RemoveUserEvent( nCurUserEvent
);
3375 void SvImpLBox::ShowFocusRect( const SvTreeListEntry
* pEntry
)
3379 long nY
= GetEntryLine( const_cast<SvTreeListEntry
*>(pEntry
) );
3380 Rectangle aRect
= pView
->GetFocusRect( const_cast<SvTreeListEntry
*>(pEntry
), nY
);
3381 vcl::Region
aOldClip( pView
->GetClipRegion());
3382 vcl::Region
aClipRegion( GetClipRegionRect() );
3383 pView
->SetClipRegion( aClipRegion
);
3384 pView
->ShowFocus( aRect
);
3385 pView
->SetClipRegion( aOldClip
);
3395 void SvImpLBox::implInitDefaultNodeImages()
3397 if ( s_pDefCollapsed
)
3398 // assume that all or nothing is initialized
3401 s_pDefCollapsed
= new Image( SvtResId( RID_IMG_TREENODE_COLLAPSED
) );
3402 s_pDefExpanded
= new Image( SvtResId( RID_IMG_TREENODE_EXPANDED
) );
3406 const Image
& SvImpLBox::GetDefaultExpandedNodeImage( )
3408 implInitDefaultNodeImages();
3409 return *s_pDefExpanded
;
3413 const Image
& SvImpLBox::GetDefaultCollapsedNodeImage( )
3415 implInitDefaultNodeImages();
3416 return *s_pDefCollapsed
;
3420 void SvImpLBox::CallEventListeners( sal_uLong nEvent
, void* pData
)
3423 pView
->CallImplEventListeners( nEvent
, pData
);
3428 bool SvImpLBox::SetCurrentTabPos( sal_uInt16 _nNewPos
)
3432 if ( pView
&& _nNewPos
< ( pView
->TabCount() - 2 ) )
3434 nCurTabPos
= _nNewPos
;
3444 bool SvImpLBox::IsSelectable( const SvTreeListEntry
* pEntry
)
3448 SvViewDataEntry
* pViewDataNewCur
= pView
->GetViewDataEntry(const_cast<SvTreeListEntry
*>(pEntry
));
3449 return (pViewDataNewCur
== 0) || pViewDataNewCur
->IsSelectable();
3457 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */