update credits
[LibreOffice.git] / svtools / source / contnr / treelistbox.cxx
blob0dc2350fad8242cd373b486237144e4c85ead405
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 String& 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 String 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)
406 DBG_CTOR(SvTreeListBox,0);
407 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
408 nImpFlags = 0;
409 pTargetEntry = 0;
410 nDragDropMode = 0;
411 SvTreeList* pTempModel = new SvTreeList;
412 pTempModel->SetRefCount( 0 );
413 SetBaseModel(pTempModel);
414 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
415 pModel->InsertView( this );
416 pHdlEntry = 0;
417 pEdCtrl = 0;
418 eSelMode = SINGLE_SELECTION;
419 nDragDropMode = SV_DRAGDROP_NONE;
420 SetType(WINDOW_TREELISTBOX);
422 InitTreeView();
424 SetSublistOpenWithLeftRight();
427 SvTreeListBox::SvTreeListBox(Window* pParent, const ResId& rResId) :
428 Control(pParent, rResId),
429 DropTargetHelper(this),
430 DragSourceHelper(this),
431 mpImpl(new SvTreeListBoxImpl(*this)),
432 mbContextBmpExpanded(false),
433 eSelMode(NO_SELECTION)
435 DBG_CTOR(SvTreeListBox,0);
436 pTargetEntry = 0;
437 nImpFlags = 0;
438 nDragOptions = DND_ACTION_COPYMOVE | DND_ACTION_LINK;
439 nDragDropMode = 0;
440 SvTreeList* pTempModel = new SvTreeList;
441 pTempModel->SetRefCount( 0 );
442 SetBaseModel(pTempModel);
443 pModel->InsertView( this );
444 pHdlEntry = 0;
445 pEdCtrl = 0;
446 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
447 SetType(WINDOW_TREELISTBOX);
449 InitTreeView();
450 Resize();
452 SetSublistOpenWithLeftRight();
455 extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeSvTreeListBox(Window *pParent, VclBuilder::stringmap &rMap)
457 WinBits nWinStyle = WB_TABSTOP;
458 OString sBorder = VclBuilder::extractCustomProperty(rMap);
459 if (!sBorder.isEmpty())
460 nWinStyle |= WB_BORDER;
461 return new SvTreeListBox(pParent, nWinStyle);
464 void SvTreeListBox::Clear()
466 DBG_CHKTHIS(SvTreeListBox,0);
467 pModel->Clear(); // Model calls SvTreeListBox::ModelHasCleared()
470 void SvTreeListBox::EnableEntryMnemonics( bool _bEnable )
472 if ( _bEnable == IsEntryMnemonicsEnabled() )
473 return;
475 mpImpl->m_bEntryMnemonicsEnabled = _bEnable;
476 Invalidate();
479 bool SvTreeListBox::IsEntryMnemonicsEnabled() const
481 return mpImpl->m_bEntryMnemonicsEnabled;
484 IMPL_LINK_INLINE_START( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry )
486 DBG_CHKTHIS(SvTreeListBox,0);
487 return (long)(CloneEntry((SvTreeListEntry*)pEntry));
489 IMPL_LINK_INLINE_END( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry )
491 sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos )
493 DBG_CHKTHIS(SvTreeListBox,0);
494 sal_uLong nInsPos = pModel->Insert( pEntry, pParent, nPos );
495 return nInsPos;
498 sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry,sal_uLong nRootPos )
500 DBG_CHKTHIS(SvTreeListBox,0);
501 sal_uLong nInsPos = pModel->Insert( pEntry, nRootPos );
502 return nInsPos;
505 long SvTreeListBox::ExpandingHdl()
507 DBG_CHKTHIS(SvTreeListBox,0);
508 return aExpandingHdl.IsSet() ? aExpandingHdl.Call( this ) : 1;
511 void SvTreeListBox::ExpandedHdl()
513 DBG_CHKTHIS(SvTreeListBox,0);
514 aExpandedHdl.Call( this );
517 void SvTreeListBox::SelectHdl()
519 DBG_CHKTHIS(SvTreeListBox,0);
520 aSelectHdl.Call( this );
523 void SvTreeListBox::DeselectHdl()
525 DBG_CHKTHIS(SvTreeListBox,0);
526 aDeselectHdl.Call( this );
529 sal_Bool SvTreeListBox::DoubleClickHdl()
531 DBG_CHKTHIS(SvTreeListBox,0);
532 aDoubleClickHdl.Call( this );
533 return sal_True;
537 sal_Bool SvTreeListBox::CheckDragAndDropMode( SvTreeListBox* pSource, sal_Int8 nAction )
539 DBG_CHKTHIS(SvTreeListBox,0);
540 if ( pSource == this )
542 if ( !(nDragDropMode & (SV_DRAGDROP_CTRL_MOVE | SV_DRAGDROP_CTRL_COPY) ) )
543 return sal_False; // D&D locked within list
544 if( DND_ACTION_MOVE == nAction )
546 if ( !(nDragDropMode & SV_DRAGDROP_CTRL_MOVE) )
547 return sal_False; // no local move
549 else
551 if ( !(nDragDropMode & SV_DRAGDROP_CTRL_COPY))
552 return sal_False; // no local copy
555 else
557 if ( !(nDragDropMode & SV_DRAGDROP_APP_DROP ) )
558 return sal_False; // no drop
559 if ( DND_ACTION_MOVE == nAction )
561 if ( !(nDragDropMode & SV_DRAGDROP_APP_MOVE) )
562 return sal_False; // no global move
564 else
566 if ( !(nDragDropMode & SV_DRAGDROP_APP_COPY))
567 return sal_False; // no global copy
570 return sal_True;
576 void SvTreeListBox::NotifyRemoving( SvTreeListEntry* )
578 DBG_CHKTHIS(SvTreeListBox,0);
582 NotifyMoving/Copying
583 ====================
585 default behavior:
587 1. target doesn't have children
588 - entry becomes sibling of target. entry comes after target
589 (->Window: below the target)
590 2. target is an expanded parent
591 - entry inserted at the beginning of the target childlist
592 3. target is a collapsed parent
593 - entry is inserted at the end of the target childlist
595 #ifdef DBG_UTIL
596 sal_Bool SvTreeListBox::NotifyMoving(
597 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
598 SvTreeListEntry* pEntry, // entry that we want to move, from
599 // GetSourceListBox()->GetModel()
600 SvTreeListEntry*& rpNewParent, // new target parent
601 sal_uLong& rNewChildPos) // position in childlist of target parent
602 #else
603 sal_Bool SvTreeListBox::NotifyMoving(
604 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
605 SvTreeListEntry*, // entry that we want to move, from
606 // GetSourceListBox()->GetModel()
607 SvTreeListEntry*& rpNewParent, // new target parent
608 sal_uLong& rNewChildPos) // position in childlist of target parent
609 #endif
611 DBG_CHKTHIS(SvTreeListBox,0);
612 DBG_ASSERT(pEntry,"NotifyMoving:SoureEntry?");
613 if( !pTarget )
615 rpNewParent = 0;
616 rNewChildPos = 0;
617 return sal_True;
619 if ( !pTarget->HasChildren() && !pTarget->HasChildrenOnDemand() )
621 // case 1
622 rpNewParent = GetParent( pTarget );
623 rNewChildPos = pModel->GetRelPos( pTarget ) + 1;
624 rNewChildPos += nCurEntrySelPos;
625 nCurEntrySelPos++;
627 else
629 // cases 2 & 3
630 rpNewParent = pTarget;
631 if( IsExpanded(pTarget))
632 rNewChildPos = 0;
633 else
634 rNewChildPos = LIST_APPEND;
636 return sal_True;
639 sal_Bool SvTreeListBox::NotifyCopying(
640 SvTreeListEntry* pTarget, // D&D dropping position in this->GetModel()
641 SvTreeListEntry* pEntry, // entry that we want to move, from
642 // GetSourceListBox()->GetModel()
643 SvTreeListEntry*& rpNewParent, // new target parent
644 sal_uLong& rNewChildPos) // position in childlist of target parent
646 DBG_CHKTHIS(SvTreeListBox,0);
647 return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos);
650 SvTreeListEntry* SvTreeListBox::FirstChild( SvTreeListEntry* pParent ) const
652 return pModel->FirstChild(pParent);
655 SvTreeListEntry* SvTreeListBox::NextSibling( SvTreeListEntry* pEntry ) const
657 return pModel->NextSibling(pEntry);
660 SvTreeListEntry* SvTreeListBox::PrevSibling( SvTreeListEntry* pEntry ) const
662 return pModel->PrevSibling(pEntry);
665 // return: all entries copied
666 sal_Bool SvTreeListBox::CopySelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
668 DBG_CHKTHIS(SvTreeListBox,0);
669 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
670 sal_Bool bSuccess = sal_True;
671 std::vector<SvTreeListEntry*> aList;
672 sal_Bool bClone = (sal_Bool)( (sal_uLong)(pSource->GetModel()) != (sal_uLong)GetModel() );
673 Link aCloneLink( pModel->GetCloneLink() );
674 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
676 // cache selection to simplify iterating over the selection when doing a D&D
677 // exchange within the same listbox
678 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
679 while ( pSourceEntry )
681 // children are copied automatically
682 pSource->SelectChildren( pSourceEntry, sal_False );
683 aList.push_back( pSourceEntry );
684 pSourceEntry = pSource->NextSelected( pSourceEntry );
687 std::vector<SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
688 for (; it != itEnd; ++it)
690 pSourceEntry = *it;
691 SvTreeListEntry* pNewParent = 0;
692 sal_uLong nInsertionPos = ULONG_MAX;
693 sal_Bool bOk=NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
694 if ( bOk )
696 if ( bClone )
698 sal_uLong nCloneCount = 0;
699 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
700 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
702 else
704 sal_uLong nListPos = pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
705 pSourceEntry = GetEntry( pNewParent, nListPos );
708 else
709 bSuccess = sal_False;
711 if( bOk == (sal_Bool)2 ) // HACK: make visible moved entry?
712 MakeVisible( pSourceEntry );
714 pModel->SetCloneLink( aCloneLink );
715 return bSuccess;
718 // return: all entries were moved
719 sal_Bool SvTreeListBox::MoveSelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
721 return MoveSelectionCopyFallbackPossible( pSource, pTarget, sal_False );
724 sal_Bool SvTreeListBox::MoveSelectionCopyFallbackPossible( SvTreeListBox* pSource, SvTreeListEntry* pTarget, sal_Bool bAllowCopyFallback )
726 DBG_CHKTHIS(SvTreeListBox,0);
727 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
728 sal_Bool bSuccess = sal_True;
729 std::vector<SvTreeListEntry*> aList;
730 sal_Bool bClone = (sal_Bool)( (sal_uLong)(pSource->GetModel()) != (sal_uLong)GetModel() );
731 Link aCloneLink( pModel->GetCloneLink() );
732 if ( bClone )
733 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
735 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
736 while ( pSourceEntry )
738 // children are automatically moved
739 pSource->SelectChildren( pSourceEntry, sal_False );
740 aList.push_back( pSourceEntry );
741 pSourceEntry = pSource->NextSelected( pSourceEntry );
744 std::vector<SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
745 for (; it != itEnd; ++it)
747 pSourceEntry = *it;
749 SvTreeListEntry* pNewParent = 0;
750 sal_uLong nInsertionPos = ULONG_MAX;
751 sal_Bool bOk = NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos);
752 sal_Bool bCopyOk = bOk;
753 if ( !bOk && bAllowCopyFallback )
755 nInsertionPos = LIST_APPEND;
756 bCopyOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
759 if ( bOk || bCopyOk )
761 if ( bClone )
763 sal_uLong nCloneCount = 0;
764 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
765 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
767 else
769 if ( bOk )
770 pModel->Move(pSourceEntry, pNewParent, nInsertionPos);
771 else
772 pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
775 else
776 bSuccess = sal_False;
778 if( bOk == (sal_Bool)2 ) // HACK: make moved entry visible?
779 MakeVisible( pSourceEntry );
781 pModel->SetCloneLink( aCloneLink );
782 return bSuccess;
785 void SvTreeListBox::RemoveSelection()
787 DBG_CHKTHIS(SvTreeListBox,0);
788 std::vector<const SvTreeListEntry*> aList;
789 // cache selection, as the implementation deselects everything on the first
790 // remove
791 SvTreeListEntry* pEntry = FirstSelected();
792 while ( pEntry )
794 aList.push_back( pEntry );
795 if ( pEntry->HasChildren() )
796 // remove deletes all children automatically
797 SelectChildren(pEntry, false);
798 pEntry = NextSelected( pEntry );
801 std::vector<const SvTreeListEntry*>::const_iterator it = aList.begin(), itEnd = aList.end();
802 for (; it != itEnd; ++it)
803 pModel->Remove(*it);
806 SvTreeListBox* SvTreeListBox::GetSourceView() const
808 return pDDSource;
811 void SvTreeListBox::RecalcViewData()
813 DBG_CHKTHIS(SvTreeListBox,0);
814 SvTreeListEntry* pEntry = First();
815 while( pEntry )
817 sal_uInt16 nCount = pEntry->ItemCount();
818 sal_uInt16 nCurPos = 0;
819 while ( nCurPos < nCount )
821 SvLBoxItem* pItem = pEntry->GetItem( nCurPos );
822 pItem->InitViewData( this, pEntry );
823 nCurPos++;
825 ViewDataInitialized( pEntry );
826 pEntry = Next( pEntry );
830 void SvTreeListBox::ViewDataInitialized( SvTreeListEntry* )
832 DBG_CHKTHIS(SvTreeListBox,0);
835 void SvTreeListBox::ImplShowTargetEmphasis( SvTreeListEntry* pEntry, sal_Bool bShow)
837 DBG_CHKTHIS(SvTreeListBox,0);
838 if ( bShow && (nImpFlags & SVLBOX_TARGEMPH_VIS) )
839 return;
840 if ( !bShow && !(nImpFlags & SVLBOX_TARGEMPH_VIS) )
841 return;
842 ShowTargetEmphasis( pEntry, bShow );
843 if( bShow )
844 nImpFlags |= SVLBOX_TARGEMPH_VIS;
845 else
846 nImpFlags &= ~SVLBOX_TARGEMPH_VIS;
849 void SvTreeListBox::OnCurrentEntryChanged()
851 if ( !mpImpl->m_bDoingQuickSelection )
852 mpImpl->m_aQuickSelectionEngine.Reset();
855 SvTreeListEntry* SvTreeListBox::GetEntry( SvTreeListEntry* pParent, sal_uLong nPos ) const
857 return pModel->GetEntry(pParent, nPos);
860 SvTreeListEntry* SvTreeListBox::GetEntry( sal_uLong nRootPos ) const
862 return pModel->GetEntry(nRootPos);
865 SvTreeListEntry* SvTreeListBox::GetEntryFromPath( const ::std::deque< sal_Int32 >& _rPath ) const
867 DBG_CHKTHIS(SvTreeListBox,0);
869 SvTreeListEntry* pEntry = NULL;
870 SvTreeListEntry* pParent = NULL;
871 for( ::std::deque< sal_Int32 >::const_iterator pItem = _rPath.begin(); pItem != _rPath.end(); ++pItem )
873 pEntry = GetEntry( pParent, *pItem );
874 if ( !pEntry )
875 break;
876 pParent = pEntry;
879 return pEntry;
882 void SvTreeListBox::FillEntryPath( SvTreeListEntry* pEntry, ::std::deque< sal_Int32 >& _rPath ) const
884 DBG_CHKTHIS(SvTreeListBox,0);
886 if ( pEntry )
888 SvTreeListEntry* pParentEntry = GetParent( pEntry );
889 while ( true )
891 sal_uLong i, nCount = GetLevelChildCount( pParentEntry );
892 for ( i = 0; i < nCount; ++i )
894 SvTreeListEntry* pTemp = GetEntry( pParentEntry, i );
895 DBG_ASSERT( pEntry, "invalid entry" );
896 if ( pEntry == pTemp )
898 _rPath.push_front( (sal_Int32)i );
899 break;
903 if ( pParentEntry )
905 pEntry = pParentEntry;
906 pParentEntry = GetParent( pParentEntry );
908 else
909 break;
914 const SvTreeListEntry* SvTreeListBox::GetParent( const SvTreeListEntry* pEntry ) const
916 return pModel->GetParent(pEntry);
919 SvTreeListEntry* SvTreeListBox::GetParent( SvTreeListEntry* pEntry ) const
921 return pModel->GetParent(pEntry);
924 SvTreeListEntry* SvTreeListBox::GetRootLevelParent( SvTreeListEntry* pEntry ) const
926 return pModel->GetRootLevelParent(pEntry);
929 sal_uLong SvTreeListBox::GetChildCount( SvTreeListEntry* pParent ) const
931 return pModel->GetChildCount(pParent);
934 sal_uLong SvTreeListBox::GetLevelChildCount( SvTreeListEntry* _pParent ) const
936 DBG_CHKTHIS(SvTreeListBox,0);
938 sal_uLong nCount = 0;
939 SvTreeListEntry* pEntry = FirstChild( _pParent );
940 while ( pEntry )
942 ++nCount;
943 pEntry = NextSibling( pEntry );
946 return nCount;
949 SvViewDataEntry* SvTreeListBox::GetViewDataEntry( SvTreeListEntry* pEntry ) const
951 return (SvViewDataEntry*)SvListView::GetViewData(pEntry);
954 SvViewDataItem* SvTreeListBox::GetViewDataItem(SvTreeListEntry* pEntry, SvLBoxItem* pItem)
956 return const_cast<SvViewDataItem*>(static_cast<const SvTreeListBox*>(this)->GetViewDataItem(pEntry, pItem));
959 const SvViewDataItem* SvTreeListBox::GetViewDataItem(const SvTreeListEntry* pEntry, const SvLBoxItem* pItem) const
961 const SvViewDataEntry* pEntryData = (const SvViewDataEntry*)SvListView::GetViewData(pEntry);
962 DBG_ASSERT(pEntryData,"Entry not in View");
963 sal_uInt16 nItemPos = pEntry->GetPos(pItem);
964 return pEntryData->GetItem(nItemPos);
967 SvViewDataEntry* SvTreeListBox::CreateViewData( SvTreeListEntry* )
969 DBG_CHKTHIS(SvTreeListBox,0);
970 SvViewDataEntry* pEntryData = new SvViewDataEntry;
971 return (SvViewDataEntry*)pEntryData;
974 void SvTreeListBox::InitViewData( SvViewDataEntry* pData, SvTreeListEntry* pEntry )
976 DBG_CHKTHIS(SvTreeListBox,0);
977 SvTreeListEntry* pInhEntry = (SvTreeListEntry*)pEntry;
978 SvViewDataEntry* pEntryData = (SvViewDataEntry*)pData;
980 pEntryData->Init(pInhEntry->ItemCount());
981 sal_uInt16 nCount = pInhEntry->ItemCount();
982 sal_uInt16 nCurPos = 0;
983 while( nCurPos < nCount )
985 SvLBoxItem* pItem = pInhEntry->GetItem( nCurPos );
986 SvViewDataItem* pItemData = pEntryData->GetItem(nCurPos);
987 pItem->InitViewData( this, pInhEntry, pItemData );
988 pItemData++;
989 nCurPos++;
995 void SvTreeListBox::EnableSelectionAsDropTarget( sal_Bool bEnable, sal_Bool bWithChildren )
997 DBG_CHKTHIS(SvTreeListBox,0);
998 sal_uInt16 nRefDepth;
999 SvTreeListEntry* pTemp;
1001 SvTreeListEntry* pSelEntry = FirstSelected();
1002 while( pSelEntry )
1004 if ( !bEnable )
1006 pSelEntry->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP;
1007 if ( bWithChildren )
1009 nRefDepth = pModel->GetDepth( pSelEntry );
1010 pTemp = Next( pSelEntry );
1011 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
1013 pTemp->nEntryFlags |= SV_ENTRYFLAG_DISABLE_DROP;
1014 pTemp = Next( pTemp );
1018 else
1020 pSelEntry->nEntryFlags &= (~SV_ENTRYFLAG_DISABLE_DROP);
1021 if ( bWithChildren )
1023 nRefDepth = pModel->GetDepth( pSelEntry );
1024 pTemp = Next( pSelEntry );
1025 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
1027 pTemp->nEntryFlags &= (~SV_ENTRYFLAG_DISABLE_DROP);
1028 pTemp = Next( pTemp );
1032 pSelEntry = NextSelected( pSelEntry );
1036 // ******************************************************************
1037 // InplaceEditing
1038 // ******************************************************************
1040 void SvTreeListBox::EditText( const String& rStr, const Rectangle& rRect,
1041 const Selection& rSel )
1043 EditText( rStr, rRect, rSel, sal_False );
1046 void SvTreeListBox::EditText( const String& rStr, const Rectangle& rRect,
1047 const Selection& rSel, sal_Bool bMulti )
1049 DBG_CHKTHIS(SvTreeListBox,0);
1050 if( pEdCtrl )
1051 delete pEdCtrl;
1052 nImpFlags |= SVLBOX_IN_EDT;
1053 nImpFlags &= ~SVLBOX_EDTEND_CALLED;
1054 HideFocus();
1055 pEdCtrl = new SvInplaceEdit2(
1056 this, rRect.TopLeft(), rRect.GetSize(), rStr,
1057 LINK( this, SvTreeListBox, TextEditEndedHdl_Impl ),
1058 rSel, bMulti );
1061 IMPL_LINK_NOARG(SvTreeListBox, TextEditEndedHdl_Impl)
1063 DBG_CHKTHIS(SvTreeListBox,0);
1064 if ( nImpFlags & SVLBOX_EDTEND_CALLED ) // avoid nesting
1065 return 0;
1066 nImpFlags |= SVLBOX_EDTEND_CALLED;
1067 String aStr;
1068 if ( !pEdCtrl->EditingCanceled() )
1069 aStr = pEdCtrl->GetText();
1070 else
1071 aStr = pEdCtrl->GetSavedValue();
1072 if ( IsEmptyTextAllowed() || aStr.Len() > 0 )
1073 EditedText( aStr );
1074 // Hide may only be called after the new text was put into the entry, so
1075 // that we don't call the selection handler in the GetFocus of the listbox
1076 // with the old entry text.
1077 pEdCtrl->Hide();
1078 // delete pEdCtrl;
1079 // pEdCtrl = 0;
1080 nImpFlags &= (~SVLBOX_IN_EDT);
1081 GrabFocus();
1082 return 0;
1085 void SvTreeListBox::CancelTextEditing()
1087 DBG_CHKTHIS(SvTreeListBox,0);
1088 if ( pEdCtrl )
1089 pEdCtrl->StopEditing( sal_True );
1090 nImpFlags &= (~SVLBOX_IN_EDT);
1093 void SvTreeListBox::EndEditing( bool bCancel )
1095 DBG_CHKTHIS(SvTreeListBox,0);
1096 if( pEdCtrl )
1097 pEdCtrl->StopEditing( bCancel );
1098 nImpFlags &= (~SVLBOX_IN_EDT);
1102 bool SvTreeListBox::IsEmptyTextAllowed() const
1104 DBG_CHKTHIS(SvTreeListBox,0);
1105 return mpImpl->m_bIsEmptyTextAllowed;
1108 void SvTreeListBox::ForbidEmptyText()
1110 DBG_CHKTHIS(SvTreeListBox,0);
1111 mpImpl->m_bIsEmptyTextAllowed = false;
1114 SvTreeListEntry* SvTreeListBox::CreateEntry() const
1116 DBG_CHKTHIS(SvTreeListBox,0);
1117 return new SvTreeListEntry;
1120 const void* SvTreeListBox::FirstSearchEntry( String& _rEntryText ) const
1122 SvTreeListEntry* pEntry = GetCurEntry();
1123 if ( pEntry )
1124 pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( NextSearchEntry( pEntry, _rEntryText ) ) );
1125 else
1127 pEntry = FirstSelected();
1128 if ( !pEntry )
1129 pEntry = First();
1132 if ( pEntry )
1133 _rEntryText = GetEntryText( pEntry );
1135 return pEntry;
1138 const void* SvTreeListBox::NextSearchEntry( const void* _pCurrentSearchEntry, String& _rEntryText ) const
1140 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pCurrentSearchEntry ) );
1142 if ( ( ( GetChildCount( pEntry ) > 0 )
1143 || ( pEntry->HasChildrenOnDemand() )
1145 && !IsExpanded( pEntry )
1148 pEntry = NextSibling( pEntry );
1150 else
1152 pEntry = Next( pEntry );
1155 if ( !pEntry )
1156 pEntry = First();
1158 if ( pEntry )
1159 _rEntryText = GetEntryText( pEntry );
1161 return pEntry;
1164 void SvTreeListBox::SelectSearchEntry( const void* _pEntry )
1166 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) );
1167 DBG_ASSERT( pEntry, "SvTreeListBox::SelectSearchEntry: invalid entry!" );
1168 if ( !pEntry )
1169 return;
1171 SelectAll( sal_False );
1172 SetCurEntry( pEntry );
1173 Select( pEntry );
1176 void SvTreeListBox::ExecuteSearchEntry( const void* /*_pEntry*/ ) const
1178 // nothing to do here, we have no "execution"
1181 ::vcl::StringEntryIdentifier SvTreeListBox::CurrentEntry( String& _out_entryText ) const
1183 // always accept the current entry if there is one
1184 SvTreeListEntry* pCurrentEntry( GetCurEntry() );
1185 if ( pCurrentEntry )
1187 _out_entryText = GetEntryText( pCurrentEntry );
1188 return pCurrentEntry;
1190 return FirstSearchEntry( _out_entryText );
1193 ::vcl::StringEntryIdentifier SvTreeListBox::NextEntry( ::vcl::StringEntryIdentifier _currentEntry, String& _out_entryText ) const
1195 return NextSearchEntry( _currentEntry, _out_entryText );
1198 void SvTreeListBox::SelectEntry( ::vcl::StringEntryIdentifier _entry )
1200 SelectSearchEntry( _entry );
1203 bool SvTreeListBox::HandleKeyInput( const KeyEvent& _rKEvt )
1205 if ( IsEntryMnemonicsEnabled()
1206 && mpImpl->m_aMnemonicEngine.HandleKeyEvent( _rKEvt )
1208 return true;
1210 if ( ( GetStyle() & WB_QUICK_SEARCH ) != 0 )
1212 mpImpl->m_bDoingQuickSelection = true;
1213 const bool bHandled = mpImpl->m_aQuickSelectionEngine.HandleKeyEvent( _rKEvt );
1214 mpImpl->m_bDoingQuickSelection = false;
1215 if ( bHandled )
1216 return true;
1219 return false;
1222 void SvTreeListBox::WriteDragServerInfo( const Point&, SvLBoxDDInfo* )
1224 DBG_CHKTHIS(SvTreeListBox,0);
1227 void SvTreeListBox::ReadDragServerInfo(const Point&, SvLBoxDDInfo* )
1229 DBG_CHKTHIS(SvTreeListBox,0);
1232 sal_Bool SvTreeListBox::EditingCanceled() const
1234 if( pEdCtrl && pEdCtrl->EditingCanceled() )
1235 return sal_True;
1236 return sal_False;
1240 //JP 28.3.2001: new Drag & Drop API
1241 sal_Int8 SvTreeListBox::AcceptDrop( const AcceptDropEvent& rEvt )
1243 DBG_CHKTHIS(SvTreeListBox,0);
1244 sal_Int8 nRet = DND_ACTION_NONE;
1246 if( rEvt.mbLeaving || !CheckDragAndDropMode( pDDSource, rEvt.mnAction ) )
1248 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1250 else if( !nDragDropMode )
1252 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no target" );
1254 else
1256 SvTreeListEntry* pEntry = GetDropTarget( rEvt.maPosPixel );
1257 if( !IsDropFormatSupported( SOT_FORMATSTR_ID_TREELISTBOX ) )
1259 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no format" );
1261 else
1263 DBG_ASSERT( pDDSource, "SvTreeListBox::QueryDrop(): SourceBox == 0" );
1264 if( !( pEntry && pDDSource->GetModel() == this->GetModel()
1265 && DND_ACTION_MOVE == rEvt.mnAction
1266 && ( pEntry->nEntryFlags & SV_ENTRYFLAG_DISABLE_DROP ) ))
1268 if( NotifyAcceptDrop( pEntry ))
1269 nRet = rEvt.mnAction;
1273 // **** draw emphasis ****
1274 if( DND_ACTION_NONE == nRet )
1275 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1276 else if( pEntry != pTargetEntry || !(nImpFlags & SVLBOX_TARGEMPH_VIS) )
1278 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1279 pTargetEntry = pEntry;
1280 ImplShowTargetEmphasis( pTargetEntry, sal_True );
1283 return nRet;
1286 sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvTreeListBox* pSourceView )
1288 DBG_CHKTHIS(SvTreeListBox,0);
1289 sal_Int8 nRet = DND_ACTION_NONE;
1291 DBG_ASSERT( pSourceView, "SvTreeListBox::ExecuteDrop(): no source view" );
1292 pSourceView->EnableSelectionAsDropTarget( sal_True, sal_True );
1294 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1295 pDDTarget = this;
1297 SvLBoxDDInfo aDDInfo;
1299 TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
1300 if( aData.HasFormat( SOT_FORMATSTR_ID_TREELISTBOX ))
1302 ::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
1303 if( aData.GetSequence( SOT_FORMATSTR_ID_TREELISTBOX, aSeq ) &&
1304 sizeof(SvLBoxDDInfo) == aSeq.getLength() )
1306 memcpy( &aDDInfo, aSeq.getConstArray(), sizeof(SvLBoxDDInfo) );
1307 nRet = rEvt.mnAction;
1311 if( DND_ACTION_NONE != nRet )
1313 nRet = DND_ACTION_NONE;
1315 ReadDragServerInfo( rEvt.maPosPixel, &aDDInfo );
1317 SvTreeListEntry* pTarget = pTargetEntry; // may be 0!
1319 if( DND_ACTION_COPY == rEvt.mnAction )
1321 if ( CopySelection( aDDInfo.pSource, pTarget ) )
1322 nRet = rEvt.mnAction;
1324 else if( DND_ACTION_MOVE == rEvt.mnAction )
1326 if ( MoveSelection( aDDInfo.pSource, pTarget ) )
1327 nRet = rEvt.mnAction;
1329 else if( DND_ACTION_COPYMOVE == rEvt.mnAction )
1331 if ( MoveSelectionCopyFallbackPossible( aDDInfo.pSource, pTarget, sal_True ) )
1332 nRet = rEvt.mnAction;
1335 return nRet;
1338 sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt )
1340 DBG_CHKTHIS(SvTreeListBox,0);
1341 return ExecuteDrop( rEvt, GetSourceView() );
1344 void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel )
1346 DBG_CHKTHIS(SvTreeListBox,0);
1348 Point aEventPos( rPosPixel );
1349 MouseEvent aMouseEvt( aEventPos, 1, MOUSE_SELECT, MOUSE_LEFT );
1350 MouseButtonUp( aMouseEvt );
1352 nOldDragMode = GetDragDropMode();
1353 if ( !nOldDragMode )
1354 return;
1356 ReleaseMouse();
1358 SvTreeListEntry* pEntry = GetEntry( rPosPixel ); // GetDropTarget( rPos );
1359 if( !pEntry )
1361 DragFinished( DND_ACTION_NONE );
1362 return;
1365 TransferDataContainer* pContainer = new TransferDataContainer;
1366 ::com::sun::star::uno::Reference<
1367 ::com::sun::star::datatransfer::XTransferable > xRef( pContainer );
1369 nDragDropMode = NotifyStartDrag( *pContainer, pEntry );
1370 if( !nDragDropMode || 0 == GetSelectionCount() )
1372 nDragDropMode = nOldDragMode;
1373 DragFinished( DND_ACTION_NONE );
1374 return;
1377 SvLBoxDDInfo aDDInfo;
1378 memset(&aDDInfo,0,sizeof(SvLBoxDDInfo));
1379 aDDInfo.pApp = GetpApp();
1380 aDDInfo.pSource = this;
1381 aDDInfo.pDDStartEntry = pEntry;
1382 // let derived views do their thing
1383 WriteDragServerInfo( rPosPixel, &aDDInfo );
1385 pContainer->CopyAnyData( SOT_FORMATSTR_ID_TREELISTBOX,
1386 (sal_Char*)&aDDInfo, sizeof(SvLBoxDDInfo) );
1387 pDDSource = this;
1388 pDDTarget = 0;
1390 sal_Bool bOldUpdateMode = Control::IsUpdateMode();
1391 Control::SetUpdateMode( sal_True );
1392 Update();
1393 Control::SetUpdateMode( bOldUpdateMode );
1395 // Disallow using the selection and its children as drop targets.
1396 // Important: If the selection of the SourceListBox is changed in the
1397 // DropHandler, the entries have to be allowed as drop targets again:
1398 // (GetSourceListBox()->EnableSelectionAsDropTarget( sal_True, sal_True );)
1399 EnableSelectionAsDropTarget( sal_False, sal_True /* with children */ );
1401 pContainer->StartDrag( this, nDragOptions, GetDragFinishedHdl() );
1404 void SvTreeListBox::DragFinished( sal_Int8
1405 #ifndef UNX
1406 nAction
1407 #endif
1410 EnableSelectionAsDropTarget( sal_True, sal_True );
1412 #ifndef UNX
1413 if( (nAction == DND_ACTION_MOVE) && ( (pDDTarget &&
1414 ((sal_uLong)(pDDTarget->GetModel())!=(sal_uLong)(this->GetModel()))) ||
1415 !pDDTarget ))
1417 RemoveSelection();
1419 #endif
1421 ImplShowTargetEmphasis( pTargetEntry, sal_False );
1422 pDDSource = 0;
1423 pDDTarget = 0;
1424 pTargetEntry = 0;
1425 nDragDropMode = nOldDragMode;
1428 DragDropMode SvTreeListBox::NotifyStartDrag( TransferDataContainer&, SvTreeListEntry* )
1430 DBG_CHKTHIS(SvTreeListBox,0);
1431 return (DragDropMode)0xffff;
1434 sal_Bool SvTreeListBox::NotifyAcceptDrop( SvTreeListEntry* )
1436 DBG_CHKTHIS(SvTreeListBox,0);
1437 return sal_True;
1440 // Handler and methods for Drag - finished handler.
1441 // The with get GetDragFinishedHdl() get link can set on the
1442 // TransferDataContainer. This link is a callback for the DragFinished
1443 // call. AddBox method is called from the GetDragFinishedHdl() and the
1444 // remove is called in link callback and in the destructor. So it can't
1445 // called to a deleted object.
1447 namespace
1449 struct SortLBoxes : public rtl::Static<std::set<sal_uLong>, SortLBoxes> {};
1452 void SvTreeListBox::AddBoxToDDList_Impl( const SvTreeListBox& rB )
1454 sal_uLong nVal = (sal_uLong)&rB;
1455 SortLBoxes::get().insert( nVal );
1458 void SvTreeListBox::RemoveBoxFromDDList_Impl( const SvTreeListBox& rB )
1460 sal_uLong nVal = (sal_uLong)&rB;
1461 SortLBoxes::get().erase( nVal );
1464 IMPL_STATIC_LINK( SvTreeListBox, DragFinishHdl_Impl, sal_Int8*, pAction )
1466 sal_uLong nVal = (sal_uLong)pThis;
1467 std::set<sal_uLong> &rSortLBoxes = SortLBoxes::get();
1468 std::set<sal_uLong>::const_iterator it = rSortLBoxes.find(nVal);
1469 if( it != rSortLBoxes.end() )
1471 pThis->DragFinished( *pAction );
1472 rSortLBoxes.erase( it );
1474 return 0;
1477 Link SvTreeListBox::GetDragFinishedHdl() const
1479 AddBoxToDDList_Impl( *this );
1480 return STATIC_LINK( this, SvTreeListBox, DragFinishHdl_Impl );
1484 Bugs/TODO
1486 - calculate rectangle when editing in-place (bug with some fonts)
1487 - SetSpaceBetweenEntries: offset is not taken into account in SetEntryHeight
1490 #define TREEFLAG_FIXEDHEIGHT 0x0010
1492 #define SV_LBOX_DEFAULT_INDENT_PIXEL 20
1494 void SvTreeListBox::InitTreeView()
1496 DBG_CHKTHIS(SvTreeListBox,0);
1497 pCheckButtonData = NULL;
1498 pEdEntry = NULL;
1499 pEdItem = NULL;
1500 nEntryHeight = 0;
1501 pEdCtrl = NULL;
1502 nFirstSelTab = 0;
1503 nLastSelTab = 0;
1504 nFocusWidth = -1;
1505 mnCheckboxItemWidth = 0;
1507 Link* pLink = new Link( LINK(this,SvTreeListBox, DefaultCompare) );
1508 mpImpl->m_pLink = pLink;
1510 nTreeFlags = TREEFLAG_RECALCTABS;
1511 nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL;
1512 nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL;
1513 pImp = new SvImpLBox( this, GetModel(), GetStyle() );
1515 mbContextBmpExpanded = true;
1516 nContextBmpWidthMax = 0;
1518 SetFont( GetFont() );
1519 AdjustEntryHeightAndRecalc( GetFont() );
1521 SetSpaceBetweenEntries( 0 );
1522 SetLineColor();
1523 InitSettings( sal_True, sal_True, sal_True );
1524 ImplInitStyle();
1525 SetTabs();
1529 SvTreeListBox::~SvTreeListBox()
1531 DBG_DTOR(SvTreeListBox,0);
1533 pImp->CallEventListeners( VCLEVENT_OBJECT_DYING );
1534 delete pImp;
1535 delete mpImpl->m_pLink;
1536 ClearTabList();
1538 delete pEdCtrl;
1539 pEdCtrl = 0;
1540 pModel->RemoveView( this );
1541 if ( pModel->GetRefCount() == 0 )
1543 pModel->Clear();
1544 delete pModel;
1545 pModel = NULL;
1548 SvTreeListBox::RemoveBoxFromDDList_Impl( *this );
1550 if( this == pDDSource )
1551 pDDSource = 0;
1552 if( this == pDDTarget )
1553 pDDTarget = 0;
1554 delete mpImpl;
1557 void SvTreeListBox::SetExtendedWinBits( ExtendedWinBits _nBits )
1559 pImp->SetExtendedWindowBits( _nBits );
1562 void SvTreeListBox::SetModel( SvTreeList* pNewModel )
1564 DBG_CHKTHIS(SvTreeListBox,0);
1565 pImp->SetModel( pNewModel );
1566 SetBaseModel(pNewModel);
1569 void SvTreeListBox::SetBaseModel( SvTreeList* pNewModel )
1571 // does the CleanUp
1572 SvListView::SetModel( pNewModel );
1573 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
1574 SvTreeListEntry* pEntry = First();
1575 while( pEntry )
1577 ModelHasInserted( pEntry );
1578 pEntry = Next( pEntry );
1582 void SvTreeListBox::DisconnectFromModel()
1584 DBG_CHKTHIS(SvTreeListBox,0);
1585 SvTreeList* pNewModel = new SvTreeList;
1586 pNewModel->SetRefCount( 0 ); // else this will never be deleted
1587 SvListView::SetModel( pNewModel );
1589 pImp->SetModel( GetModel() );
1592 void SvTreeListBox::SetSublistOpenWithReturn( sal_Bool b )
1594 pImp->bSubLstOpRet = b;
1597 void SvTreeListBox::SetSublistOpenWithLeftRight( sal_Bool b )
1599 pImp->bSubLstOpLR = b;
1602 void SvTreeListBox::Resize()
1604 DBG_CHKTHIS(SvTreeListBox,0);
1605 if( IsEditingActive() )
1606 EndEditing( sal_True );
1608 Control::Resize();
1610 pImp->Resize();
1611 nFocusWidth = -1;
1612 pImp->ShowCursor( sal_False );
1613 pImp->ShowCursor( sal_True );
1616 /* Cases:
1618 A) entries have bitmaps
1619 0. no buttons
1620 1. node buttons (can optionally also be on root items)
1621 2. node buttons (can optionally also be on root items) + CheckButton
1622 3. CheckButton
1623 B) entries don't have bitmaps (=>via WindowBits because of D&D!)
1624 0. no buttons
1625 1. node buttons (can optionally also be on root items)
1626 2. node buttons (can optionally also be on root items) + CheckButton
1627 3. CheckButton
1630 #define NO_BUTTONS 0
1631 #define NODE_BUTTONS 1
1632 #define NODE_AND_CHECK_BUTTONS 2
1633 #define CHECK_BUTTONS 3
1635 #define TABFLAGS_TEXT (SV_LBOXTAB_DYNAMIC | \
1636 SV_LBOXTAB_ADJUST_LEFT | \
1637 SV_LBOXTAB_EDITABLE | \
1638 SV_LBOXTAB_SHOW_SELECTION)
1640 #define TABFLAGS_CONTEXTBMP (SV_LBOXTAB_DYNAMIC | SV_LBOXTAB_ADJUST_CENTER)
1642 #define TABFLAGS_CHECKBTN (SV_LBOXTAB_DYNAMIC | \
1643 SV_LBOXTAB_ADJUST_CENTER | \
1644 SV_LBOXTAB_PUSHABLE)
1646 #define TAB_STARTPOS 2
1648 // take care of GetTextOffset when doing changes
1649 void SvTreeListBox::SetTabs()
1651 DBG_CHKTHIS(SvTreeListBox,0);
1652 if( IsEditingActive() )
1653 EndEditing( sal_True );
1654 nTreeFlags &= (~TREEFLAG_RECALCTABS);
1655 nFocusWidth = -1;
1656 const WinBits nStyle( GetStyle() );
1657 sal_Bool bHasButtons = (nStyle & WB_HASBUTTONS)!=0;
1658 sal_Bool bHasButtonsAtRoot = (nStyle & (WB_HASLINESATROOT |
1659 WB_HASBUTTONSATROOT))!=0;
1660 long nStartPos = TAB_STARTPOS;
1661 long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width();
1663 // pCheckButtonData->Width() knows nothing about the native checkbox width,
1664 // so we have mnCheckboxItemWidth which becomes valid when something is added.
1665 long nCheckWidth = 0;
1666 if( nTreeFlags & TREEFLAG_CHKBTN )
1667 nCheckWidth = mnCheckboxItemWidth;
1668 long nCheckWidthDIV2 = nCheckWidth / 2;
1670 long nContextWidth = nContextBmpWidthMax;
1671 long nContextWidthDIV2 = nContextWidth / 2;
1673 ClearTabList();
1675 int nCase = NO_BUTTONS;
1676 if( !(nTreeFlags & TREEFLAG_CHKBTN) )
1678 if( bHasButtons )
1679 nCase = NODE_BUTTONS;
1681 else
1683 if( bHasButtons )
1684 nCase = NODE_AND_CHECK_BUTTONS;
1685 else
1686 nCase = CHECK_BUTTONS;
1689 switch( nCase )
1691 case NO_BUTTONS :
1692 nStartPos += nContextWidthDIV2; // because of centering
1693 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1694 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1695 // only set a distance if there are bitmaps
1696 if( nContextBmpWidthMax )
1697 nStartPos += 5; // distance context bitmap to text
1698 AddTab( nStartPos, TABFLAGS_TEXT );
1699 break;
1701 case NODE_BUTTONS :
1702 if( bHasButtonsAtRoot )
1703 nStartPos += ( nIndent + (nNodeWidthPixel/2) );
1704 else
1705 nStartPos += nContextWidthDIV2;
1706 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1707 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1708 // only set a distance if there are bitmaps
1709 if( nContextBmpWidthMax )
1710 nStartPos += 5; // distance context bitmap to text
1711 AddTab( nStartPos, TABFLAGS_TEXT );
1712 break;
1714 case NODE_AND_CHECK_BUTTONS :
1715 if( bHasButtonsAtRoot )
1716 nStartPos += ( nIndent + nNodeWidthPixel );
1717 else
1718 nStartPos += nCheckWidthDIV2;
1719 AddTab( nStartPos, TABFLAGS_CHECKBTN );
1720 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1721 nStartPos += 3; // distance CheckButton to context bitmap
1722 nStartPos += nContextWidthDIV2; // center of context bitmap
1723 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1724 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1725 // only set a distance if there are bitmaps
1726 if( nContextBmpWidthMax )
1727 nStartPos += 5; // distance context bitmap to text
1728 AddTab( nStartPos, TABFLAGS_TEXT );
1729 break;
1731 case CHECK_BUTTONS :
1732 nStartPos += nCheckWidthDIV2;
1733 AddTab( nStartPos, TABFLAGS_CHECKBTN );
1734 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1735 nStartPos += 3; // distance CheckButton to context bitmap
1736 nStartPos += nContextWidthDIV2; // center of context bitmap
1737 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1738 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1739 // only set a distance if there are bitmaps
1740 if( nContextBmpWidthMax )
1741 nStartPos += 5; // distance context bitmap to text
1742 AddTab( nStartPos, TABFLAGS_TEXT );
1743 break;
1745 pImp->NotifyTabsChanged();
1748 void SvTreeListBox::InitEntry(SvTreeListEntry* pEntry,
1749 const OUString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp,
1750 SvLBoxButtonKind eButtonKind)
1752 DBG_CHKTHIS(SvTreeListBox,0);
1753 SvLBoxButton* pButton;
1754 SvLBoxString* pString;
1755 SvLBoxContextBmp* pContextBmp;
1757 if( nTreeFlags & TREEFLAG_CHKBTN )
1759 pButton= new SvLBoxButton( pEntry,eButtonKind,0,pCheckButtonData );
1760 pEntry->AddItem( pButton );
1763 pContextBmp= new SvLBoxContextBmp(
1764 pEntry,0, aCollEntryBmp,aExpEntryBmp, mbContextBmpExpanded);
1765 pEntry->AddItem( pContextBmp );
1767 pString = new SvLBoxString( pEntry, 0, aStr );
1768 pEntry->AddItem( pString );
1771 String SvTreeListBox::GetEntryText(SvTreeListEntry* pEntry) const
1773 DBG_CHKTHIS(SvTreeListBox,0);
1774 DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): no entry" );
1775 SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
1776 DBG_ASSERT( pEntry, "SvTreeListBox::GetEntryText(): item not found" );
1777 return pItem->GetText();
1780 String SvTreeListBox::SearchEntryText( SvTreeListEntry* pEntry ) const
1782 DBG_CHKTHIS(SvTreeListBox,0);
1783 DBG_ASSERT( pEntry, "SvTreeListBox::SearchEntryText(): no entry" );
1784 String sRet;
1785 sal_uInt16 nCount = pEntry->ItemCount();
1786 sal_uInt16 nCur = 0;
1787 SvLBoxItem* pItem;
1788 while( nCur < nCount )
1790 pItem = pEntry->GetItem( nCur );
1791 if (pItem->GetType() == SV_ITEM_ID_LBOXSTRING && !static_cast<const SvLBoxString*>(pItem)->GetText().isEmpty())
1793 sRet = static_cast<const SvLBoxString*>(pItem)->GetText();
1794 break;
1796 nCur++;
1798 return sRet;
1801 const Image& SvTreeListBox::GetExpandedEntryBmp(const SvTreeListEntry* pEntry) const
1803 DBG_CHKTHIS(SvTreeListBox,0);
1804 DBG_ASSERT(pEntry,"Entry?");
1805 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1806 DBG_ASSERT(pItem,"GetContextBmp:Item not found");
1807 return pItem->GetBitmap2( );
1810 const Image& SvTreeListBox::GetCollapsedEntryBmp( const SvTreeListEntry* pEntry ) const
1812 DBG_CHKTHIS(SvTreeListBox,0);
1813 DBG_ASSERT(pEntry,"Entry?");
1814 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1815 DBG_ASSERT(pItem,"GetContextBmp:Item not found");
1816 return pItem->GetBitmap1( );
1819 IMPL_LINK_INLINE_START( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData )
1821 DBG_CHKTHIS(SvTreeListBox,0);
1822 pHdlEntry = pData->GetActEntry();
1823 CheckButtonHdl();
1824 return 0;
1826 IMPL_LINK_INLINE_END( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData )
1828 SvTreeListEntry* SvTreeListBox::InsertEntry(
1829 const XubString& aText,
1830 SvTreeListEntry* pParent,
1831 sal_Bool bChildrenOnDemand, sal_uLong nPos,
1832 void* pUser,
1833 SvLBoxButtonKind eButtonKind
1836 DBG_CHKTHIS(SvTreeListBox,0);
1837 nTreeFlags |= TREEFLAG_MANINS;
1839 const Image& rDefExpBmp = pImp->GetDefaultEntryExpBmp( );
1840 const Image& rDefColBmp = pImp->GetDefaultEntryColBmp( );
1842 aCurInsertedExpBmp = rDefExpBmp;
1843 aCurInsertedColBmp = rDefColBmp;
1845 SvTreeListEntry* pEntry = CreateEntry();
1846 pEntry->SetUserData( pUser );
1847 InitEntry( pEntry, aText, rDefColBmp, rDefExpBmp, eButtonKind );
1848 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1850 if( !pParent )
1851 Insert( pEntry, nPos );
1852 else
1853 Insert( pEntry, pParent, nPos );
1855 aPrevInsertedExpBmp = rDefExpBmp;
1856 aPrevInsertedColBmp = rDefColBmp;
1858 nTreeFlags &= (~TREEFLAG_MANINS);
1860 return pEntry;
1863 SvTreeListEntry* SvTreeListBox::InsertEntry( const XubString& aText,
1864 const Image& aExpEntryBmp, const Image& aCollEntryBmp,
1865 SvTreeListEntry* pParent, sal_Bool bChildrenOnDemand, sal_uLong nPos, void* pUser,
1866 SvLBoxButtonKind eButtonKind )
1868 DBG_CHKTHIS(SvTreeListBox,0);
1869 nTreeFlags |= TREEFLAG_MANINS;
1871 aCurInsertedExpBmp = aExpEntryBmp;
1872 aCurInsertedColBmp = aCollEntryBmp;
1874 SvTreeListEntry* pEntry = CreateEntry();
1875 pEntry->SetUserData( pUser );
1876 InitEntry( pEntry, aText, aCollEntryBmp, aExpEntryBmp, eButtonKind );
1878 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1880 if( !pParent )
1881 Insert( pEntry, nPos );
1882 else
1883 Insert( pEntry, pParent, nPos );
1885 aPrevInsertedExpBmp = aExpEntryBmp;
1886 aPrevInsertedColBmp = aCollEntryBmp;
1888 nTreeFlags &= (~TREEFLAG_MANINS);
1890 return pEntry;
1893 void SvTreeListBox::SetEntryText( SvTreeListEntry* pEntry, const XubString& aStr)
1895 DBG_CHKTHIS(SvTreeListBox,0);
1896 SvLBoxString* pItem = (SvLBoxString*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
1897 DBG_ASSERT(pItem,"SetText:Item not found");
1898 pItem->SetText( aStr );
1899 pItem->InitViewData( this, pEntry, 0 );
1900 GetModel()->InvalidateEntry( pEntry );
1903 void SvTreeListBox::SetExpandedEntryBmp( SvTreeListEntry* pEntry, const Image& aBmp )
1905 DBG_CHKTHIS(SvTreeListBox,0);
1906 SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1908 DBG_ASSERT(pItem,"SetExpBmp:Item not found");
1909 pItem->SetBitmap2( aBmp );
1911 GetModel()->InvalidateEntry( pEntry );
1912 SetEntryHeight( pEntry );
1913 Size aSize = aBmp.GetSizePixel();
1914 short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() );
1915 if( nWidth > nContextBmpWidthMax )
1917 nContextBmpWidthMax = nWidth;
1918 SetTabs();
1922 void SvTreeListBox::SetCollapsedEntryBmp(SvTreeListEntry* pEntry,const Image& aBmp )
1924 DBG_CHKTHIS(SvTreeListBox,0);
1925 SvLBoxContextBmp* pItem = (SvLBoxContextBmp*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
1927 DBG_ASSERT(pItem,"SetExpBmp:Item not found");
1928 pItem->SetBitmap1( aBmp );
1930 GetModel()->InvalidateEntry( pEntry );
1931 SetEntryHeight( pEntry );
1932 Size aSize = aBmp.GetSizePixel();
1933 short nWidth = pImp->UpdateContextBmpWidthVector( pEntry, (short)aSize.Width() );
1934 if( nWidth > nContextBmpWidthMax )
1936 nContextBmpWidthMax = nWidth;
1937 SetTabs();
1941 void SvTreeListBox::ImpEntryInserted( SvTreeListEntry* pEntry )
1943 DBG_CHKTHIS(SvTreeListBox,0);
1945 SvTreeListEntry* pParent = (SvTreeListEntry*)pModel->GetParent( pEntry );
1946 if( pParent )
1948 sal_uInt16 nFlags = pParent->GetFlags();
1949 nFlags &= ~SV_ENTRYFLAG_NO_NODEBMP;
1950 pParent->SetFlags( nFlags );
1953 if(!((nTreeFlags & TREEFLAG_MANINS) &&
1954 (aPrevInsertedExpBmp == aCurInsertedExpBmp) &&
1955 (aPrevInsertedColBmp == aCurInsertedColBmp) ))
1957 Size aSize = GetCollapsedEntryBmp( pEntry ).GetSizePixel();
1958 if( aSize.Width() > nContextBmpWidthMax )
1960 nContextBmpWidthMax = (short)aSize.Width();
1961 nTreeFlags |= TREEFLAG_RECALCTABS;
1963 aSize = GetExpandedEntryBmp( pEntry ).GetSizePixel();
1964 if( aSize.Width() > nContextBmpWidthMax )
1966 nContextBmpWidthMax = (short)aSize.Width();
1967 nTreeFlags |= TREEFLAG_RECALCTABS;
1970 SetEntryHeight( (SvTreeListEntry*)pEntry );
1972 if( nTreeFlags & TREEFLAG_CHKBTN )
1974 SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
1975 if( pItem )
1977 long nWidth = pItem->GetSize(this, pEntry).Width();
1978 if( mnCheckboxItemWidth < nWidth )
1980 mnCheckboxItemWidth = nWidth;
1981 nTreeFlags |= TREEFLAG_RECALCTABS;
1989 void SvTreeListBox::SetCheckButtonState( SvTreeListEntry* pEntry, SvButtonState eState)
1991 DBG_CHKTHIS(SvTreeListBox,0);
1992 if( nTreeFlags & TREEFLAG_CHKBTN )
1994 SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
1995 if(!(pItem && pItem->CheckModification()))
1996 return ;
1997 switch( eState )
1999 case SV_BUTTON_CHECKED:
2000 pItem->SetStateChecked();
2001 break;
2003 case SV_BUTTON_UNCHECKED:
2004 pItem->SetStateUnchecked();
2005 break;
2007 case SV_BUTTON_TRISTATE:
2008 pItem->SetStateTristate();
2009 break;
2011 InvalidateEntry( pEntry );
2015 SvButtonState SvTreeListBox::GetCheckButtonState( SvTreeListEntry* pEntry ) const
2017 DBG_CHKTHIS(SvTreeListBox,0);
2018 SvButtonState eState = SV_BUTTON_UNCHECKED;
2019 if( nTreeFlags & TREEFLAG_CHKBTN )
2021 SvLBoxButton* pItem = (SvLBoxButton*)(pEntry->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
2022 if(!pItem)
2023 return SV_BUTTON_TRISTATE;
2024 sal_uInt16 nButtonFlags = pItem->GetButtonFlags();
2025 eState = pCheckButtonData->ConvertToButtonState( nButtonFlags );
2027 return eState;
2030 void SvTreeListBox::CheckButtonHdl()
2032 DBG_CHKTHIS(SvTreeListBox,0);
2033 aCheckButtonHdl.Call( this );
2034 if ( pCheckButtonData )
2035 pImp->CallEventListeners( VCLEVENT_CHECKBOX_TOGGLE, (void*)pCheckButtonData->GetActEntry() );
2039 // TODO: Currently all data is cloned so that they conform to the default tree
2040 // view format. Actually, the model should be used as a reference here. This
2041 // leads to us _not_ calling SvTreeListEntry::Clone, but only its base class
2042 // SvTreeListEntry.
2045 SvTreeListEntry* SvTreeListBox::CloneEntry( SvTreeListEntry* pSource )
2047 DBG_CHKTHIS(SvTreeListBox,0);
2048 XubString aStr;
2049 Image aCollEntryBmp;
2050 Image aExpEntryBmp;
2051 SvLBoxButtonKind eButtonKind = SvLBoxButtonKind_enabledCheckbox;
2053 SvLBoxString* pStringItem = (SvLBoxString*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXSTRING));
2054 if( pStringItem )
2055 aStr = pStringItem->GetText();
2056 SvLBoxContextBmp* pBmpItem = (SvLBoxContextBmp*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXCONTEXTBMP));
2057 if( pBmpItem )
2059 aCollEntryBmp = pBmpItem->GetBitmap1( );
2060 aExpEntryBmp = pBmpItem->GetBitmap2( );
2062 SvLBoxButton* pButtonItem = (SvLBoxButton*)(pSource->GetFirstItem(SV_ITEM_ID_LBOXBUTTON));
2063 if( pButtonItem )
2064 eButtonKind = pButtonItem->GetKind();
2065 SvTreeListEntry* pClone = CreateEntry();
2066 InitEntry( pClone, aStr, aCollEntryBmp, aExpEntryBmp, eButtonKind );
2067 pClone->SvTreeListEntry::Clone( pSource );
2068 pClone->EnableChildrenOnDemand( pSource->HasChildrenOnDemand() );
2069 pClone->SetUserData( pSource->GetUserData() );
2071 return pClone;
2074 void SvTreeListBox::SetIndent( short nNewIndent )
2076 DBG_CHKTHIS(SvTreeListBox,0);
2077 nIndent = nNewIndent;
2078 SetTabs();
2079 if( IsUpdateMode() )
2080 Invalidate();
2083 const Image& SvTreeListBox::GetDefaultExpandedEntryBmp( ) const
2085 return pImp->GetDefaultEntryExpBmp( );
2088 const Image& SvTreeListBox::GetDefaultCollapsedEntryBmp( ) const
2090 return pImp->GetDefaultEntryColBmp( );
2093 void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp )
2095 DBG_CHKTHIS(SvTreeListBox,0);
2096 Size aSize = aBmp.GetSizePixel();
2097 if( aSize.Width() > nContextBmpWidthMax )
2098 nContextBmpWidthMax = (short)aSize.Width();
2099 SetTabs();
2101 pImp->SetDefaultEntryExpBmp( aBmp );
2104 void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp )
2106 DBG_CHKTHIS(SvTreeListBox,0);
2107 Size aSize = aBmp.GetSizePixel();
2108 if( aSize.Width() > nContextBmpWidthMax )
2109 nContextBmpWidthMax = (short)aSize.Width();
2110 SetTabs();
2112 pImp->SetDefaultEntryColBmp( aBmp );
2115 void SvTreeListBox::EnableCheckButton( SvLBoxButtonData* pData )
2117 DBG_CHKTHIS(SvTreeListBox,0);
2118 DBG_ASSERT(!GetEntryCount(),"EnableCheckButton: Entry count != 0");
2119 if( !pData )
2120 nTreeFlags &= (~TREEFLAG_CHKBTN);
2121 else
2123 SetCheckButtonData( pData );
2124 nTreeFlags |= TREEFLAG_CHKBTN;
2125 pData->SetLink( LINK(this, SvTreeListBox, CheckButtonClick));
2128 SetTabs();
2129 if( IsUpdateMode() )
2130 Invalidate();
2133 void SvTreeListBox::SetCheckButtonData( SvLBoxButtonData* pData )
2135 DBG_CHKTHIS(SvTreeListBox,0);
2136 if ( pData )
2137 pCheckButtonData = pData;
2140 const Image& SvTreeListBox::GetDefaultExpandedNodeImage( )
2142 return SvImpLBox::GetDefaultExpandedNodeImage( );
2145 const Image& SvTreeListBox::GetDefaultCollapsedNodeImage( )
2147 return SvImpLBox::GetDefaultCollapsedNodeImage( );
2150 void SvTreeListBox::SetNodeBitmaps( const Image& rCollapsedNodeBmp, const Image& rExpandedNodeBmp )
2152 DBG_CHKTHIS(SvTreeListBox,0);
2153 SetExpandedNodeBmp( rExpandedNodeBmp );
2154 SetCollapsedNodeBmp( rCollapsedNodeBmp );
2155 SetTabs();
2158 sal_Bool SvTreeListBox::EditingEntry( SvTreeListEntry*, Selection& )
2160 DBG_CHKTHIS(SvTreeListBox,0);
2161 return sal_True;
2164 sal_Bool SvTreeListBox::EditedEntry( SvTreeListEntry* /*pEntry*/,const OUString& /*rNewText*/)
2166 DBG_CHKTHIS(SvTreeListBox,0);
2167 return sal_True;
2170 void SvTreeListBox::EnableInplaceEditing( bool bOn )
2172 DBG_CHKTHIS(SvTreeListBox,0);
2173 if (bOn)
2174 nImpFlags |= SVLBOX_EDT_ENABLED;
2175 else
2176 nImpFlags &= ~SVLBOX_EDT_ENABLED;
2179 void SvTreeListBox::KeyInput( const KeyEvent& rKEvt )
2181 DBG_CHKTHIS(SvTreeListBox,0);
2182 // under OS/2, we get key up/down even while editing
2183 if( IsEditingActive() )
2184 return;
2186 nImpFlags |= SVLBOX_IS_TRAVELSELECT;
2188 #ifdef OVDEBUG
2189 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
2190 switch ( nCode )
2192 case KEY_F1:
2194 SvTreeListEntry* pEntry = First();
2195 pEntry = NextVisible( pEntry );
2196 SetEntryText( pEntry, "SetEntryText" );
2198 break;
2200 #endif
2202 if( !pImp->KeyInput( rKEvt ) )
2204 bool bHandled = HandleKeyInput( rKEvt );
2205 if ( !bHandled )
2206 Control::KeyInput( rKEvt );
2209 nImpFlags &= ~SVLBOX_IS_TRAVELSELECT;
2212 void SvTreeListBox::RequestingChildren( SvTreeListEntry* pParent )
2214 DBG_CHKTHIS(SvTreeListBox,0);
2215 if( !pParent->HasChildren() )
2216 InsertEntry( OUString("<dummy>"), pParent, sal_False, LIST_APPEND );
2219 void SvTreeListBox::GetFocus()
2221 DBG_CHKTHIS(SvTreeListBox,0);
2222 pImp->GetFocus();
2223 Control::GetFocus();
2225 SvTreeListEntry* pEntry = FirstSelected();
2226 if ( pEntry )
2227 pImp->CallEventListeners( VCLEVENT_LISTBOX_SELECT, pEntry );
2231 void SvTreeListBox::LoseFocus()
2233 DBG_CHKTHIS(SvTreeListBox,0);
2234 pImp->LoseFocus();
2235 Control::LoseFocus();
2238 void SvTreeListBox::ModelHasCleared()
2240 DBG_CHKTHIS(SvTreeListBox,0);
2241 pImp->pCursor = 0; // else we crash in GetFocus when editing in-place
2242 delete pEdCtrl;
2243 pEdCtrl = NULL;
2244 pImp->Clear();
2245 nFocusWidth = -1;
2247 nContextBmpWidthMax = 0;
2248 SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() );
2249 SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() );
2251 if( !(nTreeFlags & TREEFLAG_FIXEDHEIGHT ))
2252 nEntryHeight = 0;
2253 AdjustEntryHeight( GetFont() );
2254 AdjustEntryHeight( GetDefaultExpandedEntryBmp() );
2255 AdjustEntryHeight( GetDefaultCollapsedEntryBmp() );
2257 SvListView::ModelHasCleared();
2260 void SvTreeListBox::ShowTargetEmphasis( SvTreeListEntry* pEntry, sal_Bool /*bShow*/ )
2262 DBG_CHKTHIS(SvTreeListBox,0);
2263 pImp->PaintDDCursor( pEntry );
2266 void SvTreeListBox::ScrollOutputArea( short nDeltaEntries )
2268 DBG_CHKTHIS(SvTreeListBox,0);
2269 if( !nDeltaEntries || !pImp->aVerSBar.IsVisible() )
2270 return;
2272 long nThumb = pImp->aVerSBar.GetThumbPos();
2273 long nMax = pImp->aVerSBar.GetRange().Max();
2275 NotifyBeginScroll();
2276 if( nDeltaEntries < 0 )
2278 // move window up
2279 nDeltaEntries *= -1;
2280 long nVis = pImp->aVerSBar.GetVisibleSize();
2281 long nTemp = nThumb + nVis;
2282 if( nDeltaEntries > (nMax - nTemp) )
2283 nDeltaEntries = (short)(nMax - nTemp);
2284 pImp->PageDown( (sal_uInt16)nDeltaEntries );
2286 else
2288 if( nDeltaEntries > nThumb )
2289 nDeltaEntries = (short)nThumb;
2290 pImp->PageUp( (sal_uInt16)nDeltaEntries );
2292 pImp->SyncVerThumb();
2293 NotifyEndScroll();
2296 void SvTreeListBox::ScrollToAbsPos( long nPos )
2298 pImp->ScrollToAbsPos( nPos );
2301 void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode )
2303 DBG_CHKTHIS(SvTreeListBox,0);
2304 eSelMode = eSelectMode;
2305 pImp->SetSelectionMode( eSelectMode );
2308 void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode )
2310 DBG_CHKTHIS(SvTreeListBox,0);
2311 nDragDropMode = nDDMode;
2312 pImp->SetDragDropMode( nDDMode );
2315 short SvTreeListBox::GetHeightOffset(const Image& rBmp, Size& aSizeLogic )
2317 DBG_CHKTHIS(SvTreeListBox,0);
2318 short nOffset = 0;
2319 aSizeLogic = rBmp.GetSizePixel();
2320 if( GetEntryHeight() > aSizeLogic.Height() )
2321 nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2;
2322 return nOffset;
2325 short SvTreeListBox::GetHeightOffset(const Font& /* rFont */, Size& aSizeLogic )
2327 DBG_CHKTHIS(SvTreeListBox,0);
2328 short nOffset = 0;
2329 aSizeLogic = Size(GetTextWidth(OUString('X')), GetTextHeight());
2330 if( GetEntryHeight() > aSizeLogic.Height() )
2331 nOffset = ( GetEntryHeight() - (short)aSizeLogic.Height()) / 2;
2332 return nOffset;
2335 void SvTreeListBox::SetEntryHeight( SvTreeListEntry* pEntry )
2337 DBG_CHKTHIS(SvTreeListBox,0);
2338 short nHeight, nHeightMax=0;
2339 sal_uInt16 nCount = pEntry->ItemCount();
2340 sal_uInt16 nCur = 0;
2341 SvViewDataEntry* pViewData = GetViewDataEntry( pEntry );
2342 while( nCur < nCount )
2344 SvLBoxItem* pItem = pEntry->GetItem( nCur );
2345 nHeight = (short)(pItem->GetSize( pViewData, nCur ).Height());
2346 if( nHeight > nHeightMax )
2347 nHeightMax = nHeight;
2348 nCur++;
2351 if( nHeightMax > nEntryHeight )
2353 nEntryHeight = nHeightMax;
2354 Control::SetFont( GetFont() );
2355 pImp->SetEntryHeight( nHeightMax );
2359 void SvTreeListBox::SetEntryHeight( short nHeight, sal_Bool bAlways )
2361 DBG_CHKTHIS(SvTreeListBox,0);
2363 if( bAlways || nHeight > nEntryHeight )
2365 nEntryHeight = nHeight;
2366 if( nEntryHeight )
2367 nTreeFlags |= TREEFLAG_FIXEDHEIGHT;
2368 else
2369 nTreeFlags &= ~TREEFLAG_FIXEDHEIGHT;
2370 Control::SetFont( GetFont() );
2371 pImp->SetEntryHeight( nHeight );
2376 void SvTreeListBox::AdjustEntryHeight( const Image& rBmp )
2378 DBG_CHKTHIS(SvTreeListBox,0);
2379 Size aSize;
2380 GetHeightOffset( rBmp, aSize );
2381 if( aSize.Height() > nEntryHeight )
2383 nEntryHeight = (short)aSize.Height() + nEntryHeightOffs;
2384 pImp->SetEntryHeight( nEntryHeight );
2388 void SvTreeListBox::AdjustEntryHeight( const Font& rFont )
2390 DBG_CHKTHIS(SvTreeListBox,0);
2391 Size aSize;
2392 GetHeightOffset( rFont, aSize );
2393 if( aSize.Height() > nEntryHeight )
2395 nEntryHeight = (short)aSize.Height() + nEntryHeightOffs;
2396 pImp->SetEntryHeight( nEntryHeight );
2400 sal_Bool SvTreeListBox::Expand( SvTreeListEntry* pParent )
2402 DBG_CHKTHIS(SvTreeListBox,0);
2403 pHdlEntry = pParent;
2404 sal_Bool bExpanded = sal_False;
2405 sal_uInt16 nFlags;
2407 if( pParent->HasChildrenOnDemand() )
2408 RequestingChildren( pParent );
2409 if( pParent->HasChildren() )
2411 nImpFlags |= SVLBOX_IS_EXPANDING;
2412 if( ExpandingHdl() )
2414 bExpanded = sal_True;
2415 SvListView::Expand( pParent );
2416 pImp->EntryExpanded( pParent );
2417 pHdlEntry = pParent;
2418 ExpandedHdl();
2420 nFlags = pParent->GetFlags();
2421 nFlags &= ~SV_ENTRYFLAG_NO_NODEBMP;
2422 nFlags |= SV_ENTRYFLAG_HAD_CHILDREN;
2423 pParent->SetFlags( nFlags );
2425 else
2427 nFlags = pParent->GetFlags();
2428 nFlags |= SV_ENTRYFLAG_NO_NODEBMP;
2429 pParent->SetFlags( nFlags );
2430 GetModel()->InvalidateEntry( pParent ); // repaint
2433 // #i92103#
2434 if ( bExpanded )
2436 pImp->CallEventListeners( VCLEVENT_ITEM_EXPANDED, pParent );
2439 return bExpanded;
2442 sal_Bool SvTreeListBox::Collapse( SvTreeListEntry* pParent )
2444 DBG_CHKTHIS(SvTreeListBox,0);
2445 nImpFlags &= ~SVLBOX_IS_EXPANDING;
2446 pHdlEntry = pParent;
2447 sal_Bool bCollapsed = sal_False;
2449 if( ExpandingHdl() )
2451 bCollapsed = sal_True;
2452 pImp->CollapsingEntry( pParent );
2453 SvListView::Collapse( pParent );
2454 pImp->EntryCollapsed( pParent );
2455 pHdlEntry = pParent;
2456 ExpandedHdl();
2459 // #i92103#
2460 if ( bCollapsed )
2462 pImp->CallEventListeners( VCLEVENT_ITEM_COLLAPSED, pParent );
2465 return bCollapsed;
2468 sal_Bool SvTreeListBox::Select( SvTreeListEntry* pEntry, sal_Bool bSelect )
2470 DBG_CHKTHIS(SvTreeListBox,0);
2471 DBG_ASSERT(pEntry,"Select: Null-Ptr");
2472 sal_Bool bRetVal = SvListView::Select( pEntry, bSelect );
2473 DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed");
2474 if( bRetVal )
2476 pImp->EntrySelected( pEntry, bSelect );
2477 pHdlEntry = pEntry;
2478 if( bSelect )
2480 SelectHdl();
2481 pImp->CallEventListeners( VCLEVENT_LISTBOX_SELECT, pEntry );
2483 else
2484 DeselectHdl();
2486 return bRetVal;
2489 sal_uLong SvTreeListBox::SelectChildren( SvTreeListEntry* pParent, sal_Bool bSelect )
2491 DBG_CHKTHIS(SvTreeListBox,0);
2492 pImp->DestroyAnchor();
2493 sal_uLong nRet = 0;
2494 if( !pParent->HasChildren() )
2495 return 0;
2496 sal_uInt16 nRefDepth = pModel->GetDepth( pParent );
2497 SvTreeListEntry* pChild = FirstChild( pParent );
2498 do {
2499 nRet++;
2500 Select( pChild, bSelect );
2501 pChild = Next( pChild );
2502 } while( pChild && pModel->GetDepth( pChild ) > nRefDepth );
2503 return nRet;
2506 void SvTreeListBox::SelectAll( sal_Bool bSelect, sal_Bool )
2508 DBG_CHKTHIS(SvTreeListBox,0);
2509 pImp->SelAllDestrAnch(
2510 bSelect,
2511 sal_True, // delete anchor,
2512 sal_True ); // even when using SINGLE_SELECTION, deselect the cursor
2515 void SvTreeListBox::ModelHasInsertedTree( SvTreeListEntry* pEntry )
2517 DBG_CHKTHIS(SvTreeListBox,0);
2518 sal_uInt16 nRefDepth = pModel->GetDepth( (SvTreeListEntry*)pEntry );
2519 SvTreeListEntry* pTmp = (SvTreeListEntry*)pEntry;
2522 ImpEntryInserted( pTmp );
2523 pTmp = Next( pTmp );
2524 } while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) );
2525 pImp->TreeInserted( (SvTreeListEntry*)pEntry );
2528 void SvTreeListBox::ModelHasInserted( SvTreeListEntry* pEntry )
2530 DBG_CHKTHIS(SvTreeListBox,0);
2531 ImpEntryInserted( (SvTreeListEntry*)pEntry );
2532 pImp->EntryInserted( (SvTreeListEntry*)pEntry );
2535 void SvTreeListBox::ModelIsMoving(SvTreeListEntry* pSource,
2536 SvTreeListEntry* /* pTargetParent */,
2537 sal_uLong /* nChildPos */ )
2539 DBG_CHKTHIS(SvTreeListBox,0);
2540 pImp->MovingEntry( (SvTreeListEntry*)pSource );
2543 void SvTreeListBox::ModelHasMoved( SvTreeListEntry* pSource )
2545 DBG_CHKTHIS(SvTreeListBox,0);
2546 pImp->EntryMoved( (SvTreeListEntry*)pSource );
2549 void SvTreeListBox::ModelIsRemoving( SvTreeListEntry* pEntry )
2551 DBG_CHKTHIS(SvTreeListBox,0);
2552 if(pEdEntry == pEntry)
2553 pEdEntry = NULL;
2555 pImp->RemovingEntry( (SvTreeListEntry*)pEntry );
2556 NotifyRemoving( (SvTreeListEntry*)pEntry );
2559 void SvTreeListBox::ModelHasRemoved( SvTreeListEntry* pEntry )
2561 DBG_CHKTHIS(SvTreeListBox,0);
2562 if ( pEntry == pHdlEntry)
2563 pHdlEntry = NULL;
2564 pImp->EntryRemoved();
2567 void SvTreeListBox::SetCollapsedNodeBmp( const Image& rBmp)
2569 DBG_CHKTHIS(SvTreeListBox,0);
2570 AdjustEntryHeight( rBmp );
2571 pImp->SetCollapsedNodeBmp( rBmp );
2574 void SvTreeListBox::SetExpandedNodeBmp( const Image& rBmp )
2576 DBG_CHKTHIS(SvTreeListBox,0);
2577 AdjustEntryHeight( rBmp );
2578 pImp->SetExpandedNodeBmp( rBmp );
2582 void SvTreeListBox::SetFont( const Font& rFont )
2584 DBG_CHKTHIS(SvTreeListBox,0);
2586 Font aTempFont( rFont );
2587 Font aOrigFont( GetFont() );
2588 aTempFont.SetTransparent( sal_True );
2589 if (aTempFont == aOrigFont)
2590 return;
2591 Control::SetFont( aTempFont );
2593 aTempFont.SetColor(aOrigFont.GetColor());
2594 aTempFont.SetFillColor(aOrigFont.GetFillColor());
2595 aTempFont.SetTransparent(aOrigFont.IsTransparent());
2597 if (aTempFont == aOrigFont)
2598 return;
2600 AdjustEntryHeightAndRecalc( GetFont() );
2603 void SvTreeListBox::AdjustEntryHeightAndRecalc( const Font& rFont )
2605 DBG_CHKTHIS(SvTreeListBox,0);
2606 AdjustEntryHeight( rFont );
2607 // always invalidate, else things go wrong in SetEntryHeight
2608 RecalcViewData();
2611 void SvTreeListBox::Paint( const Rectangle& rRect )
2613 DBG_CHKTHIS(SvTreeListBox,0);
2614 Control::Paint( rRect );
2615 if( nTreeFlags & TREEFLAG_RECALCTABS )
2616 SetTabs();
2617 pImp->Paint( rRect );
2620 void SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt )
2622 DBG_CHKTHIS(SvTreeListBox,0);
2623 pImp->MouseButtonDown( rMEvt );
2626 void SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt )
2628 DBG_CHKTHIS(SvTreeListBox,0);
2629 pImp->MouseButtonUp( rMEvt );
2632 void SvTreeListBox::MouseMove( const MouseEvent& rMEvt )
2634 DBG_CHKTHIS(SvTreeListBox,0);
2635 pImp->MouseMove( rMEvt );
2639 void SvTreeListBox::SetUpdateMode( sal_Bool bUpdate )
2641 DBG_CHKTHIS(SvTreeListBox,0);
2642 pImp->SetUpdateMode( bUpdate );
2645 void SvTreeListBox::SetSpaceBetweenEntries( short nOffsLogic )
2647 DBG_CHKTHIS(SvTreeListBox,0);
2648 if( nOffsLogic != nEntryHeightOffs )
2650 nEntryHeight = nEntryHeight - nEntryHeightOffs;
2651 nEntryHeightOffs = (short)nOffsLogic;
2652 nEntryHeight = nEntryHeight + nOffsLogic;
2653 AdjustEntryHeightAndRecalc( GetFont() );
2654 pImp->SetEntryHeight( nEntryHeight );
2658 void SvTreeListBox::SetCursor( SvTreeListEntry* pEntry, sal_Bool bForceNoSelect )
2660 DBG_CHKTHIS(SvTreeListBox,0);
2661 pImp->SetCursor(pEntry, bForceNoSelect);
2664 void SvTreeListBox::SetCurEntry( SvTreeListEntry* pEntry )
2666 DBG_CHKTHIS(SvTreeListBox,0);
2667 pImp->SetCurEntry( pEntry );
2670 Image SvTreeListBox::GetExpandedNodeBmp( ) const
2672 return pImp->GetExpandedNodeBmp( );
2675 Point SvTreeListBox::GetEntryPosition( SvTreeListEntry* pEntry ) const
2677 return pImp->GetEntryPosition( pEntry );
2680 void SvTreeListBox::ShowEntry( SvTreeListEntry* pEntry )
2682 MakeVisible( pEntry );
2685 void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry )
2687 pImp->MakeVisible(pEntry);
2690 void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry, sal_Bool bMoveToTop )
2692 pImp->MakeVisible( pEntry, bMoveToTop );
2695 void SvTreeListBox::ModelHasEntryInvalidated( SvTreeListEntry* pEntry )
2697 DBG_CHKTHIS(SvTreeListBox,0);
2699 // reinitialize the separate items of the entries
2700 sal_uInt16 nCount = ((SvTreeListEntry*)pEntry)->ItemCount();
2701 for( sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++ )
2703 SvLBoxItem* pItem = ((SvTreeListEntry*)pEntry)->GetItem( nIdx );
2704 pItem->InitViewData( this, (SvTreeListEntry*)pEntry, 0 );
2707 // repaint
2708 pImp->InvalidateEntry( (SvTreeListEntry*)pEntry );
2711 void SvTreeListBox::EditItemText( SvTreeListEntry* pEntry, SvLBoxString* pItem,
2712 const Selection& rSelection )
2714 DBG_CHKTHIS(SvTreeListBox,0);
2715 DBG_ASSERT(pEntry&&pItem,"EditItemText: Bad params");
2716 if( IsSelected( pEntry ))
2718 pImp->ShowCursor( sal_False );
2719 SvListView::Select( pEntry, sal_False );
2720 PaintEntry( pEntry );
2721 SvListView::Select( pEntry, sal_True );
2722 pImp->ShowCursor( sal_True );
2724 pEdEntry = pEntry;
2725 pEdItem = pItem;
2726 SvLBoxTab* pTab = GetTab( pEntry, pItem );
2727 DBG_ASSERT(pTab,"EditItemText:Tab not found");
2729 Size aItemSize( pItem->GetSize(this, pEntry) );
2730 Point aPos = GetEntryPosition( pEntry );
2731 aPos.Y() += ( nEntryHeight - aItemSize.Height() ) / 2;
2732 aPos.X() = GetTabPos( pEntry, pTab );
2733 long nOutputWidth = pImp->GetOutputSize().Width();
2734 Size aSize( nOutputWidth - aPos.X(), aItemSize.Height() );
2735 sal_uInt16 nPos = std::find( aTabs.begin(), aTabs.end(), pTab ) - aTabs.begin();
2736 if( nPos+1 < (sal_uInt16)aTabs.size() )
2738 SvLBoxTab* pRightTab = aTabs[ nPos + 1 ];
2739 long nRight = GetTabPos( pEntry, pRightTab );
2740 if( nRight <= nOutputWidth )
2741 aSize.Width() = nRight - aPos.X();
2743 Point aOrigin( GetMapMode().GetOrigin() );
2744 aPos += aOrigin; // convert to win coordinates
2745 aSize.Width() -= aOrigin.X();
2746 Rectangle aRect( aPos, aSize );
2747 EditText( pItem->GetText(), aRect, rSelection );
2750 void SvTreeListBox::EditEntry( SvTreeListEntry* pEntry )
2752 pImp->aEditClickPos = Point( -1, -1 );
2753 ImplEditEntry( pEntry );
2756 void SvTreeListBox::ImplEditEntry( SvTreeListEntry* pEntry )
2758 DBG_CHKTHIS(SvTreeListBox,0);
2759 if( IsEditingActive() )
2760 EndEditing();
2761 if( !pEntry )
2762 pEntry = GetCurEntry();
2763 if( pEntry )
2765 long nClickX = pImp->aEditClickPos.X();
2766 bool bIsMouseTriggered = nClickX >= 0;
2768 SvLBoxString* pItem = NULL;
2769 sal_uInt16 nCount = pEntry->ItemCount();
2770 long nTabPos, nNextTabPos = 0;
2771 for( sal_uInt16 i = 0 ; i < nCount ; i++ )
2773 SvLBoxItem* pTmpItem = pEntry->GetItem( i );
2774 if (pTmpItem->GetType() != SV_ITEM_ID_LBOXSTRING)
2775 continue;
2777 SvLBoxTab* pTab = GetTab( pEntry, pTmpItem );
2778 nNextTabPos = -1;
2779 if( i < nCount - 1 )
2781 SvLBoxItem* pNextItem = pEntry->GetItem( i + 1 );
2782 SvLBoxTab* pNextTab = GetTab( pEntry, pNextItem );
2783 nNextTabPos = pNextTab->GetPos();
2786 if( pTab && pTab->IsEditable() )
2788 nTabPos = pTab->GetPos();
2789 if( !bIsMouseTriggered || (nClickX > nTabPos && (nNextTabPos == -1 || nClickX < nNextTabPos ) ) )
2791 pItem = static_cast<SvLBoxString*>( pTmpItem );
2792 break;
2797 Selection aSel( SELECTION_MIN, SELECTION_MAX );
2798 if( pItem && EditingEntry( pEntry, aSel ) )
2800 SelectAll( sal_False );
2801 MakeVisible( pEntry );
2802 EditItemText( pEntry, pItem, aSel );
2807 sal_Bool SvTreeListBox::AreChildrenTransient() const
2809 return pImp->AreChildrenTransient();
2812 void SvTreeListBox::SetChildrenNotTransient()
2814 pImp->SetChildrenNotTransient();
2817 void SvTreeListBox::EditedText( const XubString& rStr )
2820 DBG_CHKTHIS(SvTreeListBox,0);
2821 if(pEdEntry) // we have to check if this entry is null that means that it is removed while editing
2823 if( EditedEntry( pEdEntry, rStr ) )
2825 ((SvLBoxString*)pEdItem)->SetText( rStr );
2826 pModel->InvalidateEntry( pEdEntry );
2828 if( GetSelectionCount() == 0 )
2829 Select( pEdEntry );
2830 if( GetSelectionMode() == MULTIPLE_SELECTION && !GetCurEntry() )
2831 SetCurEntry( pEdEntry );
2835 SvTreeListEntry* SvTreeListBox::GetDropTarget( const Point& rPos )
2837 DBG_CHKTHIS(SvTreeListBox,0);
2838 // scroll
2839 if( rPos.Y() < 12 )
2841 ImplShowTargetEmphasis(pTargetEntry, false);
2842 ScrollOutputArea( +1 );
2844 else
2846 Size aSize( pImp->GetOutputSize() );
2847 if( rPos.Y() > aSize.Height() - 12 )
2849 ImplShowTargetEmphasis(pTargetEntry, false);
2850 ScrollOutputArea( -1 );
2854 SvTreeListEntry* pTarget = pImp->GetEntry( rPos );
2855 // when dropping in a vacant space, use the last entry
2856 if( !pTarget )
2857 return (SvTreeListEntry*)LastVisible();
2858 else if( (GetDragDropMode() & SV_DRAGDROP_ENABLE_TOP) &&
2859 pTarget == First() && rPos.Y() < 6 )
2860 return 0;
2862 return pTarget;
2866 SvTreeListEntry* SvTreeListBox::GetEntry( const Point& rPos, sal_Bool bHit ) const
2868 DBG_CHKTHIS(SvTreeListBox,0);
2869 SvTreeListEntry* pEntry = pImp->GetEntry( rPos );
2870 if( pEntry && bHit )
2872 long nLine = pImp->GetEntryLine( pEntry );
2873 if( !(pImp->EntryReallyHit( pEntry, rPos, nLine)) )
2874 return 0;
2876 return pEntry;
2879 SvTreeListEntry* SvTreeListBox::GetCurEntry() const
2881 DBG_CHKTHIS(SvTreeListBox,0);
2882 return pImp->GetCurEntry();
2885 void SvTreeListBox::ImplInitStyle()
2887 DBG_CHKTHIS(SvTreeListBox,0);
2889 const WinBits nWindowStyle = GetStyle();
2891 nTreeFlags |= TREEFLAG_RECALCTABS;
2892 if( nWindowStyle & WB_SORT )
2894 GetModel()->SetSortMode( SortAscending );
2895 GetModel()->SetCompareHdl( LINK(this,SvTreeListBox,DefaultCompare));
2897 else
2899 GetModel()->SetSortMode( SortNone );
2900 GetModel()->SetCompareHdl( Link() );
2902 pImp->SetStyle( nWindowStyle );
2903 pImp->Resize();
2904 Invalidate();
2907 void SvTreeListBox::PaintEntry( SvTreeListEntry* pEntry )
2909 DBG_CHKTHIS(SvTreeListBox,0);
2910 DBG_ASSERT(pEntry,"PaintEntry:No Entry");
2911 if( pEntry )
2912 pImp->PaintEntry( pEntry );
2915 void SvTreeListBox::InvalidateEntry( SvTreeListEntry* pEntry )
2917 DBG_CHKTHIS(SvTreeListBox,0);
2918 DBG_ASSERT(pEntry,"InvalidateEntry:No Entry");
2919 if( pEntry )
2921 GetModel()->InvalidateEntry( pEntry );
2925 long SvTreeListBox::PaintEntry(SvTreeListEntry* pEntry,long nLine,sal_uInt16 nTabFlags)
2927 return PaintEntry1(pEntry,nLine,nTabFlags);
2930 long SvTreeListBox::PaintEntry1(SvTreeListEntry* pEntry,long nLine,sal_uInt16 nTabFlags,
2931 sal_Bool bHasClipRegion )
2933 DBG_CHKTHIS(SvTreeListBox,0);
2935 Rectangle aRect; // multi purpose
2937 sal_Bool bHorSBar = pImp->HasHorScrollBar();
2938 PreparePaint( pEntry );
2940 pImp->UpdateContextBmpWidthMax( pEntry );
2942 if( nTreeFlags & TREEFLAG_RECALCTABS )
2943 SetTabs();
2945 short nTempEntryHeight = GetEntryHeight();
2946 long nWidth = pImp->GetOutputSize().Width();
2948 // Did we turn on the scrollbar within PreparePaints? If yes, we have to set
2949 // the ClipRegion anew.
2950 if( !bHorSBar && pImp->HasHorScrollBar() )
2951 SetClipRegion( Region(pImp->GetClipRegionRect()) );
2953 Point aEntryPos( GetMapMode().GetOrigin() );
2954 aEntryPos.X() *= -1; // conversion document coordinates
2955 long nMaxRight = nWidth + aEntryPos.X() - 1;
2957 Color aBackupTextColor( GetTextColor() );
2958 Font aBackupFont( GetFont() );
2959 Color aBackupColor = GetFillColor();
2961 bool bCurFontIsSel = false;
2962 sal_Bool bInUse = pEntry->HasInUseEmphasis();
2963 // if a ClipRegion was set from outside, we don't have to reset it
2964 const WinBits nWindowStyle = GetStyle();
2965 const sal_Bool bResetClipRegion = !bHasClipRegion;
2966 const sal_Bool bHideSelection = ((nWindowStyle & WB_HIDESELECTION) && !HasFocus())!=0;
2967 const StyleSettings& rSettings = GetSettings().GetStyleSettings();
2969 Font aHighlightFont( GetFont() );
2970 const Color aHighlightTextColor( rSettings.GetHighlightTextColor() );
2971 aHighlightFont.SetColor( aHighlightTextColor );
2973 Size aRectSize( 0, nTempEntryHeight );
2975 if( !bHasClipRegion && nWindowStyle & WB_HSCROLL )
2977 SetClipRegion( Region(pImp->GetClipRegionRect()) );
2978 bHasClipRegion = sal_True;
2981 SvViewDataEntry* pViewDataEntry = GetViewDataEntry( pEntry );
2983 sal_uInt16 nTabCount = aTabs.size();
2984 sal_uInt16 nItemCount = pEntry->ItemCount();
2985 sal_uInt16 nCurTab = 0;
2986 sal_uInt16 nCurItem = 0;
2988 while( nCurTab < nTabCount && nCurItem < nItemCount )
2990 SvLBoxTab* pTab = aTabs[ nCurTab ];
2991 sal_uInt16 nNextTab = nCurTab + 1;
2992 SvLBoxTab* pNextTab = nNextTab < nTabCount ? aTabs[nNextTab] : 0;
2993 SvLBoxItem* pItem = nCurItem < nItemCount ? pEntry->GetItem(nCurItem) : 0;
2995 sal_uInt16 nFlags = pTab->nFlags;
2996 Size aSize( pItem->GetSize( pViewDataEntry, nCurItem ));
2997 long nTabPos = GetTabPos( pEntry, pTab );
2999 long nNextTabPos;
3000 if( pNextTab )
3001 nNextTabPos = GetTabPos( pEntry, pNextTab );
3002 else
3004 nNextTabPos = nMaxRight;
3005 if( nTabPos > nMaxRight )
3006 nNextTabPos += 50;
3009 long nX;
3010 if( pTab->nFlags & SV_LBOXTAB_ADJUST_RIGHT )
3011 // avoid cutting the right edge off the tab separation
3012 nX = nTabPos + pTab->CalcOffset(aSize.Width(), (nNextTabPos-SV_TAB_BORDER-1) -nTabPos);
3013 else
3014 nX = nTabPos + pTab->CalcOffset(aSize.Width(), nNextTabPos-nTabPos);
3016 if( nFlags & nTabFlags )
3018 if( !bHasClipRegion && nX + aSize.Width() >= nMaxRight )
3020 SetClipRegion( Region(pImp->GetClipRegionRect()) );
3021 bHasClipRegion = sal_True;
3023 aEntryPos.X() = nX;
3024 aEntryPos.Y() = nLine;
3026 // set background pattern/color
3028 Wallpaper aWallpaper = GetBackground();
3030 int bSelTab = nFlags & SV_LBOXTAB_SHOW_SELECTION;
3031 sal_uInt16 nItemType = pItem->GetType();
3033 if (pViewDataEntry->IsHighlighted() && bSelTab && !pViewDataEntry->IsCursored())
3035 Color aNewWallColor = rSettings.GetHighlightColor();
3036 if ( !bInUse || nItemType != SV_ITEM_ID_LBOXCONTEXTBMP )
3038 // if the face color is bright then the deactive color is also bright
3039 // -> so you can't see any deactive selection
3040 if ( bHideSelection && !rSettings.GetFaceColor().IsBright() &&
3041 aWallpaper.GetColor().IsBright() != rSettings.GetDeactiveColor().IsBright() )
3042 aNewWallColor = rSettings.GetDeactiveColor();
3043 // set font color to highlight
3044 if ( !bCurFontIsSel )
3046 SetTextColor( aHighlightTextColor );
3047 Control::SetFont( aHighlightFont );
3048 bCurFontIsSel = true;
3051 aWallpaper.SetColor( aNewWallColor );
3053 else // no selection
3055 if( bInUse && nItemType == SV_ITEM_ID_LBOXCONTEXTBMP )
3056 aWallpaper.SetColor( rSettings.GetFieldColor() );
3057 else if( bCurFontIsSel )
3059 bCurFontIsSel = false;
3060 SetTextColor( aBackupTextColor );
3061 Control::SetFont( aBackupFont );
3065 // draw background
3066 if( !(nTreeFlags & TREEFLAG_USESEL))
3068 // only draw the area that is used by the item
3069 aRectSize.Width() = aSize.Width();
3070 aRect.SetPos( aEntryPos );
3071 aRect.SetSize( aRectSize );
3073 else
3075 // draw from the current to the next tab
3076 if( nCurTab != 0 )
3077 aRect.Left() = nTabPos;
3078 else
3079 // if we're in the 0th tab, always draw from column 0 --
3080 // else we get problems with centered tabs
3081 aRect.Left() = 0;
3082 aRect.Top() = nLine;
3083 aRect.Bottom() = nLine + nTempEntryHeight - 1;
3084 if( pNextTab )
3086 long nRight;
3087 nRight = GetTabPos(pEntry,pNextTab)-1;
3088 if( nRight > nMaxRight )
3089 nRight = nMaxRight;
3090 aRect.Right() = nRight;
3092 else
3093 aRect.Right() = nMaxRight;
3095 // A custom selection that starts at a tab position > 0, do not fill
3096 // the background of the 0th item, else e.g. we might not be able to
3097 // realize tab listboxes with lines.
3098 if( !(nCurTab==0 && (nTreeFlags & TREEFLAG_USESEL) && nFirstSelTab) )
3100 SetFillColor( aWallpaper.GetColor() );
3101 // this case may occur for smaller horizontal resizes
3102 if( aRect.Left() < aRect.Right() )
3103 DrawRect( aRect );
3105 // draw item
3106 // center vertically
3107 aEntryPos.Y() += ( nTempEntryHeight - aSize.Height() ) / 2;
3108 pItem->Paint(aEntryPos, *this, pViewDataEntry, pEntry);
3110 // division line between tabs
3111 if (pNextTab && pItem->GetType() == SV_ITEM_ID_LBOXSTRING &&
3112 // not at the right edge of the window!
3113 aRect.Right() < nMaxRight)
3115 aRect.Left() = aRect.Right() - SV_TAB_BORDER;
3116 DrawRect( aRect );
3119 SetFillColor( aBackupColor );
3121 nCurItem++;
3122 nCurTab++;
3124 if( pViewDataEntry->IsCursored() && !HasFocus() )
3126 // cursor emphasis
3127 SetFillColor();
3128 Color aOldLineColor = GetLineColor();
3129 SetLineColor( Color( COL_BLACK ) );
3130 aRect = GetFocusRect( pEntry, nLine );
3131 aRect.Top()++;
3132 aRect.Bottom()--;
3133 DrawRect( aRect );
3134 SetLineColor( aOldLineColor );
3135 SetFillColor( aBackupColor );
3138 if( bCurFontIsSel )
3140 SetTextColor( aBackupTextColor );
3141 Control::SetFont( aBackupFont );
3144 sal_uInt16 nFirstDynTabPos;
3145 SvLBoxTab* pFirstDynamicTab = GetFirstDynamicTab( nFirstDynTabPos );
3146 long nDynTabPos = GetTabPos( pEntry, pFirstDynamicTab );
3147 nDynTabPos += pImp->nNodeBmpTabDistance;
3148 nDynTabPos += pImp->nNodeBmpWidth / 2;
3149 nDynTabPos += 4; // 4 pixels of buffer, so the node bitmap is not too close
3150 // to the next tab
3152 if( (!(pEntry->GetFlags() & SV_ENTRYFLAG_NO_NODEBMP)) &&
3153 (nWindowStyle & WB_HASBUTTONS) && pFirstDynamicTab &&
3154 ( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() ) )
3156 // find first tab and check if the node bitmap extends into it
3157 sal_uInt16 nNextTab = nFirstDynTabPos;
3158 SvLBoxTab* pNextTab;
3161 nNextTab++;
3162 pNextTab = nNextTab < nTabCount ? aTabs[nNextTab] : 0;
3163 } while( pNextTab && pNextTab->IsDynamic() );
3165 if( !pNextTab || (GetTabPos( pEntry, pNextTab ) > nDynTabPos) )
3167 if((nWindowStyle & WB_HASBUTTONSATROOT) || pModel->GetDepth(pEntry) > 0)
3169 Point aPos( GetTabPos(pEntry,pFirstDynamicTab), nLine );
3170 aPos.X() += pImp->nNodeBmpTabDistance;
3172 const Image* pImg = 0;
3174 if( IsExpanded(pEntry) )
3175 pImg = &pImp->GetExpandedNodeBmp( );
3176 else
3178 if( (!pEntry->HasChildren()) && pEntry->HasChildrenOnDemand() &&
3179 (!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) &&
3180 pImp->GetDontKnowNodeBmp().GetSizePixel().Width() )
3181 pImg = &pImp->GetDontKnowNodeBmp( );
3182 else
3183 pImg = &pImp->GetCollapsedNodeBmp( );
3185 aPos.Y() += (nTempEntryHeight - pImg->GetSizePixel().Height()) / 2;
3187 sal_uInt16 nStyle = 0;
3188 if ( !IsEnabled() )
3189 nStyle |= IMAGE_DRAW_DISABLE;
3191 //native
3192 sal_Bool bNativeOK = sal_False;
3193 if ( IsNativeControlSupported( CTRL_LISTNODE, PART_ENTIRE_CONTROL) )
3195 ImplControlValue aControlValue;
3196 Rectangle aCtrlRegion( aPos, pImg->GetSizePixel() );
3197 ControlState nState = 0;
3199 if ( IsEnabled() ) nState |= CTRL_STATE_ENABLED;
3201 if ( IsExpanded(pEntry) )
3202 aControlValue.setTristateVal( BUTTONVALUE_ON );//expanded node
3203 else
3205 if( (!pEntry->HasChildren() ) &&
3206 pEntry->HasChildrenOnDemand() &&
3207 (!(pEntry->GetFlags() & SV_ENTRYFLAG_HAD_CHILDREN)) &&
3208 pImp->GetDontKnowNodeBmp().GetSizePixel().Width()
3210 aControlValue.setTristateVal( BUTTONVALUE_DONTKNOW ); //dont know
3211 else
3212 aControlValue.setTristateVal( BUTTONVALUE_OFF ); //collapsed node
3215 bNativeOK = DrawNativeControl( CTRL_LISTNODE, PART_ENTIRE_CONTROL,
3216 aCtrlRegion, nState, aControlValue, OUString() );
3219 if( !bNativeOK) {
3220 DrawImage( aPos, *pImg ,nStyle);
3227 if( bHasClipRegion && bResetClipRegion )
3228 SetClipRegion();
3229 return 0; // nRowLen;
3232 void SvTreeListBox::PreparePaint( SvTreeListEntry* )
3236 Rectangle SvTreeListBox::GetFocusRect( SvTreeListEntry* pEntry, long nLine )
3238 DBG_CHKTHIS(SvTreeListBox,0);
3239 Size aSize;
3240 Rectangle aRect;
3241 aRect.Top() = nLine;
3242 aSize.Height() = GetEntryHeight();
3244 long nRealWidth = pImp->GetOutputSize().Width();
3245 nRealWidth -= GetMapMode().GetOrigin().X();
3247 sal_uInt16 nCurTab;
3248 SvLBoxTab* pTab = GetFirstTab( SV_LBOXTAB_SHOW_SELECTION, nCurTab );
3249 long nTabPos = 0;
3250 if( pTab )
3251 nTabPos = GetTabPos( pEntry, pTab );
3252 long nNextTabPos;
3253 if( pTab && nCurTab < aTabs.size() - 1 )
3255 SvLBoxTab* pNextTab = aTabs[ nCurTab + 1 ];
3256 nNextTabPos = GetTabPos( pEntry, pNextTab );
3258 else
3260 nNextTabPos = nRealWidth;
3261 if( nTabPos > nRealWidth )
3262 nNextTabPos += 50;
3265 sal_Bool bUserSelection = (sal_Bool)( nTreeFlags & TREEFLAG_USESEL ) != 0;
3266 if( !bUserSelection )
3268 if( pTab && nCurTab < pEntry->ItemCount() )
3270 SvLBoxItem* pItem = pEntry->GetItem( nCurTab );
3271 aSize.Width() = pItem->GetSize( this, pEntry ).Width();
3272 if( !aSize.Width() )
3273 aSize.Width() = 15;
3274 long nX = nTabPos; //GetTabPos( pEntry, pTab );
3275 // alignment
3276 nX += pTab->CalcOffset( aSize.Width(), nNextTabPos - nTabPos );
3277 aRect.Left() = nX;
3278 // make sure that first and last letter aren't cut off slightly
3279 aRect.SetSize( aSize );
3280 if( aRect.Left() > 0 )
3281 aRect.Left()--;
3282 aRect.Right()++;
3285 else
3287 // if SelTab != 0, we have to calculate also
3288 if( nFocusWidth == -1 || nFirstSelTab )
3290 sal_uInt16 nLastTab;
3291 SvLBoxTab* pLastTab = GetLastTab(SV_LBOXTAB_SHOW_SELECTION,nLastTab);
3292 nLastTab++;
3293 if( nLastTab < aTabs.size() ) // is there another one?
3294 pLastTab = aTabs[ nLastTab ];
3295 else
3296 pLastTab = 0; // select whole width
3297 aSize.Width() = pLastTab ? pLastTab->GetPos() : 0x0fffffff;
3298 nFocusWidth = (short)aSize.Width();
3299 if( pTab )
3300 nFocusWidth = nFocusWidth - (short)nTabPos; //pTab->GetPos();
3302 else
3304 aSize.Width() = nFocusWidth;
3305 if( pTab )
3307 if( nCurTab )
3308 aSize.Width() += nTabPos;
3309 else
3310 aSize.Width() += pTab->GetPos(); // Tab0 always from the leftmost position
3313 // if selection starts with 0th tab, draw from column 0 on
3314 if( nCurTab != 0 )
3316 aRect.Left() = nTabPos;
3317 aSize.Width() -= nTabPos;
3319 aRect.SetSize( aSize );
3321 // adjust right edge because of clipping
3322 if( aRect.Right() >= nRealWidth )
3324 aRect.Right() = nRealWidth-1;
3325 nFocusWidth = (short)aRect.GetWidth();
3327 return aRect;
3331 long SvTreeListBox::GetTabPos( SvTreeListEntry* pEntry, SvLBoxTab* pTab)
3333 DBG_CHKTHIS(SvTreeListBox,0);
3334 DBG_ASSERT(pTab,"No Tab");
3335 long nPos = pTab->GetPos();
3336 if( pTab->IsDynamic() )
3338 sal_uInt16 nDepth = pModel->GetDepth( pEntry );
3339 nDepth = nDepth * (sal_uInt16)nIndent;
3340 nPos += (long)nDepth;
3342 return nPos;
3345 SvLBoxItem* SvTreeListBox::GetItem_Impl( SvTreeListEntry* pEntry, long nX,
3346 SvLBoxTab** ppTab, sal_uInt16 nEmptyWidth )
3348 DBG_CHKTHIS(SvTreeListBox,0);
3349 SvLBoxItem* pItemClicked = 0;
3350 sal_uInt16 nTabCount = aTabs.size();
3351 sal_uInt16 nItemCount = pEntry->ItemCount();
3352 SvLBoxTab* pTab = aTabs.front();
3353 SvLBoxItem* pItem = pEntry->GetItem(0);
3354 sal_uInt16 nNextItem = 1;
3355 nX -= GetMapMode().GetOrigin().X();
3356 long nRealWidth = pImp->GetOutputSize().Width();
3357 nRealWidth -= GetMapMode().GetOrigin().X();
3359 while( 1 )
3361 SvLBoxTab* pNextTab=nNextItem<nTabCount ? aTabs[nNextItem] : 0;
3362 long nStart = GetTabPos( pEntry, pTab );
3364 long nNextTabPos;
3365 if( pNextTab )
3366 nNextTabPos = GetTabPos( pEntry, pNextTab );
3367 else
3369 nNextTabPos = nRealWidth;
3370 if( nStart > nRealWidth )
3371 nNextTabPos += 50;
3374 Size aItemSize( pItem->GetSize(this, pEntry));
3375 nStart += pTab->CalcOffset( aItemSize.Width(), nNextTabPos - nStart );
3376 long nLen = aItemSize.Width();
3377 if( pNextTab )
3379 long nTabWidth = GetTabPos( pEntry, pNextTab ) - nStart;
3380 if( nTabWidth < nLen )
3381 nLen = nTabWidth;
3384 if( !nLen )
3385 nLen = nEmptyWidth;
3387 if( nX >= nStart && nX < (nStart+nLen ) )
3389 pItemClicked = pItem;
3390 if( ppTab )
3392 *ppTab = pTab;
3393 break;
3396 if( nNextItem >= nItemCount || nNextItem >= nTabCount)
3397 break;
3398 pTab = aTabs[ nNextItem ];
3399 pItem = pEntry->GetItem( nNextItem );
3400 nNextItem++;
3402 return pItemClicked;
3405 long SvTreeListBox::getPreferredDimensions(std::vector<long> &rWidths) const
3407 long nHeight = 0;
3408 rWidths.clear();
3409 SvTreeListEntry* pEntry = First();
3410 while (pEntry)
3412 sal_uInt16 nCount = pEntry->ItemCount();
3413 sal_uInt16 nCurPos = 0;
3414 if (nCount > rWidths.size())
3415 rWidths.resize(nCount);
3416 while (nCurPos < nCount)
3418 SvLBoxItem* pItem = pEntry->GetItem( nCurPos );
3419 long nWidth = pItem->GetSize(this, pEntry).Width();
3420 if (nWidth)
3422 nWidth += SV_TAB_BORDER * 2;
3423 if (nWidth > rWidths[nCurPos])
3424 rWidths[nCurPos] = nWidth;
3426 ++nCurPos;
3428 pEntry = Next( pEntry );
3429 nHeight += GetEntryHeight();
3431 return nHeight;
3434 Size SvTreeListBox::GetOptimalSize() const
3436 std::vector<long> aWidths;
3437 Size aRet(0, getPreferredDimensions(aWidths));
3438 for (size_t i = 0; i < aWidths.size(); ++i)
3439 aRet.Width() += aWidths[i];
3440 if (GetStyle() & WB_BORDER)
3442 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3443 aRet.Width() += rStyleSettings.GetBorderSize() * 2;
3444 aRet.Height() += rStyleSettings.GetBorderSize() * 2;
3446 return aRet;
3449 SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX,SvLBoxTab** ppTab)
3451 return GetItem_Impl( pEntry, nX, ppTab, 0 );
3454 SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX )
3456 DBG_CHKTHIS(SvTreeListBox,0);
3457 SvLBoxTab* pDummyTab;
3458 return GetItem_Impl( pEntry, nX, &pDummyTab, 0 );
3461 void SvTreeListBox::AddTab(long nTabPos,sal_uInt16 nFlags,void* pUserData )
3463 DBG_CHKTHIS(SvTreeListBox,0);
3464 nFocusWidth = -1;
3465 SvLBoxTab* pTab = new SvLBoxTab( nTabPos, nFlags );
3466 pTab->SetUserData( pUserData );
3467 aTabs.push_back( pTab );
3468 if( nTreeFlags & TREEFLAG_USESEL )
3470 sal_uInt16 nPos = aTabs.size() - 1;
3471 if( nPos >= nFirstSelTab && nPos <= nLastSelTab )
3472 pTab->nFlags |= SV_LBOXTAB_SHOW_SELECTION;
3473 else
3474 // string items usually have to be selected -- turn this off
3475 // explicitly
3476 pTab->nFlags &= ~SV_LBOXTAB_SHOW_SELECTION;
3482 SvLBoxTab* SvTreeListBox::GetFirstDynamicTab( sal_uInt16& rPos ) const
3484 DBG_CHKTHIS(SvTreeListBox,0);
3485 sal_uInt16 nCurTab = 0;
3486 sal_uInt16 nTabCount = aTabs.size();
3487 while( nCurTab < nTabCount )
3489 SvLBoxTab* pTab = aTabs[nCurTab];
3490 if( pTab->nFlags & SV_LBOXTAB_DYNAMIC )
3492 rPos = nCurTab;
3493 return pTab;
3495 nCurTab++;
3497 return 0;
3500 SvLBoxTab* SvTreeListBox::GetFirstDynamicTab() const
3502 sal_uInt16 nDummy;
3503 return GetFirstDynamicTab( nDummy );
3506 SvLBoxTab* SvTreeListBox::GetTab( SvTreeListEntry* pEntry, SvLBoxItem* pItem) const
3508 DBG_CHKTHIS(SvTreeListBox,0);
3509 sal_uInt16 nPos = pEntry->GetPos( pItem );
3510 return aTabs[ nPos ];
3513 void SvTreeListBox::ClearTabList()
3515 DBG_CHKTHIS(SvTreeListBox,0);
3516 sal_uInt16 nTabCount = aTabs.size();
3517 while( nTabCount )
3519 nTabCount--;
3520 SvLBoxTab* pDelTab = aTabs[ nTabCount ];
3521 delete pDelTab;
3523 aTabs.clear();
3527 Size SvTreeListBox::GetOutputSizePixel() const
3529 DBG_CHKTHIS(SvTreeListBox,0);
3530 Size aSize = pImp->GetOutputSize();
3531 return aSize;
3534 void SvTreeListBox::NotifyBeginScroll()
3536 DBG_CHKTHIS(SvTreeListBox,0);
3539 void SvTreeListBox::NotifyEndScroll()
3541 DBG_CHKTHIS(SvTreeListBox,0);
3544 void SvTreeListBox::NotifyScrolling( long )
3546 DBG_CHKTHIS(SvTreeListBox,0);
3549 void SvTreeListBox::NotifyScrolled()
3551 DBG_CHKTHIS(SvTreeListBox,0);
3552 aScrolledHdl.Call( this );
3555 void SvTreeListBox::NotifyInvalidating()
3557 DBG_CHKTHIS(SvTreeListBox,0);
3560 void SvTreeListBox::Invalidate( sal_uInt16 nInvalidateFlags )
3562 DBG_CHKTHIS(SvTreeListBox,0);
3563 if( nFocusWidth == -1 )
3564 // to make sure that the control doesn't show the wrong focus rectangle
3565 // after painting
3566 pImp->RecalcFocusRect();
3567 NotifyInvalidating();
3568 Control::Invalidate( nInvalidateFlags );
3569 pImp->Invalidate();
3572 void SvTreeListBox::Invalidate( const Rectangle& rRect, sal_uInt16 nInvalidateFlags )
3574 DBG_CHKTHIS(SvTreeListBox,0);
3575 if( nFocusWidth == -1 )
3576 // to make sure that the control doesn't show the wrong focus rectangle
3577 // after painting
3578 pImp->RecalcFocusRect();
3579 NotifyInvalidating();
3580 Control::Invalidate( rRect, nInvalidateFlags );
3584 void SvTreeListBox::SetHighlightRange( sal_uInt16 nStart, sal_uInt16 nEnd)
3586 DBG_CHKTHIS(SvTreeListBox,0);
3588 sal_uInt16 nTemp;
3589 nTreeFlags |= TREEFLAG_USESEL;
3590 if( nStart > nEnd )
3592 nTemp = nStart;
3593 nStart = nEnd;
3594 nEnd = nTemp;
3596 // select all tabs that lie within the area
3597 nTreeFlags |= TREEFLAG_RECALCTABS;
3598 nFirstSelTab = nStart;
3599 nLastSelTab = nEnd;
3600 pImp->RecalcFocusRect();
3603 void SvTreeListBox::Command( const CommandEvent& rCEvt )
3605 DBG_CHKTHIS(SvTreeListBox,0);
3606 // FIXME gnumake2 resync to DEV300_m84
3607 pImp->Command( rCEvt );
3611 void SvTreeListBox::RemoveParentKeepChildren( SvTreeListEntry* pParent )
3613 DBG_CHKTHIS(SvTreeListBox,0);
3614 DBG_ASSERT(pParent,"RemoveParentKeepChildren:No Parent");
3615 SvTreeListEntry* pNewParent = GetParent( pParent );
3616 if( pParent->HasChildren())
3618 SvTreeListEntry* pChild = FirstChild( pParent );
3619 while( pChild )
3621 pModel->Move( pChild, pNewParent, LIST_APPEND );
3622 pChild = FirstChild( pParent );
3625 pModel->Remove( pParent );
3628 SvLBoxTab* SvTreeListBox::GetFirstTab( sal_uInt16 nFlagMask, sal_uInt16& rPos )
3630 sal_uInt16 nTabCount = aTabs.size();
3631 for( sal_uInt16 nPos = 0; nPos < nTabCount; nPos++ )
3633 SvLBoxTab* pTab = aTabs[ nPos ];
3634 if( (pTab->nFlags & nFlagMask) )
3636 rPos = nPos;
3637 return pTab;
3640 rPos = 0xffff;
3641 return 0;
3644 SvLBoxTab* SvTreeListBox::GetLastTab( sal_uInt16 nFlagMask, sal_uInt16& rTabPos )
3646 sal_uInt16 nPos = (sal_uInt16)aTabs.size();
3647 while( nPos )
3649 --nPos;
3650 SvLBoxTab* pTab = aTabs[ nPos ];
3651 if( (pTab->nFlags & nFlagMask) )
3653 rTabPos = nPos;
3654 return pTab;
3657 rTabPos = 0xffff;
3658 return 0;
3661 void SvTreeListBox::RequestHelp( const HelpEvent& rHEvt )
3663 if( !pImp->RequestHelp( rHEvt ) )
3664 Control::RequestHelp( rHEvt );
3667 void SvTreeListBox::CursorMoved( SvTreeListEntry* )
3671 IMPL_LINK( SvTreeListBox, DefaultCompare, SvSortData*, pData )
3673 const SvTreeListEntry* pLeft = pData->pLeft;
3674 const SvTreeListEntry* pRight = pData->pRight;
3675 String aLeft( ((SvLBoxString*)(pLeft->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText());
3676 String aRight( ((SvLBoxString*)(pRight->GetFirstItem(SV_ITEM_ID_LBOXSTRING)))->GetText());
3677 pImp->UpdateStringSorter();
3678 return pImp->m_pStringSorter->compare(aLeft, aRight);
3681 void SvTreeListBox::ModelNotification( sal_uInt16 nActionId, SvTreeListEntry* pEntry1,
3682 SvTreeListEntry* pEntry2, sal_uLong nPos )
3684 if( nActionId == LISTACTION_CLEARING )
3685 CancelTextEditing();
3687 SvListView::ModelNotification( nActionId, pEntry1, pEntry2, nPos );
3688 switch( nActionId )
3690 case LISTACTION_INSERTED:
3692 SvTreeListEntry* pEntry( dynamic_cast< SvTreeListEntry* >( pEntry1 ) );
3693 if ( !pEntry )
3695 SAL_WARN( "svtools.contnr", "SvTreeListBox::ModelNotification: invalid entry!" );
3696 break;
3699 SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem( SV_ITEM_ID_LBOXCONTEXTBMP ) );
3700 if ( !pBmpItem )
3701 break;
3702 const Image& rBitmap1( pBmpItem->GetBitmap1() );
3703 const Image& rBitmap2( pBmpItem->GetBitmap2() );
3704 short nMaxWidth = short( std::max( rBitmap1.GetSizePixel().Width(), rBitmap2.GetSizePixel().Width() ) );
3705 nMaxWidth = pImp->UpdateContextBmpWidthVector( pEntry, nMaxWidth );
3706 if( nMaxWidth > nContextBmpWidthMax )
3708 nContextBmpWidthMax = nMaxWidth;
3709 SetTabs();
3711 if (get_width_request() == -1)
3712 queue_resize();
3714 break;
3716 case LISTACTION_RESORTING:
3717 SetUpdateMode( sal_False );
3718 break;
3720 case LISTACTION_RESORTED:
3721 // after a selection: show first entry and also keep the selection
3722 MakeVisible( (SvTreeListEntry*)pModel->First(), sal_True );
3723 SetUpdateMode( sal_True );
3724 break;
3726 case LISTACTION_CLEARED:
3727 if( IsUpdateMode() )
3728 Update();
3729 break;
3733 void SvTreeListBox::EndSelection()
3735 pImp->EndSelection();
3738 void SvTreeListBox::RepaintScrollBars() const
3740 ((SvTreeListBox*)this)->pImp->RepaintScrollBars();
3743 ScrollBar *SvTreeListBox::GetVScroll()
3745 return &((SvTreeListBox*)this)->pImp->aVerSBar;
3748 ScrollBar *SvTreeListBox::GetHScroll()
3750 return &((SvTreeListBox*)this)->pImp->aHorSBar;
3753 void SvTreeListBox::EnableAsyncDrag( sal_Bool b )
3755 pImp->EnableAsyncDrag( b );
3758 SvTreeListEntry* SvTreeListBox::GetFirstEntryInView() const
3760 Point aPos;
3761 return GetEntry( aPos );
3764 SvTreeListEntry* SvTreeListBox::GetNextEntryInView(SvTreeListEntry* pEntry ) const
3766 SvTreeListEntry* pNext = (SvTreeListEntry*)NextVisible( pEntry );
3767 if( pNext )
3769 Point aPos( GetEntryPosition(pNext) );
3770 const Size& rSize = pImp->GetOutputSize();
3771 if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() )
3772 return 0;
3774 return pNext;
3777 SvTreeListEntry* SvTreeListBox::GetLastEntryInView() const
3779 SvTreeListEntry* pEntry = GetFirstEntryInView();
3780 SvTreeListEntry* pNext = 0;
3781 while( pEntry )
3783 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() + GetEntryHeight() >= rSize.Height() )
3789 break;
3790 else
3791 pEntry = pNext;
3793 else
3794 break;
3796 return pEntry;
3799 void SvTreeListBox::ShowFocusRect( const SvTreeListEntry* pEntry )
3801 pImp->ShowFocusRect( pEntry );
3804 void SvTreeListBox::DataChanged( const DataChangedEvent& rDCEvt )
3806 if( (rDCEvt.GetType()==DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) )
3808 nEntryHeight = 0; // _together_ with sal_True of 1. par (bFont) of InitSettings() a zero-height
3809 // forces complete recalc of heights!
3810 InitSettings( sal_True, sal_True, sal_True );
3811 Invalidate();
3813 else
3814 Control::DataChanged( rDCEvt );
3817 void SvTreeListBox::StateChanged( StateChangedType eType )
3819 if( eType == STATE_CHANGE_ENABLE )
3820 Invalidate( INVALIDATE_CHILDREN );
3822 Control::StateChanged( eType );
3824 if ( eType == STATE_CHANGE_STYLE )
3825 ImplInitStyle();
3828 void SvTreeListBox::InitSettings(sal_Bool bFont,sal_Bool bForeground,sal_Bool bBackground)
3830 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3831 if( bFont )
3833 Font aFont;
3834 aFont = rStyleSettings.GetFieldFont();
3835 aFont.SetColor( rStyleSettings.GetWindowTextColor() );
3836 SetPointFont( aFont );
3837 AdjustEntryHeightAndRecalc( aFont );
3840 if( bForeground || bFont )
3842 SetTextColor( rStyleSettings.GetFieldTextColor() );
3843 SetTextFillColor();
3846 if( bBackground )
3847 SetBackground( rStyleSettings.GetFieldColor() );
3849 // always try to re-create default-SvLBoxButtonData
3850 if( pCheckButtonData && pCheckButtonData->HasDefaultImages() )
3851 pCheckButtonData->SetDefaultImages( this );
3854 sal_Bool SvTreeListBox::IsCellFocusEnabled() const
3856 return pImp->IsCellFocusEnabled();
3859 bool SvTreeListBox::SetCurrentTabPos( sal_uInt16 _nNewPos )
3861 return pImp->SetCurrentTabPos( _nNewPos );
3864 sal_uInt16 SvTreeListBox::GetCurrentTabPos() const
3866 return pImp->GetCurrentTabPos();
3869 void SvTreeListBox::InitStartEntry()
3871 if( !pImp->pStartEntry )
3872 pImp->pStartEntry = GetModel()->First();
3875 PopupMenu* SvTreeListBox::CreateContextMenu( void )
3877 return NULL;
3880 void SvTreeListBox::ExcecuteContextMenuAction( sal_uInt16 )
3882 DBG_WARNING( "SvTreeListBox::ExcecuteContextMenuAction(): now there's happening nothing!" );
3885 void SvTreeListBox::EnableContextMenuHandling( void )
3887 DBG_ASSERT( pImp, "-SvTreeListBox::EnableContextMenuHandling(): No implementation!" );
3889 pImp->bContextMenuHandling = sal_True;
3892 void SvTreeListBox::EnableContextMenuHandling( sal_Bool b )
3894 DBG_ASSERT( pImp, "-SvTreeListBox::EnableContextMenuHandling(): No implementation!" );
3896 pImp->bContextMenuHandling = b;
3899 sal_Bool SvTreeListBox::IsContextMenuHandlingEnabled( void ) const
3901 DBG_ASSERT( pImp, "-SvTreeListBox::IsContextMenuHandlingEnabled(): No implementation!" );
3903 return pImp->bContextMenuHandling;
3906 void SvTreeListBox::EnableList( bool _bEnable )
3908 // call base class method
3909 Window::Enable( _bEnable != false );
3910 // then paint immediately
3911 Paint( Rectangle( Point(), GetSizePixel() ) );
3914 ::com::sun::star::uno::Reference< XAccessible > SvTreeListBox::CreateAccessible()
3916 Window* pParent = GetAccessibleParentWindow();
3917 DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" );
3919 ::com::sun::star::uno::Reference< XAccessible > xAccessible;
3920 if ( pParent )
3922 ::com::sun::star::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
3923 if ( xAccParent.is() )
3925 // need to be done here to get the vclxwindow later on in the accessbile
3926 ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xTemp(GetComponentInterface());
3927 xAccessible = pImp->m_aFactoryAccess.getFactory().createAccessibleTreeListBox( *this, xAccParent );
3930 return xAccessible;
3933 void SvTreeListBox::FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const
3935 DBG_ASSERT( pEntry, "SvTreeListBox::FillAccessibleEntryStateSet: invalid entry" );
3937 if ( pEntry->HasChildrenOnDemand() || pEntry->HasChildren() )
3939 rStateSet.AddState( AccessibleStateType::EXPANDABLE );
3940 if ( IsExpanded( pEntry ) )
3941 rStateSet.AddState( (sal_Int16)AccessibleStateType::EXPANDED );
3944 if ( GetCheckButtonState( pEntry ) == SV_BUTTON_CHECKED )
3945 rStateSet.AddState( AccessibleStateType::CHECKED );
3946 if ( IsEntryVisible( pEntry ) )
3947 rStateSet.AddState( AccessibleStateType::VISIBLE );
3948 if ( IsSelected( pEntry ) )
3949 rStateSet.AddState( AccessibleStateType::SELECTED );
3952 Rectangle SvTreeListBox::GetBoundingRect( SvTreeListEntry* pEntry )
3954 Point aPos = GetEntryPosition( pEntry );
3955 Rectangle aRect = GetFocusRect( pEntry, aPos.Y() );
3956 return aRect;
3959 void SvTreeListBox::EnableCellFocus()
3961 pImp->EnableCellFocus();
3964 void SvTreeListBox::CallImplEventListeners(sal_uLong nEvent, void* pData)
3966 CallEventListeners(nEvent, pData);
3969 void SvTreeListBox::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& /*rStateSet*/ ) const
3973 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */