GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / svtools / source / contnr / svimpbox.cxx
blob0099dd22a9c0ab653dd6245ca61b971a1a103c1d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
24 #include <stack>
26 #include <svtools/treelistbox.hxx>
27 #include <svtools/svlbitm.hxx>
28 #include <svimpbox.hxx>
29 #include <rtl/instance.hxx>
30 #include <svtools/svtresid.hxx>
31 #include <tools/wintypes.hxx>
32 #include <svtools/svtools.hrc>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/string.hxx>
36 #include "svtools/treelistentry.hxx"
37 #include "svtools/viewdataentry.hxx"
39 #define NODE_BMP_TABDIST_NOTVALID -2000000
40 #define FIRST_ENTRY_TAB 1
42 // #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors
43 Image* SvImpLBox::s_pDefCollapsed = NULL;
44 Image* SvImpLBox::s_pDefExpanded = NULL;
45 sal_Int32 SvImpLBox::s_nImageRefCount = 0;
47 SvImpLBox::SvImpLBox( SvTreeListBox* pLBView, SvTreeList* pLBTree, WinBits nWinStyle) :
49 aVerSBar( pLBView, WB_DRAG | WB_VSCROLL ),
50 aHorSBar( pLBView, WB_DRAG | WB_HSCROLL ),
51 aScrBarBox( pLBView ),
52 aOutputSize( 0, 0 ),
53 aSelEng( pLBView, (FunctionSet*)0 ),
54 aFctSet( this, &aSelEng, pLBView ),
55 nExtendedWinBits( 0 ),
56 bAreChildrenTransient( true ),
57 m_pStringSorter(NULL)
59 osl_atomic_increment(&s_nImageRefCount);
60 pView = pLBView;
61 pTree = pLBTree;
62 aSelEng.SetFunctionSet( (FunctionSet*)&aFctSet );
63 aSelEng.ExpandSelectionOnMouseMove( false );
64 SetStyle( nWinStyle );
65 SetSelectionMode( SINGLE_SELECTION );
66 SetDragDropMode( 0 );
68 aVerSBar.SetScrollHdl( LINK( this, SvImpLBox, ScrollUpDownHdl ) );
69 aHorSBar.SetScrollHdl( LINK( this, SvImpLBox, ScrollLeftRightHdl ) );
70 aHorSBar.SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) );
71 aVerSBar.SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl ) );
72 aVerSBar.SetRange( Range(0,0) );
73 aVerSBar.Hide();
74 aHorSBar.SetRange( Range(0,0) );
75 aHorSBar.SetPageSize( 24 ); // pixels
76 aHorSBar.SetLineSize( 8 ); // pixels
78 nHorSBarHeight = (short)aHorSBar.GetSizePixel().Height();
79 nVerSBarWidth = (short)aVerSBar.GetSizePixel().Width();
81 pStartEntry = 0;
82 pCursor = 0;
83 pAnchor = 0;
84 nVisibleCount = 0; // number of rows of data in control
85 nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID;
86 nYoffsNodeBmp = 0;
87 nNodeBmpWidth = 0;
89 bAsyncBeginDrag = false;
90 aAsyncBeginDragTimer.SetTimeout( 0 );
91 aAsyncBeginDragTimer.SetTimeoutHdl( LINK(this,SvImpLBox,BeginDragHdl));
92 // button animation in listbox
93 pActiveButton = 0;
94 pActiveEntry = 0;
95 pActiveTab = 0;
97 nFlags = 0;
98 nCurTabPos = FIRST_ENTRY_TAB;
100 aEditTimer.SetTimeout( 800 );
101 aEditTimer.SetTimeoutHdl( LINK(this,SvImpLBox,EditTimerCall) );
103 nMostRight = -1;
104 pMostRightEntry = 0;
105 nCurUserEvent = 0xffffffff;
107 bUpdateMode = true;
108 bInVScrollHdl = false;
109 nFlags |= F_FILLING;
111 bSubLstOpRet = bSubLstOpLR = bContextMenuHandling = bIsCellFocusEnabled = false;
114 SvImpLBox::~SvImpLBox()
116 aEditTimer.Stop();
117 StopUserEvent();
119 delete m_pStringSorter;
120 if ( osl_atomic_decrement(&s_nImageRefCount) == 0 )
122 DELETEZ(s_pDefCollapsed);
123 DELETEZ(s_pDefExpanded);
127 void SvImpLBox::UpdateStringSorter()
129 const ::com::sun::star::lang::Locale& rNewLocale = Application::GetSettings().GetLanguageTag().getLocale();
131 if( m_pStringSorter )
133 // different Locale from the older one, drop it and force recreate
134 const ::com::sun::star::lang::Locale &aLocale = m_pStringSorter->getLocale();
135 if( aLocale.Language != rNewLocale.Language ||
136 aLocale.Country != rNewLocale.Country ||
137 aLocale.Variant != rNewLocale.Variant )
139 delete m_pStringSorter;
140 m_pStringSorter = NULL;
144 if( !m_pStringSorter )
146 m_pStringSorter = new comphelper::string::NaturalStringSorter(
147 ::comphelper::getProcessComponentContext(),
148 rNewLocale);
152 // #97680# ----------------------
153 short SvImpLBox::UpdateContextBmpWidthVector( SvTreeListEntry* pEntry, short nWidth )
155 DBG_ASSERT( pView->pModel, "View and Model aren't valid!" );
157 sal_uInt16 nDepth = pView->pModel->GetDepth( pEntry );
158 // initialize vector if necessary
159 std::vector< short >::size_type nSize = aContextBmpWidthVector.size();
160 while ( nDepth > nSize )
162 aContextBmpWidthVector.resize( nSize + 1 );
163 aContextBmpWidthVector.at( nSize ) = nWidth;
164 ++nSize;
166 if( aContextBmpWidthVector.size() == nDepth )
168 aContextBmpWidthVector.resize( nDepth + 1 );
169 aContextBmpWidthVector.at( nDepth ) = 0;
171 short nContextBmpWidth = aContextBmpWidthVector[ nDepth ];
172 if( nContextBmpWidth < nWidth )
174 aContextBmpWidthVector.at( nDepth ) = nWidth;
175 return nWidth;
177 else
178 return nContextBmpWidth;
181 void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry* pEntry )
183 DBG_ASSERT( pEntry, "Moved Entry is invalid!" );
185 SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) );
186 short nExpWidth = (short)pBmpItem->GetBitmap1().GetSizePixel().Width();
187 short nColWidth = (short)pBmpItem->GetBitmap2().GetSizePixel().Width();
188 short nMax = std::max(nExpWidth, nColWidth);
189 UpdateContextBmpWidthVector( pEntry, nMax );
191 if( pEntry->HasChildren() ) // recursive call, whether expanded or not
193 SvTreeListEntry* pChild = pView->FirstChild( pEntry );
194 DBG_ASSERT( pChild, "The first child is invalid!" );
197 UpdateContextBmpWidthVectorFromMovedEntry( pChild );
198 pChild = pView->Next( pChild );
199 } while ( pChild );
203 void SvImpLBox::UpdateContextBmpWidthMax( SvTreeListEntry* pEntry )
205 sal_uInt16 nDepth = pView->pModel->GetDepth( pEntry );
206 if( aContextBmpWidthVector.size() < 1 )
207 return;
208 short nWidth = aContextBmpWidthVector[ nDepth ];
209 if( nWidth != pView->nContextBmpWidthMax ) {
210 pView->nContextBmpWidthMax = nWidth;
211 nFlags |= F_IGNORE_CHANGED_TABS;
212 pView->SetTabs();
213 nFlags &= ~F_IGNORE_CHANGED_TABS;
217 void SvImpLBox::CalcCellFocusRect( SvTreeListEntry* pEntry, Rectangle& rRect )
219 if ( pEntry && bIsCellFocusEnabled )
221 if ( nCurTabPos > FIRST_ENTRY_TAB )
223 SvLBoxItem* pItem = pCursor->GetItem( nCurTabPos );
224 rRect.Left() = pView->GetTab( pCursor, pItem )->GetPos();
226 if (pCursor->ItemCount() > static_cast<size_t>(nCurTabPos+1))
228 SvLBoxItem* pNextItem = pCursor->GetItem( nCurTabPos + 1 );
229 long nRight = pView->GetTab( pCursor, pNextItem )->GetPos() - 1;
230 if ( nRight < rRect.Right() )
231 rRect.Right() = nRight;
236 void SvImpLBox::SetStyle( WinBits i_nWinStyle )
238 m_nStyle = i_nWinStyle;
239 if ( ( m_nStyle & WB_SIMPLEMODE) && ( aSelEng.GetSelectionMode() == MULTIPLE_SELECTION ) )
240 aSelEng.AddAlways( true );
243 void SvImpLBox::SetExtendedWindowBits( ExtendedWinBits _nBits )
245 nExtendedWinBits = _nBits;
248 // don't touch the model any more
249 void SvImpLBox::Clear()
251 StopUserEvent();
252 pStartEntry = 0;
253 pAnchor = 0;
255 pActiveButton = 0;
256 pActiveEntry = 0;
257 pActiveTab = 0;
259 nMostRight = -1;
260 pMostRightEntry = 0;
262 // don't touch the cursor any more
263 if( pCursor )
265 if( pView->HasFocus() )
266 pView->HideFocus();
267 pCursor = 0;
269 aVerSBar.Hide();
270 aVerSBar.SetThumbPos( 0 );
271 Range aRange( 0, 0 );
272 aVerSBar.SetRange( aRange );
273 aOutputSize = pView->Control::GetOutputSizePixel();
274 nFlags &= ~(F_VER_SBARSIZE_WITH_HBAR | F_HOR_SBARSIZE_WITH_VBAR );
275 aHorSBar.Hide();
276 aHorSBar.SetThumbPos( 0 );
277 MapMode aMapMode( pView->GetMapMode());
278 aMapMode.SetOrigin( Point(0,0) );
279 pView->Control::SetMapMode( aMapMode );
280 aHorSBar.SetRange( aRange );
281 aHorSBar.SetSizePixel(Size(aOutputSize.Width(),nHorSBarHeight));
282 pView->SetClipRegion();
283 if( GetUpdateMode() )
284 pView->Invalidate( GetVisibleArea() );
285 nFlags |= F_FILLING;
286 if( !aHorSBar.IsVisible() && !aVerSBar.IsVisible() )
287 aScrBarBox.Hide();
289 aContextBmpWidthVector.clear();
292 // *********************************************************************
293 // Paint, navigate, scroll
294 // *********************************************************************
296 IMPL_LINK_NOARG_INLINE_START(SvImpLBox, EndScrollHdl)
298 if( nFlags & F_ENDSCROLL_SET_VIS_SIZE )
300 aVerSBar.SetVisibleSize( nNextVerVisSize );
301 nFlags &= ~F_ENDSCROLL_SET_VIS_SIZE;
303 EndScroll();
304 return 0;
306 IMPL_LINK_NOARG_INLINE_END(SvImpLBox, EndScrollHdl)
309 // handler for vertical scrollbar
311 IMPL_LINK( SvImpLBox, ScrollUpDownHdl, ScrollBar *, pScrollBar )
313 DBG_ASSERT(!bInVScrollHdl,"Scroll handler out-paces itself!");
314 long nDelta = pScrollBar->GetDelta();
315 if( !nDelta )
316 return 0;
318 nFlags &= (~F_FILLING);
320 bInVScrollHdl = true;
322 if( pView->IsEditingActive() )
324 pView->EndEditing( true ); // Cancel
325 pView->Update();
327 BeginScroll();
329 if( nDelta > 0 )
331 if( nDelta == 1 )
332 CursorDown();
333 else
334 PageDown( (sal_uInt16) nDelta );
336 else
338 nDelta *= (-1);
339 if( nDelta == 1 )
340 CursorUp();
341 else
342 PageUp( (sal_uInt16) nDelta );
344 bInVScrollHdl = false;
345 return 0;
349 void SvImpLBox::CursorDown()
351 if (!pStartEntry)
352 return;
354 SvTreeListEntry* pNextFirstToDraw = pView->NextVisible(pStartEntry);
355 if( pNextFirstToDraw )
357 nFlags &= (~F_FILLING);
358 pView->NotifyScrolling( -1 );
359 ShowCursor( false );
360 pView->Update();
361 pStartEntry = pNextFirstToDraw;
362 Rectangle aArea( GetVisibleArea() );
363 pView->Scroll( 0, -(pView->GetEntryHeight()), aArea, SCROLL_NOCHILDREN );
364 pView->Update();
365 ShowCursor( true );
366 pView->NotifyScrolled();
370 void SvImpLBox::CursorUp()
372 if (!pStartEntry)
373 return;
375 SvTreeListEntry* pPrevFirstToDraw = pView->PrevVisible(pStartEntry);
376 if( pPrevFirstToDraw )
378 nFlags &= (~F_FILLING);
379 long nEntryHeight = pView->GetEntryHeight();
380 pView->NotifyScrolling( 1 );
381 ShowCursor( false );
382 pView->Update();
383 pStartEntry = pPrevFirstToDraw;
384 Rectangle aArea( GetVisibleArea() );
385 aArea.Bottom() -= nEntryHeight;
386 pView->Scroll( 0, nEntryHeight, aArea, SCROLL_NOCHILDREN );
387 pView->Update();
388 ShowCursor( true );
389 pView->NotifyScrolled();
393 void SvImpLBox::PageDown( sal_uInt16 nDelta )
395 sal_uInt16 nRealDelta = nDelta;
397 if( !nDelta )
398 return;
400 if (!pStartEntry)
401 return;
403 SvTreeListEntry* pNext = pView->NextVisible(pStartEntry, nRealDelta);
404 if( (sal_uLong)pNext == (sal_uLong)pStartEntry )
405 return;
407 ShowCursor( false );
409 nFlags &= (~F_FILLING);
410 pView->Update();
411 pStartEntry = pNext;
413 if( nRealDelta >= nVisibleCount )
415 pView->Invalidate( GetVisibleArea() );
416 pView->Update();
418 else
420 long nScroll = nRealDelta * (-1);
421 pView->NotifyScrolling( nScroll );
422 Rectangle aArea( GetVisibleArea() );
423 nScroll = pView->GetEntryHeight()*nRealDelta;
424 nScroll = -nScroll;
425 pView->Update();
426 pView->Scroll( 0, nScroll, aArea, SCROLL_NOCHILDREN );
427 pView->Update();
428 pView->NotifyScrolled();
431 ShowCursor( true );
434 void SvImpLBox::PageUp( sal_uInt16 nDelta )
436 sal_uInt16 nRealDelta = nDelta;
437 if( !nDelta )
438 return;
440 if (!pStartEntry)
441 return;
443 SvTreeListEntry* pPrev = pView->PrevVisible(pStartEntry, nRealDelta);
444 if( (sal_uLong)pPrev == (sal_uLong)pStartEntry )
445 return;
447 nFlags &= (~F_FILLING);
448 ShowCursor( false );
450 pView->Update();
451 pStartEntry = pPrev;
452 if( nRealDelta >= nVisibleCount )
454 pView->Invalidate( GetVisibleArea() );
455 pView->Update();
457 else
459 long nEntryHeight = pView->GetEntryHeight();
460 pView->NotifyScrolling( (long)nRealDelta );
461 Rectangle aArea( GetVisibleArea() );
462 pView->Update();
463 pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, SCROLL_NOCHILDREN );
464 pView->Update();
465 pView->NotifyScrolled();
468 ShowCursor( true );
471 void SvImpLBox::KeyUp( bool bPageUp, bool bNotifyScroll )
473 if( !aVerSBar.IsVisible() )
474 return;
476 long nDelta;
477 if( bPageUp )
478 nDelta = aVerSBar.GetPageSize();
479 else
480 nDelta = 1;
482 long nThumbPos = aVerSBar.GetThumbPos();
484 if( nThumbPos < nDelta )
485 nDelta = nThumbPos;
487 if( nDelta <= 0 )
488 return;
490 nFlags &= (~F_FILLING);
491 if( bNotifyScroll )
492 BeginScroll();
494 aVerSBar.SetThumbPos( nThumbPos - nDelta );
495 if( bPageUp )
496 PageUp( (short)nDelta );
497 else
498 CursorUp();
500 if( bNotifyScroll )
501 EndScroll();
505 void SvImpLBox::KeyDown( bool bPageDown, bool bNotifyScroll )
507 if( !aVerSBar.IsVisible() )
508 return;
510 long nDelta;
511 if( bPageDown )
512 nDelta = aVerSBar.GetPageSize();
513 else
514 nDelta = 1;
516 long nThumbPos = aVerSBar.GetThumbPos();
517 long nVisibleSize = aVerSBar.GetVisibleSize();
518 long nRange = aVerSBar.GetRange().Len();
520 long nTmp = nThumbPos+nVisibleSize;
521 while( (nDelta > 0) && (nTmp+nDelta) >= nRange )
522 nDelta--;
524 if( nDelta <= 0 )
525 return;
527 nFlags &= (~F_FILLING);
528 if( bNotifyScroll )
529 BeginScroll();
531 aVerSBar.SetThumbPos( nThumbPos+nDelta );
532 if( bPageDown )
533 PageDown( (short)nDelta );
534 else
535 CursorDown();
537 if( bNotifyScroll )
538 EndScroll();
543 void SvImpLBox::InvalidateEntriesFrom( long nY ) const
545 if( !(nFlags & F_IN_PAINT ))
547 Rectangle aRect( GetVisibleArea() );
548 aRect.Top() = nY;
549 pView->Invalidate( aRect );
553 void SvImpLBox::InvalidateEntry( long nY ) const
555 if( !(nFlags & F_IN_PAINT ))
557 Rectangle aRect( GetVisibleArea() );
558 long nMaxBottom = aRect.Bottom();
559 aRect.Top() = nY;
560 aRect.Bottom() = nY; aRect.Bottom() += pView->GetEntryHeight();
561 if( aRect.Top() > nMaxBottom )
562 return;
563 if( aRect.Bottom() > nMaxBottom )
564 aRect.Bottom() = nMaxBottom;
565 pView->Invalidate( aRect );
569 void SvImpLBox::InvalidateEntry( SvTreeListEntry* pEntry )
571 if( GetUpdateMode() )
573 long nPrev = nMostRight;
574 SetMostRight( pEntry );
575 if( nPrev < nMostRight )
576 ShowVerSBar();
578 if( !(nFlags & F_IN_PAINT ))
580 bool bHasFocusRect = false;
581 if( pEntry==pCursor && pView->HasFocus() )
583 bHasFocusRect = true;
584 ShowCursor( false );
586 InvalidateEntry( GetEntryLine( pEntry ) );
587 if( bHasFocusRect )
588 ShowCursor( true );
593 void SvImpLBox::RecalcFocusRect()
595 if( pView->HasFocus() && pCursor )
597 pView->HideFocus();
598 long nY = GetEntryLine( pCursor );
599 Rectangle aRect = pView->GetFocusRect( pCursor, nY );
600 CalcCellFocusRect( pCursor, aRect );
601 Region aOldClip( pView->GetClipRegion());
602 Region aClipRegion( GetClipRegionRect() );
603 pView->SetClipRegion( aClipRegion );
604 pView->ShowFocus( aRect );
605 pView->SetClipRegion( aOldClip );
610 // Sets cursor. When using SingleSelection, the selection is adjusted.
613 void SvImpLBox::SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect )
615 SvViewDataEntry* pViewDataNewCur = 0;
616 if( pEntry )
617 pViewDataNewCur= pView->GetViewDataEntry(pEntry);
618 if( pEntry &&
619 pEntry == pCursor &&
620 pViewDataNewCur->HasFocus() &&
621 pViewDataNewCur->IsSelected())
623 return;
626 // if this cursor is not selectable, find first visible that is and use it
627 while( pEntry && pViewDataNewCur && !pViewDataNewCur->IsSelectable() )
629 pEntry = pView->NextVisible(pEntry);
630 pViewDataNewCur = pEntry ? pView->GetViewDataEntry(pEntry) : 0;
633 SvTreeListEntry* pOldCursor = pCursor;
634 if( pCursor && pEntry != pCursor )
636 pView->SetEntryFocus( pCursor, false );
637 if( bSimpleTravel )
638 pView->Select( pCursor, false );
639 pView->HideFocus();
641 pCursor = pEntry;
642 if( pCursor )
644 pViewDataNewCur->SetFocus( true );
645 if(!bForceNoSelect && bSimpleTravel && !(nFlags & F_DESEL_ALL) && GetUpdateMode())
647 pView->Select( pCursor, true );
649 // multiple selection: select in cursor move if we're not in
650 // Add mode (Ctrl-F8)
651 else if( GetUpdateMode() &&
652 pView->GetSelectionMode() == MULTIPLE_SELECTION &&
653 !(nFlags & F_DESEL_ALL) && !aSelEng.IsAddMode() &&
654 !bForceNoSelect )
656 pView->Select( pCursor, true );
658 else
660 ShowCursor( true );
663 if( pAnchor )
665 DBG_ASSERT(aSelEng.GetSelectionMode() != SINGLE_SELECTION,"Mode?");
666 SetAnchorSelection( pOldCursor, pCursor );
669 nFlags &= (~F_DESEL_ALL);
671 pView->OnCurrentEntryChanged();
674 void SvImpLBox::ShowCursor( bool bShow )
676 if( !bShow || !pCursor || !pView->HasFocus() )
678 Region aOldClip( pView->GetClipRegion());
679 Region aClipRegion( GetClipRegionRect() );
680 pView->SetClipRegion( aClipRegion );
681 pView->HideFocus();
682 pView->SetClipRegion( aOldClip );
684 else
686 long nY = GetEntryLine( pCursor );
687 Rectangle aRect = pView->GetFocusRect( pCursor, nY );
688 CalcCellFocusRect( pCursor, aRect );
689 Region aOldClip( pView->GetClipRegion());
690 Region aClipRegion( GetClipRegionRect() );
691 pView->SetClipRegion( aClipRegion );
692 pView->ShowFocus( aRect );
693 pView->SetClipRegion( aOldClip );
699 void SvImpLBox::UpdateAll(
700 bool bInvalidateCompleteView, bool bUpdateVerScrollBar )
702 if( bUpdateVerScrollBar )
703 FindMostRight(0);
704 aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) );
705 SyncVerThumb();
706 FillView();
707 ShowVerSBar();
708 if( bSimpleTravel && pCursor && pView->HasFocus() )
709 pView->Select( pCursor, true );
710 ShowCursor( true );
711 if( bInvalidateCompleteView )
712 pView->Invalidate();
713 else
714 pView->Invalidate( GetVisibleArea() );
717 IMPL_LINK_INLINE_START( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar )
719 long nDelta = pScrollBar->GetDelta();
720 if( nDelta )
722 if( pView->IsEditingActive() )
724 pView->EndEditing( true ); // Cancel
725 pView->Update();
727 pView->nFocusWidth = -1;
728 KeyLeftRight( nDelta );
730 return 0;
732 IMPL_LINK_INLINE_END( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar )
734 void SvImpLBox::KeyLeftRight( long nDelta )
736 if( !(nFlags & F_IN_RESIZE) )
737 pView->Update();
738 BeginScroll();
739 nFlags &= (~F_FILLING);
740 pView->NotifyScrolling( 0 ); // 0 == horizontal scrolling
741 ShowCursor( false );
743 // neuen Origin berechnen
744 long nPos = aHorSBar.GetThumbPos();
745 Point aOrigin( -nPos, 0 );
747 MapMode aMapMode( pView->GetMapMode() );
748 aMapMode.SetOrigin( aOrigin );
749 pView->SetMapMode( aMapMode );
751 if( !(nFlags & F_IN_RESIZE) )
753 Rectangle aRect( GetVisibleArea() );
754 pView->Scroll( -nDelta, 0, aRect, SCROLL_NOCHILDREN );
756 else
757 pView->Invalidate();
758 RecalcFocusRect();
759 ShowCursor( true );
760 pView->NotifyScrolled();
764 // returns the last entry if position is just past the last entry
765 SvTreeListEntry* SvImpLBox::GetClickedEntry( const Point& rPoint ) const
767 DBG_ASSERT( pView->GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" );
768 if ( !pView->GetModel() )
769 // this is quite impossible. Nevertheless, stack traces from the crash reporter
770 // suggest it isn't. Okay, make it safe, and wait for somebody to reproduce it
771 // reliably :-\ ....
772 // #122359# / 2005-05-23 / frank.schoenheit@sun.com
773 return NULL;
774 if( pView->GetEntryCount() == 0 || !pStartEntry || !pView->GetEntryHeight())
775 return 0;
777 sal_uInt16 nClickedEntry = (sal_uInt16)(rPoint.Y() / pView->GetEntryHeight() );
778 sal_uInt16 nTemp = nClickedEntry;
779 SvTreeListEntry* pEntry = pView->NextVisible(pStartEntry, nTemp);
780 return pEntry;
784 // checks if the entry was hit "the right way"
785 // (Focusrect+ ContextBitmap bei TreeListBox)
787 bool SvImpLBox::EntryReallyHit(SvTreeListEntry* pEntry, const Point& rPosPixel, long nLine)
789 bool bRet;
790 // we are not too exact when it comes to "special" entries
791 // (with CheckButtons etc.)
792 if( pEntry->ItemCount() >= 3 )
793 return true;
795 Rectangle aRect( pView->GetFocusRect( pEntry, nLine ));
796 aRect.Right() = GetOutputSize().Width() - pView->GetMapMode().GetOrigin().X();
798 SvLBoxContextBmp* pBmp = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
799 aRect.Left() -= pBmp->GetSize(pView,pEntry).Width();
800 aRect.Left() -= 4; // a little tolerance
802 Point aPos( rPosPixel );
803 aPos -= pView->GetMapMode().GetOrigin();
804 if( aRect.IsInside( aPos ) )
805 bRet = true;
806 else
807 bRet = false;
808 return bRet;
812 // returns 0 if position is just past the last entry
813 SvTreeListEntry* SvImpLBox::GetEntry( const Point& rPoint ) const
815 if( (pView->GetEntryCount() == 0) || !pStartEntry ||
816 (rPoint.Y() > aOutputSize.Height())
817 || !pView->GetEntryHeight())
818 return 0;
820 sal_uInt16 nClickedEntry = (sal_uInt16)(rPoint.Y() / pView->GetEntryHeight() );
821 sal_uInt16 nTemp = nClickedEntry;
822 SvTreeListEntry* pEntry = pView->NextVisible(pStartEntry, nTemp);
823 if( nTemp != nClickedEntry )
824 pEntry = 0;
825 return pEntry;
829 SvTreeListEntry* SvImpLBox::MakePointVisible(const Point& rPoint, bool bNotifyScroll)
831 if( !pCursor )
832 return 0;
833 long nY = rPoint.Y();
834 SvTreeListEntry* pEntry = 0;
835 long nMax = aOutputSize.Height();
836 if( nY < 0 || nY >= nMax ) // aOutputSize.Height() )
838 if( nY < 0 )
839 pEntry = pView->PrevVisible(pCursor);
840 else
841 pEntry = pView->NextVisible(pCursor);
843 if( pEntry && pEntry != pCursor )
844 pView->SetEntryFocus( pCursor, false );
846 if( nY < 0 )
847 KeyUp( false, bNotifyScroll );
848 else
849 KeyDown( false, bNotifyScroll );
851 else
853 pEntry = GetClickedEntry( rPoint );
854 if( !pEntry )
856 sal_uInt16 nSteps = 0xFFFF;
857 // TODO: LastVisible is not yet implemented!
858 pEntry = pView->NextVisible(pStartEntry, nSteps);
860 if( pEntry )
862 if( pEntry != pCursor &&
863 aSelEng.GetSelectionMode() == SINGLE_SELECTION
865 pView->Select( pCursor, false );
868 return pEntry;
871 Rectangle SvImpLBox::GetClipRegionRect() const
873 Point aOrigin( pView->GetMapMode().GetOrigin() );
874 aOrigin.X() *= -1; // conversion document coordinates
875 Rectangle aClipRect( aOrigin, aOutputSize );
876 aClipRect.Bottom()++;
877 return aClipRect;
881 void SvImpLBox::Paint( const Rectangle& rRect )
883 if( !pView->GetVisibleCount() )
884 return;
886 nFlags |= F_IN_PAINT;
888 if( nFlags & F_FILLING )
890 SvTreeListEntry* pFirst = pView->First();
891 if( pFirst != pStartEntry )
893 ShowCursor( false );
894 pStartEntry = pView->First();
895 aVerSBar.SetThumbPos( 0 );
896 StopUserEvent();
897 ShowCursor( true );
898 nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)1);
899 return;
903 if( !pStartEntry )
905 pStartEntry = pView->First();
908 if( nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID )
909 SetNodeBmpTabDistance();
911 long nRectHeight = rRect.GetHeight();
912 long nEntryHeight = pView->GetEntryHeight();
914 // calculate area for the entries we want to draw
915 sal_uInt16 nStartLine = (sal_uInt16)( rRect.Top() / nEntryHeight );
916 sal_uInt16 nCount = (sal_uInt16)( nRectHeight / nEntryHeight );
917 nCount += 2; // don't miss a row
919 long nY = nStartLine * nEntryHeight;
920 SvTreeListEntry* pEntry = pStartEntry;
921 while( nStartLine && pEntry )
923 pEntry = pView->NextVisible(pEntry);
924 nStartLine--;
927 Region aClipRegion( GetClipRegionRect() );
929 // first draw the lines, then clip them!
930 pView->SetClipRegion();
931 if( m_nStyle & ( WB_HASLINES | WB_HASLINESATROOT ) )
932 DrawNet();
934 pView->SetClipRegion( aClipRegion );
936 for( sal_uInt16 n=0; n< nCount && pEntry; n++ )
938 /*long nMaxRight=*/
939 pView->PaintEntry1( pEntry, nY, 0xffff, true );
940 nY += nEntryHeight;
941 pEntry = pView->NextVisible(pEntry);
944 if ( !pCursor && ( ( nExtendedWinBits & EWB_NO_AUTO_CURENTRY ) == 0 ) )
946 // do not select if multiselection or explicit set
947 bool bNotSelect = ( aSelEng.GetSelectionMode() == MULTIPLE_SELECTION )
948 || ( ( m_nStyle & WB_NOINITIALSELECTION ) == WB_NOINITIALSELECTION );
949 SetCursor( pStartEntry, bNotSelect );
952 nFlags &= (~F_DESEL_ALL);
953 pView->SetClipRegion();
954 if( !(nFlags & F_PAINTED) )
956 nFlags |= F_PAINTED;
957 RepaintScrollBars();
959 nFlags &= (~F_IN_PAINT);
962 void SvImpLBox::MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop )
964 if( !pEntry )
965 return;
967 bool bInView = IsEntryInView( pEntry );
969 if( bInView && (!bMoveToTop || pStartEntry == pEntry) )
970 return; // is already visible
972 if( pStartEntry || (m_nStyle & WB_FORCE_MAKEVISIBLE) )
973 nFlags &= (~F_FILLING);
974 if( !bInView )
976 if( !pView->IsEntryVisible(pEntry) ) // Parent(s) collapsed?
978 SvTreeListEntry* pParent = pView->GetParent( pEntry );
979 while( pParent )
981 if( !pView->IsExpanded( pParent ) )
983 #ifdef DBG_UTIL
984 bool bRet =
985 #endif
986 pView->Expand( pParent );
987 DBG_ASSERT(bRet,"Not expanded!");
989 pParent = pView->GetParent( pParent );
991 // do the parent's children fit into the view or do we have to scroll?
992 if( IsEntryInView( pEntry ) && !bMoveToTop )
993 return; // no need to scroll
997 pStartEntry = pEntry;
998 ShowCursor( false );
999 FillView();
1000 aVerSBar.SetThumbPos( (long)(pView->GetVisiblePos( pStartEntry )) );
1001 ShowCursor( true );
1002 pView->Invalidate();
1005 void SvImpLBox::ScrollToAbsPos( long nPos )
1007 if( pView->GetVisibleCount() == 0 )
1008 return;
1009 long nLastEntryPos = pView->GetAbsPos( pView->Last() );
1011 if( nPos < 0 )
1012 nPos = 0;
1013 else if( nPos > nLastEntryPos )
1014 nPos = nLastEntryPos;
1016 SvTreeListEntry* pEntry = (SvTreeListEntry*)pView->GetEntryAtAbsPos( nPos );
1017 if( !pEntry || pEntry == pStartEntry )
1018 return;
1020 if( pStartEntry || (m_nStyle & WB_FORCE_MAKEVISIBLE) )
1021 nFlags &= (~F_FILLING);
1023 if( pView->IsEntryVisible(pEntry) )
1025 pStartEntry = pEntry;
1026 ShowCursor( false );
1027 aVerSBar.SetThumbPos( nPos );
1028 ShowCursor( true );
1029 if (GetUpdateMode())
1030 pView->Invalidate();
1034 void SvImpLBox::DrawNet()
1036 if( pView->GetVisibleCount() < 2 && !pStartEntry->HasChildrenOnDemand() &&
1037 !pStartEntry->HasChildren() )
1038 return;
1040 // for platforms that don't have nets, DrawNativeControl does nothing and returns true
1041 // so that SvImpLBox::DrawNet() doesn't draw anything either
1042 if(pView->IsNativeControlSupported( CTRL_LISTNET, PART_ENTIRE_CONTROL)) {
1043 ImplControlValue aControlValue;
1044 Point aTemp(0,0); // temporary needed for g++ 3.3.5
1045 Rectangle aCtrlRegion( aTemp, Size( 0, 0 ) );
1046 ControlState nState = CTRL_STATE_ENABLED;
1047 if( pView->DrawNativeControl( CTRL_LISTNET, PART_ENTIRE_CONTROL,
1048 aCtrlRegion, nState, aControlValue, OUString() ) )
1050 return;
1055 long nEntryHeight = pView->GetEntryHeight();
1056 long nEntryHeightDIV2 = nEntryHeight / 2;
1057 if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001))
1058 nEntryHeightDIV2--;
1060 SvTreeListEntry* pChild;
1061 SvTreeListEntry* pEntry = pStartEntry;
1063 SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab();
1064 while( pTree->GetDepth( pEntry ) > 0 )
1065 pEntry = pView->GetParent( pEntry );
1066 sal_uInt16 nOffs = (sal_uInt16)(pView->GetVisiblePos( pStartEntry ) -
1067 pView->GetVisiblePos( pEntry ));
1068 long nY = 0;
1069 nY -= ( nOffs * nEntryHeight );
1071 DBG_ASSERT(pFirstDynamicTab,"No Tree!");
1073 Color aOldLineColor = pView->GetLineColor();
1074 const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings();
1075 Color aCol= rStyleSettings.GetFaceColor();
1077 if( aCol.IsRGBEqual( pView->GetBackground().GetColor()) )
1078 aCol = rStyleSettings.GetShadowColor();
1079 pView->SetLineColor( aCol );
1080 Point aPos1, aPos2;
1081 sal_uInt16 nDistance;
1082 sal_uLong nMax = nVisibleCount + nOffs + 1;
1084 const Image& rExpandedNodeBitmap = GetExpandedNodeBmp();
1086 for( sal_uLong n=0; n< nMax && pEntry; n++ )
1088 if( pView->IsExpanded(pEntry) )
1090 aPos1.X() = pView->GetTabPos(pEntry, pFirstDynamicTab);
1091 // if it is not a context bitmap, go a little to the right below the
1092 // first text (node bitmap, too)
1093 if( !pView->nContextBmpWidthMax )
1094 aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2;
1096 aPos1.Y() = nY;
1097 aPos1.Y() += nEntryHeightDIV2;
1099 pChild = pView->FirstChild( pEntry );
1100 DBG_ASSERT(pChild,"Child?");
1101 pChild = pTree->LastSibling( pChild );
1102 nDistance = (sal_uInt16)(pView->GetVisiblePos(pChild) -
1103 pView->GetVisiblePos(pEntry));
1104 aPos2 = aPos1;
1105 aPos2.Y() += nDistance * nEntryHeight;
1106 pView->DrawLine( aPos1, aPos2 );
1108 // visible in control?
1109 if( n>= nOffs && ((m_nStyle & WB_HASLINESATROOT) || !pTree->IsAtRootDepth(pEntry)))
1111 // can we recycle aPos1?
1112 if( !pView->IsExpanded(pEntry) )
1114 // nope
1115 aPos1.X() = pView->GetTabPos(pEntry, pFirstDynamicTab);
1116 // if it is not a context bitmap, go a little to the right below
1117 // the first text (node bitmap, too)
1118 if( !pView->nContextBmpWidthMax )
1119 aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2;
1120 aPos1.Y() = nY;
1121 aPos1.Y() += nEntryHeightDIV2;
1122 aPos2.X() = aPos1.X();
1124 aPos2.Y() = aPos1.Y();
1125 aPos2.X() -= pView->GetIndent();
1126 pView->DrawLine( aPos1, aPos2 );
1128 nY += nEntryHeight;
1129 pEntry = pView->NextVisible(pEntry);
1131 if( m_nStyle & WB_HASLINESATROOT )
1133 pEntry = pView->First();
1134 aPos1.X() = pView->GetTabPos( pEntry, pFirstDynamicTab);
1135 // if it is not a context bitmap, go a little to the right below the
1136 // first text (node bitmap, too)
1137 if( !pView->nContextBmpWidthMax )
1138 aPos1.X() += rExpandedNodeBitmap.GetSizePixel().Width() / 2;
1139 aPos1.X() -= pView->GetIndent();
1140 aPos1.Y() = GetEntryLine( pEntry );
1141 aPos1.Y() += nEntryHeightDIV2;
1142 pChild = pTree->LastSibling( pEntry );
1143 aPos2.X() = aPos1.X();
1144 aPos2.Y() = GetEntryLine( pChild );
1145 aPos2.Y() += nEntryHeightDIV2;
1146 pView->DrawLine( aPos1, aPos2 );
1148 pView->SetLineColor( aOldLineColor );
1151 void SvImpLBox::PositionScrollBars( Size& rSize, sal_uInt16 nMask )
1153 long nOverlap = 0;
1155 Size aVerSize( nVerSBarWidth, rSize.Height() );
1156 Size aHorSize( rSize.Width(), nHorSBarHeight );
1158 if( nMask & 0x0001 )
1159 aHorSize.Width() -= nVerSBarWidth;
1160 if( nMask & 0x0002 )
1161 aVerSize.Height() -= nHorSBarHeight;
1163 aVerSize.Height() += 2 * nOverlap;
1164 Point aVerPos( rSize.Width() - aVerSize.Width() + nOverlap, -nOverlap );
1165 aVerSBar.SetPosSizePixel( aVerPos, aVerSize );
1167 aHorSize.Width() += 2 * nOverlap;
1168 Point aHorPos( -nOverlap, rSize.Height() - aHorSize.Height() + nOverlap );
1170 aHorSBar.SetPosSizePixel( aHorPos, aHorSize );
1172 if( nMask & 0x0001 )
1173 rSize.Width() = aVerPos.X();
1174 if( nMask & 0x0002 )
1175 rSize.Height() = aHorPos.Y();
1177 if( (nMask & (0x0001|0x0002)) == (0x0001|0x0002) )
1178 aScrBarBox.Show();
1179 else
1180 aScrBarBox.Hide();
1183 // nResult: Bit0 == VerSBar Bit1 == HorSBar
1184 sal_uInt16 SvImpLBox::AdjustScrollBars( Size& rSize )
1186 long nEntryHeight = pView->GetEntryHeight();
1187 if( !nEntryHeight )
1188 return 0;
1190 sal_uInt16 nResult = 0;
1192 Size aOSize( pView->Control::GetOutputSizePixel() );
1194 const WinBits nWindowStyle = pView->GetStyle();
1195 bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0;
1196 bool bHorBar = false;
1197 long nMaxRight = aOSize.Width(); //GetOutputSize().Width();
1198 Point aOrigin( pView->GetMapMode().GetOrigin() );
1199 aOrigin.X() *= -1;
1200 nMaxRight += aOrigin.X() - 1;
1201 long nVis = nMostRight - aOrigin.X();
1202 if( (nWindowStyle & WB_HSCROLL) &&
1203 (nVis < nMostRight || nMaxRight < nMostRight) )
1205 bHorBar = true;
1208 // number of entries that are not collapsed
1209 sal_uLong nTotalCount = pView->GetVisibleCount();
1211 // number of entries visible within the view
1212 nVisibleCount = aOSize.Height() / nEntryHeight;
1214 // do we need a vertical scrollbar?
1215 if( bVerSBar || nTotalCount > nVisibleCount )
1217 nResult = 1;
1218 nFlags |= F_HOR_SBARSIZE_WITH_VBAR;
1219 nMaxRight -= nVerSBarWidth;
1220 if( !bHorBar )
1222 if( (nWindowStyle & WB_HSCROLL) &&
1223 (nVis < nMostRight || nMaxRight < nMostRight) )
1224 bHorBar = true;
1228 // do we need a horizontal scrollbar?
1229 if( bHorBar )
1231 nResult |= 0x0002;
1232 // the number of entries visible within the view has to be recalculated
1233 // because the horizontal scrollbar is now visible.
1234 nVisibleCount = (aOSize.Height() - nHorSBarHeight) / nEntryHeight;
1235 // we might actually need a vertical scrollbar now
1236 if( !(nResult & 0x0001) &&
1237 ((nTotalCount > nVisibleCount) || bVerSBar) )
1239 nResult = 3;
1240 nFlags |= F_VER_SBARSIZE_WITH_HBAR;
1244 PositionScrollBars( aOSize, nResult );
1246 // adapt Range, VisibleRange etc.
1248 // refresh output size, in case we have to scroll
1249 Rectangle aRect;
1250 aRect.SetSize( aOSize );
1251 aSelEng.SetVisibleArea( aRect );
1253 // vertical scrollbar
1254 long nTemp = (long)nVisibleCount;
1255 nTemp--;
1256 if( nTemp != aVerSBar.GetVisibleSize() )
1258 if( !bInVScrollHdl )
1260 aVerSBar.SetPageSize( nTemp - 1 );
1261 aVerSBar.SetVisibleSize( nTemp );
1263 else
1265 nFlags |= F_ENDSCROLL_SET_VIS_SIZE;
1266 nNextVerVisSize = nTemp;
1270 // horizontal scrollbar
1271 nTemp = aHorSBar.GetThumbPos();
1272 aHorSBar.SetVisibleSize( aOSize.Width() );
1273 long nNewThumbPos = aHorSBar.GetThumbPos();
1274 Range aRange( aHorSBar.GetRange() );
1275 if( aRange.Max() < nMostRight+25 )
1277 aRange.Max() = nMostRight+25;
1278 aHorSBar.SetRange( aRange );
1281 if( nTemp != nNewThumbPos )
1283 nTemp = nNewThumbPos - nTemp;
1284 if( pView->IsEditingActive() )
1286 pView->EndEditing( true ); // Cancel
1287 pView->Update();
1289 pView->nFocusWidth = -1;
1290 KeyLeftRight( nTemp );
1293 if( nResult & 0x0001 )
1294 aVerSBar.Show();
1295 else
1296 aVerSBar.Hide();
1298 if( nResult & 0x0002 )
1299 aHorSBar.Show();
1300 else
1302 aHorSBar.Hide();
1304 rSize = aOSize;
1305 return nResult;
1308 void SvImpLBox::InitScrollBarBox()
1310 aScrBarBox.SetSizePixel( Size(nVerSBarWidth, nHorSBarHeight) );
1311 Size aSize( pView->Control::GetOutputSizePixel() );
1312 aScrBarBox.SetPosPixel( Point(aSize.Width()-nVerSBarWidth, aSize.Height()-nHorSBarHeight));
1315 void SvImpLBox::Resize()
1317 aOutputSize = pView->Control::GetOutputSizePixel();
1318 if( aOutputSize.Width() <= 0 || aOutputSize.Height() <= 0 )
1319 return;
1320 nFlags |= F_IN_RESIZE;
1321 InitScrollBarBox();
1323 if( pView->GetEntryHeight())
1325 AdjustScrollBars( aOutputSize );
1326 UpdateAll(false);
1328 // HACK, as in floating and docked windows the scrollbars might not be drawn
1329 // correctly/not be drawn at all after resizing!
1330 if( aHorSBar.IsVisible())
1331 aHorSBar.Invalidate();
1332 if( aVerSBar.IsVisible())
1333 aVerSBar.Invalidate();
1334 nFlags &= (~(F_IN_RESIZE | F_PAINTED));
1337 void SvImpLBox::FillView()
1339 if( !pStartEntry )
1341 sal_uInt16 nVisibleViewCount = (sal_uInt16)(pView->GetVisibleCount());
1342 sal_uInt16 nTempThumb = (sal_uInt16)aVerSBar.GetThumbPos();
1343 if( nTempThumb >= nVisibleViewCount )
1344 nTempThumb = nVisibleViewCount - 1;
1345 pStartEntry = pView->GetEntryAtVisPos(nTempThumb);
1347 if( pStartEntry )
1349 sal_uInt16 nLast = (sal_uInt16)(pView->GetVisiblePos(pView->LastVisible()));
1350 sal_uInt16 nThumb = (sal_uInt16)(pView->GetVisiblePos( pStartEntry ));
1351 sal_uInt16 nCurDispEntries = nLast-nThumb+1;
1352 if( nCurDispEntries < nVisibleCount )
1354 ShowCursor( false );
1355 // fill window by moving the thumb up incrementally
1356 bool bFound = false;
1357 SvTreeListEntry* pTemp = pStartEntry;
1358 while( nCurDispEntries < nVisibleCount && pTemp )
1360 pTemp = pView->PrevVisible(pStartEntry);
1361 if( pTemp )
1363 nThumb--;
1364 pStartEntry = pTemp;
1365 nCurDispEntries++;
1366 bFound = true;
1369 if( bFound )
1371 aVerSBar.SetThumbPos( nThumb );
1372 ShowCursor( true ); // recalculate focus rectangle
1373 pView->Invalidate();
1382 void SvImpLBox::ShowVerSBar()
1384 bool bVerBar = ( pView->GetStyle() & WB_VSCROLL ) != 0;
1385 sal_uLong nVis = 0;
1386 if( !bVerBar )
1387 nVis = pView->GetVisibleCount();
1388 if( bVerBar || (nVisibleCount && nVis > (sal_uLong)(nVisibleCount-1)) )
1390 if( !aVerSBar.IsVisible() )
1392 pView->nFocusWidth = -1;
1393 AdjustScrollBars( aOutputSize );
1394 if( GetUpdateMode() )
1395 aVerSBar.Update();
1398 else
1400 if( aVerSBar.IsVisible() )
1402 pView->nFocusWidth = -1;
1403 AdjustScrollBars( aOutputSize );
1407 long nMaxRight = GetOutputSize().Width();
1408 Point aPos( pView->GetMapMode().GetOrigin() );
1409 aPos.X() *= -1; // convert document coordinates
1410 nMaxRight = nMaxRight + aPos.X() - 1;
1411 if( nMaxRight < nMostRight )
1413 if( !aHorSBar.IsVisible() )
1415 pView->nFocusWidth = -1;
1416 AdjustScrollBars( aOutputSize );
1417 if( GetUpdateMode() )
1418 aHorSBar.Update();
1420 else
1422 Range aRange( aHorSBar.GetRange() );
1423 if( aRange.Max() < nMostRight+25 )
1425 aRange.Max() = nMostRight+25;
1426 aHorSBar.SetRange( aRange );
1428 else
1430 pView->nFocusWidth = -1;
1431 AdjustScrollBars( aOutputSize );
1435 else
1437 if( aHorSBar.IsVisible() )
1439 pView->nFocusWidth = -1;
1440 AdjustScrollBars( aOutputSize );
1446 void SvImpLBox::SyncVerThumb()
1448 if( pStartEntry )
1450 long nEntryPos = pView->GetVisiblePos( pStartEntry );
1451 aVerSBar.SetThumbPos( nEntryPos );
1453 else
1454 aVerSBar.SetThumbPos( 0 );
1457 bool SvImpLBox::IsEntryInView( SvTreeListEntry* pEntry ) const
1459 // parent collapsed
1460 if( !pView->IsEntryVisible(pEntry) )
1461 return false;
1462 long nY = GetEntryLine( pEntry );
1463 if( nY < 0 )
1464 return false;
1465 long nMax = nVisibleCount * pView->GetEntryHeight();
1466 if( nY >= nMax )
1467 return false;
1468 return true;
1472 long SvImpLBox::GetEntryLine( SvTreeListEntry* pEntry ) const
1474 if(!pStartEntry )
1475 return -1; // invisible position
1477 long nFirstVisPos = pView->GetVisiblePos( pStartEntry );
1478 long nEntryVisPos = pView->GetVisiblePos( pEntry );
1479 nFirstVisPos = nEntryVisPos - nFirstVisPos;
1480 nFirstVisPos *= pView->GetEntryHeight();
1481 return nFirstVisPos;
1484 void SvImpLBox::SetEntryHeight( short /* nHeight */ )
1486 SetNodeBmpYOffset( GetExpandedNodeBmp() );
1487 SetNodeBmpYOffset( GetCollapsedNodeBmp() );
1488 if(!pView->HasViewData()) // are we within the Clear?
1490 Size aSize = pView->Control::GetOutputSizePixel();
1491 AdjustScrollBars( aSize );
1493 else
1495 Resize();
1496 if( GetUpdateMode() )
1497 pView->Invalidate();
1503 // ***********************************************************************
1504 // Callback Functions
1505 // ***********************************************************************
1507 void SvImpLBox::EntryExpanded( SvTreeListEntry* pEntry )
1509 // SelAllDestrAnch( false, true ); //DeselectAll();
1510 if( GetUpdateMode() )
1512 ShowCursor( false );
1513 long nY = GetEntryLine( pEntry );
1514 if( IsLineVisible(nY) )
1516 InvalidateEntriesFrom( nY );
1517 FindMostRight( pEntry, 0 );
1519 aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) );
1520 // if we expanded before the thumb, the thumb's position has to be
1521 // corrected
1522 SyncVerThumb();
1523 ShowVerSBar();
1524 ShowCursor( true );
1528 void SvImpLBox::EntryCollapsed( SvTreeListEntry* pEntry )
1530 if( !pView->IsEntryVisible( pEntry ) )
1531 return;
1533 ShowCursor( false );
1535 if( !pMostRightEntry || pTree->IsChild( pEntry,pMostRightEntry ) )
1537 FindMostRight(0);
1540 if( pStartEntry )
1542 long nOldThumbPos = aVerSBar.GetThumbPos();
1543 sal_uLong nVisList = pView->GetVisibleCount();
1544 aVerSBar.SetRange( Range(0, nVisList-1) );
1545 long nNewThumbPos = aVerSBar.GetThumbPos();
1546 if( nNewThumbPos != nOldThumbPos )
1548 pStartEntry = pView->First();
1549 sal_uInt16 nDistance = (sal_uInt16)nNewThumbPos;
1550 if( nDistance )
1551 pStartEntry = pView->NextVisible(pStartEntry, nDistance);
1552 if( GetUpdateMode() )
1553 pView->Invalidate();
1555 else
1556 SyncVerThumb();
1557 ShowVerSBar();
1559 // has the cursor been collapsed?
1560 if( pTree->IsChild( pEntry, pCursor ) )
1561 SetCursor( pEntry );
1562 if( GetUpdateMode() )
1563 ShowVerSBar();
1564 ShowCursor( true );
1565 if( GetUpdateMode() && pCursor )
1566 pView->Select( pCursor, true );
1569 void SvImpLBox::CollapsingEntry( SvTreeListEntry* pEntry )
1571 if( !pView->IsEntryVisible( pEntry ) || !pStartEntry )
1572 return;
1574 SelAllDestrAnch( false, true ); // deselect all
1576 // is the collapsed cursor visible?
1577 long nY = GetEntryLine( pEntry );
1578 if( IsLineVisible(nY) )
1580 if( GetUpdateMode() )
1581 InvalidateEntriesFrom( nY );
1583 else
1585 if( pTree->IsChild(pEntry, pStartEntry) )
1587 pStartEntry = pEntry;
1588 if( GetUpdateMode() )
1589 pView->Invalidate();
1595 void SvImpLBox::SetNodeBmpYOffset( const Image& rBmp )
1597 Size aSize;
1598 nYoffsNodeBmp = pView->GetHeightOffset( rBmp, aSize );
1599 nNodeBmpWidth = aSize.Width();
1602 void SvImpLBox::SetNodeBmpTabDistance()
1604 nNodeBmpTabDistance = -pView->GetIndent();
1605 if( pView->nContextBmpWidthMax )
1607 // only if the first dynamic tab is centered (we currently assume that)
1608 Size aSize = GetExpandedNodeBmp().GetSizePixel();
1609 nNodeBmpTabDistance -= aSize.Width() / 2;
1614 // corrects the cursor when using SingleSelection
1616 void SvImpLBox::EntrySelected( SvTreeListEntry* pEntry, bool bSelect )
1618 if( nFlags & F_IGNORE_SELECT )
1619 return;
1621 nFlags &= (~F_DESEL_ALL);
1622 if( bSelect &&
1623 aSelEng.GetSelectionMode() == SINGLE_SELECTION &&
1624 pEntry != pCursor )
1626 SetCursor( pEntry );
1627 DBG_ASSERT(pView->GetSelectionCount()==1,"selection count?");
1630 if( GetUpdateMode() && pView->IsEntryVisible(pEntry) )
1632 long nY = GetEntryLine( pEntry );
1633 if( IsLineVisible( nY ) )
1635 ShowCursor( false );
1636 pView->PaintEntry1( pEntry, nY, 0xffff ); // because of ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION );
1637 ShowCursor( true );
1643 void SvImpLBox::RemovingEntry( SvTreeListEntry* pEntry )
1645 DestroyAnchor();
1647 if( !pView->IsEntryVisible( pEntry ) )
1649 // if parent is collapsed => bye!
1650 nFlags |= F_REMOVED_ENTRY_INVISIBLE;
1651 return;
1654 if( pEntry == pMostRightEntry || (
1655 pEntry->HasChildren() && pView->IsExpanded(pEntry) &&
1656 pTree->IsChild(pEntry, pMostRightEntry)))
1658 nFlags |= F_REMOVED_RECALC_MOST_RIGHT;
1661 SvTreeListEntry* pOldStartEntry = pStartEntry;
1663 SvTreeListEntry* pParent = pView->GetModel()->GetParent(pEntry);
1665 if (pParent && pView->GetModel()->GetChildList(pParent).size() == 1)
1667 DBG_ASSERT( pView->IsExpanded( pParent ), "Parent not expanded");
1668 pParent->SetFlags( pParent->GetFlags() | SV_ENTRYFLAG_NO_NODEBMP);
1669 InvalidateEntry( pParent );
1672 if( pCursor && pTree->IsChild( pEntry, pCursor) )
1673 pCursor = pEntry;
1674 if( pStartEntry && pTree->IsChild(pEntry,pStartEntry) )
1675 pStartEntry = pEntry;
1677 SvTreeListEntry* pTemp;
1678 if( pCursor && pCursor == pEntry )
1680 if( bSimpleTravel )
1681 pView->Select( pCursor, false );
1682 ShowCursor( false ); // focus rectangle gone
1683 // NextSibling, because we also delete the children of the cursor
1684 pTemp = pView->NextSibling( pCursor );
1685 if( !pTemp )
1686 pTemp = pView->PrevVisible(pCursor);
1688 SetCursor( pTemp, true );
1690 if( pStartEntry && pStartEntry == pEntry )
1692 pTemp = pView->NextSibling( pStartEntry );
1693 if( !pTemp )
1694 pTemp = pView->PrevVisible(pStartEntry);
1695 pStartEntry = pTemp;
1697 if( GetUpdateMode())
1699 // if it is the last one, we have to invalidate it, so the lines are
1700 // drawn correctly (in this case they're deleted)
1701 if( pStartEntry && (pStartEntry != pOldStartEntry || pEntry == (SvTreeListEntry*)pView->GetModel()->Last()) )
1703 aVerSBar.SetThumbPos( pView->GetVisiblePos( pStartEntry ));
1704 pView->Invalidate( GetVisibleArea() );
1706 else
1707 InvalidateEntriesFrom( GetEntryLine( pEntry ) );
1711 void SvImpLBox::EntryRemoved()
1713 if( nFlags & F_REMOVED_ENTRY_INVISIBLE )
1715 nFlags &= (~F_REMOVED_ENTRY_INVISIBLE);
1716 return;
1718 if( !pStartEntry )
1719 pStartEntry = pTree->First();
1720 if( !pCursor )
1721 SetCursor( pStartEntry, true );
1723 if( pCursor && (bSimpleTravel || !pView->GetSelectionCount() ))
1724 pView->Select( pCursor, true );
1726 if( GetUpdateMode())
1728 if( nFlags & F_REMOVED_RECALC_MOST_RIGHT )
1729 FindMostRight(0);
1730 aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1 ) );
1731 FillView();
1732 if( pStartEntry )
1733 // if something above the thumb was deleted
1734 aVerSBar.SetThumbPos( pView->GetVisiblePos( pStartEntry) );
1736 ShowVerSBar();
1737 if( pCursor && pView->HasFocus() && !pView->IsSelected(pCursor) )
1739 if( pView->GetSelectionCount() )
1741 // is a neighboring entry selected?
1742 SvTreeListEntry* pNextCursor = (SvTreeListEntry*)pView->PrevVisible( pCursor );
1743 if( !pNextCursor || !pView->IsSelected( pNextCursor ))
1744 pNextCursor = (SvTreeListEntry*)pView->NextVisible( pCursor );
1745 if( !pNextCursor || !pView->IsSelected( pNextCursor ))
1746 // no neighbor selected: use first selected
1747 pNextCursor = pView->FirstSelected();
1748 SetCursor( pNextCursor );
1749 MakeVisible( pCursor );
1751 else
1752 pView->Select( pCursor, true );
1754 ShowCursor( true );
1756 nFlags &= (~F_REMOVED_RECALC_MOST_RIGHT);
1760 void SvImpLBox::MovingEntry( SvTreeListEntry* pEntry )
1762 int bDeselAll = nFlags & F_DESEL_ALL;
1763 SelAllDestrAnch( false, true ); // DeselectAll();
1764 if( !bDeselAll )
1765 nFlags &= (~F_DESEL_ALL);
1767 if( pEntry == pCursor )
1768 ShowCursor( false );
1769 if( IsEntryInView( pEntry ) )
1770 pView->Invalidate();
1771 if( pEntry == pStartEntry )
1773 SvTreeListEntry* pNew = 0;
1774 if( !pEntry->HasChildren() )
1776 pNew = pView->NextVisible(pStartEntry);
1777 if( !pNew )
1778 pNew = pView->PrevVisible(pStartEntry);
1780 else
1782 pNew = pTree->NextSibling( pEntry );
1783 if( !pNew )
1784 pNew = pTree->PrevSibling( pEntry );
1786 pStartEntry = pNew;
1790 void SvImpLBox::EntryMoved( SvTreeListEntry* pEntry )
1792 UpdateContextBmpWidthVectorFromMovedEntry( pEntry );
1794 if ( !pStartEntry )
1795 // this might happen if the only entry in the view is moved to its very same position
1796 // #i97346#
1797 pStartEntry = pView->First();
1799 aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1));
1800 sal_uInt16 nFirstPos = (sal_uInt16)pTree->GetAbsPos( pStartEntry );
1801 sal_uInt16 nNewPos = (sal_uInt16)pTree->GetAbsPos( pEntry );
1802 FindMostRight(0);
1803 if( nNewPos < nFirstPos ) // HACK!
1804 pStartEntry = pEntry;
1805 SyncVerThumb();
1806 if( pEntry == pCursor )
1808 if( pView->IsEntryVisible( pCursor ) )
1809 ShowCursor( true );
1810 else
1812 SvTreeListEntry* pParent = pEntry;
1813 do {
1814 pParent = pTree->GetParent( pParent );
1816 while( !pView->IsEntryVisible( pParent ) );
1817 SetCursor( pParent );
1820 if( IsEntryInView( pEntry ) )
1821 pView->Invalidate();
1826 void SvImpLBox::EntryInserted( SvTreeListEntry* pEntry )
1828 if( GetUpdateMode() )
1830 SvTreeListEntry* pParent = (SvTreeListEntry*)pTree->GetParent(pEntry);
1831 if (pParent && pTree->GetChildList(pParent).size() == 1)
1832 // draw plus sign
1833 pTree->InvalidateEntry( pParent );
1835 if( !pView->IsEntryVisible( pEntry ) )
1836 return;
1837 int bDeselAll = nFlags & F_DESEL_ALL;
1838 if( bDeselAll )
1839 SelAllDestrAnch( false, true );
1840 else
1841 DestroyAnchor();
1842 // nFlags &= (~F_DESEL_ALL);
1843 // ShowCursor( false ); // if cursor is moved lower
1844 long nY = GetEntryLine( pEntry );
1845 bool bEntryVisible = IsLineVisible( nY );
1846 if( bEntryVisible )
1848 ShowCursor( false ); // if cursor is moved lower
1849 nY -= pView->GetEntryHeight(); // because of lines
1850 InvalidateEntriesFrom( nY );
1852 else if( pStartEntry && nY < GetEntryLine(pStartEntry) )
1854 // Check if the view is filled completely. If not, then adjust
1855 // pStartEntry and the Cursor (automatic scrolling).
1856 sal_uInt16 nLast = (sal_uInt16)(pView->GetVisiblePos(pView->LastVisible()));
1857 sal_uInt16 nThumb = (sal_uInt16)(pView->GetVisiblePos( pStartEntry ));
1858 sal_uInt16 nCurDispEntries = nLast-nThumb+1;
1859 if( nCurDispEntries < nVisibleCount )
1861 // set at the next paint event
1862 pStartEntry = 0;
1863 SetCursor( 0 );
1864 pView->Invalidate();
1867 else if( !pStartEntry )
1868 pView->Invalidate();
1870 SetMostRight( pEntry );
1871 aVerSBar.SetRange( Range(0, pView->GetVisibleCount()-1));
1872 SyncVerThumb(); // if something was inserted before the thumb
1873 ShowVerSBar();
1874 ShowCursor( true );
1875 if( pStartEntry != pView->First() && (nFlags & F_FILLING) )
1876 pView->Update();
1882 // ********************************************************************
1883 // Event handler
1884 // ********************************************************************
1887 // ****** Control the control animation
1889 bool SvImpLBox::ButtonDownCheckCtrl(
1890 const MouseEvent& rMEvt, SvTreeListEntry* pEntry, long nY)
1892 SvLBoxItem* pItem = pView->GetItem(pEntry,rMEvt.GetPosPixel().X(),&pActiveTab);
1893 if (pItem && pItem->GetType() == SV_ITEM_ID_LBOXBUTTON)
1895 pActiveButton = (SvLBoxButton*)pItem;
1896 pActiveEntry = pEntry;
1897 if( pCursor == pActiveEntry )
1898 pView->HideFocus();
1899 pView->CaptureMouse();
1900 pActiveButton->SetStateHilighted( true );
1901 pView->PaintEntry1( pActiveEntry, nY,
1902 SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER |
1903 SV_LBOXTAB_ADJUST_RIGHT );
1904 return true;
1906 else
1907 pActiveButton = 0;
1908 return false;
1911 bool SvImpLBox::MouseMoveCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry* pEntry)
1913 if( pActiveButton )
1915 long nY;
1916 long nMouseX = rMEvt.GetPosPixel().X();
1917 if( pEntry == pActiveEntry &&
1918 pView->GetItem(pActiveEntry, nMouseX) == pActiveButton )
1920 if( !pActiveButton->IsStateHilighted() )
1922 pActiveButton->SetStateHilighted(true );
1923 nY = GetEntryLine( pActiveEntry );
1924 pView->PaintEntry1( pActiveEntry, nY,
1925 SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER |
1926 SV_LBOXTAB_ADJUST_RIGHT );
1929 else
1931 if( pActiveButton->IsStateHilighted() )
1933 pActiveButton->SetStateHilighted(false );
1934 nY = GetEntryLine( pActiveEntry );
1935 pView->PaintEntry1( pActiveEntry, nY, SV_LBOXTAB_PUSHABLE );
1938 return true;
1940 return false;
1943 bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt )
1945 if( pActiveButton )
1947 pView->ReleaseMouse();
1948 SvTreeListEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() );
1949 long nY = GetEntryLine( pActiveEntry );
1950 pActiveButton->SetStateHilighted( false );
1951 long nMouseX = rMEvt.GetPosPixel().X();
1952 if( pEntry == pActiveEntry &&
1953 pView->GetItem( pActiveEntry, nMouseX ) == pActiveButton )
1954 pActiveButton->ClickHdl( pView, pActiveEntry );
1955 pView->PaintEntry1( pActiveEntry, nY,
1956 SV_LBOXTAB_PUSHABLE | SV_LBOXTAB_ADJUST_CENTER |
1957 SV_LBOXTAB_ADJUST_RIGHT );
1958 if( pCursor == pActiveEntry )
1959 ShowCursor( true );
1960 pActiveButton = 0;
1961 pActiveEntry = 0;
1962 pActiveTab = 0;
1963 return true;
1965 return false;
1968 // ******* Control plus/minus button for expanding/collapsing
1970 // false == no expand/collapse button hit
1971 bool SvImpLBox::IsNodeButton( const Point& rPosPixel, SvTreeListEntry* pEntry ) const
1973 if( !pEntry->HasChildren() && !pEntry->HasChildrenOnDemand() )
1974 return false;
1976 SvLBoxTab* pFirstDynamicTab = pView->GetFirstDynamicTab();
1977 if( !pFirstDynamicTab )
1978 return false;
1980 long nMouseX = rPosPixel.X();
1981 // convert to document coordinates
1982 Point aOrigin( pView->GetMapMode().GetOrigin() );
1983 nMouseX -= aOrigin.X();
1985 long nX = pView->GetTabPos( pEntry, pFirstDynamicTab);
1986 nX += nNodeBmpTabDistance;
1987 if( nMouseX < nX )
1988 return false;
1989 nX += nNodeBmpWidth;
1990 if( nMouseX > nX )
1991 return false;
1992 return true;
1995 // false == hit no node button
1996 bool SvImpLBox::ButtonDownCheckExpand( const MouseEvent& rMEvt, SvTreeListEntry* pEntry, long /* nY */ )
1998 bool bRet = false;
2000 if ( pView->IsEditingActive() && pEntry == pView->pEdEntry )
2001 // inplace editing -> nothing to do
2002 bRet = true;
2003 else if ( IsNodeButton( rMEvt.GetPosPixel(), pEntry ) )
2005 if ( pView->IsExpanded( pEntry ) )
2007 pView->EndEditing( true );
2008 pView->Collapse( pEntry );
2010 else
2012 // you can expand an entry, which is in editing
2013 pView->Expand( pEntry );
2015 bRet = true;
2018 return bRet;
2021 void SvImpLBox::MouseButtonDown( const MouseEvent& rMEvt )
2023 if ( !rMEvt.IsLeft() && !rMEvt.IsRight())
2024 return;
2026 aEditTimer.Stop();
2027 Point aPos( rMEvt.GetPosPixel());
2029 if( aPos.X() > aOutputSize.Width() || aPos.Y() > aOutputSize.Height() )
2030 return;
2032 SvTreeListEntry* pEntry = GetEntry( aPos );
2033 if ( pEntry != pCursor )
2034 // new entry selected -> reset current tab position to first tab
2035 nCurTabPos = FIRST_ENTRY_TAB;
2036 nFlags &= (~F_FILLING);
2037 pView->GrabFocus();
2038 // the entry can still be invalid!
2039 if( !pEntry || !pView->GetViewData( pEntry ))
2040 return;
2042 long nY = GetEntryLine( pEntry );
2043 // Node-Button?
2044 if( ButtonDownCheckExpand( rMEvt, pEntry, nY ) )
2045 return;
2047 if( !EntryReallyHit(pEntry,aPos,nY))
2048 return;
2050 SvLBoxItem* pXItem = pView->GetItem( pEntry, aPos.X() );
2051 if( pXItem )
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 );
2071 if( !pEntry )
2072 return;
2073 if( pEntry != pView->pHdlEntry )
2075 // select anew & bye
2076 if( !bSimpleTravel && !aSelEng.IsAlwaysAdding())
2077 SelAllDestrAnch( false, true ); // DeselectAll();
2078 SetCursor( pEntry );
2080 return;
2082 if( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() )
2084 if( pView->IsExpanded(pEntry) )
2085 pView->Collapse( pEntry );
2086 else
2087 pView->Expand( pEntry );
2088 if( pEntry == pCursor ) // only if Entryitem was clicked
2089 // (Nodebutton is not an Entryitem!)
2090 pView->Select( pCursor, true );
2091 return;
2095 else
2097 // CheckButton? (TreeListBox: Check + Info)
2098 if( ButtonDownCheckCtrl(rMEvt, pEntry, nY) == true)
2099 return;
2100 // Inplace-Editing?
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 );
2110 EndScroll();
2111 if( nFlags & F_START_EDITTIMER )
2113 nFlags &= (~F_START_EDITTIMER);
2114 aEditClickPos = rMEvt.GetPosPixel();
2115 aEditTimer.Start();
2118 return;
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 );
2126 return;
2129 bool SvImpLBox::KeyInput( const KeyEvent& rKEvt)
2131 aEditTimer.Stop();
2132 const KeyCode& rKeyCode = rKEvt.GetKeyCode();
2134 if( rKeyCode.IsMod2() )
2135 return false; // don't evaluate Alt key
2137 nFlags &= (~F_FILLING);
2139 if( !pCursor )
2140 pCursor = pStartEntry;
2141 if( !pCursor )
2142 return false;
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();
2155 switch( aCode )
2157 case KEY_UP:
2158 if( !IsEntryInView( pCursor ) )
2159 MakeVisible( pCursor );
2161 pNewCursor = pCursor;
2164 pNewCursor = pView->PrevVisible(pNewCursor);
2165 } while( pNewCursor && !IsSelectable(pNewCursor) );
2167 if ( 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
2172 // the cursor key
2173 if ( !pNewCursor && pCursor )
2174 pNewCursor = pCursor;
2176 if( pNewCursor )
2178 aSelEng.CursorPosChanging( bShift, bMod1 );
2179 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
2180 if( !IsEntryInView( pNewCursor ) )
2181 KeyUp( false );
2183 break;
2185 case KEY_DOWN:
2186 if( !IsEntryInView( pCursor ) )
2187 MakeVisible( pCursor );
2189 pNewCursor = pCursor;
2192 pNewCursor = pView->NextVisible(pNewCursor);
2193 } while( pNewCursor && !IsSelectable(pNewCursor) );
2195 if ( 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
2201 // the cursor key
2202 // 06.09.20001 - 83416 - frank.schoenheit@sun.com
2203 if ( !pNewCursor && pCursor )
2204 pNewCursor = pCursor;
2206 if( pNewCursor )
2208 aSelEng.CursorPosChanging( bShift, bMod1 );
2209 if( IsEntryInView( pNewCursor ) )
2210 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
2211 else
2213 if( pCursor )
2214 pView->Select( pCursor, false );
2215 KeyDown( false );
2216 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
2219 else
2220 KeyDown( false ); // because scrollbar range might still
2221 // allow scrolling
2222 break;
2224 case KEY_RIGHT:
2226 if( bSubLstOpLR && IsNowExpandable() )
2227 pView->Expand( pCursor );
2228 else if ( bIsCellFocusEnabled && pCursor )
2230 if ( nCurTabPos < ( pView->TabCount() - 1 /*!2*/ ) )
2232 ++nCurTabPos;
2233 ShowCursor( true );
2234 CallEventListeners( VCLEVENT_LISTBOX_SELECT, pCursor );
2237 else if( nWindowStyle & WB_HSCROLL )
2239 long nThumb = aHorSBar.GetThumbPos();
2240 nThumb += aHorSBar.GetLineSize();
2241 long nOldThumb = aHorSBar.GetThumbPos();
2242 aHorSBar.SetThumbPos( nThumb );
2243 nThumb = nOldThumb;
2244 nThumb -= aHorSBar.GetThumbPos();
2245 nThumb *= -1;
2246 if( nThumb )
2248 KeyLeftRight( nThumb );
2249 EndScroll();
2252 else
2253 bKeyUsed = false;
2254 break;
2257 case KEY_LEFT:
2259 if ( bIsCellFocusEnabled )
2261 if ( nCurTabPos > FIRST_ENTRY_TAB )
2263 --nCurTabPos;
2264 ShowCursor( true );
2265 CallEventListeners( VCLEVENT_LISTBOX_SELECT, pCursor );
2268 else if ( nWindowStyle & WB_HSCROLL )
2270 long nThumb = aHorSBar.GetThumbPos();
2271 nThumb -= aHorSBar.GetLineSize();
2272 long nOldThumb = aHorSBar.GetThumbPos();
2273 aHorSBar.SetThumbPos( nThumb );
2274 nThumb = nOldThumb;
2275 nThumb -= aHorSBar.GetThumbPos();
2276 if( nThumb )
2278 KeyLeftRight( -nThumb );
2279 EndScroll();
2281 else if( bSubLstOpLR )
2283 if( IsExpandable() && pView->IsExpanded( pCursor ) )
2284 pView->Collapse( pCursor );
2285 else
2287 pNewCursor = pView->GetParent( pCursor );
2288 if( pNewCursor )
2289 SetCursor( pNewCursor );
2293 else if( bSubLstOpLR && IsExpandable() )
2294 pView->Collapse( pCursor );
2295 else
2296 bKeyUsed = false;
2297 break;
2300 case KEY_PAGEUP:
2301 if( !bMod1 )
2303 pNewCursor = pView->PrevVisible(pCursor, nDelta);
2305 while( nDelta && pNewCursor && !IsSelectable(pNewCursor) )
2307 pNewCursor = pView->NextVisible(pNewCursor);
2308 nDelta--;
2311 if( nDelta )
2313 DBG_ASSERT(pNewCursor&&(sal_uLong)pNewCursor!=(sal_uLong)pCursor,"Cursor?");
2314 aSelEng.CursorPosChanging( bShift, bMod1 );
2315 if( IsEntryInView( pNewCursor ) )
2316 SetCursor( pNewCursor );
2317 else
2319 SetCursor( pNewCursor );
2320 KeyUp( true );
2324 else
2325 bKeyUsed = false;
2326 break;
2328 case KEY_PAGEDOWN:
2329 if( !bMod1 )
2331 pNewCursor= pView->NextVisible(pCursor, nDelta);
2333 while( nDelta && pNewCursor && !IsSelectable(pNewCursor) )
2335 pNewCursor = pView->PrevVisible(pNewCursor);
2336 nDelta--;
2339 if( nDelta )
2341 DBG_ASSERT(pNewCursor&&(sal_uLong)pNewCursor!=(sal_uLong)pCursor,"Cursor?");
2342 aSelEng.CursorPosChanging( bShift, bMod1 );
2343 if( IsEntryInView( pNewCursor ) )
2344 SetCursor( pNewCursor );
2345 else
2347 SetCursor( pNewCursor );
2348 KeyDown( true );
2351 else
2352 KeyDown( false ); // see also: KEY_DOWN
2354 else
2355 bKeyUsed = false;
2356 break;
2358 case KEY_SPACE:
2359 if ( pView->GetSelectionMode() != NO_SELECTION )
2361 if ( bMod1 )
2363 if ( pView->GetSelectionMode() == MULTIPLE_SELECTION && !bShift )
2364 // toggle selection
2365 pView->Select( pCursor, !pView->IsSelected( pCursor ) );
2367 else if ( !bShift /*&& !bMod1*/ )
2369 if ( aSelEng.IsAddMode() )
2371 // toggle selection
2372 pView->Select( pCursor, !pView->IsSelected( pCursor ) );
2374 else if ( !pView->IsSelected( pCursor ) )
2376 SelAllDestrAnch( false );
2377 pView->Select( pCursor, true );
2379 else
2380 bKeyUsed = false;
2382 else
2383 bKeyUsed = false;
2385 else
2386 bKeyUsed = false;
2387 break;
2389 case KEY_RETURN:
2390 if( bSubLstOpRet && IsExpandable() )
2392 if( pView->IsExpanded( pCursor ) )
2393 pView->Collapse( pCursor );
2394 else
2395 pView->Expand( pCursor );
2397 else
2398 bKeyUsed = false;
2399 break;
2401 case KEY_F2:
2402 if( !bShift && !bMod1 )
2404 aEditClickPos = Point( -1, -1 );
2405 EditTimerCall( 0 );
2407 else
2408 bKeyUsed = false;
2409 break;
2411 case KEY_F8:
2412 if( bShift && pView->GetSelectionMode()==MULTIPLE_SELECTION &&
2413 !(m_nStyle & WB_SIMPLEMODE))
2415 if( aSelEng.IsAlwaysAdding() )
2416 aSelEng.AddAlways( false );
2417 else
2418 aSelEng.AddAlways( true );
2420 else
2421 bKeyUsed = false;
2422 break;
2424 case KEY_ADD:
2425 if( pCursor )
2427 if( !pView->IsExpanded(pCursor))
2428 pView->Expand( pCursor );
2429 if( bMod1 )
2431 sal_uInt16 nRefDepth = pTree->GetDepth( pCursor );
2432 SvTreeListEntry* pCur = pTree->Next( pCursor );
2433 while( pCur && pTree->GetDepth(pCur) > nRefDepth )
2435 if( pCur->HasChildren() && !pView->IsExpanded(pCur))
2436 pView->Expand( pCur );
2437 pCur = pTree->Next( pCur );
2441 else
2442 bKeyUsed = false;
2443 break;
2445 case KEY_A:
2446 if( bMod1 )
2447 SelAllDestrAnch( true );
2448 else
2449 bKeyUsed = false;
2450 break;
2452 case KEY_SUBTRACT:
2453 if( pCursor )
2455 if( pView->IsExpanded(pCursor))
2456 pView->Collapse( pCursor );
2457 if( bMod1 )
2459 // collapse all parents until we get to the root
2460 SvTreeListEntry* pParentToCollapse = (SvTreeListEntry*)pTree->GetRootLevelParent(pCursor);
2461 if( pParentToCollapse )
2463 sal_uInt16 nRefDepth;
2464 // special case explorer: if the root only has a single
2465 // entry, don't collapse the root entry
2466 if (pTree->GetChildList(0).size() < 2)
2468 nRefDepth = 1;
2469 pParentToCollapse = pCursor;
2470 while( pTree->GetParent(pParentToCollapse) &&
2471 pTree->GetDepth( pTree->GetParent(pParentToCollapse)) > 0)
2473 pParentToCollapse = pTree->GetParent(pParentToCollapse);
2476 else
2477 nRefDepth = 0;
2479 if( pView->IsExpanded(pParentToCollapse) )
2480 pView->Collapse( pParentToCollapse );
2481 SvTreeListEntry* pCur = pTree->Next( pParentToCollapse );
2482 while( pCur && pTree->GetDepth(pCur) > nRefDepth )
2484 if( pCur->HasChildren() && pView->IsExpanded(pCur) )
2485 pView->Collapse( pCur );
2486 pCur = pTree->Next( pCur );
2491 else
2492 bKeyUsed = false;
2493 break;
2495 case KEY_DIVIDE :
2496 if( bMod1 )
2497 SelAllDestrAnch( true );
2498 else
2499 bKeyUsed = false;
2500 break;
2502 case KEY_COMMA :
2503 if( bMod1 )
2504 SelAllDestrAnch( false );
2505 else
2506 bKeyUsed = false;
2507 break;
2509 case KEY_HOME :
2510 pNewCursor = pView->GetModel()->First();
2512 while( pNewCursor && !IsSelectable(pNewCursor) )
2514 pNewCursor = pView->NextVisible(pNewCursor);
2517 if( pNewCursor && pNewCursor != pCursor )
2519 // SelAllDestrAnch( false );
2520 aSelEng.CursorPosChanging( bShift, bMod1 );
2521 SetCursor( pNewCursor );
2522 if( !IsEntryInView( pNewCursor ) )
2523 MakeVisible( pNewCursor );
2525 else
2526 bKeyUsed = false;
2527 break;
2529 case KEY_END :
2530 pNewCursor = pView->GetModel()->Last();
2532 while( pNewCursor && !IsSelectable(pNewCursor) )
2534 pNewCursor = pView->PrevVisible(pNewCursor);
2537 if( pNewCursor && pNewCursor != pCursor)
2539 // SelAllDestrAnch( false );
2540 aSelEng.CursorPosChanging( bShift, bMod1 );
2541 SetCursor( pNewCursor );
2542 if( !IsEntryInView( pNewCursor ) )
2543 MakeVisible( pNewCursor );
2545 else
2546 bKeyUsed = false;
2547 break;
2549 case KEY_ESCAPE:
2550 case KEY_TAB:
2551 case KEY_DELETE:
2552 case KEY_BACKSPACE:
2553 // must not be handled because this quits dialogs and does other magic things...
2554 // if there are other single keys which should not be handled, they can be added here
2555 bKeyUsed = false;
2556 break;
2558 default:
2559 // is there any reason why we should eat the events here? The only place where this is called
2560 // is from SvTreeListBox::KeyInput. If we set bKeyUsed to true here, then the key input
2561 // is just silenced. However, we want SvLBox::KeyInput to get a chance, to do the QuickSelection
2562 // handling.
2563 // (The old code here which intentionally set bKeyUsed to TRUE said this was because of "quick search"
2564 // handling, but actually there was no quick search handling anymore. We just re-implemented it.)
2565 // #i31275# / 2009-06-16 / frank.schoenheit@sun.com
2566 bKeyUsed = false;
2567 break;
2569 return bKeyUsed;
2572 void SvImpLBox::GetFocus()
2574 if( pCursor )
2576 pView->SetEntryFocus( pCursor, true );
2577 ShowCursor( true );
2578 // auskommentiert wg. deselectall
2579 // if( bSimpleTravel && !pView->IsSelected(pCursor) )
2580 // pView->Select( pCursor, true );
2582 if( m_nStyle & WB_HIDESELECTION )
2584 SvTreeListEntry* pEntry = pView->FirstSelected();
2585 while( pEntry )
2587 InvalidateEntry( pEntry );
2588 pEntry = pView->NextSelected( pEntry );
2593 void SvImpLBox::LoseFocus()
2595 aEditTimer.Stop();
2596 if( pCursor )
2597 pView->SetEntryFocus( pCursor,false );
2598 ShowCursor( false );
2600 if( m_nStyle & WB_HIDESELECTION )
2602 SvTreeListEntry* pEntry = pView->FirstSelected();
2603 while( pEntry )
2605 InvalidateEntry( pEntry );
2606 pEntry = pView->NextSelected( pEntry );
2612 // ********************************************************************
2613 // SelectionEngine
2614 // ********************************************************************
2616 void SvImpLBox::SelectEntry( SvTreeListEntry* pEntry, bool bSelect )
2618 pView->Select( pEntry, bSelect );
2621 ImpLBSelEng::ImpLBSelEng( SvImpLBox* pImpl, SelectionEngine* pSEng,
2622 SvTreeListBox* pV )
2624 pImp = pImpl;
2625 pSelEng = pSEng;
2626 pView = pV;
2629 ImpLBSelEng::~ImpLBSelEng()
2633 void ImpLBSelEng::BeginDrag()
2635 pImp->BeginDrag();
2638 void ImpLBSelEng::CreateAnchor()
2640 pImp->pAnchor = pImp->pCursor;
2643 void ImpLBSelEng::DestroyAnchor()
2645 pImp->pAnchor = 0;
2648 sal_Bool ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, sal_Bool bDontSelectAtCursor)
2650 SvTreeListEntry* pNewCursor = pImp->MakePointVisible( rPoint );
2651 if( pNewCursor != pImp->pCursor )
2652 pImp->BeginScroll();
2654 if( pNewCursor )
2656 // at SimpleTravel, the SetCursor is selected and the select handler is
2657 // called
2658 //if( !bDontSelectAtCursor && !pImp->bSimpleTravel )
2659 // pImp->SelectEntry( pNewCursor, true );
2660 pImp->SetCursor( pNewCursor, bDontSelectAtCursor );
2661 return true;
2663 return false;
2666 sal_Bool ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint )
2668 SvTreeListEntry* pEntry = pImp->MakePointVisible( rPoint );
2669 if( pEntry )
2670 return pView->IsSelected(pEntry);
2671 return false;
2674 void ImpLBSelEng::DeselectAtPoint( const Point& rPoint )
2676 SvTreeListEntry* pEntry = pImp->MakePointVisible( rPoint );
2677 if( !pEntry )
2678 return;
2679 pImp->SelectEntry( pEntry, false );
2682 void ImpLBSelEng::DeselectAll()
2684 pImp->SelAllDestrAnch( false, false ); // don't reset SelectionEngine!
2685 pImp->nFlags &= (~F_DESEL_ALL);
2688 // ***********************************************************************
2689 // Selection
2690 // ***********************************************************************
2692 void SvImpLBox::SetAnchorSelection(SvTreeListEntry* pOldCursor,SvTreeListEntry* pNewCursor)
2694 SvTreeListEntry* pEntry;
2695 sal_uLong nAnchorVisPos = pView->GetVisiblePos( pAnchor );
2696 sal_uLong nOldVisPos = pView->GetVisiblePos( pOldCursor );
2697 sal_uLong nNewVisPos = pView->GetVisiblePos( pNewCursor );
2699 if( nOldVisPos > nAnchorVisPos ||
2700 ( nAnchorVisPos==nOldVisPos && nNewVisPos > nAnchorVisPos) )
2702 if( nNewVisPos > nOldVisPos )
2704 pEntry = pOldCursor;
2705 while( pEntry && pEntry != pNewCursor )
2707 pView->Select( pEntry, true );
2708 pEntry = pView->NextVisible(pEntry);
2710 if( pEntry )
2711 pView->Select( pEntry, true );
2712 return;
2715 if( nNewVisPos < nAnchorVisPos )
2717 pEntry = pAnchor;
2718 while( pEntry && pEntry != pOldCursor )
2720 pView->Select( pEntry, false );
2721 pEntry = pView->NextVisible(pEntry);
2723 if( pEntry )
2724 pView->Select( pEntry, false );
2726 pEntry = pNewCursor;
2727 while( pEntry && pEntry != pAnchor )
2729 pView->Select( pEntry, true );
2730 pEntry = pView->NextVisible(pEntry);
2732 if( pEntry )
2733 pView->Select( pEntry, true );
2734 return;
2737 if( nNewVisPos < nOldVisPos )
2739 pEntry = pNewCursor;
2740 pEntry = pView->NextVisible(pEntry);
2741 while( pEntry && pEntry != pOldCursor )
2743 pView->Select( pEntry, false );
2744 pEntry = pView->NextVisible(pEntry);
2746 if( pEntry )
2747 pView->Select( pEntry, false );
2748 return;
2751 else
2753 if( nNewVisPos < nOldVisPos ) // enlarge selection
2755 pEntry = pNewCursor;
2756 while( pEntry && pEntry != pOldCursor )
2758 pView->Select( pEntry, true );
2759 pEntry = pView->NextVisible(pEntry);
2761 if( pEntry )
2762 pView->Select( pEntry, true );
2763 return;
2766 if( nNewVisPos > nAnchorVisPos )
2768 pEntry = pOldCursor;
2769 while( pEntry && pEntry != pAnchor )
2771 pView->Select( pEntry, false );
2772 pEntry = pView->NextVisible(pEntry);
2774 if( pEntry )
2775 pView->Select( pEntry, false );
2776 pEntry = pAnchor;
2777 while( pEntry && pEntry != pNewCursor )
2779 pView->Select( pEntry, true );
2780 pEntry = pView->NextVisible(pEntry);
2782 if( pEntry )
2783 pView->Select( pEntry, true );
2784 return;
2787 if( nNewVisPos > nOldVisPos )
2789 pEntry = pOldCursor;
2790 while( pEntry && pEntry != pNewCursor )
2792 pView->Select( pEntry, false );
2793 pEntry = pView->NextVisible(pEntry);
2795 return;
2800 void SvImpLBox::SelAllDestrAnch(
2801 bool bSelect, bool bDestroyAnchor, bool bSingleSelToo )
2803 SvTreeListEntry* pEntry;
2804 nFlags &= (~F_DESEL_ALL);
2805 if( bSelect && bSimpleTravel )
2807 if( pCursor && !pView->IsSelected( pCursor ))
2809 pView->Select( pCursor, true );
2811 return;
2813 if( !bSelect && pView->GetSelectionCount() == 0 )
2815 if( bSimpleTravel && ( !GetUpdateMode() || !pCursor) )
2816 nFlags |= F_DESEL_ALL;
2817 return;
2819 if( bSelect && pView->GetSelectionCount() == pView->GetEntryCount())
2820 return;
2821 if( !bSingleSelToo && bSimpleTravel )
2822 return;
2824 if( !bSelect && pView->GetSelectionCount()==1 && pCursor &&
2825 pView->IsSelected( pCursor ))
2827 pView->Select( pCursor, false );
2828 if( bDestroyAnchor )
2829 DestroyAnchor(); // delete anchor & reset SelectionEngine
2830 else
2831 pAnchor = 0; // always delete internal anchor
2832 return;
2835 if( bSimpleTravel && !pCursor && !GetUpdateMode() )
2836 nFlags |= F_DESEL_ALL;
2838 ShowCursor( false );
2839 bool bUpdate = GetUpdateMode();
2841 nFlags |= F_IGNORE_SELECT; // EntryInserted should not do anything
2842 pEntry = pTree->First();
2843 while( pEntry )
2845 if( pView->Select( pEntry, bSelect ) )
2847 if( bUpdate && pView->IsEntryVisible(pEntry) )
2849 long nY = GetEntryLine( pEntry );
2850 if( IsLineVisible( nY ) )
2851 pView->PaintEntry1( pEntry, nY, 0xffff ); // because of ItemsetBrowser SV_LBOXTAB_SHOW_SELECTION );
2854 pEntry = pTree->Next( pEntry );
2856 nFlags &= ~F_IGNORE_SELECT;
2858 if( bDestroyAnchor )
2859 DestroyAnchor(); // delete anchor & reset SelectionEngine
2860 else
2861 pAnchor = 0; // always delete internal anchor
2862 ShowCursor( true );
2865 void SvImpLBox::SetSelectionMode( SelectionMode eSelMode )
2867 aSelEng.SetSelectionMode( eSelMode);
2868 if( eSelMode == SINGLE_SELECTION )
2869 bSimpleTravel = true;
2870 else
2871 bSimpleTravel = false;
2872 if( (m_nStyle & WB_SIMPLEMODE) && (eSelMode == MULTIPLE_SELECTION) )
2873 aSelEng.AddAlways( true );
2876 // ***********************************************************************
2877 // Drag & Drop
2878 // ***********************************************************************
2880 void SvImpLBox::SetDragDropMode( DragDropMode eDDMode )
2882 if( eDDMode && eDDMode != SV_DRAGDROP_APP_DROP )
2884 aSelEng.ExpandSelectionOnMouseMove( false );
2885 aSelEng.EnableDrag( true );
2887 else
2889 aSelEng.ExpandSelectionOnMouseMove( true );
2890 aSelEng.EnableDrag( false );
2894 void SvImpLBox::BeginDrag()
2896 nFlags &= (~F_FILLING);
2897 if( !bAsyncBeginDrag )
2899 BeginScroll();
2900 pView->StartDrag( 0, aSelEng.GetMousePosPixel() );
2901 EndScroll();
2903 else
2905 aAsyncBeginDragPos = aSelEng.GetMousePosPixel();
2906 aAsyncBeginDragTimer.Start();
2910 IMPL_LINK_NOARG(SvImpLBox, BeginDragHdl)
2912 pView->StartDrag( 0, aAsyncBeginDragPos );
2913 return 0;
2916 void SvImpLBox::PaintDDCursor( SvTreeListEntry* pInsertionPos )
2918 long nY;
2919 if( pInsertionPos )
2921 nY = GetEntryLine( pInsertionPos );
2922 nY += pView->GetEntryHeight();
2924 else
2925 nY = 1;
2926 RasterOp eOldOp = pView->GetRasterOp();
2927 pView->SetRasterOp( ROP_INVERT );
2928 Color aOldLineColor = pView->GetLineColor();
2929 pView->SetLineColor( Color( COL_BLACK ) );
2930 pView->DrawLine( Point( 0, nY ), Point( aOutputSize.Width(), nY ) );
2931 pView->SetLineColor( aOldLineColor );
2932 pView->SetRasterOp( eOldOp );
2935 // Delete all submenus of a PopupMenu, recursively
2936 static void lcl_DeleteSubPopups(PopupMenu* pPopup)
2938 for(sal_uInt16 i = 0; i < pPopup->GetItemCount(); i++)
2940 PopupMenu* pSubPopup = pPopup->GetPopupMenu( pPopup->GetItemId( i ));
2941 if(pSubPopup)
2943 lcl_DeleteSubPopups(pSubPopup);
2944 delete pSubPopup;
2949 void SvImpLBox::Command( const CommandEvent& rCEvt )
2951 sal_uInt16 nCommand = rCEvt.GetCommand();
2953 if( nCommand == COMMAND_CONTEXTMENU )
2954 aEditTimer.Stop();
2956 // scroll mouse event?
2957 if( ( ( nCommand == COMMAND_WHEEL ) || ( nCommand == COMMAND_STARTAUTOSCROLL ) || ( nCommand == COMMAND_AUTOSCROLL ) )
2958 && pView->HandleScrollCommand( rCEvt, &aHorSBar, &aVerSBar ) )
2959 return;
2961 if( bContextMenuHandling && nCommand == COMMAND_CONTEXTMENU )
2963 Point aPopupPos;
2964 bool bClickedIsFreePlace = false;
2965 std::stack<SvTreeListEntry*> aSelRestore;
2967 if( rCEvt.IsMouseEvent() )
2968 { // change selection, if mouse position doesn't fit to selection
2970 aPopupPos = rCEvt.GetMousePosPixel();
2972 SvTreeListEntry* pClickedEntry = GetEntry( aPopupPos );
2973 if( pClickedEntry )
2974 { // mouse in non empty area
2975 bool bClickedIsSelected = false;
2977 // collect the currently selected entries
2978 SvTreeListEntry* pSelected = pView->FirstSelected();
2979 while( pSelected )
2981 bClickedIsSelected |= ( pClickedEntry == pSelected );
2982 pSelected = pView->NextSelected( pSelected );
2985 // if the entry which the user clicked at is not selected
2986 if( !bClickedIsSelected )
2987 { // deselect all other and select the clicked one
2988 pView->SelectAll( false );
2989 pView->SetCursor( pClickedEntry );
2992 else if( aSelEng.GetSelectionMode() == SINGLE_SELECTION )
2994 bClickedIsFreePlace = true;
2995 sal_Int32 nSelectedEntries = pView->GetSelectionCount();
2996 SvTreeListEntry* pSelected = pView->FirstSelected();
2997 for(sal_uInt16 nSel = 0; nSel < nSelectedEntries; nSel++ )
2999 aSelRestore.push(pSelected);
3000 pSelected = pView->NextSelected( pSelected );
3002 pView->SelectAll( false );
3004 else
3005 { // deselect all
3006 pView->SelectAll( false );
3011 else
3012 { // key event (or at least no mouse event)
3013 sal_Int32 nSelectionCount = pView->GetSelectionCount();
3015 if( nSelectionCount )
3016 { // now always take first visible as base for positioning the menu
3017 SvTreeListEntry* pSelected = pView->FirstSelected();
3018 while( pSelected )
3020 if( IsEntryInView( pSelected ) )
3021 break;
3023 pSelected = pView->NextSelected( pSelected );
3026 if( !pSelected )
3028 // no one was visible
3029 pSelected = pView->FirstSelected();
3030 pView->MakeVisible( pSelected );
3033 aPopupPos = pView->GetFocusRect( pSelected, pView->GetEntryPosition( pSelected ).Y() ).Center();
3035 else
3036 aPopupPos = Point( 0, 0 );
3039 PopupMenu* pPopup = pView->CreateContextMenu();
3041 if( pPopup )
3043 // do action for selected entry in popup menu
3044 sal_uInt16 nMenuAction = pPopup->Execute( pView, aPopupPos );
3045 if ( nMenuAction )
3046 pView->ExcecuteContextMenuAction( nMenuAction );
3047 lcl_DeleteSubPopups(pPopup);
3048 delete pPopup;
3051 if( bClickedIsFreePlace )
3053 while(!aSelRestore.empty())
3055 SvTreeListEntry* pEntry = aSelRestore.top();
3056 //#i19717# the entry is maybe already deleted
3057 bool bFound = false;
3058 for(sal_uLong nEntry = 0; nEntry < pView->GetEntryCount(); nEntry++)
3059 if(pEntry == pView->GetEntry(nEntry))
3061 bFound = true;
3062 break;
3064 if(bFound)
3065 SetCurEntry( pEntry );
3066 aSelRestore.pop();
3070 #ifndef NOCOMMAND
3071 else
3073 const Point& rPos = rCEvt.GetMousePosPixel();
3074 if( rPos.X() < aOutputSize.Width() && rPos.Y() < aOutputSize.Height() )
3075 aSelEng.Command( rCEvt );
3077 #endif
3080 void SvImpLBox::BeginScroll()
3082 if( !(nFlags & F_IN_SCROLLING))
3084 pView->NotifyBeginScroll();
3085 nFlags |= F_IN_SCROLLING;
3089 void SvImpLBox::EndScroll()
3091 if( nFlags & F_IN_SCROLLING)
3093 pView->NotifyEndScroll();
3094 nFlags &= (~F_IN_SCROLLING);
3099 Rectangle SvImpLBox::GetVisibleArea() const
3101 Point aPos( pView->GetMapMode().GetOrigin() );
3102 aPos.X() *= -1;
3103 Rectangle aRect( aPos, aOutputSize );
3104 return aRect;
3107 void SvImpLBox::Invalidate()
3109 pView->SetClipRegion();
3112 void SvImpLBox::SetCurEntry( SvTreeListEntry* pEntry )
3114 if ( ( aSelEng.GetSelectionMode() != SINGLE_SELECTION )
3115 && ( aSelEng.GetSelectionMode() != NO_SELECTION )
3117 SelAllDestrAnch( false, true, false );
3118 if ( pEntry )
3119 MakeVisible( pEntry );
3120 SetCursor( pEntry );
3121 if ( pEntry && ( aSelEng.GetSelectionMode() != NO_SELECTION ) )
3122 pView->Select( pEntry, true );
3125 IMPL_LINK_NOARG(SvImpLBox, EditTimerCall)
3127 if( pView->IsInplaceEditingEnabled() )
3129 bool bIsMouseTriggered = aEditClickPos.X() >= 0;
3130 if ( bIsMouseTriggered )
3132 Point aCurrentMousePos = pView->GetPointerPosPixel();
3133 if ( ( abs( aCurrentMousePos.X() - aEditClickPos.X() ) > 5 )
3134 || ( abs( aCurrentMousePos.Y() - aEditClickPos.Y() ) > 5 )
3137 return 0L;
3141 SvTreeListEntry* pEntry = GetCurEntry();
3142 if( pEntry )
3144 ShowCursor( false );
3145 pView->ImplEditEntry( pEntry );
3146 ShowCursor( true );
3149 return 0;
3152 bool SvImpLBox::RequestHelp( const HelpEvent& rHEvt )
3154 if( rHEvt.GetMode() & HELPMODE_QUICK )
3156 Point aPos( pView->ScreenToOutputPixel( rHEvt.GetMousePosPixel() ));
3157 if( !GetVisibleArea().IsInside( aPos ))
3158 return false;
3160 SvTreeListEntry* pEntry = GetEntry( aPos );
3161 if( pEntry )
3163 // recalculate text rectangle
3164 SvLBoxTab* pTab;
3165 SvLBoxString* pItem = (SvLBoxString*)(pView->GetItem( pEntry, aPos.X(), &pTab ));
3166 if (!pItem || pItem->GetType() != SV_ITEM_ID_LBOXSTRING)
3167 return false;
3169 aPos = GetEntryPosition( pEntry );
3170 aPos.X() = pView->GetTabPos( pEntry, pTab ); //pTab->GetPos();
3171 Size aSize( pItem->GetSize( pView, pEntry ) );
3172 SvLBoxTab* pNextTab = NextTab( pTab );
3173 bool bItemClipped = false;
3174 // is the item cut off by its right neighbor?
3175 if( pNextTab && pView->GetTabPos(pEntry,pNextTab) < aPos.X()+aSize.Width() )
3177 aSize.Width() = pNextTab->GetPos() - pTab->GetPos();
3178 bItemClipped = true;
3180 Rectangle aItemRect( aPos, aSize );
3182 Rectangle aViewRect( GetVisibleArea() );
3184 if( bItemClipped || !aViewRect.IsInside( aItemRect ) )
3186 // clip the right edge of the item at the edge of the view
3187 //if( aItemRect.Right() > aViewRect.Right() )
3188 // aItemRect.Right() = aViewRect.Right();
3190 Point aPt = pView->OutputToScreenPixel( aItemRect.TopLeft() );
3191 aItemRect.Left() = aPt.X();
3192 aItemRect.Top() = aPt.Y();
3193 aPt = pView->OutputToScreenPixel( aItemRect.BottomRight() );
3194 aItemRect.Right() = aPt.X();
3195 aItemRect.Bottom() = aPt.Y();
3197 Help::ShowQuickHelp( pView, aItemRect,
3198 pItem->GetText(), QUICKHELP_LEFT | QUICKHELP_VCENTER );
3199 return true;
3203 return false;
3206 SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab* pTab )
3208 sal_uInt16 nTabCount = pView->TabCount();
3209 if( nTabCount <= 1 )
3210 return 0;
3211 for( sal_uInt16 nTab=0; nTab < (nTabCount-1); nTab++)
3213 if( pView->aTabs[nTab]==pTab )
3214 return (SvLBoxTab*)(pView->aTabs[nTab+1]);
3216 return 0;
3219 void SvImpLBox::EndSelection()
3221 DestroyAnchor();
3222 nFlags &= ~F_START_EDITTIMER;
3225 void SvImpLBox::RepaintScrollBars()
3229 void SvImpLBox::SetUpdateMode( bool bMode )
3231 if( bUpdateMode != bMode )
3233 bUpdateMode = bMode;
3234 if( bUpdateMode )
3235 UpdateAll( false );
3239 bool SvImpLBox::SetMostRight( SvTreeListEntry* pEntry )
3241 if( pView->nTreeFlags & TREEFLAG_RECALCTABS )
3243 nFlags |= F_IGNORE_CHANGED_TABS;
3244 pView->SetTabs();
3245 nFlags &= ~F_IGNORE_CHANGED_TABS;
3248 sal_uInt16 nLastTab = pView->aTabs.size() - 1;
3249 sal_uInt16 nLastItem = pEntry->ItemCount() - 1;
3250 if( !pView->aTabs.empty() && nLastItem != USHRT_MAX )
3252 if( nLastItem < nLastTab )
3253 nLastTab = nLastItem;
3255 SvLBoxTab* pTab = pView->aTabs[ nLastTab ];
3256 SvLBoxItem* pItem = pEntry->GetItem( nLastTab );
3258 long nTabPos = pView->GetTabPos( pEntry, pTab );
3260 long nMaxRight = GetOutputSize().Width();
3261 Point aPos( pView->GetMapMode().GetOrigin() );
3262 aPos.X() *= -1; // conversion document coordinates
3263 nMaxRight = nMaxRight + aPos.X() - 1;
3265 long nNextTab = nTabPos < nMaxRight ? nMaxRight : nMaxRight + 50;
3266 long nTabWidth = nNextTab - nTabPos + 1;
3267 long nItemSize = pItem->GetSize(pView,pEntry).Width();
3268 long nOffset = pTab->CalcOffset( nItemSize, nTabWidth );
3270 long nRight = nTabPos + nOffset + nItemSize;
3271 if( nRight > nMostRight )
3273 nMostRight = nRight;
3274 pMostRightEntry = pEntry;
3275 return true;
3278 return false;
3281 void SvImpLBox::FindMostRight( SvTreeListEntry* pEntryToIgnore )
3283 nMostRight = -1;
3284 pMostRightEntry = 0;
3285 if( !pView->GetModel() )
3286 return;
3288 SvTreeListEntry* pEntry = (SvTreeListEntry*)pView->FirstVisible();
3289 while( pEntry )
3291 if( pEntry != pEntryToIgnore )
3292 SetMostRight( pEntry );
3293 pEntry = (SvTreeListEntry*)pView->NextVisible( pEntry );
3297 void SvImpLBox::FindMostRight( SvTreeListEntry* pParent, SvTreeListEntry* pEntryToIgnore )
3299 if( !pParent )
3300 FindMostRight( pEntryToIgnore );
3301 else
3302 FindMostRight_Impl( pParent, pEntryToIgnore );
3305 void SvImpLBox::FindMostRight_Impl( SvTreeListEntry* pParent, SvTreeListEntry* pEntryToIgnore )
3307 SvTreeListEntries& rList = pTree->GetChildList( pParent );
3309 size_t nCount = rList.size();
3310 for( size_t nCur = 0; nCur < nCount; nCur++ )
3312 SvTreeListEntry* pChild = &rList[nCur];
3313 if( pChild != pEntryToIgnore )
3315 SetMostRight( pChild );
3316 if( pChild->HasChildren() && pView->IsExpanded( pChild ))
3317 FindMostRight_Impl( pChild, pEntryToIgnore );
3322 void SvImpLBox::NotifyTabsChanged()
3324 if( GetUpdateMode() && !(nFlags & F_IGNORE_CHANGED_TABS ) &&
3325 nCurUserEvent == 0xffffffff )
3327 nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent),(void*)0);
3331 bool SvImpLBox::IsExpandable() const
3333 return pCursor->HasChildren() || pCursor->HasChildrenOnDemand();
3336 bool SvImpLBox::IsNowExpandable() const
3338 return IsExpandable() && !pView->IsExpanded( pCursor );
3341 IMPL_LINK(SvImpLBox,MyUserEvent,void*, pArg )
3343 nCurUserEvent = 0xffffffff;
3344 if( !pArg )
3346 pView->Invalidate();
3347 pView->Update();
3349 else
3351 FindMostRight( 0 );
3352 ShowVerSBar();
3353 pView->Invalidate( GetVisibleArea() );
3355 return 0;
3359 void SvImpLBox::StopUserEvent()
3361 if( nCurUserEvent != 0xffffffff )
3363 Application::RemoveUserEvent( nCurUserEvent );
3364 nCurUserEvent = 0xffffffff;
3368 void SvImpLBox::ShowFocusRect( const SvTreeListEntry* pEntry )
3370 if( pEntry )
3372 long nY = GetEntryLine( (SvTreeListEntry*)pEntry );
3373 Rectangle aRect = pView->GetFocusRect( (SvTreeListEntry*)pEntry, nY );
3374 Region aOldClip( pView->GetClipRegion());
3375 Region aClipRegion( GetClipRegionRect() );
3376 pView->SetClipRegion( aClipRegion );
3377 pView->ShowFocus( aRect );
3378 pView->SetClipRegion( aOldClip );
3381 else
3383 pView->HideFocus();
3387 // -----------------------------------------------------------------------
3388 void SvImpLBox::implInitDefaultNodeImages()
3390 if ( s_pDefCollapsed )
3391 // assume that all or nothing is initialized
3392 return;
3394 s_pDefCollapsed = new Image( SvtResId( RID_IMG_TREENODE_COLLAPSED ) );
3395 s_pDefExpanded = new Image( SvtResId( RID_IMG_TREENODE_EXPANDED ) );
3398 // -----------------------------------------------------------------------
3399 const Image& SvImpLBox::GetDefaultExpandedNodeImage( )
3401 implInitDefaultNodeImages();
3402 return *s_pDefExpanded;
3405 // -----------------------------------------------------------------------
3406 const Image& SvImpLBox::GetDefaultCollapsedNodeImage( )
3408 implInitDefaultNodeImages();
3409 return *s_pDefCollapsed;
3412 // -----------------------------------------------------------------------
3413 void SvImpLBox::CallEventListeners( sal_uLong nEvent, void* pData )
3415 if ( pView )
3416 pView->CallImplEventListeners( nEvent, pData);
3419 // -----------------------------------------------------------------------
3421 bool SvImpLBox::SetCurrentTabPos( sal_uInt16 _nNewPos )
3423 bool bRet = false;
3425 if ( pView && _nNewPos < ( pView->TabCount() - 2 ) )
3427 nCurTabPos = _nNewPos;
3428 ShowCursor( true );
3429 bRet = true;
3432 return bRet;
3435 // -----------------------------------------------------------------------
3437 bool SvImpLBox::IsSelectable( const SvTreeListEntry* pEntry )
3439 if( pEntry )
3441 SvViewDataEntry* pViewDataNewCur = pView->GetViewDataEntry(const_cast<SvTreeListEntry*>(pEntry));
3442 return (pViewDataNewCur == 0) || pViewDataNewCur->IsSelectable();
3444 else
3446 return false;
3450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */