GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / svtools / source / contnr / treelistbox.cxx
blobec2960850fe62881ecc8e6af37e7af5240b0b159
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( sal_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/builder.hxx>
32 #include <sot/formats.hxx>
33 #include <unotools/accessiblestatesethelper.hxx>
34 #include <rtl/instance.hxx>
35 #include <comphelper/string.hxx>
37 #include <svtools/svmedit.hxx>
38 #include <svtools/svlbitm.hxx>
39 #include "svtools/treelistentry.hxx"
40 #include "svtools/viewdataentry.hxx"
41 #include "svimpbox.hxx"
43 #include <set>
44 #include <string.h>
45 #include <vector>
47 using namespace ::com::sun::star::accessibility;
49 // Drag&Drop
50 static SvTreeListBox* pDDSource = NULL;
51 static SvTreeListBox* pDDTarget = NULL;
53 DBG_NAME(SvInplaceEdit2)
55 #define SVLBOX_ACC_RETURN 1
56 #define SVLBOX_ACC_ESCAPE 2
58 // ***************************************************************
60 class MyEdit_Impl : public Edit
62 SvInplaceEdit2* pOwner;
63 public:
64 MyEdit_Impl( Window* pParent, SvInplaceEdit2* pOwner );
65 virtual void KeyInput( const KeyEvent& rKEvt );
66 virtual void LoseFocus();
69 class MyMultiEdit_Impl : public MultiLineEdit
71 SvInplaceEdit2* pOwner;
72 public:
73 MyMultiEdit_Impl( Window* pParent, SvInplaceEdit2* pOwner );
74 virtual void KeyInput( const KeyEvent& rKEvt );
75 virtual void LoseFocus();
78 MyEdit_Impl::MyEdit_Impl( Window* pParent, SvInplaceEdit2* _pOwner ) :
80 Edit( pParent, WB_LEFT ),
82 pOwner( _pOwner )
87 void MyEdit_Impl::KeyInput( const KeyEvent& rKEvt )
89 if( !pOwner->KeyInput( rKEvt ))
90 Edit::KeyInput( rKEvt );
93 void MyEdit_Impl::LoseFocus()
95 pOwner->LoseFocus();
98 MyMultiEdit_Impl::MyMultiEdit_Impl( Window* pParent, SvInplaceEdit2* _pOwner )
99 : MultiLineEdit( pParent,
100 WB_CENTER
101 ), pOwner(_pOwner)
105 void MyMultiEdit_Impl::KeyInput( const KeyEvent& rKEvt )
107 if( !pOwner->KeyInput( rKEvt ))
108 MultiLineEdit::KeyInput( rKEvt );
111 void MyMultiEdit_Impl::LoseFocus()
113 pOwner->LoseFocus();
117 SvInplaceEdit2::SvInplaceEdit2
119 Window* pParent, const Point& rPos,
120 const Size& rSize,
121 const OUString& rData,
122 const Link& rNotifyEditEnd,
123 const Selection& rSelection,
124 sal_Bool bMulti
127 aCallBackHdl ( rNotifyEditEnd ),
128 bCanceled ( sal_False ),
129 bAlreadyInCallBack ( sal_False )
132 DBG_CTOR(SvInplaceEdit2,0);
134 if( bMulti )
135 pEdit = new MyMultiEdit_Impl( pParent, this );
136 else
137 pEdit = new MyEdit_Impl( pParent, this );
139 Font aFont( pParent->GetFont() );
140 aFont.SetTransparent( sal_False );
141 Color aColor( pParent->GetBackground().GetColor() );
142 aFont.SetFillColor(aColor );
143 pEdit->SetFont( aFont );
144 pEdit->SetBackground( pParent->GetBackground() );
145 pEdit->SetPosPixel( rPos );
146 pEdit->SetSizePixel( rSize );
147 pEdit->SetText( rData );
148 pEdit->SetSelection( rSelection );
149 pEdit->SaveValue();
151 aAccReturn.InsertItem( SVLBOX_ACC_RETURN, KeyCode(KEY_RETURN) );
152 aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE, KeyCode(KEY_ESCAPE) );
154 aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit2, ReturnHdl_Impl) );
155 aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit2, EscapeHdl_Impl) );
156 GetpApp()->InsertAccel( &aAccReturn );
157 GetpApp()->InsertAccel( &aAccEscape );
159 pEdit->Show();
160 pEdit->GrabFocus();
163 SvInplaceEdit2::~SvInplaceEdit2()
165 DBG_DTOR(SvInplaceEdit2,0);
166 if( !bAlreadyInCallBack )
168 GetpApp()->RemoveAccel( &aAccReturn );
169 GetpApp()->RemoveAccel( &aAccEscape );
171 delete pEdit;
174 OUString SvInplaceEdit2::GetSavedValue() const
176 return pEdit->GetSavedValue();
179 void SvInplaceEdit2::Hide()
181 pEdit->Hide();
185 IMPL_LINK_NOARG_INLINE_START(SvInplaceEdit2, ReturnHdl_Impl)
187 DBG_CHKTHIS(SvInplaceEdit2,0);
188 bCanceled = sal_False;
189 CallCallBackHdl_Impl();
190 return 1;
192 IMPL_LINK_NOARG_INLINE_END(SvInplaceEdit2, ReturnHdl_Impl)
194 IMPL_LINK_NOARG_INLINE_START(SvInplaceEdit2, EscapeHdl_Impl)
196 DBG_CHKTHIS(SvInplaceEdit2,0);
197 bCanceled = sal_True;
198 CallCallBackHdl_Impl();
199 return 1;
201 IMPL_LINK_NOARG_INLINE_END(SvInplaceEdit2, EscapeHdl_Impl)
204 sal_Bool SvInplaceEdit2::KeyInput( const KeyEvent& rKEvt )
206 DBG_CHKTHIS(SvInplaceEdit2,0);
207 KeyCode aCode = rKEvt.GetKeyCode();
208 sal_uInt16 nCode = aCode.GetCode();
210 switch ( nCode )
212 case KEY_ESCAPE:
213 bCanceled = sal_True;
214 CallCallBackHdl_Impl();
215 return sal_True;
217 case KEY_RETURN:
218 bCanceled = sal_False;
219 CallCallBackHdl_Impl();
220 return sal_True;
222 return sal_False;
225 void SvInplaceEdit2::StopEditing( sal_Bool bCancel )
227 DBG_CHKTHIS(SvInplaceEdit2,0);
228 if ( !bAlreadyInCallBack )
230 bCanceled = bCancel;
231 CallCallBackHdl_Impl();
235 void SvInplaceEdit2::LoseFocus()
237 DBG_CHKTHIS(SvInplaceEdit2,0);
238 if ( !bAlreadyInCallBack
239 && ((!Application::GetFocusWindow()) || !pEdit->IsChild( Application::GetFocusWindow()) )
242 bCanceled = sal_False;
243 aTimer.SetTimeout(10);
244 aTimer.SetTimeoutHdl(LINK(this,SvInplaceEdit2,Timeout_Impl));
245 aTimer.Start();
249 IMPL_LINK_NOARG_INLINE_START(SvInplaceEdit2, Timeout_Impl)
251 DBG_CHKTHIS(SvInplaceEdit2,0);
252 CallCallBackHdl_Impl();
253 return 0;
255 IMPL_LINK_NOARG_INLINE_END(SvInplaceEdit2, Timeout_Impl)
257 void SvInplaceEdit2::CallCallBackHdl_Impl()
259 DBG_CHKTHIS(SvInplaceEdit2,0);
260 aTimer.Stop();
261 if ( !bAlreadyInCallBack )
263 bAlreadyInCallBack = sal_True;
264 GetpApp()->RemoveAccel( &aAccReturn );
265 GetpApp()->RemoveAccel( &aAccEscape );
266 pEdit->Hide();
267 aCallBackHdl.Call( this );
271 OUString SvInplaceEdit2::GetText() const
273 return pEdit->GetText();
276 // ***************************************************************
277 // class SvLBoxTab
278 // ***************************************************************
280 DBG_NAME(SvLBoxTab);
282 SvLBoxTab::SvLBoxTab()
284 DBG_CTOR(SvLBoxTab,0);
285 nPos = 0;
286 pUserData = 0;
287 nFlags = 0;
290 SvLBoxTab::SvLBoxTab( long nPosition, sal_uInt16 nTabFlags )
292 DBG_CTOR(SvLBoxTab,0);
293 nPos = nPosition;
294 pUserData = 0;
295 nFlags = nTabFlags;
298 SvLBoxTab::SvLBoxTab( const SvLBoxTab& rTab )
300 DBG_CTOR(SvLBoxTab,0);
301 nPos = rTab.nPos;
302 pUserData = rTab.pUserData;
303 nFlags = rTab.nFlags;
306 SvLBoxTab::~SvLBoxTab()
308 DBG_DTOR(SvLBoxTab,0);
312 long SvLBoxTab::CalcOffset( long nItemWidth, long nTabWidth )
314 DBG_CHKTHIS(SvLBoxTab,0);
315 long nOffset = 0;
316 if ( nFlags & SV_LBOXTAB_ADJUST_RIGHT )
318 nOffset = nTabWidth - nItemWidth;
319 if( nOffset < 0 )
320 nOffset = 0;
322 else if ( nFlags & SV_LBOXTAB_ADJUST_CENTER )
324 if( nFlags & SV_LBOXTAB_FORCE )
326 // correct implementation of centering
327 nOffset = ( nTabWidth - nItemWidth ) / 2;
328 if( nOffset < 0 )
329 nOffset = 0;
331 else
333 // historically grown, wrong calculation of tabs which is needed by
334 // Abo-Tabbox, Tools/Options/Customize etc.
335 nItemWidth++;
336 nOffset = -( nItemWidth / 2 );
339 return nOffset;
342 // ***************************************************************
343 // class SvLBoxItem
344 // ***************************************************************
346 DBG_NAME(SvLBoxItem);
348 SvLBoxItem::SvLBoxItem( SvTreeListEntry*, sal_uInt16 )
350 DBG_CTOR(SvLBoxItem,0);
353 SvLBoxItem::SvLBoxItem()
355 DBG_CTOR(SvLBoxItem,0);
358 SvLBoxItem::~SvLBoxItem()
360 DBG_DTOR(SvLBoxItem,0);
363 const Size& SvLBoxItem::GetSize(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
365 DBG_CHKTHIS(SvLBoxItem,0);
366 const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
367 return pViewData->maSize;
370 const Size& SvLBoxItem::GetSize(const SvViewDataEntry* pData, sal_uInt16 nItemPos) const
372 const SvViewDataItem* pIData = pData->GetItem(nItemPos);
373 return pIData->maSize;
376 struct SvTreeListBoxImpl
378 bool m_bIsEmptyTextAllowed:1;
379 bool m_bEntryMnemonicsEnabled:1;
380 bool m_bDoingQuickSelection:1;
382 Link* m_pLink;
384 vcl::MnemonicEngine m_aMnemonicEngine;
385 vcl::QuickSelectionEngine m_aQuickSelectionEngine;
387 SvTreeListBoxImpl(SvTreeListBox& _rBox) :
388 m_bIsEmptyTextAllowed(true),
389 m_bEntryMnemonicsEnabled(false),
390 m_bDoingQuickSelection(false),
391 m_pLink(NULL),
392 m_aMnemonicEngine(_rBox),
393 m_aQuickSelectionEngine(_rBox) {}
396 DBG_NAME(SvTreeListBox);
398 SvTreeListBox::SvTreeListBox(Window* pParent, WinBits nWinStyle) :
399 Control(pParent, nWinStyle | WB_CLIPCHILDREN),
400 DropTargetHelper(this),
401 DragSourceHelper(this),
402 mpImpl(new SvTreeListBoxImpl(*this)),
403 mbContextBmpExpanded(false),
404 eSelMode(NO_SELECTION),
405 nMinWidthInChars(0)
407 DBG_CTOR(SvTreeListBox,0);
408 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
409 nImpFlags = 0;
410 pTargetEntry = 0;
411 nDragDropMode = 0;
412 SvTreeList* pTempModel = new SvTreeList;
413 pTempModel->SetRefCount( 0 );
414 SetBaseModel(pTempModel);
415 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
416 pModel->InsertView( this );
417 pHdlEntry = 0;
418 pEdCtrl = 0;
419 eSelMode = SINGLE_SELECTION;
420 nDragDropMode = SV_DRAGDROP_NONE;
421 SetType(WINDOW_TREELISTBOX);
423 InitTreeView();
425 SetSublistOpenWithLeftRight();
428 SvTreeListBox::SvTreeListBox(Window* pParent, const ResId& rResId) :
429 Control(pParent, rResId),
430 DropTargetHelper(this),
431 DragSourceHelper(this),
432 mpImpl(new SvTreeListBoxImpl(*this)),
433 mbContextBmpExpanded(false),
434 eSelMode(NO_SELECTION),
435 nMinWidthInChars(0)
437 DBG_CTOR(SvTreeListBox,0);
438 pTargetEntry = 0;
439 nImpFlags = 0;
440 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
441 nDragDropMode = 0;
442 SvTreeList* pTempModel = new SvTreeList;
443 pTempModel->SetRefCount( 0 );
444 SetBaseModel(pTempModel);
445 pModel->InsertView( this );
446 pHdlEntry = 0;
447 pEdCtrl = 0;
448 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
449 SetType(WINDOW_TREELISTBOX);
451 InitTreeView();
452 Resize();
454 SetSublistOpenWithLeftRight();
457 extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeSvTreeListBox(Window *pParent, VclBuilder::stringmap &rMap)
459 WinBits nWinStyle = WB_TABSTOP;
460 OString sBorder = VclBuilder::extractCustomProperty(rMap);
461 if (!sBorder.isEmpty())
462 nWinStyle |= WB_BORDER;
463 return new SvTreeListBox(pParent, nWinStyle);
466 void SvTreeListBox::Clear()
468 DBG_CHKTHIS(SvTreeListBox,0);
469 pModel->Clear(); // Model calls SvTreeListBox::ModelHasCleared()
472 void SvTreeListBox::EnableEntryMnemonics( bool _bEnable )
474 if ( _bEnable == IsEntryMnemonicsEnabled() )
475 return;
477 mpImpl->m_bEntryMnemonicsEnabled = _bEnable;
478 Invalidate();
481 bool SvTreeListBox::IsEntryMnemonicsEnabled() const
483 return mpImpl->m_bEntryMnemonicsEnabled;
486 IMPL_LINK_INLINE_START( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry )
488 DBG_CHKTHIS(SvTreeListBox,0);
489 return (sal_IntPtr)(CloneEntry((SvTreeListEntry*)pEntry));
491 IMPL_LINK_INLINE_END( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry )
493 sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos )
495 DBG_CHKTHIS(SvTreeListBox,0);
496 sal_uLong nInsPos = pModel->Insert( pEntry, pParent, nPos );
497 return nInsPos;
500 sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry,sal_uLong nRootPos )
502 DBG_CHKTHIS(SvTreeListBox,0);
503 sal_uLong nInsPos = pModel->Insert( pEntry, nRootPos );
504 return nInsPos;
507 long SvTreeListBox::ExpandingHdl()
509 DBG_CHKTHIS(SvTreeListBox,0);
510 return aExpandingHdl.IsSet() ? aExpandingHdl.Call( this ) : 1;
513 void SvTreeListBox::ExpandedHdl()
515 DBG_CHKTHIS(SvTreeListBox,0);
516 aExpandedHdl.Call( this );
519 void SvTreeListBox::SelectHdl()
521 DBG_CHKTHIS(SvTreeListBox,0);
522 aSelectHdl.Call( this );
525 void SvTreeListBox::DeselectHdl()
527 DBG_CHKTHIS(SvTreeListBox,0);
528 aDeselectHdl.Call( this );
531 sal_Bool SvTreeListBox::DoubleClickHdl()
533 DBG_CHKTHIS(SvTreeListBox,0);
534 aDoubleClickHdl.Call( this );
535 return sal_True;
539 sal_Bool SvTreeListBox::CheckDragAndDropMode( SvTreeListBox* pSource, sal_Int8 nAction )
541 DBG_CHKTHIS(SvTreeListBox,0);
542 if ( pSource == this )
544 if ( !(nDragDropMode & (SV_DRAGDROP_CTRL_MOVE | SV_DRAGDROP_CTRL_COPY) ) )
545 return sal_False; // D&D locked within list
546 if( DND_ACTION_MOVE == nAction )
548 if ( !(nDragDropMode & SV_DRAGDROP_CTRL_MOVE) )
549 return sal_False; // no local move
551 else
553 if ( !(nDragDropMode & SV_DRAGDROP_CTRL_COPY))
554 return sal_False; // no local copy
557 else
559 if ( !(nDragDropMode & SV_DRAGDROP_APP_DROP ) )
560 return sal_False; // no drop
561 if ( DND_ACTION_MOVE == nAction )
563 if ( !(nDragDropMode & SV_DRAGDROP_APP_MOVE) )
564 return sal_False; // no global move
566 else
568 if ( !(nDragDropMode & SV_DRAGDROP_APP_COPY))
569 return sal_False; // no global copy
572 return sal_True;
578 void SvTreeListBox::NotifyRemoving( SvTreeListEntry* )
580 DBG_CHKTHIS(SvTreeListBox,0);
584 NotifyMoving/Copying
585 ====================
587 default behavior:
589 1. target doesn't have children
590 - entry becomes sibling of target. entry comes after target
591 (->Window: below the target)
592 2. target is an expanded parent
593 - entry inserted at the beginning of the target childlist
594 3. target is a collapsed parent
595 - entry is inserted at the end of the target childlist
597 #ifdef DBG_UTIL
598 sal_Bool SvTreeListBox::NotifyMoving(
599 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
600 SvTreeListEntry* pEntry, // entry that we want to move, from
601 // GetSourceListBox()->GetModel()
602 SvTreeListEntry*& rpNewParent, // new target parent
603 sal_uLong& rNewChildPos) // position in childlist of target parent
604 #else
605 sal_Bool SvTreeListBox::NotifyMoving(
606 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
607 SvTreeListEntry*, // entry that we want to move, from
608 // GetSourceListBox()->GetModel()
609 SvTreeListEntry*& rpNewParent, // new target parent
610 sal_uLong& rNewChildPos) // position in childlist of target parent
611 #endif
613 DBG_CHKTHIS(SvTreeListBox,0);
614 DBG_ASSERT(pEntry,"NotifyMoving:SoureEntry?");
615 if( !pTarget )
617 rpNewParent = 0;
618 rNewChildPos = 0;
619 return sal_True;
621 if ( !pTarget->HasChildren() && !pTarget->HasChildrenOnDemand() )
623 // case 1
624 rpNewParent = GetParent( pTarget );
625 rNewChildPos = pModel->GetRelPos( pTarget ) + 1;
626 rNewChildPos += nCurEntrySelPos;
627 nCurEntrySelPos++;
629 else
631 // cases 2 & 3
632 rpNewParent = pTarget;
633 if( IsExpanded(pTarget))
634 rNewChildPos = 0;
635 else
636 rNewChildPos = LIST_APPEND;
638 return sal_True;
641 sal_Bool SvTreeListBox::NotifyCopying(
642 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
643 SvTreeListEntry* pEntry, // entry that we want to move, from
644 // GetSourceListBox()->GetModel()
645 SvTreeListEntry*& rpNewParent, // new target parent
646 sal_uLong& rNewChildPos) // position in childlist of target parent
648 DBG_CHKTHIS(SvTreeListBox,0);
649 return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos);
652 SvTreeListEntry* SvTreeListBox::FirstChild( SvTreeListEntry* pParent ) const
654 return pModel->FirstChild(pParent);
657 SvTreeListEntry* SvTreeListBox::NextSibling( SvTreeListEntry* pEntry ) const
659 return pModel->NextSibling(pEntry);
662 SvTreeListEntry* SvTreeListBox::PrevSibling( SvTreeListEntry* pEntry ) const
664 return pModel->PrevSibling(pEntry);
667 // return: all entries copied
668 sal_Bool SvTreeListBox::CopySelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
670 DBG_CHKTHIS(SvTreeListBox,0);
671 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
672 sal_Bool bSuccess = sal_True;
673 std::vector<SvTreeListEntry*> aList;
674 sal_Bool bClone = (sal_Bool)( (sal_uLong)(pSource->GetModel()) != (sal_uLong)GetModel() );
675 Link aCloneLink( pModel->GetCloneLink() );
676 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
678 // cache selection to simplify iterating over the selection when doing a D&D
679 // exchange within the same listbox
680 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
681 while ( pSourceEntry )
683 // children are copied automatically
684 pSource->SelectChildren( pSourceEntry, sal_False );
685 aList.push_back( pSourceEntry );
686 pSourceEntry = pSource->NextSelected( pSourceEntry );
689 std::vector<SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
690 for (; it != itEnd; ++it)
692 pSourceEntry = *it;
693 SvTreeListEntry* pNewParent = 0;
694 sal_uLong nInsertionPos = ULONG_MAX;
695 sal_Bool bOk=NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
696 if ( bOk )
698 if ( bClone )
700 sal_uLong nCloneCount = 0;
701 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
702 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
704 else
706 sal_uLong nListPos = pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
707 pSourceEntry = GetEntry( pNewParent, nListPos );
710 else
711 bSuccess = sal_False;
713 if( bOk == (sal_Bool)2 ) // HACK: make visible moved entry?
714 MakeVisible( pSourceEntry );
716 pModel->SetCloneLink( aCloneLink );
717 return bSuccess;
720 // return: all entries were moved
721 sal_Bool SvTreeListBox::MoveSelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
723 return MoveSelectionCopyFallbackPossible( pSource, pTarget, sal_False );
726 sal_Bool SvTreeListBox::MoveSelectionCopyFallbackPossible( SvTreeListBox* pSource, SvTreeListEntry* pTarget, sal_Bool bAllowCopyFallback )
728 DBG_CHKTHIS(SvTreeListBox,0);
729 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
730 sal_Bool bSuccess = sal_True;
731 std::vector<SvTreeListEntry*> aList;
732 sal_Bool bClone = (sal_Bool)( (sal_uLong)(pSource->GetModel()) != (sal_uLong)GetModel() );
733 Link aCloneLink( pModel->GetCloneLink() );
734 if ( bClone )
735 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
737 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
738 while ( pSourceEntry )
740 // children are automatically moved
741 pSource->SelectChildren( pSourceEntry, sal_False );
742 aList.push_back( pSourceEntry );
743 pSourceEntry = pSource->NextSelected( pSourceEntry );
746 std::vector<SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
747 for (; it != itEnd; ++it)
749 pSourceEntry = *it;
751 SvTreeListEntry* pNewParent = 0;
752 sal_uLong nInsertionPos = ULONG_MAX;
753 sal_Bool bOk = NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos);
754 sal_Bool bCopyOk = bOk;
755 if ( !bOk && bAllowCopyFallback )
757 nInsertionPos = LIST_APPEND;
758 bCopyOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
761 if ( bOk || bCopyOk )
763 if ( bClone )
765 sal_uLong nCloneCount = 0;
766 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
767 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
769 else
771 if ( bOk )
772 pModel->Move(pSourceEntry, pNewParent, nInsertionPos);
773 else
774 pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
777 else
778 bSuccess = sal_False;
780 if( bOk == (sal_Bool)2 ) // HACK: make moved entry visible?
781 MakeVisible( pSourceEntry );
783 pModel->SetCloneLink( aCloneLink );
784 return bSuccess;
787 void SvTreeListBox::RemoveSelection()
789 DBG_CHKTHIS(SvTreeListBox,0);
790 std::vector<const SvTreeListEntry*> aList;
791 // cache selection, as the implementation deselects everything on the first
792 // remove
793 SvTreeListEntry* pEntry = FirstSelected();
794 while ( pEntry )
796 aList.push_back( pEntry );
797 if ( pEntry->HasChildren() )
798 // remove deletes all children automatically
799 SelectChildren(pEntry, false);
800 pEntry = NextSelected( pEntry );
803 std::vector<const SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
804 for (; it != itEnd; ++it)
805 pModel->Remove(*it);
808 SvTreeListBox* SvTreeListBox::GetSourceView() const
810 return pDDSource;
813 void SvTreeListBox::RecalcViewData()
815 DBG_CHKTHIS(SvTreeListBox,0);
816 SvTreeListEntry* pEntry = First();
817 while( pEntry )
819 sal_uInt16 nCount = pEntry->ItemCount();
820 sal_uInt16 nCurPos = 0;
821 while ( nCurPos < nCount )
823 SvLBoxItem* pItem = pEntry->GetItem( nCurPos );
824 pItem->InitViewData( this, pEntry );
825 nCurPos++;
827 ViewDataInitialized( pEntry );
828 pEntry = Next( pEntry );
832 void SvTreeListBox::ViewDataInitialized( SvTreeListEntry* )
834 DBG_CHKTHIS(SvTreeListBox,0);
837 void SvTreeListBox::ImplShowTargetEmphasis( SvTreeListEntry* pEntry, sal_Bool bShow)
839 DBG_CHKTHIS(SvTreeListBox,0);
840 if ( bShow && (nImpFlags & SVLBOX_TARGEMPH_VIS) )
841 return;
842 if ( !bShow && !(nImpFlags & SVLBOX_TARGEMPH_VIS) )
843 return;
844 ShowTargetEmphasis( pEntry, bShow );
845 if( bShow )
846 nImpFlags |= SVLBOX_TARGEMPH_VIS;
847 else
848 nImpFlags &= ~SVLBOX_TARGEMPH_VIS;
851 void SvTreeListBox::OnCurrentEntryChanged()
853 if ( !mpImpl->m_bDoingQuickSelection )
854 mpImpl->m_aQuickSelectionEngine.Reset();
857 SvTreeListEntry* SvTreeListBox::GetEntry( SvTreeListEntry* pParent, sal_uLong nPos ) const
859 return pModel->GetEntry(pParent, nPos);
862 SvTreeListEntry* SvTreeListBox::GetEntry( sal_uLong nRootPos ) const
864 return pModel->GetEntry(nRootPos);
867 SvTreeListEntry* SvTreeListBox::GetEntryFromPath( const ::std::deque< sal_Int32 >& _rPath ) const
869 DBG_CHKTHIS(SvTreeListBox,0);
871 SvTreeListEntry* pEntry = NULL;
872 SvTreeListEntry* pParent = NULL;
873 for( ::std::deque< sal_Int32 >::const_iterator pItem = _rPath.begin(); pItem != _rPath.end(); ++pItem )
875 pEntry = GetEntry( pParent, *pItem );
876 if ( !pEntry )
877 break;
878 pParent = pEntry;
881 return pEntry;
884 void SvTreeListBox::FillEntryPath( SvTreeListEntry* pEntry, ::std::deque< sal_Int32 >& _rPath ) const
886 DBG_CHKTHIS(SvTreeListBox,0);
888 if ( pEntry )
890 SvTreeListEntry* pParentEntry = GetParent( pEntry );
891 while ( true )
893 sal_uLong i, nCount = GetLevelChildCount( pParentEntry );
894 for ( i = 0; i < nCount; ++i )
896 SvTreeListEntry* pTemp = GetEntry( pParentEntry, i );
897 DBG_ASSERT( pEntry, "invalid entry" );
898 if ( pEntry == pTemp )
900 _rPath.push_front( (sal_Int32)i );
901 break;
905 if ( pParentEntry )
907 pEntry = pParentEntry;
908 pParentEntry = GetParent( pParentEntry );
910 else
911 break;
916 const SvTreeListEntry* SvTreeListBox::GetParent( const SvTreeListEntry* pEntry ) const
918 return pModel->GetParent(pEntry);
921 SvTreeListEntry* SvTreeListBox::GetParent( SvTreeListEntry* pEntry ) const
923 return pModel->GetParent(pEntry);
926 SvTreeListEntry* SvTreeListBox::GetRootLevelParent( SvTreeListEntry* pEntry ) const
928 return pModel->GetRootLevelParent(pEntry);
931 sal_uLong SvTreeListBox::GetChildCount( SvTreeListEntry* pParent ) const
933 return pModel->GetChildCount(pParent);
936 sal_uLong SvTreeListBox::GetLevelChildCount( SvTreeListEntry* _pParent ) const
938 DBG_CHKTHIS(SvTreeListBox,0);
940 sal_uLong nCount = 0;
941 SvTreeListEntry* pEntry = FirstChild( _pParent );
942 while ( pEntry )
944 ++nCount;
945 pEntry = NextSibling( pEntry );
948 return nCount;
951 SvViewDataEntry* SvTreeListBox::GetViewDataEntry( SvTreeListEntry* pEntry ) const
953 return (SvViewDataEntry*)SvListView::GetViewData(pEntry);
956 SvViewDataItem* SvTreeListBox::GetViewDataItem(SvTreeListEntry* pEntry, SvLBoxItem* pItem)
958 return const_cast<SvViewDataItem*>(static_cast<const SvTreeListBox*>(this)->GetViewDataItem(pEntry, pItem));
961 const SvViewDataItem* SvTreeListBox::GetViewDataItem(const SvTreeListEntry* pEntry, const SvLBoxItem* pItem) const
963 const SvViewDataEntry* pEntryData = (const SvViewDataEntry*)SvListView::GetViewData(pEntry);
964 DBG_ASSERT(pEntryData,"Entry not in View");
965 sal_uInt16 nItemPos = pEntry->GetPos(pItem);
966 return pEntryData->GetItem(nItemPos);
969 SvViewDataEntry* SvTreeListBox::CreateViewData( SvTreeListEntry* )
971 DBG_CHKTHIS(SvTreeListBox,0);
972 SvViewDataEntry* pEntryData = new SvViewDataEntry;
973 return (SvViewDataEntry*)pEntryData;
976 void SvTreeListBox::InitViewData( SvViewDataEntry* pData, SvTreeListEntry* pEntry )
978 DBG_CHKTHIS(SvTreeListBox,0);
979 SvTreeListEntry* pInhEntry = (SvTreeListEntry*)pEntry;
980 SvViewDataEntry* pEntryData = (SvViewDataEntry*)pData;
982 pEntryData->Init(pInhEntry->ItemCount());
983 sal_uInt16 nCount = pInhEntry->ItemCount();
984 sal_uInt16 nCurPos = 0;
985 while( nCurPos < nCount )
987 SvLBoxItem* pItem = pInhEntry->GetItem( nCurPos );
988 SvViewDataItem* pItemData = pEntryData->GetItem(nCurPos);
989 pItem->InitViewData( this, pInhEntry, pItemData );
990 pItemData++;
991 nCurPos++;
997 void SvTreeListBox::EnableSelectionAsDropTarget( sal_Bool bEnable, sal_Bool bWithChildren )
999 DBG_CHKTHIS(SvTreeListBox,0);
1000 sal_uInt16 nRefDepth;
1001 SvTreeListEntry* pTemp;
1003 SvTreeListEntry* pSelEntry = FirstSelected();
1004 while( pSelEntry )
1006 if ( !bEnable )
1008 pSelEntry->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP;
1009 if ( bWithChildren )
1011 nRefDepth = pModel->GetDepth( pSelEntry );
1012 pTemp = Next( pSelEntry );
1013 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
1015 pTemp->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP;
1016 pTemp = Next( pTemp );
1020 else
1022 pSelEntry->nEntryFlags &= (~SV_ENTRYFLAG_DISABLE_DROP);
1023 if ( bWithChildren )
1025 nRefDepth = pModel->GetDepth( pSelEntry );
1026 pTemp = Next( pSelEntry );
1027 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
1029 pTemp->nEntryFlags &= (~SV_ENTRYFLAG_DISABLE_DROP);
1030 pTemp = Next( pTemp );
1034 pSelEntry = NextSelected( pSelEntry );
1038 // ******************************************************************
1039 // InplaceEditing
1040 // ******************************************************************
1042 void SvTreeListBox::EditText( const OUString& rStr, const Rectangle& rRect,
1043 const Selection& rSel )
1045 EditText( rStr, rRect, rSel, sal_False );
1048 void SvTreeListBox::EditText( const OUString& rStr, const Rectangle& rRect,
1049 const Selection& rSel, sal_Bool bMulti )
1051 DBG_CHKTHIS(SvTreeListBox,0);
1052 if( pEdCtrl )
1053 delete pEdCtrl;
1054 nImpFlags |= SVLBOX_IN_EDT;
1055 nImpFlags &= ~SVLBOX_EDTEND_CALLED;
1056 HideFocus();
1057 pEdCtrl = new SvInplaceEdit2(
1058 this, rRect.TopLeft(), rRect.GetSize(), rStr,
1059 LINK( this, SvTreeListBox, TextEditEndedHdl_Impl ),
1060 rSel, bMulti );
1063 IMPL_LINK_NOARG(SvTreeListBox, TextEditEndedHdl_Impl)
1065 DBG_CHKTHIS(SvTreeListBox,0);
1066 if ( nImpFlags & SVLBOX_EDTEND_CALLED ) // avoid nesting
1067 return 0;
1068 nImpFlags |= SVLBOX_EDTEND_CALLED;
1069 OUString aStr;
1070 if ( !pEdCtrl->EditingCanceled() )
1071 aStr = pEdCtrl->GetText();
1072 else
1073 aStr = pEdCtrl->GetSavedValue();
1074 if ( IsEmptyTextAllowed() || !aStr.isEmpty() )
1075 EditedText( aStr );
1076 // Hide may only be called after the new text was put into the entry, so
1077 // that we don't call the selection handler in the GetFocus of the listbox
1078 // with the old entry text.
1079 pEdCtrl->Hide();
1080 // delete pEdCtrl;
1081 // pEdCtrl = 0;
1082 nImpFlags &= (~SVLBOX_IN_EDT);
1083 GrabFocus();
1084 return 0;
1087 void SvTreeListBox::CancelTextEditing()
1089 DBG_CHKTHIS(SvTreeListBox,0);
1090 if ( pEdCtrl )
1091 pEdCtrl->StopEditing( sal_True );
1092 nImpFlags &= (~SVLBOX_IN_EDT);
1095 void SvTreeListBox::EndEditing( bool bCancel )
1097 DBG_CHKTHIS(SvTreeListBox,0);
1098 if( pEdCtrl )
1099 pEdCtrl->StopEditing( bCancel );
1100 nImpFlags &= (~SVLBOX_IN_EDT);
1104 bool SvTreeListBox::IsEmptyTextAllowed() const
1106 DBG_CHKTHIS(SvTreeListBox,0);
1107 return mpImpl->m_bIsEmptyTextAllowed;
1110 void SvTreeListBox::ForbidEmptyText()
1112 DBG_CHKTHIS(SvTreeListBox,0);
1113 mpImpl->m_bIsEmptyTextAllowed = false;
1116 SvTreeListEntry* SvTreeListBox::CreateEntry() const
1118 DBG_CHKTHIS(SvTreeListBox,0);
1119 return new SvTreeListEntry;
1122 const void* SvTreeListBox::FirstSearchEntry( OUString& _rEntryText ) const
1124 SvTreeListEntry* pEntry = GetCurEntry();
1125 if ( pEntry )
1126 pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( NextSearchEntry( pEntry, _rEntryText ) ) );
1127 else
1129 pEntry = FirstSelected();
1130 if ( !pEntry )
1131 pEntry = First();
1134 if ( pEntry )
1135 _rEntryText = GetEntryText( pEntry );
1137 return pEntry;
1140 const void* SvTreeListBox::NextSearchEntry( const void* _pCurrentSearchEntry, OUString& _rEntryText ) const
1142 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pCurrentSearchEntry ) );
1144 if ( ( ( GetChildCount( pEntry ) > 0 )
1145 || ( pEntry->HasChildrenOnDemand() )
1147 && !IsExpanded( pEntry )
1150 pEntry = NextSibling( pEntry );
1152 else
1154 pEntry = Next( pEntry );
1157 if ( !pEntry )
1158 pEntry = First();
1160 if ( pEntry )
1161 _rEntryText = GetEntryText( pEntry );
1163 return pEntry;
1166 void SvTreeListBox::SelectSearchEntry( const void* _pEntry )
1168 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) );
1169 DBG_ASSERT( pEntry, "SvTreeListBox::SelectSearchEntry: invalid entry!" );
1170 if ( !pEntry )
1171 return;
1173 SelectAll( sal_False );
1174 SetCurEntry( pEntry );
1175 Select( pEntry );
1178 void SvTreeListBox::ExecuteSearchEntry( const void* /*_pEntry*/ ) const
1180 // nothing to do here, we have no "execution"
1183 ::vcl::StringEntryIdentifier SvTreeListBox::CurrentEntry( OUString& _out_entryText ) const
1185 // always accept the current entry if there is one
1186 SvTreeListEntry* pCurrentEntry( GetCurEntry() );
1187 if ( pCurrentEntry )
1189 _out_entryText = GetEntryText( pCurrentEntry );
1190 return pCurrentEntry;
1192 return FirstSearchEntry( _out_entryText );
1195 ::vcl::StringEntryIdentifier SvTreeListBox::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, OUString& _out_entryText ) const
1197 return NextSearchEntry( _currentEntry, _out_entryText );
1200 void SvTreeListBox::SelectEntry( ::vcl::StringEntryIdentifier _entry )
1202 SelectSearchEntry( _entry );
1205 bool SvTreeListBox::HandleKeyInput( const KeyEvent& _rKEvt )
1207 if ( IsEntryMnemonicsEnabled()
1208 && mpImpl->m_aMnemonicEngine.HandleKeyEvent( _rKEvt )
1210 return true;
1212 if ( ( GetStyle() & WB_QUICK_SEARCH ) != 0 )
1214 mpImpl->m_bDoingQuickSelection = true;
1215 const bool bHandled = mpImpl->m_aQuickSelectionEngine.HandleKeyEvent( _rKEvt );
1216 mpImpl->m_bDoingQuickSelection = false;
1217 if ( bHandled )
1218 return true;
1221 return false;
1224 void SvTreeListBox::WriteDragServerInfo( const Point&, SvLBoxDDInfo* )
1226 DBG_CHKTHIS(SvTreeListBox,0);
1229 void SvTreeListBox::ReadDragServerInfo(const Point&, SvLBoxDDInfo* )
1231 DBG_CHKTHIS(SvTreeListBox,0);
1234 sal_Bool SvTreeListBox::EditingCanceled() const
1236 if( pEdCtrl && pEdCtrl->EditingCanceled() )
1237 return sal_True;
1238 return sal_False;
1242 //JP 28.3.2001: new Drag & Drop API
1243 sal_Int8 SvTreeListBox::AcceptDrop( const AcceptDropEvent& rEvt )
1245 DBG_CHKTHIS(SvTreeListBox,0);
1246 sal_Int8 nRet = DND_ACTION_NONE;
1248 if( rEvt.mbLeaving || !CheckDragAndDropMode( pDDSource, rEvt.mnAction ) )
1250 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1252 else if( !nDragDropMode )
1254 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no target" );
1256 else
1258 SvTreeListEntry* pEntry = GetDropTarget( rEvt.maPosPixel );
1259 if( !IsDropFormatSupported( SOT_FORMATSTR_ID_TREELISTBOX ) )
1261 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no format" );
1263 else
1265 DBG_ASSERT( pDDSource, "SvTreeListBox::QueryDrop(): SourceBox == 0" );
1266 if( !( pEntry && pDDSource->GetModel() == this->GetModel()
1267 && DND_ACTION_MOVE == rEvt.mnAction
1268 && ( pEntry->nEntryFlags & SV_ENTRYFLAG_DISABLE_DROP ) ))
1270 if( NotifyAcceptDrop( pEntry ))
1271 nRet = rEvt.mnAction;
1275 // **** draw emphasis ****
1276 if( DND_ACTION_NONE == nRet )
1277 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1278 else if( pEntry != pTargetEntry || !(nImpFlags & SVLBOX_TARGEMPH_VIS) )
1280 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1281 pTargetEntry = pEntry;
1282 ImplShowTargetEmphasis( pTargetEntry, sal_True );
1285 return nRet;
1288 sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvTreeListBox* pSourceView )
1290 DBG_CHKTHIS(SvTreeListBox,0);
1291 sal_Int8 nRet = DND_ACTION_NONE;
1293 DBG_ASSERT( pSourceView, "SvTreeListBox::ExecuteDrop(): no source view" );
1294 pSourceView->EnableSelectionAsDropTarget( sal_True, sal_True );
1296 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1297 pDDTarget = this;
1299 SvLBoxDDInfo aDDInfo;
1301 TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
1302 if( aData.HasFormat( SOT_FORMATSTR_ID_TREELISTBOX ))
1304 ::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
1305 if( aData.GetSequence( SOT_FORMATSTR_ID_TREELISTBOX, aSeq ) &&
1306 sizeof(SvLBoxDDInfo) == aSeq.getLength() )
1308 memcpy( &aDDInfo, aSeq.getConstArray(), sizeof(SvLBoxDDInfo) );
1309 nRet = rEvt.mnAction;
1313 if( DND_ACTION_NONE != nRet )
1315 nRet = DND_ACTION_NONE;
1317 ReadDragServerInfo( rEvt.maPosPixel, &aDDInfo );
1319 SvTreeListEntry* pTarget = pTargetEntry; // may be 0!
1321 if( DND_ACTION_COPY == rEvt.mnAction )
1323 if ( CopySelection( aDDInfo.pSource, pTarget ) )
1324 nRet = rEvt.mnAction;
1326 else if( DND_ACTION_MOVE == rEvt.mnAction )
1328 if ( MoveSelection( aDDInfo.pSource, pTarget ) )
1329 nRet = rEvt.mnAction;
1331 else if( DND_ACTION_COPYMOVE == rEvt.mnAction )
1333 if ( MoveSelectionCopyFallbackPossible( aDDInfo.pSource, pTarget, sal_True ) )
1334 nRet = rEvt.mnAction;
1337 return nRet;
1340 sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt )
1342 DBG_CHKTHIS(SvTreeListBox,0);
1343 return ExecuteDrop( rEvt, GetSourceView() );
1346 void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel )
1348 DBG_CHKTHIS(SvTreeListBox,0);
1350 Point aEventPos( rPosPixel );
1351 MouseEvent aMouseEvt( aEventPos, 1, MOUSE_SELECT, MOUSE_LEFT );
1352 MouseButtonUp( aMouseEvt );
1354 nOldDragMode = GetDragDropMode();
1355 if ( !nOldDragMode )
1356 return;
1358 ReleaseMouse();
1360 SvTreeListEntry* pEntry = GetEntry( rPosPixel ); // GetDropTarget( rPos );
1361 if( !pEntry )
1363 DragFinished( DND_ACTION_NONE );
1364 return;
1367 TransferDataContainer* pContainer = new TransferDataContainer;
1368 ::com::sun::star::uno::Reference<
1369 ::com::sun::star::datatransfer::XTransferable > xRef( pContainer );
1371 nDragDropMode = NotifyStartDrag( *pContainer, pEntry );
1372 if( !nDragDropMode || 0 == GetSelectionCount() )
1374 nDragDropMode = nOldDragMode;
1375 DragFinished( DND_ACTION_NONE );
1376 return;
1379 SvLBoxDDInfo aDDInfo;
1380 memset(&aDDInfo,0,sizeof(SvLBoxDDInfo));
1381 aDDInfo.pApp = GetpApp();
1382 aDDInfo.pSource = this;
1383 aDDInfo.pDDStartEntry = pEntry;
1384 // let derived views do their thing
1385 WriteDragServerInfo( rPosPixel, &aDDInfo );
1387 pContainer->CopyAnyData( SOT_FORMATSTR_ID_TREELISTBOX,
1388 (sal_Char*)&aDDInfo, sizeof(SvLBoxDDInfo) );
1389 pDDSource = this;
1390 pDDTarget = 0;
1392 sal_Bool bOldUpdateMode = Control::IsUpdateMode();
1393 Control::SetUpdateMode( sal_True );
1394 Update();
1395 Control::SetUpdateMode( bOldUpdateMode );
1397 // Disallow using the selection and its children as drop targets.
1398 // Important: If the selection of the SourceListBox is changed in the
1399 // DropHandler, the entries have to be allowed as drop targets again:
1400 // (GetSourceListBox()->EnableSelectionAsDropTarget( sal_True, sal_True );)
1401 EnableSelectionAsDropTarget( sal_False, sal_True /* with children */ );
1403 pContainer->StartDrag( this, nDragOptions, GetDragFinishedHdl() );
1406 void SvTreeListBox::DragFinished( sal_Int8
1407 #ifndef UNX
1408 nAction
1409 #endif
1412 EnableSelectionAsDropTarget( sal_True, sal_True );
1414 #ifndef UNX
1415 if( (nAction == DND_ACTION_MOVE) && ( (pDDTarget &&
1416 ((sal_uLong)(pDDTarget->GetModel())!=(sal_uLong)(this->GetModel()))) ||
1417 !pDDTarget ))
1419 RemoveSelection();
1421 #endif
1423 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1424 pDDSource = 0;
1425 pDDTarget = 0;
1426 pTargetEntry = 0;
1427 nDragDropMode = nOldDragMode;
1430 DragDropMode SvTreeListBox::NotifyStartDrag( TransferDataContainer&, SvTreeListEntry* )
1432 DBG_CHKTHIS(SvTreeListBox,0);
1433 return (DragDropMode)0xffff;
1436 sal_Bool SvTreeListBox::NotifyAcceptDrop( SvTreeListEntry* )
1438 DBG_CHKTHIS(SvTreeListBox,0);
1439 return sal_True;
1442 // Handler and methods for Drag - finished handler.
1443 // The with get GetDragFinishedHdl() get link can set on the
1444 // TransferDataContainer. This link is a callback for the DragFinished
1445 // call. AddBox method is called from the GetDragFinishedHdl() and the
1446 // remove is called in link callback and in the destructor. So it can't
1447 // called to a deleted object.
1449 namespace
1451 struct SortLBoxes : public rtl::Static<std::set<sal_uLong>, SortLBoxes> {};
1454 void SvTreeListBox::AddBoxToDDList_Impl( const SvTreeListBox& rB )
1456 sal_uLong nVal = (sal_uLong)&rB;
1457 SortLBoxes::get().insert( nVal );
1460 void SvTreeListBox::RemoveBoxFromDDList_Impl( const SvTreeListBox& rB )
1462 sal_uLong nVal = (sal_uLong)&rB;
1463 SortLBoxes::get().erase( nVal );
1466 IMPL_STATIC_LINK( SvTreeListBox, DragFinishHdl_Impl, sal_Int8*, pAction )
1468 sal_uLong nVal = (sal_uLong)pThis;
1469 std::set<sal_uLong> &rSortLBoxes = SortLBoxes::get();
1470 std::set<sal_uLong>::const_iterator it = rSortLBoxes.find(nVal);
1471 if( it != rSortLBoxes.end() )
1473 pThis->DragFinished( *pAction );
1474 rSortLBoxes.erase( it );
1476 return 0;
1479 Link SvTreeListBox::GetDragFinishedHdl() const
1481 AddBoxToDDList_Impl( *this );
1482 return STATIC_LINK( this, SvTreeListBox, DragFinishHdl_Impl );
1486 Bugs/TODO
1488 - calculate rectangle when editing in-place (bug with some fonts)
1489 - SetSpaceBetweenEntries: offset is not taken into account in SetEntryHeight
1492 #define TREEFLAG_FIXEDHEIGHT 0x0010
1494 #define SV_LBOX_DEFAULT_INDENT_PIXEL 20
1496 void SvTreeListBox::InitTreeView()
1498 DBG_CHKTHIS(SvTreeListBox,0);
1499 pCheckButtonData = NULL;
1500 pEdEntry = NULL;
1501 pEdItem = NULL;
1502 nEntryHeight = 0;
1503 pEdCtrl = NULL;
1504 nFirstSelTab = 0;
1505 nLastSelTab = 0;
1506 nFocusWidth = -1;
1507 mnCheckboxItemWidth = 0;
1509 Link* pLink = new Link( LINK(this,SvTreeListBox, DefaultCompare) );
1510 mpImpl->m_pLink = pLink;
1512 nTreeFlags = TREEFLAG_RECALCTABS;
1513 nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL;
1514 nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL;
1515 pImp = new SvImpLBox( this, GetModel(), GetStyle() );
1517 mbContextBmpExpanded = true;
1518 nContextBmpWidthMax = 0;
1520 SetFont( GetFont() );
1521 AdjustEntryHeightAndRecalc( GetFont() );
1523 SetSpaceBetweenEntries( 0 );
1524 SetLineColor();
1525 InitSettings( sal_True, sal_True, sal_True );
1526 ImplInitStyle();
1527 SetTabs();
1531 SvTreeListBox::~SvTreeListBox()
1533 DBG_DTOR(SvTreeListBox,0);
1535 pImp->CallEventListeners( VCLEVENT_OBJECT_DYING );
1536 delete pImp;
1537 delete mpImpl->m_pLink;
1538 ClearTabList();
1540 delete pEdCtrl;
1541 pEdCtrl = 0;
1542 pModel->RemoveView( this );
1543 if ( pModel->GetRefCount() == 0 )
1545 pModel->Clear();
1546 delete pModel;
1547 pModel = NULL;
1550 SvTreeListBox::RemoveBoxFromDDList_Impl( *this );
1552 if( this == pDDSource )
1553 pDDSource = 0;
1554 if( this == pDDTarget )
1555 pDDTarget = 0;
1556 delete mpImpl;
1559 void SvTreeListBox::SetExtendedWinBits( ExtendedWinBits _nBits )
1561 pImp->SetExtendedWindowBits( _nBits );
1564 void SvTreeListBox::SetModel( SvTreeList* pNewModel )
1566 DBG_CHKTHIS(SvTreeListBox,0);
1567 pImp->SetModel( pNewModel );
1568 SetBaseModel(pNewModel);
1571 void SvTreeListBox::SetBaseModel( SvTreeList* pNewModel )
1573 // does the CleanUp
1574 SvListView::SetModel( pNewModel );
1575 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
1576 SvTreeListEntry* pEntry = First();
1577 while( pEntry )
1579 ModelHasInserted( pEntry );
1580 pEntry = Next( pEntry );
1584 void SvTreeListBox::DisconnectFromModel()
1586 DBG_CHKTHIS(SvTreeListBox,0);
1587 SvTreeList* pNewModel = new SvTreeList;
1588 pNewModel->SetRefCount( 0 ); // else this will never be deleted
1589 SvListView::SetModel( pNewModel );
1591 pImp->SetModel( GetModel() );
1594 void SvTreeListBox::SetSublistOpenWithReturn( sal_Bool b )
1596 pImp->bSubLstOpRet = b;
1599 void SvTreeListBox::SetSublistOpenWithLeftRight( sal_Bool b )
1601 pImp->bSubLstOpLR = b;
1604 void SvTreeListBox::Resize()
1606 DBG_CHKTHIS(SvTreeListBox,0);
1607 if( IsEditingActive() )
1608 EndEditing( sal_True );
1610 Control::Resize();
1612 pImp->Resize();
1613 nFocusWidth = -1;
1614 pImp->ShowCursor( sal_False );
1615 pImp->ShowCursor( sal_True );
1618 /* Cases:
1620 A) entries have bitmaps
1621 0. no buttons
1622 1. node buttons (can optionally also be on root items)
1623 2. node buttons (can optionally also be on root items) + CheckButton
1624 3. CheckButton
1625 B) entries don't have bitmaps (=>via WindowBits because of D&D!)
1626 0. no buttons
1627 1. node buttons (can optionally also be on root items)
1628 2. node buttons (can optionally also be on root items) + CheckButton
1629 3. CheckButton
1632 #define NO_BUTTONS 0
1633 #define NODE_BUTTONS 1
1634 #define NODE_AND_CHECK_BUTTONS 2
1635 #define CHECK_BUTTONS 3
1637 #define TABFLAGS_TEXT (SV_LBOXTAB_DYNAMIC | \
1638 SV_LBOXTAB_ADJUST_LEFT | \
1639 SV_LBOXTAB_EDITABLE | \
1640 SV_LBOXTAB_SHOW_SELECTION)
1642 #define TABFLAGS_CONTEXTBMP (SV_LBOXTAB_DYNAMIC | SV_LBOXTAB_ADJUST_CENTER)
1644 #define TABFLAGS_CHECKBTN (SV_LBOXTAB_DYNAMIC | \
1645 SV_LBOXTAB_ADJUST_CENTER | \
1646 SV_LBOXTAB_PUSHABLE)
1648 #define TAB_STARTPOS 2
1650 // take care of GetTextOffset when doing changes
1651 void SvTreeListBox::SetTabs()
1653 DBG_CHKTHIS(SvTreeListBox,0);
1654 if( IsEditingActive() )
1655 EndEditing( sal_True );
1656 nTreeFlags &= (~TREEFLAG_RECALCTABS);
1657 nFocusWidth = -1;
1658 const WinBits nStyle( GetStyle() );
1659 sal_Bool bHasButtons = (nStyle & WB_HASBUTTONS)!=0;
1660 sal_Bool bHasButtonsAtRoot = (nStyle & (WB_HASLINESATROOT |
1661 WB_HASBUTTONSATROOT))!=0;
1662 long nStartPos = TAB_STARTPOS;
1663 long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width();
1665 // pCheckButtonData->Width() knows nothing about the native checkbox width,
1666 // so we have mnCheckboxItemWidth which becomes valid when something is added.
1667 long nCheckWidth = 0;
1668 if( nTreeFlags & TREEFLAG_CHKBTN )
1669 nCheckWidth = mnCheckboxItemWidth;
1670 long nCheckWidthDIV2 = nCheckWidth / 2;
1672 long nContextWidth = nContextBmpWidthMax;
1673 long nContextWidthDIV2 = nContextWidth / 2;
1675 ClearTabList();
1677 int nCase = NO_BUTTONS;
1678 if( !(nTreeFlags & TREEFLAG_CHKBTN) )
1680 if( bHasButtons )
1681 nCase = NODE_BUTTONS;
1683 else
1685 if( bHasButtons )
1686 nCase = NODE_AND_CHECK_BUTTONS;
1687 else
1688 nCase = CHECK_BUTTONS;
1691 switch( nCase )
1693 case NO_BUTTONS :
1694 nStartPos += nContextWidthDIV2; // because of centering
1695 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1696 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1697 // only set a distance if there are bitmaps
1698 if( nContextBmpWidthMax )
1699 nStartPos += 5; // distance context bitmap to text
1700 AddTab( nStartPos, TABFLAGS_TEXT );
1701 break;
1703 case NODE_BUTTONS :
1704 if( bHasButtonsAtRoot )
1705 nStartPos += ( nIndent + (nNodeWidthPixel/2) );
1706 else
1707 nStartPos += nContextWidthDIV2;
1708 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1709 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1710 // only set a distance if there are bitmaps
1711 if( nContextBmpWidthMax )
1712 nStartPos += 5; // distance context bitmap to text
1713 AddTab( nStartPos, TABFLAGS_TEXT );
1714 break;
1716 case NODE_AND_CHECK_BUTTONS :
1717 if( bHasButtonsAtRoot )
1718 nStartPos += ( nIndent + nNodeWidthPixel );
1719 else
1720 nStartPos += nCheckWidthDIV2;
1721 AddTab( nStartPos, TABFLAGS_CHECKBTN );
1722 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1723 nStartPos += 3; // distance CheckButton to context bitmap
1724 nStartPos += nContextWidthDIV2; // center of context bitmap
1725 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1726 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1727 // only set a distance if there are bitmaps
1728 if( nContextBmpWidthMax )
1729 nStartPos += 5; // distance context bitmap to text
1730 AddTab( nStartPos, TABFLAGS_TEXT );
1731 break;
1733 case CHECK_BUTTONS :
1734 nStartPos += nCheckWidthDIV2;
1735 AddTab( nStartPos, TABFLAGS_CHECKBTN );
1736 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1737 nStartPos += 3; // distance CheckButton to context bitmap
1738 nStartPos += nContextWidthDIV2; // center of context bitmap
1739 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1740 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1741 // only set a distance if there are bitmaps
1742 if( nContextBmpWidthMax )
1743 nStartPos += 5; // distance context bitmap to text
1744 AddTab( nStartPos, TABFLAGS_TEXT );
1745 break;
1747 pImp->NotifyTabsChanged();
1750 void SvTreeListBox::InitEntry(SvTreeListEntry* pEntry,
1751 const OUString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp,
1752 SvLBoxButtonKind eButtonKind)
1754 DBG_CHKTHIS(SvTreeListBox,0);
1755 SvLBoxButton* pButton;
1756 SvLBoxString* pString;
1757 SvLBoxContextBmp* pContextBmp;
1759 if( nTreeFlags & TREEFLAG_CHKBTN )
1761 pButton= new SvLBoxButton( pEntry,eButtonKind,0,pCheckButtonData );
1762 pEntry->AddItem( pButton );
1765 pContextBmp= new SvLBoxContextBmp(
1766 pEntry,0, aCollEntryBmp,aExpEntryBmp, mbContextBmpExpanded);
1767 pEntry->AddItem( pContextBmp );
1769 pString = new SvLBoxString( pEntry, 0, aStr );
1770 pEntry->AddItem( pString );
1773 OUString SvTreeListBox::GetEntryText(SvTreeListEntry* pEntry) const
1775 DBG_CHKTHIS(SvTreeListBox,0);
1776 DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): no entry" );
1777 SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
1778 DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): item not found" );
1779 return pItem->GetText();
1782 OUString SvTreeListBox::SearchEntryText( SvTreeListEntry* pEntry ) const
1784 DBG_CHKTHIS(SvTreeListBox,0);
1785 DBG_ASSERT( pEntry, "SvTreeListBox::SearchEntryText(): no entry" );
1786 OUString sRet;
1787 sal_uInt16 nCount = pEntry->ItemCount();
1788 sal_uInt16 nCur = 0;
1789 SvLBoxItem* pItem;
1790 while( nCur < nCount )
1792 pItem = pEntry->GetItem( nCur );
1793 if (pItem->GetType() == SV_ITEM_ID_LBOXSTRING && !static_cast<const SvLBoxString*>(pItem)->GetText().isEmpty())
1795 sRet = static_cast<const SvLBoxString*>(pItem)->GetText();
1796 break;
1798 nCur++;
1800 return sRet;
1803 const Image& SvTreeListBox::GetExpandedEntryBmp(const SvTreeListEntry* pEntry) const
1805 DBG_CHKTHIS(SvTreeListBox,0);
1806 DBG_ASSERT(pEntry,"Entry?");
1807 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1808 DBG_ASSERT(pItem,"GetContextBmp:Item not found");
1809 return pItem->GetBitmap2( );
1812 const Image& SvTreeListBox::GetCollapsedEntryBmp( const SvTreeListEntry* pEntry ) const
1814 DBG_CHKTHIS(SvTreeListBox,0);
1815 DBG_ASSERT(pEntry,"Entry?");
1816 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1817 DBG_ASSERT(pItem,"GetContextBmp:Item not found");
1818 return pItem->GetBitmap1( );
1821 IMPL_LINK_INLINE_START( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData )
1823 DBG_CHKTHIS(SvTreeListBox,0);
1824 pHdlEntry = pData->GetActEntry();
1825 CheckButtonHdl();
1826 return 0;
1828 IMPL_LINK_INLINE_END( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData )
1830 SvTreeListEntry* SvTreeListBox::InsertEntry(
1831 const OUString& rText,
1832 SvTreeListEntry* pParent,
1833 sal_Bool bChildrenOnDemand, sal_uLong nPos,
1834 void* pUser,
1835 SvLBoxButtonKind eButtonKind
1838 DBG_CHKTHIS(SvTreeListBox,0);
1839 nTreeFlags |= TREEFLAG_MANINS;
1841 const Image& rDefExpBmp = pImp->GetDefaultEntryExpBmp( );
1842 const Image& rDefColBmp = pImp->GetDefaultEntryColBmp( );
1844 aCurInsertedExpBmp = rDefExpBmp;
1845 aCurInsertedColBmp = rDefColBmp;
1847 SvTreeListEntry* pEntry = CreateEntry();
1848 pEntry->SetUserData( pUser );
1849 InitEntry( pEntry, rText, rDefColBmp, rDefExpBmp, eButtonKind );
1850 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1852 if( !pParent )
1853 Insert( pEntry, nPos );
1854 else
1855 Insert( pEntry, pParent, nPos );
1857 aPrevInsertedExpBmp = rDefExpBmp;
1858 aPrevInsertedColBmp = rDefColBmp;
1860 nTreeFlags &= (~TREEFLAG_MANINS);
1862 return pEntry;
1865 SvTreeListEntry* SvTreeListBox::InsertEntry( const OUString& rText,
1866 const Image& aExpEntryBmp, const Image& aCollEntryBmp,
1867 SvTreeListEntry* pParent, sal_Bool bChildrenOnDemand, sal_uLong nPos, void* pUser,
1868 SvLBoxButtonKind eButtonKind )
1870 DBG_CHKTHIS(SvTreeListBox,0);
1871 nTreeFlags |= TREEFLAG_MANINS;
1873 aCurInsertedExpBmp = aExpEntryBmp;
1874 aCurInsertedColBmp = aCollEntryBmp;
1876 SvTreeListEntry* pEntry = CreateEntry();
1877 pEntry->SetUserData( pUser );
1878 InitEntry( pEntry, rText, aCollEntryBmp, aExpEntryBmp, eButtonKind );
1880 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1882 if( !pParent )
1883 Insert( pEntry, nPos );
1884 else
1885 Insert( pEntry, pParent, nPos );
1887 aPrevInsertedExpBmp = aExpEntryBmp;
1888 aPrevInsertedColBmp = aCollEntryBmp;
1890 nTreeFlags &= (~TREEFLAG_MANINS);
1892 return pEntry;
1895 void SvTreeListBox::SetEntryText(SvTreeListEntry* pEntry, const OUString& rStr)
1897 DBG_CHKTHIS(SvTreeListBox,0);
1898 SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
1899 DBG_ASSERT(pItem,"SetText:Item not found");
1900 pItem->SetText(rStr);
1901 pItem->InitViewData( this, pEntry, 0 );
1902 GetModel()->InvalidateEntry( pEntry );
1905 void SvTreeListBox::SetExpandedEntryBmp( SvTreeListEntry* pEntry, const Image& aBmp )
1907 DBG_CHKTHIS(SvTreeListBox,0);
1908 SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1910 DBG_ASSERT(pItem,"SetExpBmp:Item not found");
1911 pItem->SetBitmap2( aBmp );
1913 GetModel()->InvalidateEntry( pEntry );
1914 SetEntryHeight( pEntry );
1915 Size aSize = aBmp.GetSizePixel();
1916 short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() );
1917 if( nWidth > nContextBmpWidthMax )
1919 nContextBmpWidthMax = nWidth;
1920 SetTabs();
1924 void SvTreeListBox::SetCollapsedEntryBmp(SvTreeListEntry* pEntry,const Image& aBmp )
1926 DBG_CHKTHIS(SvTreeListBox,0);
1927 SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1929 DBG_ASSERT(pItem,"SetExpBmp:Item not found");
1930 pItem->SetBitmap1( aBmp );
1932 GetModel()->InvalidateEntry( pEntry );
1933 SetEntryHeight( pEntry );
1934 Size aSize = aBmp.GetSizePixel();
1935 short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() );
1936 if( nWidth > nContextBmpWidthMax )
1938 nContextBmpWidthMax = nWidth;
1939 SetTabs();
1943 void SvTreeListBox::ImpEntryInserted( SvTreeListEntry* pEntry )
1945 DBG_CHKTHIS(SvTreeListBox,0);
1947 SvTreeListEntry* pParent = (SvTreeListEntry*)pModel->GetParent( pEntry );
1948 if( pParent )
1950 sal_uInt16 nFlags = pParent->GetFlags();
1951 nFlags &= ~SV_ENTRYFLAG_NO_NODEBMP;
1952 pParent->SetFlags( nFlags );
1955 if(!((nTreeFlags & TREEFLAG_MANINS) &&
1956 (aPrevInsertedExpBmp == aCurInsertedExpBmp) &&
1957 (aPrevInsertedColBmp == aCurInsertedColBmp) ))
1959 Size aSize = GetCollapsedEntryBmp( pEntry ).GetSizePixel();
1960 if( aSize.Width() > nContextBmpWidthMax )
1962 nContextBmpWidthMax = (short)aSize.Width();
1963 nTreeFlags |= TREEFLAG_RECALCTABS;
1965 aSize = GetExpandedEntryBmp( pEntry ).GetSizePixel();
1966 if( aSize.Width() > nContextBmpWidthMax )
1968 nContextBmpWidthMax = (short)aSize.Width();
1969 nTreeFlags |= TREEFLAG_RECALCTABS;
1972 SetEntryHeight( (SvTreeListEntry*)pEntry );
1974 if( nTreeFlags & TREEFLAG_CHKBTN )
1976 SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
1977 if( pItem )
1979 long nWidth = pItem->GetSize(this, pEntry).Width();
1980 if( mnCheckboxItemWidth < nWidth )
1982 mnCheckboxItemWidth = nWidth;
1983 nTreeFlags |= TREEFLAG_RECALCTABS;
1991 void SvTreeListBox::SetCheckButtonState( SvTreeListEntry* pEntry, SvButtonState eState)
1993 DBG_CHKTHIS(SvTreeListBox,0);
1994 if( nTreeFlags & TREEFLAG_CHKBTN )
1996 SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
1997 if(!(pItem && pItem->CheckModification()))
1998 return ;
1999 switch( eState )
2001 case SV_BUTTON_CHECKED:
2002 pItem->SetStateChecked();
2003 break;
2005 case SV_BUTTON_UNCHECKED:
2006 pItem->SetStateUnchecked();
2007 break;
2009 case SV_BUTTON_TRISTATE:
2010 pItem->SetStateTristate();
2011 break;
2013 InvalidateEntry( pEntry );
2017 void SvTreeListBox::SetCheckButtonInvisible( SvTreeListEntry* pEntry)
2019 DBG_CHKTHIS(SvTreeListBox,0);
2020 if( nTreeFlags & TREEFLAG_CHKBTN )
2022 SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
2023 pItem->SetStateInvisible();
2024 InvalidateEntry( pEntry );
2028 SvButtonState SvTreeListBox::GetCheckButtonState( SvTreeListEntry* pEntry ) const
2030 DBG_CHKTHIS(SvTreeListBox,0);
2031 SvButtonState eState = SV_BUTTON_UNCHECKED;
2032 if( nTreeFlags & TREEFLAG_CHKBTN )
2034 SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
2035 if(!pItem)
2036 return SV_BUTTON_TRISTATE;
2037 sal_uInt16 nButtonFlags = pItem->GetButtonFlags();
2038 eState = pCheckButtonData->ConvertToButtonState( nButtonFlags );
2040 return eState;
2043 void SvTreeListBox::CheckButtonHdl()
2045 DBG_CHKTHIS(SvTreeListBox,0);
2046 aCheckButtonHdl.Call( this );
2047 if ( pCheckButtonData )
2048 pImp->CallEventListeners( VCLEVENT_CHECKBOX_TOGGLE, (void*)pCheckButtonData->GetActEntry() );
2052 // TODO: Currently all data is cloned so that they conform to the default tree
2053 // view format. Actually, the model should be used as a reference here. This
2054 // leads to us _not_ calling SvTreeListEntry::Clone, but only its base class
2055 // SvTreeListEntry.
2058 SvTreeListEntry* SvTreeListBox::CloneEntry( SvTreeListEntry* pSource )
2060 DBG_CHKTHIS(SvTreeListBox,0);
2061 OUString aStr;
2062 Image aCollEntryBmp;
2063 Image aExpEntryBmp;
2064 SvLBoxButtonKind eButtonKind = SvLBoxButtonKind_enabledCheckbox;
2066 SvLBoxString* pStringItem = (SvLBoxString*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
2067 if( pStringItem )
2068 aStr = pStringItem->GetText();
2069 SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
2070 if( pBmpItem )
2072 aCollEntryBmp = pBmpItem->GetBitmap1( );
2073 aExpEntryBmp = pBmpItem->GetBitmap2( );
2075 SvLBoxButton* pButtonItem = (SvLBoxButton*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
2076 if( pButtonItem )
2077 eButtonKind = pButtonItem->GetKind();
2078 SvTreeListEntry* pClone = CreateEntry();
2079 InitEntry( pClone, aStr, aCollEntryBmp, aExpEntryBmp, eButtonKind );
2080 pClone->SvTreeListEntry::Clone( pSource );
2081 pClone->EnableChildrenOnDemand( pSource->HasChildrenOnDemand() );
2082 pClone->SetUserData( pSource->GetUserData() );
2084 return pClone;
2087 void SvTreeListBox::SetIndent( short nNewIndent )
2089 DBG_CHKTHIS(SvTreeListBox,0);
2090 nIndent = nNewIndent;
2091 SetTabs();
2092 if( IsUpdateMode() )
2093 Invalidate();
2096 const Image& SvTreeListBox::GetDefaultExpandedEntryBmp( ) const
2098 return pImp->GetDefaultEntryExpBmp( );
2101 const Image& SvTreeListBox::GetDefaultCollapsedEntryBmp( ) const
2103 return pImp->GetDefaultEntryColBmp( );
2106 void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp )
2108 DBG_CHKTHIS(SvTreeListBox,0);
2109 Size aSize = aBmp.GetSizePixel();
2110 if( aSize.Width() > nContextBmpWidthMax )
2111 nContextBmpWidthMax = (short)aSize.Width();
2112 SetTabs();
2114 pImp->SetDefaultEntryExpBmp( aBmp );
2117 void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp )
2119 DBG_CHKTHIS(SvTreeListBox,0);
2120 Size aSize = aBmp.GetSizePixel();
2121 if( aSize.Width() > nContextBmpWidthMax )
2122 nContextBmpWidthMax = (short)aSize.Width();
2123 SetTabs();
2125 pImp->SetDefaultEntryColBmp( aBmp );
2128 void SvTreeListBox::EnableCheckButton( SvLBoxButtonData* pData )
2130 DBG_CHKTHIS(SvTreeListBox,0);
2131 DBG_ASSERT(!GetEntryCount(),"EnableCheckButton: Entry count != 0");
2132 if( !pData )
2133 nTreeFlags &= (~TREEFLAG_CHKBTN);
2134 else
2136 SetCheckButtonData( pData );
2137 nTreeFlags |= TREEFLAG_CHKBTN;
2138 pData->SetLink( LINK(this, SvTreeListBox, CheckButtonClick));
2141 SetTabs();
2142 if( IsUpdateMode() )
2143 Invalidate();
2146 void SvTreeListBox::SetCheckButtonData( SvLBoxButtonData* pData )
2148 DBG_CHKTHIS(SvTreeListBox,0);
2149 if ( pData )
2150 pCheckButtonData = pData;
2153 const Image& SvTreeListBox::GetDefaultExpandedNodeImage( )
2155 return SvImpLBox::GetDefaultExpandedNodeImage( );
2158 const Image& SvTreeListBox::GetDefaultCollapsedNodeImage( )
2160 return SvImpLBox::GetDefaultCollapsedNodeImage( );
2163 void SvTreeListBox::SetNodeBitmaps( const Image& rCollapsedNodeBmp, const Image& rExpandedNodeBmp )
2165 DBG_CHKTHIS(SvTreeListBox,0);
2166 SetExpandedNodeBmp( rExpandedNodeBmp );
2167 SetCollapsedNodeBmp( rCollapsedNodeBmp );
2168 SetTabs();
2171 sal_Bool SvTreeListBox::EditingEntry( SvTreeListEntry*, Selection& )
2173 DBG_CHKTHIS(SvTreeListBox,0);
2174 return sal_True;
2177 sal_Bool SvTreeListBox::EditedEntry( SvTreeListEntry* /*pEntry*/,const OUString& /*rNewText*/)
2179 DBG_CHKTHIS(SvTreeListBox,0);
2180 return sal_True;
2183 void SvTreeListBox::EnableInplaceEditing( bool bOn )
2185 DBG_CHKTHIS(SvTreeListBox,0);
2186 if (bOn)
2187 nImpFlags |= SVLBOX_EDT_ENABLED;
2188 else
2189 nImpFlags &= ~SVLBOX_EDT_ENABLED;
2192 void SvTreeListBox::KeyInput( const KeyEvent& rKEvt )
2194 DBG_CHKTHIS(SvTreeListBox,0);
2195 // under OS/2, we get key up/down even while editing
2196 if( IsEditingActive() )
2197 return;
2199 nImpFlags |= SVLBOX_IS_TRAVELSELECT;
2201 #ifdef OVDEBUG
2202 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
2203 switch ( nCode )
2205 case KEY_F1:
2207 SvTreeListEntry* pEntry = First();
2208 pEntry = NextVisible( pEntry );
2209 SetEntryText( pEntry, "SetEntryText" );
2211 break;
2213 #endif
2215 if( !pImp->KeyInput( rKEvt ) )
2217 bool bHandled = HandleKeyInput( rKEvt );
2218 if ( !bHandled )
2219 Control::KeyInput( rKEvt );
2222 nImpFlags &= ~SVLBOX_IS_TRAVELSELECT;
2225 void SvTreeListBox::RequestingChildren( SvTreeListEntry* pParent )
2227 DBG_CHKTHIS(SvTreeListBox,0);
2228 if( !pParent->HasChildren() )
2229 InsertEntry( OUString("<dummy>"), pParent, sal_False, LIST_APPEND );
2232 void SvTreeListBox::GetFocus()
2234 DBG_CHKTHIS(SvTreeListBox,0);
2235 pImp->GetFocus();
2236 Control::GetFocus();
2238 SvTreeListEntry* pEntry = FirstSelected();
2239 if ( pEntry )
2240 pImp->CallEventListeners( VCLEVENT_LISTBOX_SELECT, pEntry );
2244 void SvTreeListBox::LoseFocus()
2246 DBG_CHKTHIS(SvTreeListBox,0);
2247 pImp->LoseFocus();
2248 Control::LoseFocus();
2251 void SvTreeListBox::ModelHasCleared()
2253 DBG_CHKTHIS(SvTreeListBox,0);
2254 pImp->pCursor = 0; // else we crash in GetFocus when editing in-place
2255 delete pEdCtrl;
2256 pEdCtrl = NULL;
2257 pImp->Clear();
2258 nFocusWidth = -1;
2260 nContextBmpWidthMax = 0;
2261 SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() );
2262 SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() );
2264 if( !(nTreeFlags & TREEFLAG_FIXEDHEIGHT ))
2265 nEntryHeight = 0;
2266 AdjustEntryHeight( GetFont() );
2267 AdjustEntryHeight( GetDefaultExpandedEntryBmp() );
2268 AdjustEntryHeight( GetDefaultCollapsedEntryBmp() );
2270 SvListView::ModelHasCleared();
2273 void SvTreeListBox::ShowTargetEmphasis( SvTreeListEntry* pEntry, sal_Bool /*bShow*/ )
2275 DBG_CHKTHIS(SvTreeListBox,0);
2276 pImp->PaintDDCursor( pEntry );
2279 void SvTreeListBox::ScrollOutputArea( short nDeltaEntries )
2281 DBG_CHKTHIS(SvTreeListBox,0);
2282 if( !nDeltaEntries || !pImp->aVerSBar.IsVisible() )
2283 return;
2285 long nThumb = pImp->aVerSBar.GetThumbPos();
2286 long nMax = pImp->aVerSBar.GetRange().Max();
2288 NotifyBeginScroll();
2289 if( nDeltaEntries < 0 )
2291 // move window up
2292 nDeltaEntries *= -1;
2293 long nVis = pImp->aVerSBar.GetVisibleSize();
2294 long nTemp = nThumb + nVis;
2295 if( nDeltaEntries > (nMax - nTemp) )
2296 nDeltaEntries = (short)(nMax - nTemp);
2297 pImp->PageDown( (sal_uInt16)nDeltaEntries );
2299 else
2301 if( nDeltaEntries > nThumb )
2302 nDeltaEntries = (short)nThumb;
2303 pImp->PageUp( (sal_uInt16)nDeltaEntries );
2305 pImp->SyncVerThumb();
2306 NotifyEndScroll();
2309 void SvTreeListBox::ScrollToAbsPos( long nPos )
2311 pImp->ScrollToAbsPos( nPos );
2314 void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode )
2316 DBG_CHKTHIS(SvTreeListBox,0);
2317 eSelMode = eSelectMode;
2318 pImp->SetSelectionMode( eSelectMode );
2321 void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode )
2323 DBG_CHKTHIS(SvTreeListBox,0);
2324 nDragDropMode = nDDMode;
2325 pImp->SetDragDropMode( nDDMode );
2328 short SvTreeListBox::GetHeightOffset(const Image& rBmp, Size& aSizeLogic )
2330 DBG_CHKTHIS(SvTreeListBox,0);
2331 short nOffset = 0;
2332 aSizeLogic = rBmp.GetSizePixel();
2333 if( GetEntryHeight() > aSizeLogic.Height() )
2334 nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2;
2335 return nOffset;
2338 short SvTreeListBox::GetHeightOffset(const Font& /* rFont */, Size& aSizeLogic )
2340 DBG_CHKTHIS(SvTreeListBox,0);
2341 short nOffset = 0;
2342 aSizeLogic = Size(GetTextWidth(OUString('X')), GetTextHeight());
2343 if( GetEntryHeight() > aSizeLogic.Height() )
2344 nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2;
2345 return nOffset;
2348 void SvTreeListBox::SetEntryHeight( SvTreeListEntry* pEntry )
2350 DBG_CHKTHIS(SvTreeListBox,0);
2351 short nHeight, nHeightMax=0;
2352 sal_uInt16 nCount = pEntry->ItemCount();
2353 sal_uInt16 nCur = 0;
2354 SvViewDataEntry* pViewData = GetViewDataEntry( pEntry );
2355 while( nCur < nCount )
2357 SvLBoxItem* pItem = pEntry->GetItem( nCur );
2358 nHeight = (short)(pItem->GetSize( pViewData, nCur ).Height());
2359 if( nHeight > nHeightMax )
2360 nHeightMax = nHeight;
2361 nCur++;
2364 if( nHeightMax > nEntryHeight )
2366 nEntryHeight = nHeightMax;
2367 Control::SetFont( GetFont() );
2368 pImp->SetEntryHeight( nHeightMax );
2372 void SvTreeListBox::SetEntryHeight( short nHeight, sal_Bool bAlways )
2374 DBG_CHKTHIS(SvTreeListBox,0);
2376 if( bAlways || nHeight > nEntryHeight )
2378 nEntryHeight = nHeight;
2379 if( nEntryHeight )
2380 nTreeFlags |= TREEFLAG_FIXEDHEIGHT;
2381 else
2382 nTreeFlags &= ~TREEFLAG_FIXEDHEIGHT;
2383 Control::SetFont( GetFont() );
2384 pImp->SetEntryHeight( nHeight );
2389 void SvTreeListBox::AdjustEntryHeight( const Image& rBmp )
2391 DBG_CHKTHIS(SvTreeListBox,0);
2392 Size aSize;
2393 GetHeightOffset( rBmp, aSize );
2394 if( aSize.Height() > nEntryHeight )
2396 nEntryHeight = (short)aSize.Height() + nEntryHeightOffs;
2397 pImp->SetEntryHeight( nEntryHeight );
2401 void SvTreeListBox::AdjustEntryHeight( const Font& rFont )
2403 DBG_CHKTHIS(SvTreeListBox,0);
2404 Size aSize;
2405 GetHeightOffset( rFont, aSize );
2406 if( aSize.Height() > nEntryHeight )
2408 nEntryHeight = (short)aSize.Height() + nEntryHeightOffs;
2409 pImp->SetEntryHeight( nEntryHeight );
2413 sal_Bool SvTreeListBox::Expand( SvTreeListEntry* pParent )
2415 DBG_CHKTHIS(SvTreeListBox,0);
2416 pHdlEntry = pParent;
2417 sal_Bool bExpanded = sal_False;
2418 sal_uInt16 nFlags;
2420 if( pParent->HasChildrenOnDemand() )
2421 RequestingChildren( pParent );
2422 if( pParent->HasChildren() )
2424 nImpFlags |= SVLBOX_IS_EXPANDING;
2425 if( ExpandingHdl() )
2427 bExpanded = sal_True;
2428 SvListView::Expand( pParent );
2429 pImp->EntryExpanded( pParent );
2430 pHdlEntry = pParent;
2431 ExpandedHdl();
2433 nFlags = pParent->GetFlags();
2434 nFlags &= ~SV_ENTRYFLAG_NO_NODEBMP;
2435 nFlags |= SV_ENTRYFLAG_HAD_CHILDREN;
2436 pParent->SetFlags( nFlags );
2438 else
2440 nFlags = pParent->GetFlags();
2441 nFlags |= SV_ENTRYFLAG_NO_NODEBMP;
2442 pParent->SetFlags( nFlags );
2443 GetModel()->InvalidateEntry( pParent ); // repaint
2446 // #i92103#
2447 if ( bExpanded )
2449 pImp->CallEventListeners( VCLEVENT_ITEM_EXPANDED, pParent );
2452 return bExpanded;
2455 sal_Bool SvTreeListBox::Collapse( SvTreeListEntry* pParent )
2457 DBG_CHKTHIS(SvTreeListBox,0);
2458 nImpFlags &= ~SVLBOX_IS_EXPANDING;
2459 pHdlEntry = pParent;
2460 sal_Bool bCollapsed = sal_False;
2462 if( ExpandingHdl() )
2464 bCollapsed = sal_True;
2465 pImp->CollapsingEntry( pParent );
2466 SvListView::Collapse( pParent );
2467 pImp->EntryCollapsed( pParent );
2468 pHdlEntry = pParent;
2469 ExpandedHdl();
2472 // #i92103#
2473 if ( bCollapsed )
2475 pImp->CallEventListeners( VCLEVENT_ITEM_COLLAPSED, pParent );
2478 return bCollapsed;
2481 sal_Bool SvTreeListBox::Select( SvTreeListEntry* pEntry, sal_Bool bSelect )
2483 DBG_CHKTHIS(SvTreeListBox,0);
2484 DBG_ASSERT(pEntry,"Select: Null-Ptr");
2485 sal_Bool bRetVal = SvListView::Select( pEntry, bSelect );
2486 DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed");
2487 if( bRetVal )
2489 pImp->EntrySelected( pEntry, bSelect );
2490 pHdlEntry = pEntry;
2491 if( bSelect )
2493 SelectHdl();
2494 pImp->CallEventListeners( VCLEVENT_LISTBOX_SELECT, pEntry );
2496 else
2497 DeselectHdl();
2499 return bRetVal;
2502 sal_uLong SvTreeListBox::SelectChildren( SvTreeListEntry* pParent, sal_Bool bSelect )
2504 DBG_CHKTHIS(SvTreeListBox,0);
2505 pImp->DestroyAnchor();
2506 sal_uLong nRet = 0;
2507 if( !pParent->HasChildren() )
2508 return 0;
2509 sal_uInt16 nRefDepth = pModel->GetDepth( pParent );
2510 SvTreeListEntry* pChild = FirstChild( pParent );
2511 do {
2512 nRet++;
2513 Select( pChild, bSelect );
2514 pChild = Next( pChild );
2515 } while( pChild && pModel->GetDepth( pChild ) > nRefDepth );
2516 return nRet;
2519 void SvTreeListBox::SelectAll( sal_Bool bSelect, sal_Bool )
2521 DBG_CHKTHIS(SvTreeListBox,0);
2522 pImp->SelAllDestrAnch(
2523 bSelect,
2524 sal_True, // delete anchor,
2525 sal_True ); // even when using SINGLE_SELECTION, deselect the cursor
2528 void SvTreeListBox::ModelHasInsertedTree( SvTreeListEntry* pEntry )
2530 DBG_CHKTHIS(SvTreeListBox,0);
2531 sal_uInt16 nRefDepth = pModel->GetDepth( (SvTreeListEntry*)pEntry );
2532 SvTreeListEntry* pTmp = (SvTreeListEntry*)pEntry;
2535 ImpEntryInserted( pTmp );
2536 pTmp = Next( pTmp );
2537 } while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) );
2538 pImp->TreeInserted( (SvTreeListEntry*)pEntry );
2541 void SvTreeListBox::ModelHasInserted( SvTreeListEntry* pEntry )
2543 DBG_CHKTHIS(SvTreeListBox,0);
2544 ImpEntryInserted( (SvTreeListEntry*)pEntry );
2545 pImp->EntryInserted( (SvTreeListEntry*)pEntry );
2548 void SvTreeListBox::ModelIsMoving(SvTreeListEntry* pSource,
2549 SvTreeListEntry* /* pTargetParent */,
2550 sal_uLong /* nChildPos */ )
2552 DBG_CHKTHIS(SvTreeListBox,0);
2553 pImp->MovingEntry( (SvTreeListEntry*)pSource );
2556 void SvTreeListBox::ModelHasMoved( SvTreeListEntry* pSource )
2558 DBG_CHKTHIS(SvTreeListBox,0);
2559 pImp->EntryMoved( (SvTreeListEntry*)pSource );
2562 void SvTreeListBox::ModelIsRemoving( SvTreeListEntry* pEntry )
2564 DBG_CHKTHIS(SvTreeListBox,0);
2565 if(pEdEntry == pEntry)
2566 pEdEntry = NULL;
2568 pImp->RemovingEntry( (SvTreeListEntry*)pEntry );
2569 NotifyRemoving( (SvTreeListEntry*)pEntry );
2572 void SvTreeListBox::ModelHasRemoved( SvTreeListEntry* pEntry )
2574 DBG_CHKTHIS(SvTreeListBox,0);
2575 if ( pEntry == pHdlEntry)
2576 pHdlEntry = NULL;
2577 pImp->EntryRemoved();
2580 void SvTreeListBox::SetCollapsedNodeBmp( const Image& rBmp)
2582 DBG_CHKTHIS(SvTreeListBox,0);
2583 AdjustEntryHeight( rBmp );
2584 pImp->SetCollapsedNodeBmp( rBmp );
2587 void SvTreeListBox::SetExpandedNodeBmp( const Image& rBmp )
2589 DBG_CHKTHIS(SvTreeListBox,0);
2590 AdjustEntryHeight( rBmp );
2591 pImp->SetExpandedNodeBmp( rBmp );
2595 void SvTreeListBox::SetFont( const Font& rFont )
2597 DBG_CHKTHIS(SvTreeListBox,0);
2599 Font aTempFont( rFont );
2600 Font aOrigFont( GetFont() );
2601 aTempFont.SetTransparent( sal_True );
2602 if (aTempFont == aOrigFont)
2603 return;
2604 Control::SetFont( aTempFont );
2606 aTempFont.SetColor(aOrigFont.GetColor());
2607 aTempFont.SetFillColor(aOrigFont.GetFillColor());
2608 aTempFont.SetTransparent(aOrigFont.IsTransparent());
2610 if (aTempFont == aOrigFont)
2611 return;
2613 AdjustEntryHeightAndRecalc( GetFont() );
2616 void SvTreeListBox::AdjustEntryHeightAndRecalc( const Font& rFont )
2618 DBG_CHKTHIS(SvTreeListBox,0);
2619 AdjustEntryHeight( rFont );
2620 // always invalidate, else things go wrong in SetEntryHeight
2621 RecalcViewData();
2624 void SvTreeListBox::Paint( const Rectangle& rRect )
2626 DBG_CHKTHIS(SvTreeListBox,0);
2627 Control::Paint( rRect );
2628 if( nTreeFlags & TREEFLAG_RECALCTABS )
2629 SetTabs();
2630 pImp->Paint( rRect );
2633 void SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt )
2635 DBG_CHKTHIS(SvTreeListBox,0);
2636 pImp->MouseButtonDown( rMEvt );
2639 void SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt )
2641 DBG_CHKTHIS(SvTreeListBox,0);
2642 pImp->MouseButtonUp( rMEvt );
2645 void SvTreeListBox::MouseMove( const MouseEvent& rMEvt )
2647 DBG_CHKTHIS(SvTreeListBox,0);
2648 pImp->MouseMove( rMEvt );
2652 void SvTreeListBox::SetUpdateMode( sal_Bool bUpdate )
2654 DBG_CHKTHIS(SvTreeListBox,0);
2655 pImp->SetUpdateMode( bUpdate );
2658 void SvTreeListBox::SetSpaceBetweenEntries( short nOffsLogic )
2660 DBG_CHKTHIS(SvTreeListBox,0);
2661 if( nOffsLogic != nEntryHeightOffs )
2663 nEntryHeight = nEntryHeight - nEntryHeightOffs;
2664 nEntryHeightOffs = (short)nOffsLogic;
2665 nEntryHeight = nEntryHeight + nOffsLogic;
2666 AdjustEntryHeightAndRecalc( GetFont() );
2667 pImp->SetEntryHeight( nEntryHeight );
2671 void SvTreeListBox::SetCursor( SvTreeListEntry* pEntry, sal_Bool bForceNoSelect )
2673 DBG_CHKTHIS(SvTreeListBox,0);
2674 pImp->SetCursor(pEntry, bForceNoSelect);
2677 void SvTreeListBox::SetCurEntry( SvTreeListEntry* pEntry )
2679 DBG_CHKTHIS(SvTreeListBox,0);
2680 pImp->SetCurEntry( pEntry );
2683 Image SvTreeListBox::GetExpandedNodeBmp( ) const
2685 return pImp->GetExpandedNodeBmp( );
2688 Point SvTreeListBox::GetEntryPosition( SvTreeListEntry* pEntry ) const
2690 return pImp->GetEntryPosition( pEntry );
2693 void SvTreeListBox::ShowEntry( SvTreeListEntry* pEntry )
2695 MakeVisible( pEntry );
2698 void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry )
2700 pImp->MakeVisible(pEntry);
2703 void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry, sal_Bool bMoveToTop )
2705 pImp->MakeVisible( pEntry, bMoveToTop );
2708 void SvTreeListBox::ModelHasEntryInvalidated( SvTreeListEntry* pEntry )
2710 DBG_CHKTHIS(SvTreeListBox,0);
2712 // reinitialize the separate items of the entries
2713 sal_uInt16 nCount = ((SvTreeListEntry*)pEntry)->ItemCount();
2714 for( sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++ )
2716 SvLBoxItem* pItem = ((SvTreeListEntry*)pEntry)->GetItem( nIdx );
2717 pItem->InitViewData( this, (SvTreeListEntry*)pEntry, 0 );
2720 // repaint
2721 pImp->InvalidateEntry( (SvTreeListEntry*)pEntry );
2724 void SvTreeListBox::EditItemText( SvTreeListEntry* pEntry, SvLBoxString* pItem,
2725 const Selection& rSelection )
2727 DBG_CHKTHIS(SvTreeListBox,0);
2728 DBG_ASSERT(pEntry&&pItem,"EditItemText: Bad params");
2729 if( IsSelected( pEntry ))
2731 pImp->ShowCursor( sal_False );
2732 SvListView::Select( pEntry, sal_False );
2733 PaintEntry( pEntry );
2734 SvListView::Select( pEntry, sal_True );
2735 pImp->ShowCursor( sal_True );
2737 pEdEntry = pEntry;
2738 pEdItem = pItem;
2739 SvLBoxTab* pTab = GetTab( pEntry, pItem );
2740 DBG_ASSERT(pTab,"EditItemText:Tab not found");
2742 Size aItemSize( pItem->GetSize(this, pEntry) );
2743 Point aPos = GetEntryPosition( pEntry );
2744 aPos.Y() += ( nEntryHeight - aItemSize.Height() ) / 2;
2745 aPos.X() = GetTabPos( pEntry, pTab );
2746 long nOutputWidth = pImp->GetOutputSize().Width();
2747 Size aSize( nOutputWidth - aPos.X(), aItemSize.Height() );
2748 sal_uInt16 nPos = std::find( aTabs.begin(), aTabs.end(), pTab ) - aTabs.begin();
2749 if( nPos+1 < (sal_uInt16)aTabs.size() )
2751 SvLBoxTab* pRightTab = aTabs[ nPos + 1 ];
2752 long nRight = GetTabPos( pEntry, pRightTab );
2753 if( nRight <= nOutputWidth )
2754 aSize.Width() = nRight - aPos.X();
2756 Point aOrigin( GetMapMode().GetOrigin() );
2757 aPos += aOrigin; // convert to win coordinates
2758 aSize.Width() -= aOrigin.X();
2759 Rectangle aRect( aPos, aSize );
2760 EditText( pItem->GetText(), aRect, rSelection );
2763 void SvTreeListBox::EditEntry( SvTreeListEntry* pEntry )
2765 pImp->aEditClickPos = Point( -1, -1 );
2766 ImplEditEntry( pEntry );
2769 void SvTreeListBox::ImplEditEntry( SvTreeListEntry* pEntry )
2771 DBG_CHKTHIS(SvTreeListBox,0);
2772 if( IsEditingActive() )
2773 EndEditing();
2774 if( !pEntry )
2775 pEntry = GetCurEntry();
2776 if( pEntry )
2778 long nClickX = pImp->aEditClickPos.X();
2779 bool bIsMouseTriggered = nClickX >= 0;
2781 SvLBoxString* pItem = NULL;
2782 sal_uInt16 nCount = pEntry->ItemCount();
2783 long nTabPos, nNextTabPos = 0;
2784 for( sal_uInt16 i = 0 ; i < nCount ; i++ )
2786 SvLBoxItem* pTmpItem = pEntry->GetItem( i );
2787 if (pTmpItem->GetType() != SV_ITEM_ID_LBOXSTRING)
2788 continue;
2790 SvLBoxTab* pTab = GetTab( pEntry, pTmpItem );
2791 nNextTabPos = -1;
2792 if( i < nCount - 1 )
2794 SvLBoxItem* pNextItem = pEntry->GetItem( i + 1 );
2795 SvLBoxTab* pNextTab = GetTab( pEntry, pNextItem );
2796 nNextTabPos = pNextTab->GetPos();
2799 if( pTab && pTab->IsEditable() )
2801 nTabPos = pTab->GetPos();
2802 if( !bIsMouseTriggered || (nClickX > nTabPos && (nNextTabPos == -1 || nClickX < nNextTabPos ) ) )
2804 pItem = static_cast<SvLBoxString*>( pTmpItem );
2805 break;
2810 Selection aSel( SELECTION_MIN, SELECTION_MAX );
2811 if( pItem && EditingEntry( pEntry, aSel ) )
2813 SelectAll( sal_False );
2814 MakeVisible( pEntry );
2815 EditItemText( pEntry, pItem, aSel );
2820 sal_Bool SvTreeListBox::AreChildrenTransient() const
2822 return pImp->AreChildrenTransient();
2825 void SvTreeListBox::SetChildrenNotTransient()
2827 pImp->SetChildrenNotTransient();
2830 void SvTreeListBox::EditedText( const OUString& rStr )
2833 DBG_CHKTHIS(SvTreeListBox,0);
2834 if(pEdEntry) // we have to check if this entry is null that means that it is removed while editing
2836 if( EditedEntry( pEdEntry, rStr ) )
2838 ((SvLBoxString*)pEdItem)->SetText( rStr );
2839 pModel->InvalidateEntry( pEdEntry );
2841 if( GetSelectionCount() == 0 )
2842 Select( pEdEntry );
2843 if( GetSelectionMode() == MULTIPLE_SELECTION && !GetCurEntry() )
2844 SetCurEntry( pEdEntry );
2848 SvTreeListEntry* SvTreeListBox::GetDropTarget( const Point& rPos )
2850 DBG_CHKTHIS(SvTreeListBox,0);
2851 // scroll
2852 if( rPos.Y() < 12 )
2854 ImplShowTargetEmphasis(pTargetEntry, false);
2855 ScrollOutputArea( +1 );
2857 else
2859 Size aSize( pImp->GetOutputSize() );
2860 if( rPos.Y() > aSize.Height() - 12 )
2862 ImplShowTargetEmphasis(pTargetEntry, false);
2863 ScrollOutputArea( -1 );
2867 SvTreeListEntry* pTarget = pImp->GetEntry( rPos );
2868 // when dropping in a vacant space, use the last entry
2869 if( !pTarget )
2870 return (SvTreeListEntry*)LastVisible();
2871 else if( (GetDragDropMode() & SV_DRAGDROP_ENABLE_TOP) &&
2872 pTarget == First() && rPos.Y() < 6 )
2873 return 0;
2875 return pTarget;
2879 SvTreeListEntry* SvTreeListBox::GetEntry( const Point& rPos, sal_Bool bHit ) const
2881 DBG_CHKTHIS(SvTreeListBox,0);
2882 SvTreeListEntry* pEntry = pImp->GetEntry( rPos );
2883 if( pEntry && bHit )
2885 long nLine = pImp->GetEntryLine( pEntry );
2886 if( !(pImp->EntryReallyHit( pEntry, rPos, nLine)) )
2887 return 0;
2889 return pEntry;
2892 SvTreeListEntry* SvTreeListBox::GetCurEntry() const
2894 DBG_CHKTHIS(SvTreeListBox,0);
2895 return pImp->GetCurEntry();
2898 void SvTreeListBox::ImplInitStyle()
2900 DBG_CHKTHIS(SvTreeListBox,0);
2902 const WinBits nWindowStyle = GetStyle();
2904 nTreeFlags |= TREEFLAG_RECALCTABS;
2905 if( nWindowStyle & WB_SORT )
2907 GetModel()->SetSortMode( SortAscending );
2908 GetModel()->SetCompareHdl( LINK(this,SvTreeListBox,DefaultCompare));
2910 else
2912 GetModel()->SetSortMode( SortNone );
2913 GetModel()->SetCompareHdl( Link() );
2915 pImp->SetStyle( nWindowStyle );
2916 pImp->Resize();
2917 Invalidate();
2920 void SvTreeListBox::PaintEntry( SvTreeListEntry* pEntry )
2922 DBG_CHKTHIS(SvTreeListBox,0);
2923 DBG_ASSERT(pEntry,"PaintEntry:No Entry");
2924 if( pEntry )
2925 pImp->PaintEntry( pEntry );
2928 void SvTreeListBox::InvalidateEntry( SvTreeListEntry* pEntry )
2930 DBG_CHKTHIS(SvTreeListBox,0);
2931 DBG_ASSERT(pEntry,"InvalidateEntry:No Entry");
2932 if( pEntry )
2934 GetModel()->InvalidateEntry( pEntry );
2938 long SvTreeListBox::PaintEntry(SvTreeListEntry* pEntry,long nLine,sal_uInt16 nTabFlags)
2940 return PaintEntry1(pEntry,nLine,nTabFlags);
2943 long SvTreeListBox::PaintEntry1(SvTreeListEntry* pEntry,long nLine,sal_uInt16 nTabFlags,
2944 sal_Bool bHasClipRegion )
2946 DBG_CHKTHIS(SvTreeListBox,0);
2948 Rectangle aRect; // multi purpose
2950 sal_Bool bHorSBar = pImp->HasHorScrollBar();
2951 PreparePaint( pEntry );
2953 pImp->UpdateContextBmpWidthMax( pEntry );
2955 if( nTreeFlags & TREEFLAG_RECALCTABS )
2956 SetTabs();
2958 short nTempEntryHeight = GetEntryHeight();
2959 long nWidth = pImp->GetOutputSize().Width();
2961 // Did we turn on the scrollbar within PreparePaints? If yes, we have to set
2962 // the ClipRegion anew.
2963 if( !bHorSBar && pImp->HasHorScrollBar() )
2964 SetClipRegion( Region(pImp->GetClipRegionRect()) );
2966 Point aEntryPos( GetMapMode().GetOrigin() );
2967 aEntryPos.X() *= -1; // conversion document coordinates
2968 long nMaxRight = nWidth + aEntryPos.X() - 1;
2970 Color aBackupTextColor( GetTextColor() );
2971 Font aBackupFont( GetFont() );
2972 Color aBackupColor = GetFillColor();
2974 bool bCurFontIsSel = false;
2975 sal_Bool bInUse = pEntry->HasInUseEmphasis();
2976 // if a ClipRegion was set from outside, we don't have to reset it
2977 const WinBits nWindowStyle = GetStyle();
2978 const sal_Bool bResetClipRegion = !bHasClipRegion;
2979 const sal_Bool bHideSelection = ((nWindowStyle & WB_HIDESELECTION) && !HasFocus())!=0;
2980 const StyleSettings& rSettings = GetSettings().GetStyleSettings();
2982 Font aHighlightFont( GetFont() );
2983 const Color aHighlightTextColor( rSettings.GetHighlightTextColor() );
2984 aHighlightFont.SetColor( aHighlightTextColor );
2986 Size aRectSize( 0, nTempEntryHeight );
2988 if( !bHasClipRegion && nWindowStyle & WB_HSCROLL )
2990 SetClipRegion( Region(pImp->GetClipRegionRect()) );
2991 bHasClipRegion = sal_True;
2994 SvViewDataEntry* pViewDataEntry = GetViewDataEntry( pEntry );
2996 sal_uInt16 nTabCount = aTabs.size();
2997 sal_uInt16 nItemCount = pEntry->ItemCount();
2998 sal_uInt16 nCurTab = 0;
2999 sal_uInt16 nCurItem = 0;
3001 while( nCurTab < nTabCount && nCurItem < nItemCount )
3003 SvLBoxTab* pTab = aTabs[ nCurTab ];
3004 sal_uInt16 nNextTab = nCurTab + 1;
3005 SvLBoxTab* pNextTab = nNextTab < nTabCount ? aTabs[nNextTab] : 0;
3006 SvLBoxItem* pItem = nCurItem < nItemCount ? pEntry->GetItem(nCurItem) : 0;
3008 sal_uInt16 nFlags = pTab->nFlags;
3009 Size aSize( pItem->GetSize( pViewDataEntry, nCurItem ));
3010 long nTabPos = GetTabPos( pEntry, pTab );
3012 long nNextTabPos;
3013 if( pNextTab )
3014 nNextTabPos = GetTabPos( pEntry, pNextTab );
3015 else
3017 nNextTabPos = nMaxRight;
3018 if( nTabPos > nMaxRight )
3019 nNextTabPos += 50;
3022 long nX;
3023 if( pTab->nFlags & SV_LBOXTAB_ADJUST_RIGHT )
3024 // avoid cutting the right edge off the tab separation
3025 nX = nTabPos + pTab->CalcOffset(aSize.Width(), (nNextTabPos-SV_TAB_BORDER-1) -nTabPos);
3026 else
3027 nX = nTabPos + pTab->CalcOffset(aSize.Width(), nNextTabPos-nTabPos);
3029 if( nFlags & nTabFlags )
3031 if( !bHasClipRegion && nX + aSize.Width() >= nMaxRight )
3033 SetClipRegion( Region(pImp->GetClipRegionRect()) );
3034 bHasClipRegion = sal_True;
3036 aEntryPos.X() = nX;
3037 aEntryPos.Y() = nLine;
3039 // set background pattern/color
3041 Wallpaper aWallpaper = GetBackground();
3043 int bSelTab = nFlags & SV_LBOXTAB_SHOW_SELECTION;
3044 sal_uInt16 nItemType = pItem->GetType();
3046 if (pViewDataEntry->IsHighlighted() && bSelTab && !pViewDataEntry->IsCursored())
3048 Color aNewWallColor = rSettings.GetHighlightColor();
3049 if ( !bInUse || nItemType != SV_ITEM_ID_LBOXCONTEXTBMP )
3051 // if the face color is bright then the deactive color is also bright
3052 // -> so you can't see any deactive selection
3053 if ( bHideSelection && !rSettings.GetFaceColor().IsBright() &&
3054 aWallpaper.GetColor().IsBright() != rSettings.GetDeactiveColor().IsBright() )
3055 aNewWallColor = rSettings.GetDeactiveColor();
3056 // set font color to highlight
3057 if ( !bCurFontIsSel )
3059 SetTextColor( aHighlightTextColor );
3060 Control::SetFont( aHighlightFont );
3061 bCurFontIsSel = true;
3064 aWallpaper.SetColor( aNewWallColor );
3066 else // no selection
3068 if( bInUse && nItemType == SV_ITEM_ID_LBOXCONTEXTBMP )
3069 aWallpaper.SetColor( rSettings.GetFieldColor() );
3070 else if( bCurFontIsSel )
3072 bCurFontIsSel = false;
3073 SetTextColor( aBackupTextColor );
3074 Control::SetFont( aBackupFont );
3078 // draw background
3079 if( !(nTreeFlags & TREEFLAG_USESEL))
3081 // only draw the area that is used by the item
3082 aRectSize.Width() = aSize.Width();
3083 aRect.SetPos( aEntryPos );
3084 aRect.SetSize( aRectSize );
3086 else
3088 // draw from the current to the next tab
3089 if( nCurTab != 0 )
3090 aRect.Left() = nTabPos;
3091 else
3092 // if we're in the 0th tab, always draw from column 0 --
3093 // else we get problems with centered tabs
3094 aRect.Left() = 0;
3095 aRect.Top() = nLine;
3096 aRect.Bottom() = nLine + nTempEntryHeight - 1;
3097 if( pNextTab )
3099 long nRight;
3100 nRight = GetTabPos(pEntry,pNextTab)-1;
3101 if( nRight > nMaxRight )
3102 nRight = nMaxRight;
3103 aRect.Right() = nRight;
3105 else
3106 aRect.Right() = nMaxRight;
3108 // A custom selection that starts at a tab position > 0, do not fill
3109 // the background of the 0th item, else e.g. we might not be able to
3110 // realize tab listboxes with lines.
3111 if( !(nCurTab==0 && (nTreeFlags & TREEFLAG_USESEL) && nFirstSelTab) )
3113 SetFillColor( aWallpaper.GetColor() );
3114 // this case may occur for smaller horizontal resizes
3115 if( aRect.Left() < aRect.Right() )
3116 DrawRect( aRect );
3118 // draw item
3119 // center vertically
3120 aEntryPos.Y() += ( nTempEntryHeight - aSize.Height() ) / 2;
3121 pItem->Paint(aEntryPos, *this, pViewDataEntry, pEntry);
3123 // division line between tabs
3124 if (pNextTab && pItem->GetType() == SV_ITEM_ID_LBOXSTRING &&
3125 // not at the right edge of the window!
3126 aRect.Right() < nMaxRight)
3128 aRect.Left() = aRect.Right() - SV_TAB_BORDER;
3129 DrawRect( aRect );
3132 SetFillColor( aBackupColor );
3134 nCurItem++;
3135 nCurTab++;
3137 if( pViewDataEntry->IsCursored() && !HasFocus() )
3139 // cursor emphasis
3140 SetFillColor();
3141 Color aOldLineColor = GetLineColor();
3142 SetLineColor( Color( COL_BLACK ) );
3143 aRect = GetFocusRect( pEntry, nLine );
3144 aRect.Top()++;
3145 aRect.Bottom()--;
3146 DrawRect( aRect );
3147 SetLineColor( aOldLineColor );
3148 SetFillColor( aBackupColor );
3151 if( bCurFontIsSel )
3153 SetTextColor( aBackupTextColor );
3154 Control::SetFont( aBackupFont );
3157 sal_uInt16 nFirstDynTabPos;
3158 SvLBoxTab* pFirstDynamicTab = GetFirstDynamicTab( nFirstDynTabPos );
3159 long nDynTabPos = GetTabPos( pEntry, pFirstDynamicTab );
3160 nDynTabPos += pImp->nNodeBmpTabDistance;
3161 nDynTabPos += pImp->nNodeBmpWidth / 2;
3162 nDynTabPos += 4; // 4 pixels of buffer, so the node bitmap is not too close
3163 // to the next tab
3165 if( (!(pEntry->GetFlags() & SV_ENTRYFLAG_NO_NODEBMP)) &&
3166 (nWindowStyle & WB_HASBUTTONS) && pFirstDynamicTab &&
3167 ( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() ) )
3169 // find first tab and check if the node bitmap extends into it
3170 sal_uInt16 nNextTab = nFirstDynTabPos;
3171 SvLBoxTab* pNextTab;
3174 nNextTab++;
3175 pNextTab = nNextTab < nTabCount ? aTabs[nNextTab] : 0;
3176 } while( pNextTab && pNextTab->IsDynamic() );
3178 if( !pNextTab || (GetTabPos( pEntry, pNextTab ) > nDynTabPos) )
3180 if((nWindowStyle & WB_HASBUTTONSATROOT) || pModel->GetDepth(pEntry) > 0)
3182 Point aPos( GetTabPos(pEntry,pFirstDynamicTab), nLine );
3183 aPos.X() += pImp->nNodeBmpTabDistance;
3185 const Image* pImg = 0;
3187 if( IsExpanded(pEntry) )
3188 pImg = &pImp->GetExpandedNodeBmp( );
3189 else
3191 if( (!pEntry->HasChildren()) && pEntry->HasChildrenOnDemand() &&
3192 (!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) &&
3193 pImp->GetDontKnowNodeBmp().GetSizePixel().Width() )
3194 pImg = &pImp->GetDontKnowNodeBmp( );
3195 else
3196 pImg = &pImp->GetCollapsedNodeBmp( );
3198 aPos.Y() += (nTempEntryHeight - pImg->GetSizePixel().Height()) / 2;
3200 sal_uInt16 nStyle = 0;
3201 if ( !IsEnabled() )
3202 nStyle |= IMAGE_DRAW_DISABLE;
3204 //native
3205 sal_Bool bNativeOK = sal_False;
3206 if ( IsNativeControlSupported( CTRL_LISTNODE, PART_ENTIRE_CONTROL) )
3208 ImplControlValue aControlValue;
3209 Rectangle aCtrlRegion( aPos, pImg->GetSizePixel() );
3210 ControlState nState = 0;
3212 if ( IsEnabled() ) nState |= CTRL_STATE_ENABLED;
3214 if ( IsExpanded(pEntry) )
3215 aControlValue.setTristateVal( BUTTONVALUE_ON );//expanded node
3216 else
3218 if( (!pEntry->HasChildren() ) &&
3219 pEntry->HasChildrenOnDemand() &&
3220 (!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) &&
3221 pImp->GetDontKnowNodeBmp().GetSizePixel().Width()
3223 aControlValue.setTristateVal( BUTTONVALUE_DONTKNOW ); //dont know
3224 else
3225 aControlValue.setTristateVal( BUTTONVALUE_OFF ); //collapsed node
3228 bNativeOK = DrawNativeControl( CTRL_LISTNODE, PART_ENTIRE_CONTROL,
3229 aCtrlRegion, nState, aControlValue, OUString() );
3232 if( !bNativeOK) {
3233 DrawImage( aPos, *pImg ,nStyle);
3240 if( bHasClipRegion && bResetClipRegion )
3241 SetClipRegion();
3242 return 0; // nRowLen;
3245 void SvTreeListBox::PreparePaint( SvTreeListEntry* )
3249 Rectangle SvTreeListBox::GetFocusRect( SvTreeListEntry* pEntry, long nLine )
3251 DBG_CHKTHIS(SvTreeListBox,0);
3252 Size aSize;
3253 Rectangle aRect;
3254 aRect.Top() = nLine;
3255 aSize.Height() = GetEntryHeight();
3257 long nRealWidth = pImp->GetOutputSize().Width();
3258 nRealWidth -= GetMapMode().GetOrigin().X();
3260 sal_uInt16 nCurTab;
3261 SvLBoxTab* pTab = GetFirstTab( SV_LBOXTAB_SHOW_SELECTION, nCurTab );
3262 long nTabPos = 0;
3263 if( pTab )
3264 nTabPos = GetTabPos( pEntry, pTab );
3265 long nNextTabPos;
3266 if( pTab && nCurTab < aTabs.size() - 1 )
3268 SvLBoxTab* pNextTab = aTabs[ nCurTab + 1 ];
3269 nNextTabPos = GetTabPos( pEntry, pNextTab );
3271 else
3273 nNextTabPos = nRealWidth;
3274 if( nTabPos > nRealWidth )
3275 nNextTabPos += 50;
3278 sal_Bool bUserSelection = (sal_Bool)( nTreeFlags & TREEFLAG_USESEL ) != 0;
3279 if( !bUserSelection )
3281 if( pTab && nCurTab < pEntry->ItemCount() )
3283 SvLBoxItem* pItem = pEntry->GetItem( nCurTab );
3284 aSize.Width() = pItem->GetSize( this, pEntry ).Width();
3285 if( !aSize.Width() )
3286 aSize.Width() = 15;
3287 long nX = nTabPos; //GetTabPos( pEntry, pTab );
3288 // alignment
3289 nX += pTab->CalcOffset( aSize.Width(), nNextTabPos - nTabPos );
3290 aRect.Left() = nX;
3291 // make sure that first and last letter aren't cut off slightly
3292 aRect.SetSize( aSize );
3293 if( aRect.Left() > 0 )
3294 aRect.Left()--;
3295 aRect.Right()++;
3298 else
3300 // if SelTab != 0, we have to calculate also
3301 if( nFocusWidth == -1 || nFirstSelTab )
3303 sal_uInt16 nLastTab;
3304 SvLBoxTab* pLastTab = GetLastTab(SV_LBOXTAB_SHOW_SELECTION,nLastTab);
3305 nLastTab++;
3306 if( nLastTab < aTabs.size() ) // is there another one?
3307 pLastTab = aTabs[ nLastTab ];
3308 else
3309 pLastTab = 0; // select whole width
3310 aSize.Width() = pLastTab ? pLastTab->GetPos() : 0x0fffffff;
3311 nFocusWidth = (short)aSize.Width();
3312 if( pTab )
3313 nFocusWidth = nFocusWidth - (short)nTabPos; //pTab->GetPos();
3315 else
3317 aSize.Width() = nFocusWidth;
3318 if( pTab )
3320 if( nCurTab )
3321 aSize.Width() += nTabPos;
3322 else
3323 aSize.Width() += pTab->GetPos(); // Tab0 always from the leftmost position
3326 // if selection starts with 0th tab, draw from column 0 on
3327 if( nCurTab != 0 )
3329 aRect.Left() = nTabPos;
3330 aSize.Width() -= nTabPos;
3332 aRect.SetSize( aSize );
3334 // adjust right edge because of clipping
3335 if( aRect.Right() >= nRealWidth )
3337 aRect.Right() = nRealWidth-1;
3338 nFocusWidth = (short)aRect.GetWidth();
3340 return aRect;
3344 sal_IntPtr SvTreeListBox::GetTabPos( SvTreeListEntry* pEntry, SvLBoxTab* pTab)
3346 DBG_CHKTHIS(SvTreeListBox,0);
3347 DBG_ASSERT(pTab,"No Tab");
3348 sal_IntPtr nPos = pTab->GetPos();
3349 if( pTab->IsDynamic() )
3351 sal_uInt16 nDepth = pModel->GetDepth( pEntry );
3352 nDepth = nDepth * (sal_uInt16)nIndent;
3353 nPos += (sal_IntPtr)nDepth;
3355 return nPos;
3358 SvLBoxItem* SvTreeListBox::GetItem_Impl( SvTreeListEntry* pEntry, long nX,
3359 SvLBoxTab** ppTab, sal_uInt16 nEmptyWidth )
3361 DBG_CHKTHIS(SvTreeListBox,0);
3362 SvLBoxItem* pItemClicked = 0;
3363 sal_uInt16 nTabCount = aTabs.size();
3364 sal_uInt16 nItemCount = pEntry->ItemCount();
3365 SvLBoxTab* pTab = aTabs.front();
3366 SvLBoxItem* pItem = pEntry->GetItem(0);
3367 sal_uInt16 nNextItem = 1;
3368 nX -= GetMapMode().GetOrigin().X();
3369 long nRealWidth = pImp->GetOutputSize().Width();
3370 nRealWidth -= GetMapMode().GetOrigin().X();
3372 while( 1 )
3374 SvLBoxTab* pNextTab=nNextItem<nTabCount ? aTabs[nNextItem] : 0;
3375 long nStart = GetTabPos( pEntry, pTab );
3377 long nNextTabPos;
3378 if( pNextTab )
3379 nNextTabPos = GetTabPos( pEntry, pNextTab );
3380 else
3382 nNextTabPos = nRealWidth;
3383 if( nStart > nRealWidth )
3384 nNextTabPos += 50;
3387 Size aItemSize( pItem->GetSize(this, pEntry));
3388 nStart += pTab->CalcOffset( aItemSize.Width(), nNextTabPos - nStart );
3389 long nLen = aItemSize.Width();
3390 if( pNextTab )
3392 long nTabWidth = GetTabPos( pEntry, pNextTab ) - nStart;
3393 if( nTabWidth < nLen )
3394 nLen = nTabWidth;
3397 if( !nLen )
3398 nLen = nEmptyWidth;
3400 if( nX >= nStart && nX < (nStart+nLen ) )
3402 pItemClicked = pItem;
3403 if( ppTab )
3405 *ppTab = pTab;
3406 break;
3409 if( nNextItem >= nItemCount || nNextItem >= nTabCount)
3410 break;
3411 pTab = aTabs[ nNextItem ];
3412 pItem = pEntry->GetItem( nNextItem );
3413 nNextItem++;
3415 return pItemClicked;
3418 long SvTreeListBox::getPreferredDimensions(std::vector<long> &rWidths) const
3420 long nHeight = 0;
3421 rWidths.clear();
3422 SvTreeListEntry* pEntry = First();
3423 while (pEntry)
3425 sal_uInt16 nCount = pEntry->ItemCount();
3426 sal_uInt16 nCurPos = 0;
3427 if (nCount > rWidths.size())
3428 rWidths.resize(nCount);
3429 while (nCurPos < nCount)
3431 SvLBoxItem* pItem = pEntry->GetItem( nCurPos );
3432 long nWidth = pItem->GetSize(this, pEntry).Width();
3433 if (nWidth)
3435 nWidth += SV_TAB_BORDER * 2;
3436 if (nWidth > rWidths[nCurPos])
3437 rWidths[nCurPos] = nWidth;
3439 ++nCurPos;
3441 pEntry = Next( pEntry );
3442 nHeight += GetEntryHeight();
3444 return nHeight;
3447 Size SvTreeListBox::GetOptimalSize() const
3449 std::vector<long> aWidths;
3450 Size aRet(0, getPreferredDimensions(aWidths));
3451 for (size_t i = 0; i < aWidths.size(); ++i)
3452 aRet.Width() += aWidths[i];
3453 if (GetStyle() & WB_BORDER)
3455 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3456 aRet.Width() += rStyleSettings.GetBorderSize() * 2;
3457 aRet.Height() += rStyleSettings.GetBorderSize() * 2;
3459 long nMinWidth = nMinWidthInChars * approximate_char_width();
3460 aRet.Width() = std::max(aRet.Width(), nMinWidth);
3461 return aRet;
3464 SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX,SvLBoxTab** ppTab)
3466 return GetItem_Impl( pEntry, nX, ppTab, 0 );
3469 SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX )
3471 DBG_CHKTHIS(SvTreeListBox,0);
3472 SvLBoxTab* pDummyTab;
3473 return GetItem_Impl( pEntry, nX, &pDummyTab, 0 );
3476 void SvTreeListBox::AddTab(long nTabPos,sal_uInt16 nFlags,void* pUserData )
3478 DBG_CHKTHIS(SvTreeListBox,0);
3479 nFocusWidth = -1;
3480 SvLBoxTab* pTab = new SvLBoxTab( nTabPos, nFlags );
3481 pTab->SetUserData( pUserData );
3482 aTabs.push_back( pTab );
3483 if( nTreeFlags & TREEFLAG_USESEL )
3485 sal_uInt16 nPos = aTabs.size() - 1;
3486 if( nPos >= nFirstSelTab && nPos <= nLastSelTab )
3487 pTab->nFlags |= SV_LBOXTAB_SHOW_SELECTION;
3488 else
3489 // string items usually have to be selected -- turn this off
3490 // explicitly
3491 pTab->nFlags &= ~SV_LBOXTAB_SHOW_SELECTION;
3497 SvLBoxTab* SvTreeListBox::GetFirstDynamicTab( sal_uInt16& rPos ) const
3499 DBG_CHKTHIS(SvTreeListBox,0);
3500 sal_uInt16 nCurTab = 0;
3501 sal_uInt16 nTabCount = aTabs.size();
3502 while( nCurTab < nTabCount )
3504 SvLBoxTab* pTab = aTabs[nCurTab];
3505 if( pTab->nFlags & SV_LBOXTAB_DYNAMIC )
3507 rPos = nCurTab;
3508 return pTab;
3510 nCurTab++;
3512 return 0;
3515 SvLBoxTab* SvTreeListBox::GetFirstDynamicTab() const
3517 sal_uInt16 nDummy;
3518 return GetFirstDynamicTab( nDummy );
3521 SvLBoxTab* SvTreeListBox::GetTab( SvTreeListEntry* pEntry, SvLBoxItem* pItem) const
3523 DBG_CHKTHIS(SvTreeListBox,0);
3524 sal_uInt16 nPos = pEntry->GetPos( pItem );
3525 return aTabs[ nPos ];
3528 void SvTreeListBox::ClearTabList()
3530 DBG_CHKTHIS(SvTreeListBox,0);
3531 sal_uInt16 nTabCount = aTabs.size();
3532 while( nTabCount )
3534 nTabCount--;
3535 SvLBoxTab* pDelTab = aTabs[ nTabCount ];
3536 delete pDelTab;
3538 aTabs.clear();
3542 Size SvTreeListBox::GetOutputSizePixel() const
3544 DBG_CHKTHIS(SvTreeListBox,0);
3545 Size aSize = pImp->GetOutputSize();
3546 return aSize;
3549 void SvTreeListBox::NotifyBeginScroll()
3551 DBG_CHKTHIS(SvTreeListBox,0);
3554 void SvTreeListBox::NotifyEndScroll()
3556 DBG_CHKTHIS(SvTreeListBox,0);
3559 void SvTreeListBox::NotifyScrolling( long )
3561 DBG_CHKTHIS(SvTreeListBox,0);
3564 void SvTreeListBox::NotifyScrolled()
3566 DBG_CHKTHIS(SvTreeListBox,0);
3567 aScrolledHdl.Call( this );
3570 void SvTreeListBox::NotifyInvalidating()
3572 DBG_CHKTHIS(SvTreeListBox,0);
3575 void SvTreeListBox::Invalidate( sal_uInt16 nInvalidateFlags )
3577 DBG_CHKTHIS(SvTreeListBox,0);
3578 if( nFocusWidth == -1 )
3579 // to make sure that the control doesn't show the wrong focus rectangle
3580 // after painting
3581 pImp->RecalcFocusRect();
3582 NotifyInvalidating();
3583 Control::Invalidate( nInvalidateFlags );
3584 pImp->Invalidate();
3587 void SvTreeListBox::Invalidate( const Rectangle& rRect, sal_uInt16 nInvalidateFlags )
3589 DBG_CHKTHIS(SvTreeListBox,0);
3590 if( nFocusWidth == -1 )
3591 // to make sure that the control doesn't show the wrong focus rectangle
3592 // after painting
3593 pImp->RecalcFocusRect();
3594 NotifyInvalidating();
3595 Control::Invalidate( rRect, nInvalidateFlags );
3599 void SvTreeListBox::SetHighlightRange( sal_uInt16 nStart, sal_uInt16 nEnd)
3601 DBG_CHKTHIS(SvTreeListBox,0);
3603 sal_uInt16 nTemp;
3604 nTreeFlags |= TREEFLAG_USESEL;
3605 if( nStart > nEnd )
3607 nTemp = nStart;
3608 nStart = nEnd;
3609 nEnd = nTemp;
3611 // select all tabs that lie within the area
3612 nTreeFlags |= TREEFLAG_RECALCTABS;
3613 nFirstSelTab = nStart;
3614 nLastSelTab = nEnd;
3615 pImp->RecalcFocusRect();
3618 void SvTreeListBox::Command( const CommandEvent& rCEvt )
3620 DBG_CHKTHIS(SvTreeListBox,0);
3621 // FIXME gnumake2 resync to DEV300_m84
3622 pImp->Command( rCEvt );
3626 void SvTreeListBox::RemoveParentKeepChildren( SvTreeListEntry* pParent )
3628 DBG_CHKTHIS(SvTreeListBox,0);
3629 DBG_ASSERT(pParent,"RemoveParentKeepChildren:No Parent");
3630 SvTreeListEntry* pNewParent = GetParent( pParent );
3631 if( pParent->HasChildren())
3633 SvTreeListEntry* pChild = FirstChild( pParent );
3634 while( pChild )
3636 pModel->Move( pChild, pNewParent, LIST_APPEND );
3637 pChild = FirstChild( pParent );
3640 pModel->Remove( pParent );
3643 SvLBoxTab* SvTreeListBox::GetFirstTab( sal_uInt16 nFlagMask, sal_uInt16& rPos )
3645 sal_uInt16 nTabCount = aTabs.size();
3646 for( sal_uInt16 nPos = 0; nPos < nTabCount; nPos++ )
3648 SvLBoxTab* pTab = aTabs[ nPos ];
3649 if( (pTab->nFlags & nFlagMask) )
3651 rPos = nPos;
3652 return pTab;
3655 rPos = 0xffff;
3656 return 0;
3659 SvLBoxTab* SvTreeListBox::GetLastTab( sal_uInt16 nFlagMask, sal_uInt16& rTabPos )
3661 sal_uInt16 nPos = (sal_uInt16)aTabs.size();
3662 while( nPos )
3664 --nPos;
3665 SvLBoxTab* pTab = aTabs[ nPos ];
3666 if( (pTab->nFlags & nFlagMask) )
3668 rTabPos = nPos;
3669 return pTab;
3672 rTabPos = 0xffff;
3673 return 0;
3676 void SvTreeListBox::RequestHelp( const HelpEvent& rHEvt )
3678 if( !pImp->RequestHelp( rHEvt ) )
3679 Control::RequestHelp( rHEvt );
3682 void SvTreeListBox::CursorMoved( SvTreeListEntry* )
3686 IMPL_LINK( SvTreeListBox, DefaultCompare, SvSortData*, pData )
3688 const SvTreeListEntry* pLeft = pData->pLeft;
3689 const SvTreeListEntry* pRight = pData->pRight;
3690 OUString aLeft( ((SvLBoxString*)(pLeft->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText());
3691 OUString aRight( ((SvLBoxString*)(pRight->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText());
3692 pImp->UpdateStringSorter();
3693 return pImp->m_pStringSorter->compare(aLeft, aRight);
3696 void SvTreeListBox::ModelNotification( sal_uInt16 nActionId, SvTreeListEntry* pEntry1,
3697 SvTreeListEntry* pEntry2, sal_uLong nPos )
3699 SolarMutexGuard aSolarGuard;
3701 if( nActionId == LISTACTION_CLEARING )
3702 CancelTextEditing();
3704 SvListView::ModelNotification( nActionId, pEntry1, pEntry2, nPos );
3705 switch( nActionId )
3707 case LISTACTION_INSERTED:
3709 SvTreeListEntry* pEntry( dynamic_cast< SvTreeListEntry* >( pEntry1 ) );
3710 if ( !pEntry )
3712 SAL_WARN( "svtools.contnr", "SvTreeListBox::ModelNotification: invalid entry!" );
3713 break;
3716 SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) );
3717 if ( !pBmpItem )
3718 break;
3719 const Image& rBitmap1( pBmpItem->GetBitmap1() );
3720 const Image& rBitmap2( pBmpItem->GetBitmap2() );
3721 short nMaxWidth = short( std::max( rBitmap1.GetSizePixel().Width(), rBitmap2.GetSizePixel().Width() ) );
3722 nMaxWidth = pImp->UpdateContextBmpWidthVector( pEntry, nMaxWidth );
3723 if( nMaxWidth > nContextBmpWidthMax )
3725 nContextBmpWidthMax = nMaxWidth;
3726 SetTabs();
3728 if (get_width_request() == -1)
3729 queue_resize();
3731 break;
3733 case LISTACTION_RESORTING:
3734 SetUpdateMode( sal_False );
3735 break;
3737 case LISTACTION_RESORTED:
3738 // after a selection: show first entry and also keep the selection
3739 MakeVisible( (SvTreeListEntry*)pModel->First(), sal_True );
3740 SetUpdateMode( sal_True );
3741 break;
3743 case LISTACTION_CLEARED:
3744 if( IsUpdateMode() )
3745 Update();
3746 break;
3750 void SvTreeListBox::EndSelection()
3752 pImp->EndSelection();
3755 void SvTreeListBox::RepaintScrollBars() const
3757 ((SvTreeListBox*)this)->pImp->RepaintScrollBars();
3760 ScrollBar *SvTreeListBox::GetVScroll()
3762 return &((SvTreeListBox*)this)->pImp->aVerSBar;
3765 ScrollBar *SvTreeListBox::GetHScroll()
3767 return &((SvTreeListBox*)this)->pImp->aHorSBar;
3770 void SvTreeListBox::EnableAsyncDrag( sal_Bool b )
3772 pImp->EnableAsyncDrag( b );
3775 SvTreeListEntry* SvTreeListBox::GetFirstEntryInView() const
3777 Point aPos;
3778 return GetEntry( aPos );
3781 SvTreeListEntry* SvTreeListBox::GetNextEntryInView(SvTreeListEntry* pEntry ) const
3783 SvTreeListEntry* pNext = (SvTreeListEntry*)NextVisible( pEntry );
3784 if( pNext )
3786 Point aPos( GetEntryPosition(pNext) );
3787 const Size& rSize = pImp->GetOutputSize();
3788 if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() )
3789 return 0;
3791 return pNext;
3794 SvTreeListEntry* SvTreeListBox::GetLastEntryInView() const
3796 SvTreeListEntry* pEntry = GetFirstEntryInView();
3797 SvTreeListEntry* pNext = 0;
3798 while( pEntry )
3800 pNext = (SvTreeListEntry*)NextVisible( pEntry );
3801 if( pNext )
3803 Point aPos( GetEntryPosition(pNext) );
3804 const Size& rSize = pImp->GetOutputSize();
3805 if( aPos.Y() < 0 || aPos.Y() + GetEntryHeight() >= rSize.Height() )
3806 break;
3807 else
3808 pEntry = pNext;
3810 else
3811 break;
3813 return pEntry;
3816 void SvTreeListBox::ShowFocusRect( const SvTreeListEntry* pEntry )
3818 pImp->ShowFocusRect( pEntry );
3821 void SvTreeListBox::DataChanged( const DataChangedEvent& rDCEvt )
3823 if( (rDCEvt.GetType()==DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) )
3825 nEntryHeight = 0; // _together_ with sal_True of 1. par (bFont) of InitSettings() a zero-height
3826 // forces complete recalc of heights!
3827 InitSettings( sal_True, sal_True, sal_True );
3828 Invalidate();
3830 else
3831 Control::DataChanged( rDCEvt );
3834 void SvTreeListBox::StateChanged( StateChangedType eType )
3836 if( eType == STATE_CHANGE_ENABLE )
3837 Invalidate( INVALIDATE_CHILDREN );
3839 Control::StateChanged( eType );
3841 if ( eType == STATE_CHANGE_STYLE )
3842 ImplInitStyle();
3845 void SvTreeListBox::InitSettings(sal_Bool bFont,sal_Bool bForeground,sal_Bool bBackground)
3847 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3848 if( bFont )
3850 Font aFont;
3851 aFont = rStyleSettings.GetFieldFont();
3852 aFont.SetColor( rStyleSettings.GetWindowTextColor() );
3853 SetPointFont( aFont );
3854 AdjustEntryHeightAndRecalc( aFont );
3857 if( bForeground || bFont )
3859 SetTextColor( rStyleSettings.GetFieldTextColor() );
3860 SetTextFillColor();
3863 if( bBackground )
3864 SetBackground( rStyleSettings.GetFieldColor() );
3866 // always try to re-create default-SvLBoxButtonData
3867 if( pCheckButtonData && pCheckButtonData->HasDefaultImages() )
3868 pCheckButtonData->SetDefaultImages( this );
3871 sal_Bool SvTreeListBox::IsCellFocusEnabled() const
3873 return pImp->IsCellFocusEnabled();
3876 bool SvTreeListBox::SetCurrentTabPos( sal_uInt16 _nNewPos )
3878 return pImp->SetCurrentTabPos( _nNewPos );
3881 sal_uInt16 SvTreeListBox::GetCurrentTabPos() const
3883 return pImp->GetCurrentTabPos();
3886 void SvTreeListBox::InitStartEntry()
3888 if( !pImp->pStartEntry )
3889 pImp->pStartEntry = GetModel()->First();
3892 PopupMenu* SvTreeListBox::CreateContextMenu( void )
3894 return NULL;
3897 void SvTreeListBox::ExcecuteContextMenuAction( sal_uInt16 )
3899 DBG_WARNING( "SvTreeListBox::ExcecuteContextMenuAction(): now there's happening nothing!" );
3902 void SvTreeListBox::EnableContextMenuHandling( void )
3904 DBG_ASSERT( pImp, "-SvTreeListBox::EnableContextMenuHandling(): No implementation!" );
3906 pImp->bContextMenuHandling = sal_True;
3909 void SvTreeListBox::EnableContextMenuHandling( sal_Bool b )
3911 DBG_ASSERT( pImp, "-SvTreeListBox::EnableContextMenuHandling(): No implementation!" );
3913 pImp->bContextMenuHandling = b;
3916 sal_Bool SvTreeListBox::IsContextMenuHandlingEnabled( void ) const
3918 DBG_ASSERT( pImp, "-SvTreeListBox::IsContextMenuHandlingEnabled(): No implementation!" );
3920 return pImp->bContextMenuHandling;
3923 void SvTreeListBox::EnableList( bool _bEnable )
3925 // call base class method
3926 Window::Enable( _bEnable != false );
3927 // then paint immediately
3928 Paint( Rectangle( Point(), GetSizePixel() ) );
3931 ::com::sun::star::uno::Reference< XAccessible > SvTreeListBox::CreateAccessible()
3933 Window* pParent = GetAccessibleParentWindow();
3934 DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" );
3936 ::com::sun::star::uno::Reference< XAccessible > xAccessible;
3937 if ( pParent )
3939 ::com::sun::star::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
3940 if ( xAccParent.is() )
3942 // need to be done here to get the vclxwindow later on in the accessbile
3943 ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xTemp(GetComponentInterface());
3944 xAccessible = pImp->m_aFactoryAccess.getFactory().createAccessibleTreeListBox( *this, xAccParent );
3947 return xAccessible;
3950 void SvTreeListBox::FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const
3952 DBG_ASSERT( pEntry, "SvTreeListBox::FillAccessibleEntryStateSet: invalid entry" );
3954 if ( pEntry->HasChildrenOnDemand() || pEntry->HasChildren() )
3956 rStateSet.AddState( AccessibleStateType::EXPANDABLE );
3957 if ( IsExpanded( pEntry ) )
3958 rStateSet.AddState( (sal_Int16)AccessibleStateType::EXPANDED );
3961 if ( GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED )
3962 rStateSet.AddState( AccessibleStateType::CHECKED );
3963 if ( IsEntryVisible( pEntry ) )
3964 rStateSet.AddState( AccessibleStateType::VISIBLE );
3965 if ( IsSelected( pEntry ) )
3966 rStateSet.AddState( AccessibleStateType::SELECTED );
3969 Rectangle SvTreeListBox::GetBoundingRect( SvTreeListEntry* pEntry )
3971 Point aPos = GetEntryPosition( pEntry );
3972 Rectangle aRect = GetFocusRect( pEntry, aPos.Y() );
3973 return aRect;
3976 void SvTreeListBox::EnableCellFocus()
3978 pImp->EnableCellFocus();
3981 void SvTreeListBox::CallImplEventListeners(sal_uLong nEvent, void* pData)
3983 CallEventListeners(nEvent, pData);
3986 void SvTreeListBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& /*rStateSet*/ ) const
3990 void SvTreeListBox::set_min_width_in_chars(sal_Int32 nChars)
3992 nMinWidthInChars = nChars;
3993 queue_resize();
3996 bool SvTreeListBox::set_property(const OString &rKey, const OString &rValue)
3998 if (rKey == "min-width-chars")
4000 set_min_width_in_chars(rValue.toInt32());
4002 else
4003 return Control::set_property(rKey, rValue);
4004 return true;
4007 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */