Bump version to 5.0-14
[LibreOffice.git] / svtools / source / contnr / treelistbox.cxx
blobc418956ab643464b81d933bab16645633ab0cf4a
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 .
21 TODO:
22 - delete anchor in SelectionEngine when selecting manually
23 - SelectAll( false ) => only repaint the delselected entries
26 #include <svtools/treelistbox.hxx>
27 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
28 #include <vcl/svapp.hxx>
29 #include <vcl/accel.hxx>
30 #include <vcl/i18nhelp.hxx>
31 #include <vcl/builderfactory.hxx>
32 #include <vcl/settings.hxx>
33 #include <sot/formats.hxx>
34 #include <unotools/accessiblestatesethelper.hxx>
35 #include <rtl/instance.hxx>
36 #include <comphelper/string.hxx>
38 #include <svtools/svmedit.hxx>
39 #include <svtools/svlbitm.hxx>
40 #include <svtools/treelistentry.hxx>
41 #include <svtools/viewdataentry.hxx>
42 #include "svimpbox.hxx"
44 #include <set>
45 #include <string.h>
46 #include <vector>
48 using namespace css::accessibility;
50 // Drag&Drop
51 static VclPtr<SvTreeListBox> pDDSource;
52 static VclPtr<SvTreeListBox> pDDTarget;
54 #define SVLBOX_ACC_RETURN 1
55 #define SVLBOX_ACC_ESCAPE 2
57 // ***************************************************************
59 class MyEdit_Impl : public Edit
61 SvInplaceEdit2* pOwner;
62 public:
63 MyEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* pOwner );
64 virtual ~MyEdit_Impl() { disposeOnce(); }
65 virtual void dispose() SAL_OVERRIDE { pOwner = NULL; Edit::dispose(); }
66 virtual void KeyInput( const KeyEvent& rKEvt ) SAL_OVERRIDE;
67 virtual void LoseFocus() SAL_OVERRIDE;
70 class MyMultiEdit_Impl : public MultiLineEdit
72 SvInplaceEdit2* pOwner;
73 public:
74 MyMultiEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* pOwner );
75 virtual ~MyMultiEdit_Impl() { disposeOnce(); }
76 virtual void dispose() SAL_OVERRIDE { pOwner = NULL; MultiLineEdit::dispose(); }
77 virtual void KeyInput( const KeyEvent& rKEvt ) SAL_OVERRIDE;
78 virtual void LoseFocus() SAL_OVERRIDE;
81 MyEdit_Impl::MyEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* _pOwner ) :
83 Edit( pParent, WB_LEFT ),
85 pOwner( _pOwner )
90 void MyEdit_Impl::KeyInput( const KeyEvent& rKEvt )
92 if( !pOwner->KeyInput( rKEvt ))
93 Edit::KeyInput( rKEvt );
96 void MyEdit_Impl::LoseFocus()
98 if (pOwner)
99 pOwner->LoseFocus();
102 MyMultiEdit_Impl::MyMultiEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* _pOwner )
103 : MultiLineEdit( pParent,
104 WB_CENTER
105 ), pOwner(_pOwner)
109 void MyMultiEdit_Impl::KeyInput( const KeyEvent& rKEvt )
111 if( !pOwner->KeyInput( rKEvt ))
112 MultiLineEdit::KeyInput( rKEvt );
115 void MyMultiEdit_Impl::LoseFocus()
117 if (pOwner)
118 pOwner->LoseFocus();
122 SvInplaceEdit2::SvInplaceEdit2
124 vcl::Window* pParent, const Point& rPos,
125 const Size& rSize,
126 const OUString& rData,
127 const Link<>& rNotifyEditEnd,
128 const Selection& rSelection,
129 bool bMulti
132 aCallBackHdl ( rNotifyEditEnd ),
133 bCanceled ( false ),
134 bAlreadyInCallBack ( false )
138 if( bMulti )
139 pEdit = VclPtr<MyMultiEdit_Impl>::Create( pParent, this );
140 else
141 pEdit = VclPtr<MyEdit_Impl>::Create( pParent, this );
143 vcl::Font aFont( pParent->GetFont() );
144 aFont.SetTransparent( false );
145 Color aColor( pParent->GetBackground().GetColor() );
146 aFont.SetFillColor(aColor );
147 pEdit->SetFont( aFont );
148 pEdit->SetBackground( pParent->GetBackground() );
149 pEdit->SetPosPixel( rPos );
150 pEdit->SetSizePixel( rSize );
151 pEdit->SetText( rData );
152 pEdit->SetSelection( rSelection );
153 pEdit->SaveValue();
155 aAccReturn.InsertItem( SVLBOX_ACC_RETURN, vcl::KeyCode(KEY_RETURN) );
156 aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE, vcl::KeyCode(KEY_ESCAPE) );
158 aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit2, ReturnHdl_Impl) );
159 aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit2, EscapeHdl_Impl) );
160 Application::InsertAccel( &aAccReturn );
161 Application::InsertAccel( &aAccEscape );
163 pEdit->Show();
164 pEdit->GrabFocus();
167 SvInplaceEdit2::~SvInplaceEdit2()
169 if( !bAlreadyInCallBack )
171 Application::RemoveAccel( &aAccReturn );
172 Application::RemoveAccel( &aAccEscape );
174 pEdit.disposeAndClear();
177 OUString SvInplaceEdit2::GetSavedValue() const
179 return pEdit->GetSavedValue();
182 void SvInplaceEdit2::Hide()
184 pEdit->Hide();
188 IMPL_LINK_NOARG(SvInplaceEdit2, ReturnHdl_Impl)
190 bCanceled = false;
191 CallCallBackHdl_Impl();
192 return 1;
195 IMPL_LINK_NOARG(SvInplaceEdit2, EscapeHdl_Impl)
197 bCanceled = true;
198 CallCallBackHdl_Impl();
199 return 1;
202 bool SvInplaceEdit2::KeyInput( const KeyEvent& rKEvt )
204 vcl::KeyCode aCode = rKEvt.GetKeyCode();
205 sal_uInt16 nCode = aCode.GetCode();
207 switch ( nCode )
209 case KEY_ESCAPE:
210 bCanceled = true;
211 CallCallBackHdl_Impl();
212 return true;
214 case KEY_RETURN:
215 bCanceled = false;
216 CallCallBackHdl_Impl();
217 return true;
219 return false;
222 void SvInplaceEdit2::StopEditing( bool bCancel )
224 if ( !bAlreadyInCallBack )
226 bCanceled = bCancel;
227 CallCallBackHdl_Impl();
231 void SvInplaceEdit2::LoseFocus()
233 if ( !bAlreadyInCallBack
234 && ((!Application::GetFocusWindow()) || !pEdit->IsChild( Application::GetFocusWindow()) )
237 bCanceled = false;
238 aIdle.SetPriority(SchedulerPriority::REPAINT);
239 aIdle.SetIdleHdl(LINK(this,SvInplaceEdit2,Timeout_Impl));
240 aIdle.Start();
244 IMPL_LINK_NOARG_TYPED(SvInplaceEdit2, Timeout_Impl, Idle *, void)
246 CallCallBackHdl_Impl();
249 void SvInplaceEdit2::CallCallBackHdl_Impl()
251 aIdle.Stop();
252 if ( !bAlreadyInCallBack )
254 bAlreadyInCallBack = true;
255 Application::RemoveAccel( &aAccReturn );
256 Application::RemoveAccel( &aAccEscape );
257 pEdit->Hide();
258 aCallBackHdl.Call( this );
262 OUString SvInplaceEdit2::GetText() const
264 return pEdit->GetText();
267 // ***************************************************************
268 // class SvLBoxTab
269 // ***************************************************************
272 SvLBoxTab::SvLBoxTab()
274 nPos = 0;
275 pUserData = 0;
276 nFlags = SvLBoxTabFlags::NONE;
279 SvLBoxTab::SvLBoxTab( long nPosition, SvLBoxTabFlags nTabFlags )
281 nPos = nPosition;
282 pUserData = 0;
283 nFlags = nTabFlags;
286 SvLBoxTab::SvLBoxTab( const SvLBoxTab& rTab )
288 nPos = rTab.nPos;
289 pUserData = rTab.pUserData;
290 nFlags = rTab.nFlags;
293 SvLBoxTab::~SvLBoxTab()
298 long SvLBoxTab::CalcOffset( long nItemWidth, long nTabWidth )
300 long nOffset = 0;
301 if ( nFlags & SvLBoxTabFlags::ADJUST_RIGHT )
303 nOffset = nTabWidth - nItemWidth;
304 if( nOffset < 0 )
305 nOffset = 0;
307 else if ( nFlags & SvLBoxTabFlags::ADJUST_CENTER )
309 if( nFlags & SvLBoxTabFlags::FORCE )
311 // correct implementation of centering
312 nOffset = ( nTabWidth - nItemWidth ) / 2;
313 if( nOffset < 0 )
314 nOffset = 0;
316 else
318 // historically grown, wrong calculation of tabs which is needed by
319 // Abo-Tabbox, Tools/Options/Customize etc.
320 nItemWidth++;
321 nOffset = -( nItemWidth / 2 );
324 return nOffset;
327 // ***************************************************************
328 // class SvLBoxItem
329 // ***************************************************************
332 SvLBoxItem::SvLBoxItem( SvTreeListEntry*, sal_uInt16 )
336 SvLBoxItem::SvLBoxItem()
340 SvLBoxItem::~SvLBoxItem()
344 const Size& SvLBoxItem::GetSize(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
346 const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
347 return pViewData->maSize;
350 const Size& SvLBoxItem::GetSize(const SvViewDataEntry* pData, sal_uInt16 nItemPos)
352 const SvViewDataItem* pIData = pData->GetItem(nItemPos);
353 return pIData->maSize;
356 struct SvTreeListBoxImpl
358 bool m_bIsEmptyTextAllowed:1;
359 bool m_bEntryMnemonicsEnabled:1;
360 bool m_bDoingQuickSelection:1;
362 Link<>* m_pLink;
364 vcl::MnemonicEngine m_aMnemonicEngine;
365 vcl::QuickSelectionEngine m_aQuickSelectionEngine;
367 SvTreeListBoxImpl(SvTreeListBox& _rBox) :
368 m_bIsEmptyTextAllowed(true),
369 m_bEntryMnemonicsEnabled(false),
370 m_bDoingQuickSelection(false),
371 m_pLink(NULL),
372 m_aMnemonicEngine(_rBox),
373 m_aQuickSelectionEngine(_rBox) {}
377 SvTreeListBox::SvTreeListBox(vcl::Window* pParent, WinBits nWinStyle) :
378 Control(pParent, nWinStyle | WB_CLIPCHILDREN),
379 DropTargetHelper(this),
380 DragSourceHelper(this),
381 mpImpl(new SvTreeListBoxImpl(*this)),
382 mbContextBmpExpanded(false),
383 mbAlternatingRowColors(false),
384 eSelMode(NO_SELECTION),
385 nMinWidthInChars(0)
387 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
388 nImpFlags = SvTreeListBoxFlags::NONE;
389 pTargetEntry = 0;
390 nDragDropMode = DragDropMode::NONE;
391 SvTreeList* pTempModel = new SvTreeList;
392 pTempModel->SetRefCount( 0 );
393 SetBaseModel(pTempModel);
394 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
395 pModel->InsertView( this );
396 pHdlEntry = 0;
397 pEdCtrl = 0;
398 eSelMode = SINGLE_SELECTION;
399 nDragDropMode = DragDropMode::NONE;
400 SetType(WINDOW_TREELISTBOX);
402 InitTreeView();
404 SetSublistOpenWithLeftRight();
407 SvTreeListBox::SvTreeListBox(vcl::Window* pParent, const ResId& rResId) :
408 Control(pParent, rResId),
409 DropTargetHelper(this),
410 DragSourceHelper(this),
411 mpImpl(new SvTreeListBoxImpl(*this)),
412 mbContextBmpExpanded(false),
413 mbAlternatingRowColors(false),
414 eSelMode(NO_SELECTION),
415 nMinWidthInChars(0)
417 pTargetEntry = 0;
418 nImpFlags = SvTreeListBoxFlags::NONE;
419 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
420 nDragDropMode = DragDropMode::NONE;
421 SvTreeList* pTempModel = new SvTreeList;
422 pTempModel->SetRefCount( 0 );
423 SetBaseModel(pTempModel);
424 pModel->InsertView( this );
425 pHdlEntry = 0;
426 pEdCtrl = 0;
427 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
428 SetType(WINDOW_TREELISTBOX);
430 InitTreeView();
431 Resize();
433 SetSublistOpenWithLeftRight();
436 VCL_BUILDER_DECL_FACTORY(SvTreeListBox)
438 WinBits nWinStyle = WB_TABSTOP;
439 OString sBorder = VclBuilder::extractCustomProperty(rMap);
440 if (!sBorder.isEmpty())
441 nWinStyle |= WB_BORDER;
442 rRet = VclPtr<SvTreeListBox>::Create(pParent, nWinStyle);
445 void SvTreeListBox::Clear()
447 if (pModel)
448 pModel->Clear(); // Model calls SvTreeListBox::ModelHasCleared()
451 void SvTreeListBox::EnableEntryMnemonics( bool _bEnable )
453 if ( _bEnable == IsEntryMnemonicsEnabled() )
454 return;
456 mpImpl->m_bEntryMnemonicsEnabled = _bEnable;
457 Invalidate();
460 bool SvTreeListBox::IsEntryMnemonicsEnabled() const
462 return mpImpl->m_bEntryMnemonicsEnabled;
465 IMPL_LINK( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry )
467 return reinterpret_cast<sal_IntPtr>(CloneEntry(pEntry));
470 sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos )
472 sal_uLong nInsPos = pModel->Insert( pEntry, pParent, nPos );
473 pEntry->SetBackColor( GetBackground().GetColor() );
474 if(mbAlternatingRowColors)
476 if(nPos == TREELIST_APPEND)
478 if(Prev(pEntry) && Prev(pEntry)->GetBackColor() == GetBackground().GetColor())
479 pEntry->SetBackColor( GetSettings().GetStyleSettings().GetAlternatingRowColor() );
481 else
482 SetAlternatingRowColors( true );
484 return nInsPos;
487 sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry,sal_uLong nRootPos )
489 sal_uLong nInsPos = pModel->Insert( pEntry, nRootPos );
490 pEntry->SetBackColor( GetBackground().GetColor() );
491 if(mbAlternatingRowColors)
493 if(nRootPos == TREELIST_APPEND)
495 if(Prev(pEntry) && Prev(pEntry)->GetBackColor() == GetBackground().GetColor())
496 pEntry->SetBackColor( GetSettings().GetStyleSettings().GetAlternatingRowColor() );
498 else
499 SetAlternatingRowColors( true );
501 return nInsPos;
504 bool SvTreeListBox::ExpandingHdl()
506 return !aExpandingHdl.IsSet() || aExpandingHdl.Call( this );
509 void SvTreeListBox::ExpandedHdl()
511 aExpandedHdl.Call( this );
514 void SvTreeListBox::SelectHdl()
516 aSelectHdl.Call( this );
519 void SvTreeListBox::DeselectHdl()
521 aDeselectHdl.Call( this );
524 bool SvTreeListBox::DoubleClickHdl()
526 aDoubleClickHdl.Call( this );
527 return true;
531 bool SvTreeListBox::CheckDragAndDropMode( SvTreeListBox* pSource, sal_Int8 nAction )
533 if ( pSource == this )
535 if ( !(nDragDropMode & (DragDropMode::CTRL_MOVE | DragDropMode::CTRL_COPY) ) )
536 return false; // D&D locked within list
537 if( DND_ACTION_MOVE == nAction )
539 if ( !(nDragDropMode & DragDropMode::CTRL_MOVE) )
540 return false; // no local move
542 else
544 if ( !(nDragDropMode & DragDropMode::CTRL_COPY))
545 return false; // no local copy
548 else
550 if ( !(nDragDropMode & DragDropMode::APP_DROP ) )
551 return false; // no drop
552 if ( DND_ACTION_MOVE == nAction )
554 if ( !(nDragDropMode & DragDropMode::APP_MOVE) )
555 return false; // no global move
557 else
559 if ( !(nDragDropMode & DragDropMode::APP_COPY))
560 return false; // no global copy
563 return true;
570 NotifyMoving/Copying
571 ====================
573 default behavior:
575 1. target doesn't have children
576 - entry becomes sibling of target. entry comes after target
577 (->Window: below the target)
578 2. target is an expanded parent
579 - entry inserted at the beginning of the target childlist
580 3. target is a collapsed parent
581 - entry is inserted at the end of the target childlist
583 #ifdef DBG_UTIL
584 TriState SvTreeListBox::NotifyMoving(
585 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
586 SvTreeListEntry* pEntry, // entry that we want to move, from
587 // GetSourceListBox()->GetModel()
588 SvTreeListEntry*& rpNewParent, // new target parent
589 sal_uLong& rNewChildPos) // position in childlist of target parent
590 #else
591 TriState SvTreeListBox::NotifyMoving(
592 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
593 SvTreeListEntry*, // entry that we want to move, from
594 // GetSourceListBox()->GetModel()
595 SvTreeListEntry*& rpNewParent, // new target parent
596 sal_uLong& rNewChildPos) // position in childlist of target parent
597 #endif
599 DBG_ASSERT(pEntry,"NotifyMoving:SoureEntry?");
600 if( !pTarget )
602 rpNewParent = 0;
603 rNewChildPos = 0;
604 return TRISTATE_TRUE;
606 if ( !pTarget->HasChildren() && !pTarget->HasChildrenOnDemand() )
608 // case 1
609 rpNewParent = GetParent( pTarget );
610 rNewChildPos = SvTreeList::GetRelPos( pTarget ) + 1;
611 rNewChildPos += nCurEntrySelPos;
612 nCurEntrySelPos++;
614 else
616 // cases 2 & 3
617 rpNewParent = pTarget;
618 if( IsExpanded(pTarget))
619 rNewChildPos = 0;
620 else
621 rNewChildPos = TREELIST_APPEND;
623 return TRISTATE_TRUE;
626 TriState SvTreeListBox::NotifyCopying(
627 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
628 SvTreeListEntry* pEntry, // entry that we want to move, from
629 // GetSourceListBox()->GetModel()
630 SvTreeListEntry*& rpNewParent, // new target parent
631 sal_uLong& rNewChildPos) // position in childlist of target parent
633 return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos);
636 SvTreeListEntry* SvTreeListBox::FirstChild( SvTreeListEntry* pParent ) const
638 return pModel->FirstChild(pParent);
641 SvTreeListEntry* SvTreeListBox::NextSibling( SvTreeListEntry* pEntry )
643 return SvTreeList::NextSibling(pEntry);
646 SvTreeListEntry* SvTreeListBox::PrevSibling( SvTreeListEntry* pEntry )
648 return SvTreeList::PrevSibling(pEntry);
651 // return: all entries copied
652 bool SvTreeListBox::CopySelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
654 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
655 bool bSuccess = true;
656 std::vector<SvTreeListEntry*> aList;
657 bool bClone = ( pSource->GetModel() != GetModel() );
658 Link<> aCloneLink( pModel->GetCloneLink() );
659 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
661 // cache selection to simplify iterating over the selection when doing a D&D
662 // exchange within the same listbox
663 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
664 while ( pSourceEntry )
666 // children are copied automatically
667 pSource->SelectChildren( pSourceEntry, false );
668 aList.push_back( pSourceEntry );
669 pSourceEntry = pSource->NextSelected( pSourceEntry );
672 std::vector<SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
673 for (; it != itEnd; ++it)
675 pSourceEntry = *it;
676 SvTreeListEntry* pNewParent = 0;
677 sal_uLong nInsertionPos = TREELIST_APPEND;
678 TriState nOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
679 if ( nOk )
681 if ( bClone )
683 sal_uLong nCloneCount = 0;
684 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
685 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
687 else
689 sal_uLong nListPos = pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
690 pSourceEntry = GetEntry( pNewParent, nListPos );
693 else
694 bSuccess = false;
696 if (nOk == TRISTATE_INDET) // HACK: make visible moved entry
697 MakeVisible( pSourceEntry );
699 pModel->SetCloneLink( aCloneLink );
700 return bSuccess;
703 // return: all entries were moved
704 bool SvTreeListBox::MoveSelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
706 return MoveSelectionCopyFallbackPossible( pSource, pTarget, false );
709 bool SvTreeListBox::MoveSelectionCopyFallbackPossible( SvTreeListBox* pSource, SvTreeListEntry* pTarget, bool bAllowCopyFallback )
711 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
712 bool bSuccess = true;
713 std::vector<SvTreeListEntry*> aList;
714 bool bClone = ( pSource->GetModel() != GetModel() );
715 Link<> aCloneLink( pModel->GetCloneLink() );
716 if ( bClone )
717 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
719 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
720 while ( pSourceEntry )
722 // children are automatically moved
723 pSource->SelectChildren( pSourceEntry, false );
724 aList.push_back( pSourceEntry );
725 pSourceEntry = pSource->NextSelected( pSourceEntry );
728 std::vector<SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
729 for (; it != itEnd; ++it)
731 pSourceEntry = *it;
733 SvTreeListEntry* pNewParent = 0;
734 sal_uLong nInsertionPos = TREELIST_APPEND;
735 TriState nOk = NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos);
736 TriState nCopyOk = nOk;
737 if ( !nOk && bAllowCopyFallback )
739 nInsertionPos = TREELIST_APPEND;
740 nCopyOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
743 if ( nOk || nCopyOk )
745 if ( bClone )
747 sal_uLong nCloneCount = 0;
748 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
749 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
751 else
753 if ( nOk )
754 pModel->Move(pSourceEntry, pNewParent, nInsertionPos);
755 else
756 pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
759 else
760 bSuccess = false;
762 if (nOk == TRISTATE_INDET) // HACK: make moved entry visible
763 MakeVisible( pSourceEntry );
765 pModel->SetCloneLink( aCloneLink );
766 return bSuccess;
769 void SvTreeListBox::RemoveSelection()
771 std::vector<const SvTreeListEntry*> aList;
772 // cache selection, as the implementation deselects everything on the first
773 // remove
774 SvTreeListEntry* pEntry = FirstSelected();
775 while ( pEntry )
777 aList.push_back( pEntry );
778 if ( pEntry->HasChildren() )
779 // remove deletes all children automatically
780 SelectChildren(pEntry, false);
781 pEntry = NextSelected( pEntry );
784 std::vector<const SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
785 for (; it != itEnd; ++it)
786 pModel->Remove(*it);
789 SvTreeListBox* SvTreeListBox::GetSourceView()
791 return pDDSource;
794 void SvTreeListBox::RecalcViewData()
796 SvTreeListEntry* pEntry = First();
797 while( pEntry )
799 sal_uInt16 nCount = pEntry->ItemCount();
800 sal_uInt16 nCurPos = 0;
801 while ( nCurPos < nCount )
803 SvLBoxItem* pItem = pEntry->GetItem( nCurPos );
804 pItem->InitViewData( this, pEntry );
805 nCurPos++;
807 pEntry = Next( pEntry );
811 void SvTreeListBox::ImplShowTargetEmphasis( SvTreeListEntry* pEntry, bool bShow)
813 if ( bShow && (nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
814 return;
815 if ( !bShow && !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
816 return;
817 ShowTargetEmphasis( pEntry, bShow );
818 if( bShow )
819 nImpFlags |= SvTreeListBoxFlags::TARGEMPH_VIS;
820 else
821 nImpFlags &= ~SvTreeListBoxFlags::TARGEMPH_VIS;
824 void SvTreeListBox::OnCurrentEntryChanged()
826 if ( !mpImpl->m_bDoingQuickSelection )
827 mpImpl->m_aQuickSelectionEngine.Reset();
830 SvTreeListEntry* SvTreeListBox::GetEntry( SvTreeListEntry* pParent, sal_uLong nPos ) const
832 return pModel->GetEntry(pParent, nPos);
835 SvTreeListEntry* SvTreeListBox::GetEntry( sal_uLong nRootPos ) const
837 return pModel->GetEntry(nRootPos);
840 SvTreeListEntry* SvTreeListBox::GetEntryFromPath( const ::std::deque< sal_Int32 >& _rPath ) const
843 SvTreeListEntry* pEntry = NULL;
844 SvTreeListEntry* pParent = NULL;
845 for( ::std::deque< sal_Int32 >::const_iterator pItem = _rPath.begin(); pItem != _rPath.end(); ++pItem )
847 pEntry = GetEntry( pParent, *pItem );
848 if ( !pEntry )
849 break;
850 pParent = pEntry;
853 return pEntry;
856 void SvTreeListBox::FillEntryPath( SvTreeListEntry* pEntry, ::std::deque< sal_Int32 >& _rPath ) const
859 if ( pEntry )
861 SvTreeListEntry* pParentEntry = GetParent( pEntry );
862 while ( true )
864 sal_uLong i, nCount = GetLevelChildCount( pParentEntry );
865 for ( i = 0; i < nCount; ++i )
867 SvTreeListEntry* pTemp = GetEntry( pParentEntry, i );
868 DBG_ASSERT( pEntry, "invalid entry" );
869 if ( pEntry == pTemp )
871 _rPath.push_front( (sal_Int32)i );
872 break;
876 if ( pParentEntry )
878 pEntry = pParentEntry;
879 pParentEntry = GetParent( pParentEntry );
881 else
882 break;
887 const SvTreeListEntry* SvTreeListBox::GetParent( const SvTreeListEntry* pEntry ) const
889 return pModel->GetParent(pEntry);
892 SvTreeListEntry* SvTreeListBox::GetParent( SvTreeListEntry* pEntry ) const
894 return pModel->GetParent(pEntry);
897 SvTreeListEntry* SvTreeListBox::GetRootLevelParent( SvTreeListEntry* pEntry ) const
899 return pModel->GetRootLevelParent(pEntry);
902 sal_uLong SvTreeListBox::GetChildCount( SvTreeListEntry* pParent ) const
904 return pModel->GetChildCount(pParent);
907 sal_uLong SvTreeListBox::GetLevelChildCount( SvTreeListEntry* _pParent ) const
910 //if _pParent is 0, then pEntry is the first child of the root.
911 SvTreeListEntry* pEntry = FirstChild( _pParent );
913 if( !pEntry )//there is only root, root don't have children
914 return 0;
916 if( !_pParent )//root and children of root
917 return pEntry->pParent->maChildren.size();
919 return _pParent->maChildren.size();
922 SvViewDataEntry* SvTreeListBox::GetViewDataEntry( SvTreeListEntry* pEntry ) const
924 return const_cast<SvViewDataEntry*>(SvListView::GetViewData(pEntry));
927 SvViewDataItem* SvTreeListBox::GetViewDataItem(SvTreeListEntry* pEntry, SvLBoxItem* pItem)
929 return const_cast<SvViewDataItem*>(static_cast<const SvTreeListBox*>(this)->GetViewDataItem(pEntry, pItem));
932 const SvViewDataItem* SvTreeListBox::GetViewDataItem(const SvTreeListEntry* pEntry, const SvLBoxItem* pItem) const
934 const SvViewDataEntry* pEntryData = SvListView::GetViewData(pEntry);
935 DBG_ASSERT(pEntryData,"Entry not in View");
936 sal_uInt16 nItemPos = pEntry->GetPos(pItem);
937 return pEntryData->GetItem(nItemPos);
940 SvViewDataEntry* SvTreeListBox::CreateViewData( SvTreeListEntry* )
942 SvViewDataEntry* pEntryData = new SvViewDataEntry;
943 return pEntryData;
946 void SvTreeListBox::InitViewData( SvViewDataEntry* pData, SvTreeListEntry* pEntry )
948 SvTreeListEntry* pInhEntry = pEntry;
949 SvViewDataEntry* pEntryData = pData;
951 pEntryData->Init(pInhEntry->ItemCount());
952 sal_uInt16 nCount = pInhEntry->ItemCount();
953 sal_uInt16 nCurPos = 0;
954 while( nCurPos < nCount )
956 SvLBoxItem* pItem = pInhEntry->GetItem( nCurPos );
957 SvViewDataItem* pItemData = pEntryData->GetItem(nCurPos);
958 pItem->InitViewData( this, pInhEntry, pItemData );
959 pItemData++;
960 nCurPos++;
964 void SvTreeListBox::EnableSelectionAsDropTarget( bool bEnable, bool bWithChildren )
966 sal_uInt16 nRefDepth;
967 SvTreeListEntry* pTemp;
969 SvTreeListEntry* pSelEntry = FirstSelected();
970 while( pSelEntry )
972 if ( !bEnable )
974 pSelEntry->nEntryFlags |= SvTLEntryFlags::DISABLE_DROP;
975 if ( bWithChildren )
977 nRefDepth = pModel->GetDepth( pSelEntry );
978 pTemp = Next( pSelEntry );
979 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
981 pTemp->nEntryFlags |= SvTLEntryFlags::DISABLE_DROP;
982 pTemp = Next( pTemp );
986 else
988 pSelEntry->nEntryFlags &= (~SvTLEntryFlags::DISABLE_DROP);
989 if ( bWithChildren )
991 nRefDepth = pModel->GetDepth( pSelEntry );
992 pTemp = Next( pSelEntry );
993 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
995 pTemp->nEntryFlags &= (~SvTLEntryFlags::DISABLE_DROP);
996 pTemp = Next( pTemp );
1000 pSelEntry = NextSelected( pSelEntry );
1004 // ******************************************************************
1005 // InplaceEditing
1006 // ******************************************************************
1008 void SvTreeListBox::EditText( const OUString& rStr, const Rectangle& rRect,
1009 const Selection& rSel )
1011 EditText( rStr, rRect, rSel, false );
1014 void SvTreeListBox::EditText( const OUString& rStr, const Rectangle& rRect,
1015 const Selection& rSel, bool bMulti )
1017 if( pEdCtrl )
1018 delete pEdCtrl;
1019 nImpFlags |= SvTreeListBoxFlags::IN_EDT;
1020 nImpFlags &= ~SvTreeListBoxFlags::EDTEND_CALLED;
1021 HideFocus();
1022 pEdCtrl = new SvInplaceEdit2(
1023 this, rRect.TopLeft(), rRect.GetSize(), rStr,
1024 LINK( this, SvTreeListBox, TextEditEndedHdl_Impl ),
1025 rSel, bMulti );
1028 IMPL_LINK_NOARG(SvTreeListBox, TextEditEndedHdl_Impl)
1030 if ( nImpFlags & SvTreeListBoxFlags::EDTEND_CALLED ) // avoid nesting
1031 return 0;
1032 nImpFlags |= SvTreeListBoxFlags::EDTEND_CALLED;
1033 OUString aStr;
1034 if ( !pEdCtrl->EditingCanceled() )
1035 aStr = pEdCtrl->GetText();
1036 else
1037 aStr = pEdCtrl->GetSavedValue();
1038 if ( IsEmptyTextAllowed() || !aStr.isEmpty() )
1039 EditedText( aStr );
1040 // Hide may only be called after the new text was put into the entry, so
1041 // that we don't call the selection handler in the GetFocus of the listbox
1042 // with the old entry text.
1043 pEdCtrl->Hide();
1044 // delete pEdCtrl;
1045 // pEdCtrl = 0;
1046 nImpFlags &= (~SvTreeListBoxFlags::IN_EDT);
1047 GrabFocus();
1048 return 0;
1051 void SvTreeListBox::CancelTextEditing()
1053 if ( pEdCtrl )
1054 pEdCtrl->StopEditing( true );
1055 nImpFlags &= (~SvTreeListBoxFlags::IN_EDT);
1058 void SvTreeListBox::EndEditing( bool bCancel )
1060 if( pEdCtrl )
1061 pEdCtrl->StopEditing( bCancel );
1062 nImpFlags &= (~SvTreeListBoxFlags::IN_EDT);
1066 bool SvTreeListBox::IsEmptyTextAllowed() const
1068 return mpImpl->m_bIsEmptyTextAllowed;
1071 void SvTreeListBox::ForbidEmptyText()
1073 mpImpl->m_bIsEmptyTextAllowed = false;
1076 SvTreeListEntry* SvTreeListBox::CreateEntry() const
1078 return new SvTreeListEntry;
1081 const void* SvTreeListBox::FirstSearchEntry( OUString& _rEntryText ) const
1083 SvTreeListEntry* pEntry = GetCurEntry();
1084 if ( pEntry )
1085 pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( NextSearchEntry( pEntry, _rEntryText ) ) );
1086 else
1088 pEntry = FirstSelected();
1089 if ( !pEntry )
1090 pEntry = First();
1093 if ( pEntry )
1094 _rEntryText = GetEntryText( pEntry );
1096 return pEntry;
1099 const void* SvTreeListBox::NextSearchEntry( const void* _pCurrentSearchEntry, OUString& _rEntryText ) const
1101 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pCurrentSearchEntry ) );
1103 if ( ( ( GetChildCount( pEntry ) > 0 )
1104 || ( pEntry->HasChildrenOnDemand() )
1106 && !IsExpanded( pEntry )
1109 pEntry = NextSibling( pEntry );
1111 else
1113 pEntry = Next( pEntry );
1116 if ( !pEntry )
1117 pEntry = First();
1119 if ( pEntry )
1120 _rEntryText = GetEntryText( pEntry );
1122 return pEntry;
1125 void SvTreeListBox::SelectSearchEntry( const void* _pEntry )
1127 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) );
1128 DBG_ASSERT( pEntry, "SvTreeListBox::SelectSearchEntry: invalid entry!" );
1129 if ( !pEntry )
1130 return;
1132 SelectAll( false );
1133 SetCurEntry( pEntry );
1134 Select( pEntry );
1137 void SvTreeListBox::ExecuteSearchEntry( const void* /*_pEntry*/ ) const
1139 // nothing to do here, we have no "execution"
1142 vcl::StringEntryIdentifier SvTreeListBox::CurrentEntry( OUString& _out_entryText ) const
1144 // always accept the current entry if there is one
1145 SvTreeListEntry* pCurrentEntry( GetCurEntry() );
1146 if ( pCurrentEntry )
1148 _out_entryText = GetEntryText( pCurrentEntry );
1149 return pCurrentEntry;
1151 return FirstSearchEntry( _out_entryText );
1154 vcl::StringEntryIdentifier SvTreeListBox::NextEntry( vcl::StringEntryIdentifier _currentEntry, OUString& _out_entryText ) const
1156 return NextSearchEntry( _currentEntry, _out_entryText );
1159 void SvTreeListBox::SelectEntry( vcl::StringEntryIdentifier _entry )
1161 SelectSearchEntry( _entry );
1164 bool SvTreeListBox::HandleKeyInput( const KeyEvent& _rKEvt )
1166 if ( IsEntryMnemonicsEnabled()
1167 && mpImpl->m_aMnemonicEngine.HandleKeyEvent( _rKEvt )
1169 return true;
1171 if ( ( GetStyle() & WB_QUICK_SEARCH ) != 0 )
1173 mpImpl->m_bDoingQuickSelection = true;
1174 const bool bHandled = mpImpl->m_aQuickSelectionEngine.HandleKeyEvent( _rKEvt );
1175 mpImpl->m_bDoingQuickSelection = false;
1176 if ( bHandled )
1177 return true;
1180 return false;
1183 bool SvTreeListBox::EditingCanceled() const
1185 if( pEdCtrl && pEdCtrl->EditingCanceled() )
1186 return true;
1187 return false;
1191 //JP 28.3.2001: new Drag & Drop API
1192 sal_Int8 SvTreeListBox::AcceptDrop( const AcceptDropEvent& rEvt )
1194 sal_Int8 nRet = DND_ACTION_NONE;
1196 if( rEvt.mbLeaving || !CheckDragAndDropMode( pDDSource, rEvt.mnAction ) )
1198 ImplShowTargetEmphasis( pTargetEntry, false );
1200 else if( nDragDropMode == DragDropMode::NONE )
1202 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no target" );
1204 else
1206 SvTreeListEntry* pEntry = GetDropTarget( rEvt.maPosPixel );
1207 if( !IsDropFormatSupported( SotClipboardFormatId::TREELISTBOX ) )
1209 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no format" );
1211 else
1213 DBG_ASSERT( pDDSource, "SvTreeListBox::QueryDrop(): SourceBox == 0" );
1214 if( !( pEntry && pDDSource->GetModel() == this->GetModel()
1215 && DND_ACTION_MOVE == rEvt.mnAction
1216 && ( pEntry->nEntryFlags & SvTLEntryFlags::DISABLE_DROP ) ))
1218 if( NotifyAcceptDrop( pEntry ))
1219 nRet = rEvt.mnAction;
1223 // **** draw emphasis ****
1224 if( DND_ACTION_NONE == nRet )
1225 ImplShowTargetEmphasis( pTargetEntry, false );
1226 else if( pEntry != pTargetEntry || !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
1228 ImplShowTargetEmphasis( pTargetEntry, false );
1229 pTargetEntry = pEntry;
1230 ImplShowTargetEmphasis( pTargetEntry, true );
1233 return nRet;
1236 sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvTreeListBox* pSourceView )
1238 DBG_ASSERT( pSourceView, "SvTreeListBox::ExecuteDrop(): no source view" );
1239 pSourceView->EnableSelectionAsDropTarget( true, true );
1241 ImplShowTargetEmphasis( pTargetEntry, false );
1242 pDDTarget = this;
1244 TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
1246 sal_Int8 nRet;
1247 if( aData.HasFormat( SotClipboardFormatId::TREELISTBOX ))
1248 nRet = rEvt.mnAction;
1249 else
1250 nRet = DND_ACTION_NONE;
1252 if( DND_ACTION_NONE != nRet )
1254 nRet = DND_ACTION_NONE;
1256 SvTreeListEntry* pTarget = pTargetEntry; // may be 0!
1258 if( DND_ACTION_COPY == rEvt.mnAction )
1260 if ( CopySelection( pDDSource, pTarget ) )
1261 nRet = rEvt.mnAction;
1263 else if( DND_ACTION_MOVE == rEvt.mnAction )
1265 if ( MoveSelection( pDDSource, pTarget ) )
1266 nRet = rEvt.mnAction;
1268 else if( DND_ACTION_COPYMOVE == rEvt.mnAction )
1270 if ( MoveSelectionCopyFallbackPossible( pDDSource, pTarget, true ) )
1271 nRet = rEvt.mnAction;
1274 return nRet;
1277 sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt )
1279 return ExecuteDrop( rEvt, GetSourceView() );
1283 * This sets the global variables used to determine the
1284 * in-process drag source.
1286 void SvTreeListBox::SetupDragOrigin()
1288 pDDSource = this;
1289 pDDTarget = 0;
1292 void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel )
1295 Point aEventPos( rPosPixel );
1296 MouseEvent aMouseEvt( aEventPos, 1, MouseEventModifiers::SELECT, MOUSE_LEFT );
1297 MouseButtonUp( aMouseEvt );
1299 nOldDragMode = GetDragDropMode();
1300 if ( nOldDragMode == DragDropMode::NONE )
1301 return;
1303 ReleaseMouse();
1305 SvTreeListEntry* pEntry = GetEntry( rPosPixel ); // GetDropTarget( rPos );
1306 if( !pEntry )
1308 DragFinished( DND_ACTION_NONE );
1309 return;
1312 TransferDataContainer* pContainer = new TransferDataContainer;
1313 ::com::sun::star::uno::Reference<
1314 ::com::sun::star::datatransfer::XTransferable > xRef( pContainer );
1315 nDragDropMode = NotifyStartDrag( *pContainer, pEntry );
1316 if( nDragDropMode == DragDropMode::NONE || 0 == GetSelectionCount() )
1318 nDragDropMode = nOldDragMode;
1319 DragFinished( DND_ACTION_NONE );
1320 delete pContainer;
1321 return;
1324 SetupDragOrigin();
1326 // apparently some (unused) content is needed
1327 pContainer->CopyAnyData( SotClipboardFormatId::TREELISTBOX,
1328 "unused", SAL_N_ELEMENTS("unused") );
1330 bool bOldUpdateMode = Control::IsUpdateMode();
1331 Control::SetUpdateMode( true );
1332 Update();
1333 Control::SetUpdateMode( bOldUpdateMode );
1335 // Disallow using the selection and its children as drop targets.
1336 // Important: If the selection of the SourceListBox is changed in the
1337 // DropHandler, the entries have to be allowed as drop targets again:
1338 // (GetSourceListBox()->EnableSelectionAsDropTarget( true, true );)
1339 EnableSelectionAsDropTarget( false, true /* with children */ );
1341 pContainer->StartDrag( this, nDragOptions, GetDragFinishedHdl() );
1344 void SvTreeListBox::DragFinished( sal_Int8
1345 #ifndef UNX
1346 nAction
1347 #endif
1350 EnableSelectionAsDropTarget( true, true );
1352 #ifndef UNX
1353 if( (nAction == DND_ACTION_MOVE) && ( (pDDTarget &&
1354 ((sal_uLong)(pDDTarget->GetModel())!=(sal_uLong)(this->GetModel()))) ||
1355 !pDDTarget ))
1357 RemoveSelection();
1359 #endif
1361 ImplShowTargetEmphasis( pTargetEntry, false );
1362 pDDSource = 0;
1363 pDDTarget = 0;
1364 pTargetEntry = 0;
1365 nDragDropMode = nOldDragMode;
1368 DragDropMode SvTreeListBox::NotifyStartDrag( TransferDataContainer&, SvTreeListEntry* )
1370 return (DragDropMode)0xffff;
1373 bool SvTreeListBox::NotifyAcceptDrop( SvTreeListEntry* )
1375 return true;
1378 // Handler and methods for Drag - finished handler.
1379 // The with get GetDragFinishedHdl() get link can set on the
1380 // TransferDataContainer. This link is a callback for the DragFinished
1381 // call. AddBox method is called from the GetDragFinishedHdl() and the
1382 // remove is called in link callback and in the destructor. So it can't
1383 // called to a deleted object.
1385 namespace
1387 struct SortLBoxes : public rtl::Static<std::set<sal_uLong>, SortLBoxes> {};
1390 void SvTreeListBox::AddBoxToDDList_Impl( const SvTreeListBox& rB )
1392 sal_uLong nVal = reinterpret_cast<sal_uLong>(&rB);
1393 SortLBoxes::get().insert( nVal );
1396 void SvTreeListBox::RemoveBoxFromDDList_Impl( const SvTreeListBox& rB )
1398 sal_uLong nVal = reinterpret_cast<sal_uLong>(&rB);
1399 SortLBoxes::get().erase( nVal );
1402 IMPL_LINK( SvTreeListBox, DragFinishHdl_Impl, sal_Int8*, pAction )
1404 sal_uLong nVal = reinterpret_cast<sal_uLong>(this);
1405 std::set<sal_uLong> &rSortLBoxes = SortLBoxes::get();
1406 std::set<sal_uLong>::const_iterator it = rSortLBoxes.find(nVal);
1407 if( it != rSortLBoxes.end() )
1409 DragFinished( *pAction );
1410 rSortLBoxes.erase( it );
1412 return 0;
1415 Link<> SvTreeListBox::GetDragFinishedHdl() const
1417 AddBoxToDDList_Impl( *this );
1418 return LINK( const_cast<SvTreeListBox*>(this), SvTreeListBox, DragFinishHdl_Impl );
1422 Bugs/TODO
1424 - calculate rectangle when editing in-place (bug with some fonts)
1425 - SetSpaceBetweenEntries: offset is not taken into account in SetEntryHeight
1428 #define SV_LBOX_DEFAULT_INDENT_PIXEL 20
1430 void SvTreeListBox::InitTreeView()
1432 pCheckButtonData = NULL;
1433 pEdEntry = NULL;
1434 pEdItem = NULL;
1435 nEntryHeight = 0;
1436 pEdCtrl = NULL;
1437 nFirstSelTab = 0;
1438 nLastSelTab = 0;
1439 nFocusWidth = -1;
1440 nAllItemAccRoleType = SvTreeAccRoleType::NONE;
1441 mnCheckboxItemWidth = 0;
1443 Link<>* pLink = new Link<>( LINK(this,SvTreeListBox, DefaultCompare) );
1444 mpImpl->m_pLink = pLink;
1446 nTreeFlags = SvTreeFlags::RECALCTABS;
1447 nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL;
1448 nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL;
1449 pImp = new SvImpLBox( this, GetModel(), GetStyle() );
1451 mbContextBmpExpanded = true;
1452 nContextBmpWidthMax = 0;
1454 SetFont( GetFont() );
1455 AdjustEntryHeightAndRecalc( GetFont() );
1457 SetSpaceBetweenEntries( 0 );
1458 SetLineColor();
1459 InitSettings( true, true, true );
1460 ImplInitStyle();
1461 SetTabs();
1464 OUString SvTreeListBox::GetEntryAltText( SvTreeListEntry* ) const
1466 return OUString();
1469 OUString SvTreeListBox::GetEntryLongDescription( SvTreeListEntry* ) const
1471 return OUString();
1474 OUString SvTreeListBox::SearchEntryTextWithHeadTitle( SvTreeListEntry* pEntry )
1476 DBG_ASSERT( pEntry, "SvTreeListBox::SearchEntryText(): no entry" );
1477 OUString sRet;
1479 sal_uInt16 nCount = pEntry->ItemCount();
1480 sal_uInt16 nCur = 0;
1481 sal_uInt16 nHeaderCur = 0;
1482 while( nCur < nCount )
1484 // MT: SV_ITEM_ID_EXTENDRLBOXSTRING / GetExtendText() was in use in IA2 cws, but only used in sc: ScSolverOptionsString. Needed?
1485 SvLBoxItem* pItem = pEntry->GetItem( nCur );
1486 if ( (pItem->GetType() == SV_ITEM_ID_LBOXSTRING ) &&
1487 !static_cast<SvLBoxString*>( pItem )->GetText().isEmpty() )
1489 //want the column header
1490 if (!headString.isEmpty())
1492 sal_Int32 nEnd = headString.indexOf('\t');
1493 if( nEnd == -1 )
1495 if (!sRet.isEmpty())
1497 sRet += ",";
1499 if (!headString.isEmpty())
1501 sRet += headString ;
1502 sRet += ":" ;
1505 else
1507 OUString aString=headString.getToken(nHeaderCur, '\t');
1508 if (!sRet.isEmpty())
1510 sRet += ",";
1512 if (!aString.isEmpty())
1514 sRet += aString ;
1515 sRet += ":" ;
1517 nHeaderCur++;
1519 sRet += static_cast<SvLBoxString*>( pItem )->GetText();
1521 else
1523 sRet += static_cast<SvLBoxString*>( pItem )->GetText();
1524 sRet += ",";
1526 //end want to the column header
1528 nCur++;
1531 if (!sRet.isEmpty())
1532 sRet = sRet.copy(0, sRet.getLength() - 1);
1533 return sRet;
1536 SvTreeListBox::~SvTreeListBox()
1538 disposeOnce();
1541 void SvTreeListBox::dispose()
1543 if( pImp )
1545 pImp->CallEventListeners( VCLEVENT_OBJECT_DYING );
1546 delete pImp;
1547 pImp = NULL;
1549 if( mpImpl )
1551 delete mpImpl->m_pLink;
1552 mpImpl->m_pLink = NULL;
1554 ClearTabList();
1556 delete pEdCtrl;
1557 pEdCtrl = NULL;
1559 if( pModel )
1561 pModel->RemoveView( this );
1562 if ( pModel->GetRefCount() == 0 )
1564 pModel->Clear();
1565 delete pModel;
1566 pModel = NULL;
1570 SvTreeListBox::RemoveBoxFromDDList_Impl( *this );
1572 if( this == pDDSource )
1573 pDDSource = 0;
1574 if( this == pDDTarget )
1575 pDDTarget = 0;
1576 delete mpImpl;
1577 mpImpl = NULL;
1580 Control::dispose();
1583 void SvTreeListBox::SetExtendedWinBits( ExtendedWinBits _nBits )
1585 pImp->SetExtendedWindowBits( _nBits );
1588 void SvTreeListBox::SetModel( SvTreeList* pNewModel )
1590 pImp->SetModel( pNewModel );
1591 SetBaseModel(pNewModel);
1594 void SvTreeListBox::SetBaseModel( SvTreeList* pNewModel )
1596 // does the CleanUp
1597 SvListView::SetModel( pNewModel );
1598 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
1599 SvTreeListEntry* pEntry = First();
1600 while( pEntry )
1602 ModelHasInserted( pEntry );
1603 pEntry = Next( pEntry );
1607 void SvTreeListBox::DisconnectFromModel()
1609 SvTreeList* pNewModel = new SvTreeList;
1610 pNewModel->SetRefCount( 0 ); // else this will never be deleted
1611 SvListView::SetModel( pNewModel );
1613 pImp->SetModel( GetModel() );
1616 void SvTreeListBox::SetSublistOpenWithReturn( bool b )
1618 pImp->bSubLstOpRet = b;
1621 void SvTreeListBox::SetSublistOpenWithLeftRight( bool b )
1623 pImp->bSubLstOpLR = b;
1626 void SvTreeListBox::Resize()
1628 if( IsEditingActive() )
1629 EndEditing( true );
1631 Control::Resize();
1633 pImp->Resize();
1634 nFocusWidth = -1;
1635 pImp->ShowCursor( false );
1636 pImp->ShowCursor( true );
1639 /* Cases:
1641 A) entries have bitmaps
1642 0. no buttons
1643 1. node buttons (can optionally also be on root items)
1644 2. node buttons (can optionally also be on root items) + CheckButton
1645 3. CheckButton
1646 B) entries don't have bitmaps (=>via WindowBits because of D&D!)
1647 0. no buttons
1648 1. node buttons (can optionally also be on root items)
1649 2. node buttons (can optionally also be on root items) + CheckButton
1650 3. CheckButton
1653 #define NO_BUTTONS 0
1654 #define NODE_BUTTONS 1
1655 #define NODE_AND_CHECK_BUTTONS 2
1656 #define CHECK_BUTTONS 3
1658 #define TABFLAGS_TEXT (SvLBoxTabFlags::DYNAMIC | \
1659 SvLBoxTabFlags::ADJUST_LEFT | \
1660 SvLBoxTabFlags::EDITABLE | \
1661 SvLBoxTabFlags::SHOW_SELECTION)
1663 #define TABFLAGS_CONTEXTBMP (SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER)
1665 #define TABFLAGS_CHECKBTN (SvLBoxTabFlags::DYNAMIC | \
1666 SvLBoxTabFlags::ADJUST_CENTER | \
1667 SvLBoxTabFlags::PUSHABLE)
1669 #define TAB_STARTPOS 2
1671 // take care of GetTextOffset when doing changes
1672 void SvTreeListBox::SetTabs()
1674 if( IsEditingActive() )
1675 EndEditing( true );
1676 nTreeFlags &= (~SvTreeFlags::RECALCTABS);
1677 nFocusWidth = -1;
1678 const WinBits nStyle( GetStyle() );
1679 bool bHasButtons = (nStyle & WB_HASBUTTONS)!=0;
1680 bool bHasButtonsAtRoot = (nStyle & (WB_HASLINESATROOT |
1681 WB_HASBUTTONSATROOT))!=0;
1682 long nStartPos = TAB_STARTPOS;
1683 long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width();
1685 // pCheckButtonData->Width() knows nothing about the native checkbox width,
1686 // so we have mnCheckboxItemWidth which becomes valid when something is added.
1687 long nCheckWidth = 0;
1688 if( nTreeFlags & SvTreeFlags::CHKBTN )
1689 nCheckWidth = mnCheckboxItemWidth;
1690 long nCheckWidthDIV2 = nCheckWidth / 2;
1692 long nContextWidth = nContextBmpWidthMax;
1693 long nContextWidthDIV2 = nContextWidth / 2;
1695 ClearTabList();
1697 int nCase = NO_BUTTONS;
1698 if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
1700 if( bHasButtons )
1701 nCase = NODE_BUTTONS;
1703 else
1705 if( bHasButtons )
1706 nCase = NODE_AND_CHECK_BUTTONS;
1707 else
1708 nCase = CHECK_BUTTONS;
1711 switch( nCase )
1713 case NO_BUTTONS :
1714 nStartPos += nContextWidthDIV2; // because of centering
1715 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1716 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1717 // only set a distance if there are bitmaps
1718 if( nContextBmpWidthMax )
1719 nStartPos += 5; // distance context bitmap to text
1720 AddTab( nStartPos, TABFLAGS_TEXT );
1721 break;
1723 case NODE_BUTTONS :
1724 if( bHasButtonsAtRoot )
1725 nStartPos += ( nIndent + (nNodeWidthPixel/2) );
1726 else
1727 nStartPos += nContextWidthDIV2;
1728 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1729 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1730 // only set a distance if there are bitmaps
1731 if( nContextBmpWidthMax )
1732 nStartPos += 5; // distance context bitmap to text
1733 AddTab( nStartPos, TABFLAGS_TEXT );
1734 break;
1736 case NODE_AND_CHECK_BUTTONS :
1737 if( bHasButtonsAtRoot )
1738 nStartPos += ( nIndent + nNodeWidthPixel );
1739 else
1740 nStartPos += nCheckWidthDIV2;
1741 AddTab( nStartPos, TABFLAGS_CHECKBTN );
1742 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1743 nStartPos += 3; // distance CheckButton to context bitmap
1744 nStartPos += nContextWidthDIV2; // center of context bitmap
1745 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1746 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1747 // only set a distance if there are bitmaps
1748 if( nContextBmpWidthMax )
1749 nStartPos += 5; // distance context bitmap to text
1750 AddTab( nStartPos, TABFLAGS_TEXT );
1751 break;
1753 case CHECK_BUTTONS :
1754 nStartPos += nCheckWidthDIV2;
1755 AddTab( nStartPos, TABFLAGS_CHECKBTN );
1756 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1757 nStartPos += 3; // distance CheckButton to context bitmap
1758 nStartPos += nContextWidthDIV2; // center of context bitmap
1759 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1760 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1761 // only set a distance if there are bitmaps
1762 if( nContextBmpWidthMax )
1763 nStartPos += 5; // distance context bitmap to text
1764 AddTab( nStartPos, TABFLAGS_TEXT );
1765 break;
1767 pImp->NotifyTabsChanged();
1770 void SvTreeListBox::InitEntry(SvTreeListEntry* pEntry,
1771 const OUString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp,
1772 SvLBoxButtonKind eButtonKind)
1774 SvLBoxString* pString;
1775 SvLBoxContextBmp* pContextBmp;
1777 if( nTreeFlags & SvTreeFlags::CHKBTN )
1779 SvLBoxButton* pButton= new SvLBoxButton( pEntry,eButtonKind,0,pCheckButtonData );
1780 pEntry->AddItem( pButton );
1783 pContextBmp= new SvLBoxContextBmp(
1784 pEntry,0, aCollEntryBmp,aExpEntryBmp, mbContextBmpExpanded);
1785 pEntry->AddItem( pContextBmp );
1787 pString = new SvLBoxString( pEntry, 0, aStr );
1788 pEntry->AddItem( pString );
1791 OUString SvTreeListBox::GetEntryText(SvTreeListEntry* pEntry) const
1793 DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): no entry" );
1794 SvLBoxString* pItem = static_cast<SvLBoxString*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
1795 DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): item not found" );
1796 return pItem->GetText();
1799 const Image& SvTreeListBox::GetExpandedEntryBmp(const SvTreeListEntry* pEntry)
1801 DBG_ASSERT(pEntry,"Entry?");
1802 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1803 DBG_ASSERT(pItem,"GetContextBmp:Item not found");
1804 return pItem->GetBitmap2( );
1807 const Image& SvTreeListBox::GetCollapsedEntryBmp( const SvTreeListEntry* pEntry )
1809 DBG_ASSERT(pEntry,"Entry?");
1810 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1811 DBG_ASSERT(pItem,"GetContextBmp:Item not found");
1812 return pItem->GetBitmap1( );
1815 IMPL_LINK( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData )
1817 pHdlEntry = pData->GetActEntry();
1818 CheckButtonHdl();
1819 return 0;
1822 SvTreeListEntry* SvTreeListBox::InsertEntry(
1823 const OUString& rText,
1824 SvTreeListEntry* pParent,
1825 bool bChildrenOnDemand, sal_uLong nPos,
1826 void* pUser,
1827 SvLBoxButtonKind eButtonKind
1830 nTreeFlags |= SvTreeFlags::MANINS;
1832 const Image& rDefExpBmp = pImp->GetDefaultEntryExpBmp( );
1833 const Image& rDefColBmp = pImp->GetDefaultEntryColBmp( );
1835 aCurInsertedExpBmp = rDefExpBmp;
1836 aCurInsertedColBmp = rDefColBmp;
1838 SvTreeListEntry* pEntry = CreateEntry();
1839 pEntry->SetUserData( pUser );
1840 InitEntry( pEntry, rText, rDefColBmp, rDefExpBmp, eButtonKind );
1841 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1843 if( !pParent )
1844 Insert( pEntry, nPos );
1845 else
1846 Insert( pEntry, pParent, nPos );
1848 aPrevInsertedExpBmp = rDefExpBmp;
1849 aPrevInsertedColBmp = rDefColBmp;
1851 nTreeFlags &= (~SvTreeFlags::MANINS);
1853 return pEntry;
1856 SvTreeListEntry* SvTreeListBox::InsertEntry( const OUString& rText,
1857 const Image& aExpEntryBmp, const Image& aCollEntryBmp,
1858 SvTreeListEntry* pParent, bool bChildrenOnDemand, sal_uLong nPos, void* pUser,
1859 SvLBoxButtonKind eButtonKind )
1861 nTreeFlags |= SvTreeFlags::MANINS;
1863 aCurInsertedExpBmp = aExpEntryBmp;
1864 aCurInsertedColBmp = aCollEntryBmp;
1866 SvTreeListEntry* pEntry = CreateEntry();
1867 pEntry->SetUserData( pUser );
1868 InitEntry( pEntry, rText, aCollEntryBmp, aExpEntryBmp, eButtonKind );
1870 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1872 if( !pParent )
1873 Insert( pEntry, nPos );
1874 else
1875 Insert( pEntry, pParent, nPos );
1877 aPrevInsertedExpBmp = aExpEntryBmp;
1878 aPrevInsertedColBmp = aCollEntryBmp;
1880 nTreeFlags &= (~SvTreeFlags::MANINS);
1882 return pEntry;
1885 void SvTreeListBox::SetEntryText(SvTreeListEntry* pEntry, const OUString& rStr)
1887 SvLBoxString* pItem = static_cast<SvLBoxString*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
1888 DBG_ASSERT(pItem,"SetText:Item not found");
1889 pItem->SetText(rStr);
1890 pItem->InitViewData( this, pEntry, 0 );
1891 GetModel()->InvalidateEntry( pEntry );
1894 void SvTreeListBox::SetExpandedEntryBmp( SvTreeListEntry* pEntry, const Image& aBmp )
1896 SvLBoxContextBmp* pItem = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1898 DBG_ASSERT(pItem,"SetExpBmp:Item not found");
1899 pItem->SetBitmap2( aBmp );
1901 GetModel()->InvalidateEntry( pEntry );
1902 SetEntryHeight( pEntry );
1903 Size aSize = aBmp.GetSizePixel();
1904 short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() );
1905 if( nWidth > nContextBmpWidthMax )
1907 nContextBmpWidthMax = nWidth;
1908 SetTabs();
1912 void SvTreeListBox::SetCollapsedEntryBmp(SvTreeListEntry* pEntry,const Image& aBmp )
1914 SvLBoxContextBmp* pItem = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1916 DBG_ASSERT(pItem,"SetExpBmp:Item not found");
1917 pItem->SetBitmap1( aBmp );
1919 GetModel()->InvalidateEntry( pEntry );
1920 SetEntryHeight( pEntry );
1921 Size aSize = aBmp.GetSizePixel();
1922 short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() );
1923 if( nWidth > nContextBmpWidthMax )
1925 nContextBmpWidthMax = nWidth;
1926 SetTabs();
1930 void SvTreeListBox::ImpEntryInserted( SvTreeListEntry* pEntry )
1933 SvTreeListEntry* pParent = pModel->GetParent( pEntry );
1934 if( pParent )
1936 SvTLEntryFlags nFlags = pParent->GetFlags();
1937 nFlags &= ~SvTLEntryFlags::NO_NODEBMP;
1938 pParent->SetFlags( nFlags );
1941 if(!((nTreeFlags & SvTreeFlags::MANINS) &&
1942 (aPrevInsertedExpBmp == aCurInsertedExpBmp) &&
1943 (aPrevInsertedColBmp == aCurInsertedColBmp) ))
1945 Size aSize = GetCollapsedEntryBmp( pEntry ).GetSizePixel();
1946 if( aSize.Width() > nContextBmpWidthMax )
1948 nContextBmpWidthMax = (short)aSize.Width();
1949 nTreeFlags |= SvTreeFlags::RECALCTABS;
1951 aSize = GetExpandedEntryBmp( pEntry ).GetSizePixel();
1952 if( aSize.Width() > nContextBmpWidthMax )
1954 nContextBmpWidthMax = (short)aSize.Width();
1955 nTreeFlags |= SvTreeFlags::RECALCTABS;
1958 SetEntryHeight( pEntry );
1960 if( nTreeFlags & SvTreeFlags::CHKBTN )
1962 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
1963 if( pItem )
1965 long nWidth = pItem->GetSize(this, pEntry).Width();
1966 if( mnCheckboxItemWidth < nWidth )
1968 mnCheckboxItemWidth = nWidth;
1969 nTreeFlags |= SvTreeFlags::RECALCTABS;
1977 void SvTreeListBox::SetCheckButtonState( SvTreeListEntry* pEntry, SvButtonState eState)
1979 if( nTreeFlags & SvTreeFlags::CHKBTN )
1981 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
1982 if(!(pItem && pItem->CheckModification()))
1983 return ;
1984 switch( eState )
1986 case SV_BUTTON_CHECKED:
1987 pItem->SetStateChecked();
1988 break;
1990 case SV_BUTTON_UNCHECKED:
1991 pItem->SetStateUnchecked();
1992 break;
1994 case SV_BUTTON_TRISTATE:
1995 pItem->SetStateTristate();
1996 break;
1998 InvalidateEntry( pEntry );
2002 void SvTreeListBox::SetCheckButtonInvisible( SvTreeListEntry* pEntry)
2004 if( nTreeFlags & SvTreeFlags::CHKBTN )
2006 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
2007 pItem->SetStateInvisible();
2008 InvalidateEntry( pEntry );
2012 SvButtonState SvTreeListBox::GetCheckButtonState( SvTreeListEntry* pEntry ) const
2014 SvButtonState eState = SV_BUTTON_UNCHECKED;
2015 if( nTreeFlags & SvTreeFlags::CHKBTN )
2017 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
2018 if(!pItem)
2019 return SV_BUTTON_TRISTATE;
2020 SvItemStateFlags nButtonFlags = pItem->GetButtonFlags();
2021 eState = SvLBoxButtonData::ConvertToButtonState( nButtonFlags );
2023 return eState;
2026 void SvTreeListBox::CheckButtonHdl()
2028 aCheckButtonHdl.Call( this );
2029 if ( pCheckButtonData )
2030 pImp->CallEventListeners( VCLEVENT_CHECKBOX_TOGGLE, (void*)pCheckButtonData->GetActEntry() );
2034 // TODO: Currently all data is cloned so that they conform to the default tree
2035 // view format. Actually, the model should be used as a reference here. This
2036 // leads to us _not_ calling SvTreeListEntry::Clone, but only its base class
2037 // SvTreeListEntry.
2040 SvTreeListEntry* SvTreeListBox::CloneEntry( SvTreeListEntry* pSource )
2042 OUString aStr;
2043 Image aCollEntryBmp;
2044 Image aExpEntryBmp;
2045 SvLBoxButtonKind eButtonKind = SvLBoxButtonKind_enabledCheckbox;
2047 SvLBoxString* pStringItem = static_cast<SvLBoxString*>(pSource->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
2048 if( pStringItem )
2049 aStr = pStringItem->GetText();
2050 SvLBoxContextBmp* pBmpItem = static_cast<SvLBoxContextBmp*>(pSource->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
2051 if( pBmpItem )
2053 aCollEntryBmp = pBmpItem->GetBitmap1( );
2054 aExpEntryBmp = pBmpItem->GetBitmap2( );
2056 SvLBoxButton* pButtonItem = static_cast<SvLBoxButton*>(pSource->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
2057 if( pButtonItem )
2058 eButtonKind = pButtonItem->GetKind();
2059 SvTreeListEntry* pClone = CreateEntry();
2060 InitEntry( pClone, aStr, aCollEntryBmp, aExpEntryBmp, eButtonKind );
2061 pClone->SvTreeListEntry::Clone( pSource );
2062 pClone->EnableChildrenOnDemand( pSource->HasChildrenOnDemand() );
2063 pClone->SetUserData( pSource->GetUserData() );
2065 return pClone;
2068 void SvTreeListBox::SetIndent( short nNewIndent )
2070 nIndent = nNewIndent;
2071 SetTabs();
2072 if( IsUpdateMode() )
2073 Invalidate();
2076 const Image& SvTreeListBox::GetDefaultExpandedEntryBmp( ) const
2078 return pImp->GetDefaultEntryExpBmp( );
2081 const Image& SvTreeListBox::GetDefaultCollapsedEntryBmp( ) const
2083 return pImp->GetDefaultEntryColBmp( );
2086 void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp )
2088 Size aSize = aBmp.GetSizePixel();
2089 if( aSize.Width() > nContextBmpWidthMax )
2090 nContextBmpWidthMax = (short)aSize.Width();
2091 SetTabs();
2093 pImp->SetDefaultEntryExpBmp( aBmp );
2096 void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp )
2098 Size aSize = aBmp.GetSizePixel();
2099 if( aSize.Width() > nContextBmpWidthMax )
2100 nContextBmpWidthMax = (short)aSize.Width();
2101 SetTabs();
2103 pImp->SetDefaultEntryColBmp( aBmp );
2106 void SvTreeListBox::EnableCheckButton( SvLBoxButtonData* pData )
2108 DBG_ASSERT(!GetEntryCount(),"EnableCheckButton: Entry count != 0");
2109 if( !pData )
2110 nTreeFlags &= (~SvTreeFlags::CHKBTN);
2111 else
2113 SetCheckButtonData( pData );
2114 nTreeFlags |= SvTreeFlags::CHKBTN;
2115 pData->SetLink( LINK(this, SvTreeListBox, CheckButtonClick));
2118 SetTabs();
2119 if( IsUpdateMode() )
2120 Invalidate();
2123 void SvTreeListBox::SetCheckButtonData( SvLBoxButtonData* pData )
2125 if ( pData )
2126 pCheckButtonData = pData;
2129 const Image& SvTreeListBox::GetDefaultExpandedNodeImage( )
2131 return SvImpLBox::GetDefaultExpandedNodeImage( );
2134 const Image& SvTreeListBox::GetDefaultCollapsedNodeImage( )
2136 return SvImpLBox::GetDefaultCollapsedNodeImage( );
2139 void SvTreeListBox::SetNodeBitmaps( const Image& rCollapsedNodeBmp, const Image& rExpandedNodeBmp )
2141 SetExpandedNodeBmp( rExpandedNodeBmp );
2142 SetCollapsedNodeBmp( rCollapsedNodeBmp );
2143 SetTabs();
2146 bool SvTreeListBox::EditingEntry( SvTreeListEntry*, Selection& )
2148 return true;
2151 bool SvTreeListBox::EditedEntry( SvTreeListEntry* /*pEntry*/,const OUString& /*rNewText*/)
2153 return true;
2156 void SvTreeListBox::EnableInplaceEditing( bool bOn )
2158 if (bOn)
2159 nImpFlags |= SvTreeListBoxFlags::EDT_ENABLED;
2160 else
2161 nImpFlags &= ~SvTreeListBoxFlags::EDT_ENABLED;
2164 void SvTreeListBox::KeyInput( const KeyEvent& rKEvt )
2166 // under OS/2, we get key up/down even while editing
2167 if( IsEditingActive() )
2168 return;
2170 nImpFlags |= SvTreeListBoxFlags::IS_TRAVELSELECT;
2172 if( !pImp->KeyInput( rKEvt ) )
2174 bool bHandled = HandleKeyInput( rKEvt );
2175 if ( !bHandled )
2176 Control::KeyInput( rKEvt );
2179 nImpFlags &= ~SvTreeListBoxFlags::IS_TRAVELSELECT;
2182 void SvTreeListBox::RequestingChildren( SvTreeListEntry* pParent )
2184 if( !pParent->HasChildren() )
2185 InsertEntry( OUString("<dummy>"), pParent, false, TREELIST_APPEND );
2188 void SvTreeListBox::GetFocus()
2190 //If there is no item in the tree, draw focus.
2191 if( !First())
2193 Invalidate();
2195 pImp->GetFocus();
2196 Control::GetFocus();
2198 SvTreeListEntry* pEntry = FirstSelected();
2199 if ( !pEntry )
2201 pEntry = pImp->GetCurrentEntry();
2203 if (pImp->pCursor)
2205 if (pEntry != pImp->pCursor)
2206 pEntry = pImp->pCursor;
2208 if ( pEntry )
2209 pImp->CallEventListeners( VCLEVENT_LISTBOX_TREEFOCUS, pEntry );
2213 void SvTreeListBox::LoseFocus()
2215 // If there is no item in the tree, delete visual focus.
2216 if ( !First() )
2217 Invalidate();
2218 if ( pImp )
2219 pImp->LoseFocus();
2220 Control::LoseFocus();
2223 void SvTreeListBox::ModelHasCleared()
2225 pImp->pCursor = 0; // else we crash in GetFocus when editing in-place
2226 delete pEdCtrl;
2227 pEdCtrl = NULL;
2228 pImp->Clear();
2229 nFocusWidth = -1;
2231 nContextBmpWidthMax = 0;
2232 SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() );
2233 SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() );
2235 if( !(nTreeFlags & SvTreeFlags::FIXEDHEIGHT ))
2236 nEntryHeight = 0;
2237 AdjustEntryHeight( GetFont() );
2238 AdjustEntryHeight( GetDefaultExpandedEntryBmp() );
2239 AdjustEntryHeight( GetDefaultCollapsedEntryBmp() );
2241 SvListView::ModelHasCleared();
2244 void SvTreeListBox::ShowTargetEmphasis( SvTreeListEntry* pEntry, bool /*bShow*/ )
2246 pImp->PaintDDCursor( pEntry );
2249 void SvTreeListBox::ScrollOutputArea( short nDeltaEntries )
2251 if( !nDeltaEntries || !pImp->aVerSBar->IsVisible() )
2252 return;
2254 long nThumb = pImp->aVerSBar->GetThumbPos();
2255 long nMax = pImp->aVerSBar->GetRange().Max();
2257 if( nDeltaEntries < 0 )
2259 // move window up
2260 nDeltaEntries *= -1;
2261 long nVis = pImp->aVerSBar->GetVisibleSize();
2262 long nTemp = nThumb + nVis;
2263 if( nDeltaEntries > (nMax - nTemp) )
2264 nDeltaEntries = (short)(nMax - nTemp);
2265 pImp->PageDown( (sal_uInt16)nDeltaEntries );
2267 else
2269 if( nDeltaEntries > nThumb )
2270 nDeltaEntries = (short)nThumb;
2271 pImp->PageUp( (sal_uInt16)nDeltaEntries );
2273 pImp->SyncVerThumb();
2274 NotifyEndScroll();
2277 void SvTreeListBox::ScrollToAbsPos( long nPos )
2279 pImp->ScrollToAbsPos( nPos );
2282 void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode )
2284 eSelMode = eSelectMode;
2285 pImp->SetSelectionMode( eSelectMode );
2288 void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode )
2290 nDragDropMode = nDDMode;
2291 pImp->SetDragDropMode( nDDMode );
2294 short SvTreeListBox::GetHeightOffset(const Image& rBmp, Size& aSizeLogic )
2296 short nOffset = 0;
2297 aSizeLogic = rBmp.GetSizePixel();
2298 if( GetEntryHeight() > aSizeLogic.Height() )
2299 nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2;
2300 return nOffset;
2303 short SvTreeListBox::GetHeightOffset(const vcl::Font& /* rFont */, Size& aSizeLogic )
2305 short nOffset = 0;
2306 aSizeLogic = Size(GetTextWidth(OUString('X')), GetTextHeight());
2307 if( GetEntryHeight() > aSizeLogic.Height() )
2308 nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2;
2309 return nOffset;
2312 void SvTreeListBox::SetEntryHeight( SvTreeListEntry* pEntry )
2314 short nHeightMax=0;
2315 sal_uInt16 nCount = pEntry->ItemCount();
2316 sal_uInt16 nCur = 0;
2317 SvViewDataEntry* pViewData = GetViewDataEntry( pEntry );
2318 while( nCur < nCount )
2320 short nHeight = (short)(SvLBoxItem::GetSize( pViewData, nCur ).Height());
2321 if( nHeight > nHeightMax )
2322 nHeightMax = nHeight;
2323 nCur++;
2326 if( nHeightMax > nEntryHeight )
2328 nEntryHeight = nHeightMax;
2329 Control::SetFont( GetFont() );
2330 pImp->SetEntryHeight( nHeightMax );
2334 void SvTreeListBox::SetEntryHeight( short nHeight, bool bAlways )
2337 if( bAlways || nHeight > nEntryHeight )
2339 nEntryHeight = nHeight;
2340 if( nEntryHeight )
2341 nTreeFlags |= SvTreeFlags::FIXEDHEIGHT;
2342 else
2343 nTreeFlags &= ~SvTreeFlags::FIXEDHEIGHT;
2344 Control::SetFont( GetFont() );
2345 pImp->SetEntryHeight( nHeight );
2350 void SvTreeListBox::AdjustEntryHeight( const Image& rBmp )
2352 Size aSize;
2353 GetHeightOffset( rBmp, aSize );
2354 if( aSize.Height() > nEntryHeight )
2356 nEntryHeight = (short)aSize.Height() + nEntryHeightOffs;
2357 pImp->SetEntryHeight( nEntryHeight );
2361 void SvTreeListBox::AdjustEntryHeight( const vcl::Font& rFont )
2363 Size aSize;
2364 GetHeightOffset( rFont, aSize );
2365 if( aSize.Height() > nEntryHeight )
2367 nEntryHeight = (short)aSize.Height() + nEntryHeightOffs;
2368 pImp->SetEntryHeight( nEntryHeight );
2372 bool SvTreeListBox::Expand( SvTreeListEntry* pParent )
2374 pHdlEntry = pParent;
2375 bool bExpanded = false;
2376 SvTLEntryFlags nFlags;
2378 if( pParent->HasChildrenOnDemand() )
2379 RequestingChildren( pParent );
2380 if( pParent->HasChildren() )
2382 nImpFlags |= SvTreeListBoxFlags::IS_EXPANDING;
2383 if( ExpandingHdl() )
2385 bExpanded = true;
2386 ExpandListEntry( pParent );
2387 pImp->EntryExpanded( pParent );
2388 pHdlEntry = pParent;
2389 ExpandedHdl();
2391 nFlags = pParent->GetFlags();
2392 nFlags &= ~SvTLEntryFlags::NO_NODEBMP;
2393 nFlags |= SvTLEntryFlags::HAD_CHILDREN;
2394 pParent->SetFlags( nFlags );
2396 else
2398 nFlags = pParent->GetFlags();
2399 nFlags |= SvTLEntryFlags::NO_NODEBMP;
2400 pParent->SetFlags( nFlags );
2401 GetModel()->InvalidateEntry( pParent ); // repaint
2404 // #i92103#
2405 if ( bExpanded )
2407 pImp->CallEventListeners( VCLEVENT_ITEM_EXPANDED, pParent );
2410 return bExpanded;
2413 bool SvTreeListBox::Collapse( SvTreeListEntry* pParent )
2415 nImpFlags &= ~SvTreeListBoxFlags::IS_EXPANDING;
2416 pHdlEntry = pParent;
2417 bool bCollapsed = false;
2419 if( ExpandingHdl() )
2421 bCollapsed = true;
2422 pImp->CollapsingEntry( pParent );
2423 CollapseListEntry( pParent );
2424 pImp->EntryCollapsed( pParent );
2425 pHdlEntry = pParent;
2426 ExpandedHdl();
2429 // #i92103#
2430 if ( bCollapsed )
2432 pImp->CallEventListeners( VCLEVENT_ITEM_COLLAPSED, pParent );
2435 return bCollapsed;
2438 bool SvTreeListBox::Select( SvTreeListEntry* pEntry, bool bSelect )
2440 DBG_ASSERT(pEntry,"Select: Null-Ptr");
2441 bool bRetVal = SelectListEntry( pEntry, bSelect );
2442 DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed");
2443 if( bRetVal )
2445 pImp->EntrySelected( pEntry, bSelect );
2446 pHdlEntry = pEntry;
2447 if( bSelect )
2449 SelectHdl();
2450 CallEventListeners( VCLEVENT_LISTBOX_TREESELECT, pEntry);
2452 else
2453 DeselectHdl();
2455 return bRetVal;
2458 sal_uLong SvTreeListBox::SelectChildren( SvTreeListEntry* pParent, bool bSelect )
2460 pImp->DestroyAnchor();
2461 sal_uLong nRet = 0;
2462 if( !pParent->HasChildren() )
2463 return 0;
2464 sal_uInt16 nRefDepth = pModel->GetDepth( pParent );
2465 SvTreeListEntry* pChild = FirstChild( pParent );
2466 do {
2467 nRet++;
2468 Select( pChild, bSelect );
2469 pChild = Next( pChild );
2470 } while( pChild && pModel->GetDepth( pChild ) > nRefDepth );
2471 return nRet;
2474 void SvTreeListBox::SelectAll( bool bSelect, bool )
2476 pImp->SelAllDestrAnch(
2477 bSelect,
2478 true, // delete anchor,
2479 true ); // even when using SINGLE_SELECTION, deselect the cursor
2482 void SvTreeListBox::ModelHasInsertedTree( SvTreeListEntry* pEntry )
2484 sal_uInt16 nRefDepth = pModel->GetDepth( pEntry );
2485 SvTreeListEntry* pTmp = pEntry;
2488 ImpEntryInserted( pTmp );
2489 pTmp = Next( pTmp );
2490 } while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) );
2491 pImp->TreeInserted( pEntry );
2494 void SvTreeListBox::ModelHasInserted( SvTreeListEntry* pEntry )
2496 ImpEntryInserted( pEntry );
2497 pImp->EntryInserted( pEntry );
2500 void SvTreeListBox::ModelIsMoving(SvTreeListEntry* pSource,
2501 SvTreeListEntry* /* pTargetParent */,
2502 sal_uLong /* nChildPos */ )
2504 pImp->MovingEntry( pSource );
2507 void SvTreeListBox::ModelHasMoved( SvTreeListEntry* pSource )
2509 pImp->EntryMoved( pSource );
2512 void SvTreeListBox::ModelIsRemoving( SvTreeListEntry* pEntry )
2514 if(pEdEntry == pEntry)
2515 pEdEntry = NULL;
2517 pImp->RemovingEntry( pEntry );
2520 void SvTreeListBox::ModelHasRemoved( SvTreeListEntry* pEntry )
2522 if ( pEntry == pHdlEntry)
2523 pHdlEntry = NULL;
2524 pImp->EntryRemoved();
2527 void SvTreeListBox::SetCollapsedNodeBmp( const Image& rBmp)
2529 AdjustEntryHeight( rBmp );
2530 pImp->SetCollapsedNodeBmp( rBmp );
2533 void SvTreeListBox::SetExpandedNodeBmp( const Image& rBmp )
2535 AdjustEntryHeight( rBmp );
2536 pImp->SetExpandedNodeBmp( rBmp );
2540 void SvTreeListBox::SetFont( const vcl::Font& rFont )
2542 vcl::Font aTempFont( rFont );
2543 vcl::Font aOrigFont( GetFont() );
2544 aTempFont.SetTransparent( true );
2545 if (aTempFont == aOrigFont)
2546 return;
2547 Control::SetFont( aTempFont );
2549 aTempFont.SetColor(aOrigFont.GetColor());
2550 aTempFont.SetFillColor(aOrigFont.GetFillColor());
2551 aTempFont.SetTransparent(aOrigFont.IsTransparent());
2553 if (aTempFont == aOrigFont)
2554 return;
2556 AdjustEntryHeightAndRecalc( GetFont() );
2559 void SvTreeListBox::AdjustEntryHeightAndRecalc( const vcl::Font& rFont )
2561 AdjustEntryHeight( rFont );
2562 // always invalidate, else things go wrong in SetEntryHeight
2563 RecalcViewData();
2566 void SvTreeListBox::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
2568 Control::Paint(rRenderContext, rRect);
2569 if (nTreeFlags & SvTreeFlags::RECALCTABS)
2570 SetTabs();
2571 pImp->Paint(rRenderContext, rRect);
2573 //Add visual focus draw
2574 if (!First())
2576 if (HasFocus())
2578 long nHeight = rRenderContext.GetTextHeight();
2579 Rectangle aRect(Point(0, 0), Size(GetSizePixel().Width(), nHeight));
2580 ShowFocus(aRect);
2582 else
2584 HideFocus();
2589 void SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt )
2591 pImp->MouseButtonDown( rMEvt );
2594 void SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt )
2596 pImp->MouseButtonUp( rMEvt );
2599 void SvTreeListBox::MouseMove( const MouseEvent& rMEvt )
2601 pImp->MouseMove( rMEvt );
2605 void SvTreeListBox::SetUpdateMode( bool bUpdate )
2607 pImp->SetUpdateMode( bUpdate );
2610 void SvTreeListBox::SetSpaceBetweenEntries( short nOffsLogic )
2612 if( nOffsLogic != nEntryHeightOffs )
2614 nEntryHeight = nEntryHeight - nEntryHeightOffs;
2615 nEntryHeightOffs = (short)nOffsLogic;
2616 nEntryHeight = nEntryHeight + nOffsLogic;
2617 AdjustEntryHeightAndRecalc( GetFont() );
2618 pImp->SetEntryHeight( nEntryHeight );
2622 void SvTreeListBox::SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect )
2624 pImp->SetCursor(pEntry, bForceNoSelect);
2627 void SvTreeListBox::SetCurEntry( SvTreeListEntry* pEntry )
2629 pImp->SetCurEntry( pEntry );
2632 Image SvTreeListBox::GetExpandedNodeBmp( ) const
2634 return pImp->GetExpandedNodeBmp( );
2637 Point SvTreeListBox::GetEntryPosition( SvTreeListEntry* pEntry ) const
2639 return pImp->GetEntryPosition( pEntry );
2642 void SvTreeListBox::ShowEntry( SvTreeListEntry* pEntry )
2644 MakeVisible( pEntry );
2647 void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry )
2649 pImp->MakeVisible(pEntry);
2652 void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop )
2654 pImp->MakeVisible( pEntry, bMoveToTop );
2657 void SvTreeListBox::ModelHasEntryInvalidated( SvTreeListEntry* pEntry )
2660 // reinitialize the separate items of the entries
2661 sal_uInt16 nCount = pEntry->ItemCount();
2662 for( sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++ )
2664 SvLBoxItem* pItem = pEntry->GetItem( nIdx );
2665 pItem->InitViewData( this, pEntry, 0 );
2668 // repaint
2669 pImp->InvalidateEntry( pEntry );
2672 void SvTreeListBox::EditItemText(SvTreeListEntry* pEntry, SvLBoxString* pItem, const Selection& rSelection)
2674 DBG_ASSERT(pEntry&&pItem,"EditItemText: Bad params");
2675 if( IsSelected( pEntry ))
2677 pImp->ShowCursor( false );
2678 SelectListEntry( pEntry, false );
2679 pImp->InvalidateEntry(pEntry);
2680 SelectListEntry( pEntry, true );
2681 pImp->ShowCursor( true );
2683 pEdEntry = pEntry;
2684 pEdItem = pItem;
2685 SvLBoxTab* pTab = GetTab( pEntry, pItem );
2686 DBG_ASSERT(pTab,"EditItemText:Tab not found");
2688 Size aItemSize( pItem->GetSize(this, pEntry) );
2689 Point aPos = GetEntryPosition( pEntry );
2690 aPos.Y() += ( nEntryHeight - aItemSize.Height() ) / 2;
2691 aPos.X() = GetTabPos( pEntry, pTab );
2692 long nOutputWidth = pImp->GetOutputSize().Width();
2693 Size aSize( nOutputWidth - aPos.X(), aItemSize.Height() );
2694 sal_uInt16 nPos = std::find( aTabs.begin(), aTabs.end(), pTab ) - aTabs.begin();
2695 if( nPos+1 < (sal_uInt16)aTabs.size() )
2697 SvLBoxTab* pRightTab = aTabs[ nPos + 1 ];
2698 long nRight = GetTabPos( pEntry, pRightTab );
2699 if( nRight <= nOutputWidth )
2700 aSize.Width() = nRight - aPos.X();
2702 Point aOrigin( GetMapMode().GetOrigin() );
2703 aPos += aOrigin; // convert to win coordinates
2704 aSize.Width() -= aOrigin.X();
2705 Rectangle aRect( aPos, aSize );
2706 EditText( pItem->GetText(), aRect, rSelection );
2709 void SvTreeListBox::EditEntry( SvTreeListEntry* pEntry )
2711 pImp->aEditClickPos = Point( -1, -1 );
2712 ImplEditEntry( pEntry );
2715 void SvTreeListBox::ImplEditEntry( SvTreeListEntry* pEntry )
2717 if( IsEditingActive() )
2718 EndEditing();
2719 if( !pEntry )
2720 pEntry = GetCurEntry();
2721 if( pEntry )
2723 long nClickX = pImp->aEditClickPos.X();
2724 bool bIsMouseTriggered = nClickX >= 0;
2726 SvLBoxString* pItem = NULL;
2727 sal_uInt16 nCount = pEntry->ItemCount();
2728 long nTabPos, nNextTabPos = 0;
2729 for( sal_uInt16 i = 0 ; i < nCount ; i++ )
2731 SvLBoxItem* pTmpItem = pEntry->GetItem( i );
2732 if (pTmpItem->GetType() != SV_ITEM_ID_LBOXSTRING)
2733 continue;
2735 SvLBoxTab* pTab = GetTab( pEntry, pTmpItem );
2736 nNextTabPos = -1;
2737 if( i < nCount - 1 )
2739 SvLBoxItem* pNextItem = pEntry->GetItem( i + 1 );
2740 SvLBoxTab* pNextTab = GetTab( pEntry, pNextItem );
2741 nNextTabPos = pNextTab->GetPos();
2744 if( pTab && pTab->IsEditable() )
2746 nTabPos = pTab->GetPos();
2747 if( !bIsMouseTriggered || (nClickX > nTabPos && (nNextTabPos == -1 || nClickX < nNextTabPos ) ) )
2749 pItem = static_cast<SvLBoxString*>( pTmpItem );
2750 break;
2755 Selection aSel( SELECTION_MIN, SELECTION_MAX );
2756 if( pItem && EditingEntry( pEntry, aSel ) )
2758 SelectAll( false );
2759 MakeVisible( pEntry );
2760 EditItemText( pEntry, pItem, aSel );
2765 bool SvTreeListBox::AreChildrenTransient() const
2767 return pImp->AreChildrenTransient();
2770 void SvTreeListBox::SetChildrenNotTransient()
2772 pImp->SetChildrenNotTransient();
2775 void SvTreeListBox::EditedText( const OUString& rStr )
2778 if(pEdEntry) // we have to check if this entry is null that means that it is removed while editing
2780 if( EditedEntry( pEdEntry, rStr ) )
2782 static_cast<SvLBoxString*>(pEdItem)->SetText( rStr );
2783 pModel->InvalidateEntry( pEdEntry );
2785 if( GetSelectionCount() == 0 )
2786 Select( pEdEntry );
2787 if( GetSelectionMode() == MULTIPLE_SELECTION && !GetCurEntry() )
2788 SetCurEntry( pEdEntry );
2792 SvTreeListEntry* SvTreeListBox::GetDropTarget( const Point& rPos )
2794 // scroll
2795 if( rPos.Y() < 12 )
2797 ImplShowTargetEmphasis(pTargetEntry, false);
2798 ScrollOutputArea( +1 );
2800 else
2802 Size aSize( pImp->GetOutputSize() );
2803 if( rPos.Y() > aSize.Height() - 12 )
2805 ImplShowTargetEmphasis(pTargetEntry, false);
2806 ScrollOutputArea( -1 );
2810 SvTreeListEntry* pTarget = pImp->GetEntry( rPos );
2811 // when dropping in a vacant space, use the last entry
2812 if( !pTarget )
2813 return LastVisible();
2814 else if( (GetDragDropMode() & DragDropMode::ENABLE_TOP) &&
2815 pTarget == First() && rPos.Y() < 6 )
2816 return 0;
2818 return pTarget;
2822 SvTreeListEntry* SvTreeListBox::GetEntry( const Point& rPos, bool bHit ) const
2824 SvTreeListEntry* pEntry = pImp->GetEntry( rPos );
2825 if( pEntry && bHit )
2827 long nLine = pImp->GetEntryLine( pEntry );
2828 if( !(pImp->EntryReallyHit( pEntry, rPos, nLine)) )
2829 return 0;
2831 return pEntry;
2834 SvTreeListEntry* SvTreeListBox::GetCurEntry() const
2836 return pImp ? pImp->GetCurEntry() : NULL;
2839 void SvTreeListBox::ImplInitStyle()
2841 const WinBits nWindowStyle = GetStyle();
2843 nTreeFlags |= SvTreeFlags::RECALCTABS;
2844 if (nWindowStyle & WB_SORT)
2846 GetModel()->SetSortMode(SortAscending);
2847 GetModel()->SetCompareHdl(LINK(this, SvTreeListBox, DefaultCompare));
2849 else
2851 GetModel()->SetSortMode(SortNone);
2852 GetModel()->SetCompareHdl(Link<>());
2854 pImp->SetStyle(nWindowStyle);
2855 pImp->Resize();
2856 Invalidate();
2859 void SvTreeListBox::InvalidateEntry(SvTreeListEntry* pEntry)
2861 DBG_ASSERT(pEntry,"InvalidateEntry:No Entry");
2862 if (pEntry)
2864 GetModel()->InvalidateEntry(pEntry);
2868 long SvTreeListBox::PaintEntry(SvTreeListEntry* pEntry, long nLine, vcl::RenderContext& rRenderContext, SvLBoxTabFlags nTabFlags)
2870 return PaintEntry1(pEntry, nLine, rRenderContext, nTabFlags);
2873 long SvTreeListBox::PaintEntry1(SvTreeListEntry* pEntry, long nLine, vcl::RenderContext& rRenderContext,
2874 SvLBoxTabFlags nTabFlags, bool bHasClipRegion)
2877 Rectangle aRect; // multi purpose
2879 bool bHorSBar = pImp->HasHorScrollBar();
2880 PreparePaint(rRenderContext, pEntry);
2882 pImp->UpdateContextBmpWidthMax(pEntry);
2884 if (nTreeFlags & SvTreeFlags::RECALCTABS)
2885 SetTabs();
2887 short nTempEntryHeight = GetEntryHeight();
2888 long nWidth = pImp->GetOutputSize().Width();
2890 // Did we turn on the scrollbar within PreparePaints? If yes, we have to set
2891 // the ClipRegion anew.
2892 if (!bHorSBar && pImp->HasHorScrollBar())
2893 rRenderContext.SetClipRegion(vcl::Region(pImp->GetClipRegionRect()));
2895 Point aEntryPos(rRenderContext.GetMapMode().GetOrigin());
2896 aEntryPos.X() *= -1; // conversion document coordinates
2897 long nMaxRight = nWidth + aEntryPos.X() - 1;
2899 Color aBackupTextColor(rRenderContext.GetTextColor());
2900 vcl::Font aBackupFont(rRenderContext.GetFont());
2901 Color aBackupColor = rRenderContext.GetFillColor();
2903 bool bCurFontIsSel = false;
2904 bool bInUse = pEntry->HasInUseEmphasis();
2905 // if a ClipRegion was set from outside, we don't have to reset it
2906 const WinBits nWindowStyle = GetStyle();
2907 const bool bResetClipRegion = !bHasClipRegion;
2908 const bool bHideSelection = (nWindowStyle & WB_HIDESELECTION) !=0 && !HasFocus();
2909 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
2911 vcl::Font aHighlightFont(rRenderContext.GetFont());
2912 const Color aHighlightTextColor(rSettings.GetHighlightTextColor());
2913 aHighlightFont.SetColor(aHighlightTextColor);
2915 Size aRectSize(0, nTempEntryHeight);
2917 if (!bHasClipRegion && nWindowStyle & WB_HSCROLL)
2919 rRenderContext.SetClipRegion(vcl::Region(pImp->GetClipRegionRect()));
2920 bHasClipRegion = true;
2923 SvViewDataEntry* pViewDataEntry = GetViewDataEntry( pEntry );
2925 sal_uInt16 nTabCount = aTabs.size();
2926 sal_uInt16 nItemCount = pEntry->ItemCount();
2927 sal_uInt16 nCurTab = 0;
2928 sal_uInt16 nCurItem = 0;
2930 while (nCurTab < nTabCount && nCurItem < nItemCount)
2932 SvLBoxTab* pTab = aTabs[nCurTab];
2933 sal_uInt16 nNextTab = nCurTab + 1;
2934 SvLBoxTab* pNextTab = nNextTab < nTabCount ? aTabs[nNextTab] : 0;
2935 SvLBoxItem* pItem = nCurItem < nItemCount ? pEntry->GetItem(nCurItem) : 0;
2937 SvLBoxTabFlags nFlags = pTab->nFlags;
2938 Size aSize(SvLBoxItem::GetSize(pViewDataEntry, nCurItem));
2939 long nTabPos = GetTabPos(pEntry, pTab);
2941 long nNextTabPos;
2942 if (pNextTab)
2943 nNextTabPos = GetTabPos(pEntry, pNextTab);
2944 else
2946 nNextTabPos = nMaxRight;
2947 if (nTabPos > nMaxRight)
2948 nNextTabPos += 50;
2951 long nX;
2952 if( pTab->nFlags & SvLBoxTabFlags::ADJUST_RIGHT )
2953 // avoid cutting the right edge off the tab separation
2954 nX = nTabPos + pTab->CalcOffset(aSize.Width(), (nNextTabPos - SV_TAB_BORDER - 1) - nTabPos);
2955 else
2956 nX = nTabPos + pTab->CalcOffset(aSize.Width(), nNextTabPos - nTabPos);
2958 if (nFlags & nTabFlags)
2960 if (!bHasClipRegion && nX + aSize.Width() >= nMaxRight)
2962 rRenderContext.SetClipRegion(vcl::Region(pImp->GetClipRegionRect()));
2963 bHasClipRegion = true;
2965 aEntryPos.X() = nX;
2966 aEntryPos.Y() = nLine;
2968 // set background pattern/color
2970 Wallpaper aWallpaper = rRenderContext.GetBackground();
2972 bool bSelTab = bool(nFlags & SvLBoxTabFlags::SHOW_SELECTION);
2973 sal_uInt16 nItemType = pItem->GetType();
2975 if (pViewDataEntry->IsHighlighted() && bSelTab && !pViewDataEntry->IsCursored())
2977 Color aNewWallColor = rSettings.GetHighlightColor();
2978 if (!bInUse || nItemType != SV_ITEM_ID_LBOXCONTEXTBMP)
2980 // if the face color is bright then the deactive color is also bright
2981 // -> so you can't see any deactive selection
2982 if (bHideSelection && !rSettings.GetFaceColor().IsBright()
2983 && aWallpaper.GetColor().IsBright() != rSettings.GetDeactiveColor().IsBright())
2985 aNewWallColor = rSettings.GetDeactiveColor();
2987 // set font color to highlight
2988 if (!bCurFontIsSel)
2990 rRenderContext.SetTextColor(aHighlightTextColor);
2991 rRenderContext.SetFont(aHighlightFont);
2992 bCurFontIsSel = true;
2995 aWallpaper.SetColor(aNewWallColor);
2997 else // no selection
2999 if (bInUse && nItemType == SV_ITEM_ID_LBOXCONTEXTBMP)
3001 aWallpaper.SetColor(rSettings.GetFieldColor());
3003 else if (bCurFontIsSel)
3005 bCurFontIsSel = false;
3006 rRenderContext.SetTextColor(aBackupTextColor);
3007 rRenderContext.SetFont(aBackupFont);
3009 else
3011 aWallpaper.SetColor(pEntry->GetBackColor());
3015 // draw background
3016 if (!(nTreeFlags & SvTreeFlags::USESEL))
3018 // only draw the area that is used by the item
3019 aRectSize.Width() = aSize.Width();
3020 aRect.SetPos(aEntryPos);
3021 aRect.SetSize(aRectSize);
3023 else
3025 // draw from the current to the next tab
3026 if (nCurTab != 0)
3027 aRect.Left() = nTabPos;
3028 else
3029 // if we're in the 0th tab, always draw from column 0 --
3030 // else we get problems with centered tabs
3031 aRect.Left() = 0;
3032 aRect.Top() = nLine;
3033 aRect.Bottom() = nLine + nTempEntryHeight - 1;
3034 if (pNextTab)
3036 long nRight;
3037 nRight = GetTabPos(pEntry, pNextTab) - 1;
3038 if (nRight > nMaxRight)
3039 nRight = nMaxRight;
3040 aRect.Right() = nRight;
3042 else
3044 aRect.Right() = nMaxRight;
3047 // A custom selection that starts at a tab position > 0, do not fill
3048 // the background of the 0th item, else e.g. we might not be able to
3049 // realize tab listboxes with lines.
3050 if (!(nCurTab == 0 && (nTreeFlags & SvTreeFlags::USESEL) && nFirstSelTab))
3052 Color aBackgroundColor = aWallpaper.GetColor();
3053 if (aBackgroundColor != Color(COL_TRANSPARENT))
3055 rRenderContext.SetFillColor(aBackgroundColor);
3056 // this case may occur for smaller horizontal resizes
3057 if (aRect.Left() < aRect.Right())
3058 rRenderContext.DrawRect(aRect);
3061 // draw item
3062 // center vertically
3063 aEntryPos.Y() += (nTempEntryHeight - aSize.Height()) / 2;
3064 pViewDataEntry->SetPaintRectangle(aRect);
3066 pItem->Paint(aEntryPos, *this, rRenderContext, pViewDataEntry, pEntry);
3068 // division line between tabs
3069 if (pNextTab && pItem->GetType() == SV_ITEM_ID_LBOXSTRING &&
3070 // not at the right edge of the window!
3071 aRect.Right() < nMaxRight)
3073 aRect.Left() = aRect.Right() - SV_TAB_BORDER;
3074 rRenderContext.DrawRect(aRect);
3077 rRenderContext.SetFillColor(aBackupColor);
3079 nCurItem++;
3080 nCurTab++;
3082 if (pViewDataEntry->IsCursored() && !HasFocus())
3084 // cursor emphasis
3085 rRenderContext.SetFillColor();
3086 Color aOldLineColor = rRenderContext.GetLineColor();
3087 rRenderContext.SetLineColor(Color(COL_BLACK));
3088 aRect = GetFocusRect(pEntry, nLine);
3089 aRect.Top()++;
3090 aRect.Bottom()--;
3091 rRenderContext.DrawRect(aRect);
3092 rRenderContext.SetLineColor(aOldLineColor);
3093 rRenderContext.SetFillColor(aBackupColor);
3096 if (bCurFontIsSel)
3098 rRenderContext.SetTextColor(aBackupTextColor);
3099 rRenderContext.SetFont(aBackupFont);
3102 sal_uInt16 nFirstDynTabPos;
3103 SvLBoxTab* pFirstDynamicTab = GetFirstDynamicTab(nFirstDynTabPos);
3104 long nDynTabPos = GetTabPos(pEntry, pFirstDynamicTab);
3105 nDynTabPos += pImp->nNodeBmpTabDistance;
3106 nDynTabPos += pImp->nNodeBmpWidth / 2;
3107 nDynTabPos += 4; // 4 pixels of buffer, so the node bitmap is not too close
3108 // to the next tab
3110 if( (!(pEntry->GetFlags() & SvTLEntryFlags::NO_NODEBMP)) &&
3111 (nWindowStyle & WB_HASBUTTONS) && pFirstDynamicTab &&
3112 (pEntry->HasChildren() || pEntry->HasChildrenOnDemand()))
3114 // find first tab and check if the node bitmap extends into it
3115 sal_uInt16 nNextTab = nFirstDynTabPos;
3116 SvLBoxTab* pNextTab;
3119 nNextTab++;
3120 pNextTab = nNextTab < nTabCount ? aTabs[nNextTab] : 0;
3121 } while (pNextTab && pNextTab->IsDynamic());
3123 if (!pNextTab || (GetTabPos( pEntry, pNextTab ) > nDynTabPos))
3125 if ((nWindowStyle & WB_HASBUTTONSATROOT) || pModel->GetDepth(pEntry) > 0)
3127 Point aPos(GetTabPos(pEntry, pFirstDynamicTab), nLine);
3128 aPos.X() += pImp->nNodeBmpTabDistance;
3130 const Image* pImg = 0;
3132 if (IsExpanded(pEntry))
3133 pImg = &pImp->GetExpandedNodeBmp();
3134 else
3136 if ((!pEntry->HasChildren()) && pEntry->HasChildrenOnDemand() &&
3137 (!(pEntry->GetFlags() & SvTLEntryFlags::HAD_CHILDREN)) &&
3138 pImp->GetDontKnowNodeBmp().GetSizePixel().Width())
3140 pImg = &pImp->GetDontKnowNodeBmp( );
3142 else
3144 pImg = &pImp->GetCollapsedNodeBmp( );
3147 aPos.Y() += (nTempEntryHeight - pImg->GetSizePixel().Height()) / 2;
3149 DrawImageFlags nStyle = DrawImageFlags::NONE;
3150 if (!IsEnabled())
3151 nStyle |= DrawImageFlags::Disable;
3153 //native
3154 bool bNativeOK = false;
3155 if (rRenderContext.IsNativeControlSupported(CTRL_LISTNODE, PART_ENTIRE_CONTROL))
3157 ImplControlValue aControlValue;
3158 Rectangle aCtrlRegion(aPos, pImg->GetSizePixel());
3159 ControlState nState = ControlState::NONE;
3161 if (IsEnabled())
3162 nState |= ControlState::ENABLED;
3164 if (IsExpanded(pEntry))
3165 aControlValue.setTristateVal(BUTTONVALUE_ON); //expanded node
3166 else
3168 if ((!pEntry->HasChildren()) && pEntry->HasChildrenOnDemand() &&
3169 (!(pEntry->GetFlags() & SvTLEntryFlags::HAD_CHILDREN)) &&
3170 pImp->GetDontKnowNodeBmp().GetSizePixel().Width())
3172 aControlValue.setTristateVal( BUTTONVALUE_DONTKNOW ); //dont know
3174 else
3176 aControlValue.setTristateVal( BUTTONVALUE_OFF ); //collapsed node
3180 bNativeOK = rRenderContext.DrawNativeControl(CTRL_LISTNODE, PART_ENTIRE_CONTROL, aCtrlRegion, nState, aControlValue, OUString());
3183 if (!bNativeOK)
3185 rRenderContext.DrawImage(aPos, *pImg ,nStyle);
3191 if (bHasClipRegion && bResetClipRegion)
3192 rRenderContext.SetClipRegion();
3194 return 0; // nRowLen;
3197 void SvTreeListBox::PreparePaint(vcl::RenderContext& /*rRenderContext*/, SvTreeListEntry* /*pEntry*/)
3201 Rectangle SvTreeListBox::GetFocusRect( SvTreeListEntry* pEntry, long nLine )
3203 Size aSize;
3204 Rectangle aRect;
3205 aRect.Top() = nLine;
3206 aSize.Height() = GetEntryHeight();
3208 long nRealWidth = pImp->GetOutputSize().Width();
3209 nRealWidth -= GetMapMode().GetOrigin().X();
3211 sal_uInt16 nCurTab;
3212 SvLBoxTab* pTab = GetFirstTab( SvLBoxTabFlags::SHOW_SELECTION, nCurTab );
3213 long nTabPos = 0;
3214 if( pTab )
3215 nTabPos = GetTabPos( pEntry, pTab );
3216 long nNextTabPos;
3217 if( pTab && nCurTab < aTabs.size() - 1 )
3219 SvLBoxTab* pNextTab = aTabs[ nCurTab + 1 ];
3220 nNextTabPos = GetTabPos( pEntry, pNextTab );
3222 else
3224 nNextTabPos = nRealWidth;
3225 if( nTabPos > nRealWidth )
3226 nNextTabPos += 50;
3229 bool bUserSelection = bool( nTreeFlags & SvTreeFlags::USESEL );
3230 if( !bUserSelection )
3232 if( pTab && nCurTab < pEntry->ItemCount() )
3234 SvLBoxItem* pItem = pEntry->GetItem( nCurTab );
3235 aSize.Width() = pItem->GetSize( this, pEntry ).Width();
3236 if( !aSize.Width() )
3237 aSize.Width() = 15;
3238 long nX = nTabPos; //GetTabPos( pEntry, pTab );
3239 // alignment
3240 nX += pTab->CalcOffset( aSize.Width(), nNextTabPos - nTabPos );
3241 aRect.Left() = nX;
3242 // make sure that first and last letter aren't cut off slightly
3243 aRect.SetSize( aSize );
3244 if( aRect.Left() > 0 )
3245 aRect.Left()--;
3246 aRect.Right()++;
3249 else
3251 // if SelTab != 0, we have to calculate also
3252 if( nFocusWidth == -1 || nFirstSelTab )
3254 SvLBoxTab* pLastTab = NULL; // default to select whole width
3256 sal_uInt16 nLastTab;
3257 GetLastTab(SvLBoxTabFlags::SHOW_SELECTION,nLastTab);
3258 nLastTab++;
3259 if( nLastTab < aTabs.size() ) // is there another one?
3260 pLastTab = aTabs[ nLastTab ];
3262 aSize.Width() = pLastTab ? pLastTab->GetPos() : 0x0fffffff;
3263 nFocusWidth = (short)aSize.Width();
3264 if( pTab )
3265 nFocusWidth = nFocusWidth - (short)nTabPos; //pTab->GetPos();
3267 else
3269 aSize.Width() = nFocusWidth;
3270 if( pTab )
3272 if( nCurTab )
3273 aSize.Width() += nTabPos;
3274 else
3275 aSize.Width() += pTab->GetPos(); // Tab0 always from the leftmost position
3278 // if selection starts with 0th tab, draw from column 0 on
3279 if( nCurTab != 0 )
3281 aRect.Left() = nTabPos;
3282 aSize.Width() -= nTabPos;
3284 aRect.SetSize( aSize );
3286 // adjust right edge because of clipping
3287 if( aRect.Right() >= nRealWidth )
3289 aRect.Right() = nRealWidth-1;
3290 nFocusWidth = (short)aRect.GetWidth();
3292 return aRect;
3296 sal_IntPtr SvTreeListBox::GetTabPos( SvTreeListEntry* pEntry, SvLBoxTab* pTab)
3298 DBG_ASSERT(pTab,"No Tab");
3299 sal_IntPtr nPos = pTab->GetPos();
3300 if( pTab->IsDynamic() )
3302 sal_uInt16 nDepth = pModel->GetDepth( pEntry );
3303 nDepth = nDepth * (sal_uInt16)nIndent;
3304 nPos += (sal_IntPtr)nDepth;
3306 return nPos;
3309 SvLBoxItem* SvTreeListBox::GetItem_Impl( SvTreeListEntry* pEntry, long nX,
3310 SvLBoxTab** ppTab, sal_uInt16 nEmptyWidth )
3312 SvLBoxItem* pItemClicked = 0;
3313 sal_uInt16 nTabCount = aTabs.size();
3314 sal_uInt16 nItemCount = pEntry->ItemCount();
3315 SvLBoxTab* pTab = aTabs.front();
3316 SvLBoxItem* pItem = pEntry->GetItem(0);
3317 sal_uInt16 nNextItem = 1;
3318 nX -= GetMapMode().GetOrigin().X();
3319 long nRealWidth = pImp->GetOutputSize().Width();
3320 nRealWidth -= GetMapMode().GetOrigin().X();
3322 while( true )
3324 SvLBoxTab* pNextTab=nNextItem<nTabCount ? aTabs[nNextItem] : 0;
3325 long nStart = GetTabPos( pEntry, pTab );
3327 long nNextTabPos;
3328 if( pNextTab )
3329 nNextTabPos = GetTabPos( pEntry, pNextTab );
3330 else
3332 nNextTabPos = nRealWidth;
3333 if( nStart > nRealWidth )
3334 nNextTabPos += 50;
3337 Size aItemSize( pItem->GetSize(this, pEntry));
3338 nStart += pTab->CalcOffset( aItemSize.Width(), nNextTabPos - nStart );
3339 long nLen = aItemSize.Width();
3340 if( pNextTab )
3342 long nTabWidth = GetTabPos( pEntry, pNextTab ) - nStart;
3343 if( nTabWidth < nLen )
3344 nLen = nTabWidth;
3347 if( !nLen )
3348 nLen = nEmptyWidth;
3350 if( nX >= nStart && nX < (nStart+nLen ) )
3352 pItemClicked = pItem;
3353 if( ppTab )
3355 *ppTab = pTab;
3356 break;
3359 if( nNextItem >= nItemCount || nNextItem >= nTabCount)
3360 break;
3361 pTab = aTabs[ nNextItem ];
3362 pItem = pEntry->GetItem( nNextItem );
3363 nNextItem++;
3365 return pItemClicked;
3368 long SvTreeListBox::getPreferredDimensions(std::vector<long> &rWidths) const
3370 long nHeight = 0;
3371 rWidths.clear();
3372 SvTreeListEntry* pEntry = First();
3373 while (pEntry)
3375 sal_uInt16 nCount = pEntry->ItemCount();
3376 sal_uInt16 nCurPos = 0;
3377 if (nCount > rWidths.size())
3378 rWidths.resize(nCount);
3379 while (nCurPos < nCount)
3381 SvLBoxItem* pItem = pEntry->GetItem( nCurPos );
3382 long nWidth = pItem->GetSize(this, pEntry).Width();
3383 if (nWidth)
3385 nWidth += SV_TAB_BORDER * 2;
3386 if (nWidth > rWidths[nCurPos])
3387 rWidths[nCurPos] = nWidth;
3389 ++nCurPos;
3391 pEntry = Next( pEntry );
3392 nHeight += GetEntryHeight();
3394 return nHeight;
3397 Size SvTreeListBox::GetOptimalSize() const
3399 std::vector<long> aWidths;
3400 Size aRet(0, getPreferredDimensions(aWidths));
3401 for (size_t i = 0; i < aWidths.size(); ++i)
3402 aRet.Width() += aWidths[i];
3403 if (GetStyle() & WB_BORDER)
3405 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3406 aRet.Width() += rStyleSettings.GetBorderSize() * 2;
3407 aRet.Height() += rStyleSettings.GetBorderSize() * 2;
3409 long nMinWidth = nMinWidthInChars * approximate_char_width();
3410 aRet.Width() = std::max(aRet.Width(), nMinWidth);
3411 return aRet;
3414 void SvTreeListBox::SetAlternatingRowColors( bool bEnable )
3416 mbAlternatingRowColors = bEnable;
3417 if( mbAlternatingRowColors )
3419 SvTreeListEntry* pEntry = pModel->First();
3420 for(size_t i = 0; pEntry; ++i)
3422 pEntry->SetBackColor( i % 2 == 0 ? GetBackground().GetColor() : GetSettings().GetStyleSettings().GetAlternatingRowColor());
3423 pEntry = pModel->Next(pEntry);
3426 else
3427 for(SvTreeListEntry* pEntry = pModel->First(); pEntry; pEntry = pModel->Next(pEntry))
3428 pEntry->SetBackColor( GetBackground().GetColor() );
3430 pImp->UpdateAll();
3433 SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX,SvLBoxTab** ppTab)
3435 return GetItem_Impl( pEntry, nX, ppTab, 0 );
3438 SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX )
3440 SvLBoxTab* pDummyTab;
3441 return GetItem_Impl( pEntry, nX, &pDummyTab, 0 );
3444 void SvTreeListBox::AddTab(long nTabPos, SvLBoxTabFlags nFlags, void* pUserData )
3446 nFocusWidth = -1;
3447 SvLBoxTab* pTab = new SvLBoxTab( nTabPos, nFlags );
3448 pTab->SetUserData( pUserData );
3449 aTabs.push_back( pTab );
3450 if( nTreeFlags & SvTreeFlags::USESEL )
3452 sal_uInt16 nPos = aTabs.size() - 1;
3453 if( nPos >= nFirstSelTab && nPos <= nLastSelTab )
3454 pTab->nFlags |= SvLBoxTabFlags::SHOW_SELECTION;
3455 else
3456 // string items usually have to be selected -- turn this off
3457 // explicitly
3458 pTab->nFlags &= ~SvLBoxTabFlags::SHOW_SELECTION;
3464 SvLBoxTab* SvTreeListBox::GetFirstDynamicTab( sal_uInt16& rPos ) const
3466 sal_uInt16 nCurTab = 0;
3467 sal_uInt16 nTabCount = aTabs.size();
3468 while( nCurTab < nTabCount )
3470 SvLBoxTab* pTab = aTabs[nCurTab];
3471 if( pTab->nFlags & SvLBoxTabFlags::DYNAMIC )
3473 rPos = nCurTab;
3474 return pTab;
3476 nCurTab++;
3478 return 0;
3481 SvLBoxTab* SvTreeListBox::GetFirstDynamicTab() const
3483 sal_uInt16 nDummy;
3484 return GetFirstDynamicTab( nDummy );
3487 SvLBoxTab* SvTreeListBox::GetTab( SvTreeListEntry* pEntry, SvLBoxItem* pItem) const
3489 sal_uInt16 nPos = pEntry->GetPos( pItem );
3490 return aTabs[ nPos ];
3493 void SvTreeListBox::ClearTabList()
3495 sal_uInt16 nTabCount = aTabs.size();
3496 while( nTabCount )
3498 nTabCount--;
3499 SvLBoxTab* pDelTab = aTabs[ nTabCount ];
3500 delete pDelTab;
3502 aTabs.clear();
3506 Size SvTreeListBox::GetOutputSizePixel() const
3508 Size aSize = pImp->GetOutputSize();
3509 return aSize;
3512 void SvTreeListBox::NotifyEndScroll()
3516 void SvTreeListBox::NotifyScrolled()
3518 aScrolledHdl.Call( this );
3521 void SvTreeListBox::Invalidate( sal_uInt16 nInvalidateFlags )
3523 if (!pImp)
3524 return;
3525 if( nFocusWidth == -1 )
3526 // to make sure that the control doesn't show the wrong focus rectangle
3527 // after painting
3528 pImp->RecalcFocusRect();
3529 Control::Invalidate( nInvalidateFlags );
3530 pImp->Invalidate();
3533 void SvTreeListBox::Invalidate( const Rectangle& rRect, sal_uInt16 nInvalidateFlags )
3535 if( nFocusWidth == -1 )
3536 // to make sure that the control doesn't show the wrong focus rectangle
3537 // after painting
3538 pImp->RecalcFocusRect();
3539 Control::Invalidate( rRect, nInvalidateFlags );
3543 void SvTreeListBox::SetHighlightRange( sal_uInt16 nStart, sal_uInt16 nEnd)
3546 sal_uInt16 nTemp;
3547 nTreeFlags |= SvTreeFlags::USESEL;
3548 if( nStart > nEnd )
3550 nTemp = nStart;
3551 nStart = nEnd;
3552 nEnd = nTemp;
3554 // select all tabs that lie within the area
3555 nTreeFlags |= SvTreeFlags::RECALCTABS;
3556 nFirstSelTab = nStart;
3557 nLastSelTab = nEnd;
3558 pImp->RecalcFocusRect();
3561 void SvTreeListBox::Command( const CommandEvent& rCEvt )
3563 // FIXME gnumake2 resync to DEV300_m84
3564 pImp->Command( rCEvt );
3568 void SvTreeListBox::RemoveParentKeepChildren( SvTreeListEntry* pParent )
3570 DBG_ASSERT(pParent,"RemoveParentKeepChildren:No Parent");
3571 SvTreeListEntry* pNewParent = GetParent( pParent );
3572 if( pParent->HasChildren())
3574 SvTreeListEntry* pChild = FirstChild( pParent );
3575 while( pChild )
3577 pModel->Move( pChild, pNewParent, TREELIST_APPEND );
3578 pChild = FirstChild( pParent );
3581 pModel->Remove( pParent );
3584 SvLBoxTab* SvTreeListBox::GetFirstTab( SvLBoxTabFlags nFlagMask, sal_uInt16& rPos )
3586 sal_uInt16 nTabCount = aTabs.size();
3587 for( sal_uInt16 nPos = 0; nPos < nTabCount; nPos++ )
3589 SvLBoxTab* pTab = aTabs[ nPos ];
3590 if( (pTab->nFlags & nFlagMask) )
3592 rPos = nPos;
3593 return pTab;
3596 rPos = 0xffff;
3597 return 0;
3600 SvLBoxTab* SvTreeListBox::GetLastTab( SvLBoxTabFlags nFlagMask, sal_uInt16& rTabPos )
3602 sal_uInt16 nPos = (sal_uInt16)aTabs.size();
3603 while( nPos )
3605 --nPos;
3606 SvLBoxTab* pTab = aTabs[ nPos ];
3607 if( (pTab->nFlags & nFlagMask) )
3609 rTabPos = nPos;
3610 return pTab;
3613 rTabPos = 0xffff;
3614 return 0;
3617 void SvTreeListBox::RequestHelp( const HelpEvent& rHEvt )
3619 if( !pImp->RequestHelp( rHEvt ) )
3620 Control::RequestHelp( rHEvt );
3623 IMPL_LINK( SvTreeListBox, DefaultCompare, SvSortData*, pData )
3625 const SvTreeListEntry* pLeft = pData->pLeft;
3626 const SvTreeListEntry* pRight = pData->pRight;
3627 OUString aLeft( static_cast<const SvLBoxString*>(pLeft->GetFirstItem(SV_ITEM_ID_LBOXSTRING))->GetText());
3628 OUString aRight( static_cast<const SvLBoxString*>(pRight->GetFirstItem(SV_ITEM_ID_LBOXSTRING))->GetText());
3629 pImp->UpdateStringSorter();
3630 return pImp->m_pStringSorter->compare(aLeft, aRight);
3633 void SvTreeListBox::ModelNotification( SvListAction nActionId, SvTreeListEntry* pEntry1,
3634 SvTreeListEntry* pEntry2, sal_uLong nPos )
3636 SolarMutexGuard aSolarGuard;
3638 if( nActionId == SvListAction::CLEARING )
3639 CancelTextEditing();
3641 SvListView::ModelNotification( nActionId, pEntry1, pEntry2, nPos );
3642 switch( nActionId )
3644 case SvListAction::INSERTED:
3646 SvTreeListEntry* pEntry( dynamic_cast< SvTreeListEntry* >( pEntry1 ) );
3647 if ( !pEntry )
3649 SAL_WARN( "svtools.contnr", "SvTreeListBox::ModelNotification: invalid entry!" );
3650 break;
3653 SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) );
3654 if ( !pBmpItem )
3655 break;
3656 const Image& rBitmap1( pBmpItem->GetBitmap1() );
3657 const Image& rBitmap2( pBmpItem->GetBitmap2() );
3658 short nMaxWidth = short( std::max( rBitmap1.GetSizePixel().Width(), rBitmap2.GetSizePixel().Width() ) );
3659 nMaxWidth = pImp->UpdateContextBmpWidthVector( pEntry, nMaxWidth );
3660 if( nMaxWidth > nContextBmpWidthMax )
3662 nContextBmpWidthMax = nMaxWidth;
3663 SetTabs();
3665 if (get_width_request() == -1)
3666 queue_resize();
3668 break;
3670 case SvListAction::RESORTING:
3671 SetUpdateMode( false );
3672 break;
3674 case SvListAction::RESORTED:
3675 // after a selection: show first entry and also keep the selection
3676 MakeVisible( pModel->First(), true );
3677 SetUpdateMode( true );
3678 break;
3680 case SvListAction::CLEARED:
3681 if( IsUpdateMode() )
3682 Update();
3683 break;
3685 default: break;
3689 void SvTreeListBox::EndSelection()
3691 pImp->EndSelection();
3694 ScrollBar *SvTreeListBox::GetVScroll()
3696 return pImp->aVerSBar.get();
3699 ScrollBar *SvTreeListBox::GetHScroll()
3701 return pImp->aHorSBar.get();
3704 void SvTreeListBox::EnableAsyncDrag( bool b )
3706 pImp->EnableAsyncDrag( b );
3709 SvTreeListEntry* SvTreeListBox::GetFirstEntryInView() const
3711 Point aPos;
3712 return GetEntry( aPos );
3715 SvTreeListEntry* SvTreeListBox::GetNextEntryInView(SvTreeListEntry* pEntry ) const
3717 SvTreeListEntry* pNext = NextVisible( pEntry );
3718 if( pNext )
3720 Point aPos( GetEntryPosition(pNext) );
3721 const Size& rSize = pImp->GetOutputSize();
3722 if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() )
3723 return 0;
3725 return pNext;
3728 SvTreeListEntry* SvTreeListBox::GetLastEntryInView() const
3730 SvTreeListEntry* pEntry = GetFirstEntryInView();
3731 SvTreeListEntry* pNext = 0;
3732 while( pEntry )
3734 pNext = NextVisible( pEntry );
3735 if( pNext )
3737 Point aPos( GetEntryPosition(pNext) );
3738 const Size& rSize = pImp->GetOutputSize();
3739 if( aPos.Y() < 0 || aPos.Y() + GetEntryHeight() >= rSize.Height() )
3740 break;
3741 else
3742 pEntry = pNext;
3744 else
3745 break;
3747 return pEntry;
3750 void SvTreeListBox::ShowFocusRect( const SvTreeListEntry* pEntry )
3752 pImp->ShowFocusRect( pEntry );
3755 void SvTreeListBox::DataChanged( const DataChangedEvent& rDCEvt )
3757 if( (rDCEvt.GetType()==DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
3759 nEntryHeight = 0; // _together_ with true of 1. par (bFont) of InitSettings() a zero-height
3760 // forces complete recalc of heights!
3761 InitSettings( true, true, true );
3762 Invalidate();
3764 else
3765 Control::DataChanged( rDCEvt );
3768 void SvTreeListBox::StateChanged( StateChangedType eType )
3770 if( eType == StateChangedType::Enable )
3771 Invalidate( INVALIDATE_CHILDREN );
3773 Control::StateChanged( eType );
3775 if ( eType == StateChangedType::Style )
3776 ImplInitStyle();
3779 void SvTreeListBox::ApplySettings(vcl::RenderContext& rRenderContext)
3781 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
3782 vcl::Font aFont;
3783 aFont = rStyleSettings.GetFieldFont();
3784 aFont.SetColor(rStyleSettings.GetWindowTextColor());
3785 SetPointFont(rRenderContext, aFont);
3786 AdjustEntryHeightAndRecalc(aFont);
3788 rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor());
3789 rRenderContext.SetTextFillColor();
3790 rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
3792 // always try to re-create default-SvLBoxButtonData
3793 if (pCheckButtonData && pCheckButtonData->HasDefaultImages())
3794 pCheckButtonData->SetDefaultImages(this);
3797 void SvTreeListBox::InitSettings(bool bFont, bool bForeground, bool bBackground)
3799 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3800 if (bFont)
3802 vcl::Font aFont;
3803 aFont = rStyleSettings.GetFieldFont();
3804 aFont.SetColor(rStyleSettings.GetWindowTextColor());
3805 SetPointFont(*this, aFont);
3806 AdjustEntryHeightAndRecalc(aFont);
3809 if (bForeground || bFont)
3811 SetTextColor(rStyleSettings.GetFieldTextColor());
3812 SetTextFillColor();
3815 if (bBackground)
3816 SetBackground(rStyleSettings.GetFieldColor());
3818 // always try to re-create default-SvLBoxButtonData
3819 if( pCheckButtonData && pCheckButtonData->HasDefaultImages() )
3820 pCheckButtonData->SetDefaultImages(this);
3823 bool SvTreeListBox::IsCellFocusEnabled() const
3825 return pImp->IsCellFocusEnabled();
3828 bool SvTreeListBox::SetCurrentTabPos( sal_uInt16 _nNewPos )
3830 return pImp->SetCurrentTabPos( _nNewPos );
3833 sal_uInt16 SvTreeListBox::GetCurrentTabPos() const
3835 return pImp->GetCurrentTabPos();
3838 void SvTreeListBox::InitStartEntry()
3840 if( !pImp->pStartEntry )
3841 pImp->pStartEntry = GetModel()->First();
3844 PopupMenu* SvTreeListBox::CreateContextMenu()
3846 return NULL;
3849 void SvTreeListBox::ExcecuteContextMenuAction( sal_uInt16 )
3851 DBG_WARNING( "SvTreeListBox::ExcecuteContextMenuAction(): now there's happening nothing!" );
3854 void SvTreeListBox::EnableContextMenuHandling()
3856 assert(pImp && "-SvTreeListBox::EnableContextMenuHandling(): No implementation!");
3857 pImp->bContextMenuHandling = true;
3860 void SvTreeListBox::EnableList( bool _bEnable )
3862 // call base class method
3863 Window::Enable(_bEnable);
3864 // then invalidate
3865 Invalidate(Rectangle(Point(), GetSizePixel()));
3868 ::com::sun::star::uno::Reference< XAccessible > SvTreeListBox::CreateAccessible()
3870 vcl::Window* pParent = GetAccessibleParentWindow();
3871 DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" );
3873 ::com::sun::star::uno::Reference< XAccessible > xAccessible;
3874 if ( pParent )
3876 ::com::sun::star::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
3877 if ( xAccParent.is() )
3879 // need to be done here to get the vclxwindow later on in the accessbile
3880 ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xTemp(GetComponentInterface());
3881 xAccessible = pImp->m_aFactoryAccess.getFactory().createAccessibleTreeListBox( *this, xAccParent );
3884 return xAccessible;
3887 void SvTreeListBox::FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const
3889 assert(pEntry && "SvTreeListBox::FillAccessibleEntryStateSet: invalid entry");
3891 if ( pEntry->HasChildrenOnDemand() || pEntry->HasChildren() )
3893 rStateSet.AddState( AccessibleStateType::EXPANDABLE );
3894 if ( IsExpanded( pEntry ) )
3895 rStateSet.AddState( (sal_Int16)AccessibleStateType::EXPANDED );
3898 if ( GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED )
3899 rStateSet.AddState( AccessibleStateType::CHECKED );
3900 if ( IsEntryVisible( pEntry ) )
3901 rStateSet.AddState( AccessibleStateType::VISIBLE );
3902 if ( IsSelected( pEntry ) )
3903 rStateSet.AddState( AccessibleStateType::SELECTED );
3904 if ( IsEnabled() )
3906 rStateSet.AddState( AccessibleStateType::ENABLED );
3907 rStateSet.AddState( AccessibleStateType::FOCUSABLE );
3908 rStateSet.AddState( AccessibleStateType::SELECTABLE );
3909 SvViewDataEntry* pViewDataNewCur = GetViewDataEntry(pEntry);
3910 if (pViewDataNewCur && pViewDataNewCur->HasFocus())
3911 rStateSet.AddState( AccessibleStateType::FOCUSED );
3915 Rectangle SvTreeListBox::GetBoundingRect( SvTreeListEntry* pEntry )
3917 Point aPos = GetEntryPosition( pEntry );
3918 Rectangle aRect = GetFocusRect( pEntry, aPos.Y() );
3919 return aRect;
3922 void SvTreeListBox::EnableCellFocus()
3924 pImp->EnableCellFocus();
3927 void SvTreeListBox::CallImplEventListeners(sal_uLong nEvent, void* pData)
3929 CallEventListeners(nEvent, pData);
3932 void SvTreeListBox::set_min_width_in_chars(sal_Int32 nChars)
3934 nMinWidthInChars = nChars;
3935 queue_resize();
3938 bool SvTreeListBox::set_property(const OString &rKey, const OString &rValue)
3940 if (rKey == "min-width-chars")
3942 set_min_width_in_chars(rValue.toInt32());
3944 else
3945 return Control::set_property(rKey, rValue);
3946 return true;
3949 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */