1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 /*
21 TODO:
22 - delete anchor in SelectionEngine when selecting manually
23 - SelectAll( false ) => only repaint the deselected entries
24 */
25
26 #include <vcl/treelistbox.hxx>
27 #include <vcl/accessiblefactory.hxx>
28 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
29 #include <vcl/svapp.hxx>
30 #include <vcl/accel.hxx>
31 #include <vcl/settings.hxx>
32 #include <vcl/commandevent.hxx>
33 #include <vcl/uitest/uiobject.hxx>
34 #include <sot/formats.hxx>
35 #include <unotools/accessiblestatesethelper.hxx>
36 #include <rtl/instance.hxx>
37 #include <comphelper/string.hxx>
38 #include <sal/log.hxx>
39 #include <tools/debug.hxx>
40
41 #include <vcl/svlbitm.hxx>
42 #include <vcl/treelistentry.hxx>
43 #include <vcl/viewdataentry.hxx>
44 #include <svimpbox.hxx>
45
46 #include <set>
47 #include <string.h>
48 #include <vector>
49
50 using namespace css::accessibility;
51
52 // Drag&Drop
53 static VclPtr<SvTreeListBox> g_pDDSource;
54 static VclPtr<SvTreeListBox> g_pDDTarget;
55
56 #define SVLBOX_ACC_RETURN 1
57 #define SVLBOX_ACC_ESCAPE 2
58
59 // ***************************************************************
60
61 class MyEdit_Impl : public Edit
62 {
63 SvInplaceEdit2* pOwner;
64 public:
65 MyEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* pOwner );
~MyEdit_Impl()66 virtual ~MyEdit_Impl() override { disposeOnce(); }
dispose()67 virtual void dispose() override { pOwner = nullptr; Edit::dispose(); }
68 virtual void KeyInput( const KeyEvent& rKEvt ) override;
69 virtual void LoseFocus() override;
70 };
71
MyEdit_Impl(vcl::Window * pParent,SvInplaceEdit2 * _pOwner)72 MyEdit_Impl::MyEdit_Impl( vcl::Window* pParent, SvInplaceEdit2* _pOwner ) :
73
74 Edit( pParent, WB_LEFT ),
75
76 pOwner( _pOwner )
77
78 {
79 }
80
KeyInput(const KeyEvent & rKEvt)81 void MyEdit_Impl::KeyInput( const KeyEvent& rKEvt )
82 {
83 if( !pOwner->KeyInput( rKEvt ))
84 Edit::KeyInput( rKEvt );
85 }
86
LoseFocus()87 void MyEdit_Impl::LoseFocus()
88 {
89 if (pOwner)
90 pOwner->LoseFocus();
91 }
92
SvInplaceEdit2(vcl::Window * pParent,const Point & rPos,const Size & rSize,const OUString & rData,const Link<SvInplaceEdit2 &,void> & rNotifyEditEnd,const Selection & rSelection)93 SvInplaceEdit2::SvInplaceEdit2
94 (
95 vcl::Window* pParent, const Point& rPos,
96 const Size& rSize,
97 const OUString& rData,
98 const Link<SvInplaceEdit2&,void>& rNotifyEditEnd,
99 const Selection& rSelection
100 ) :
101
102 aCallBackHdl ( rNotifyEditEnd ),
103 bCanceled ( false ),
104 bAlreadyInCallBack ( false )
105
106 {
107
108 pEdit = VclPtr<MyEdit_Impl>::Create( pParent, this );
109
110 vcl::Font aFont( pParent->GetFont() );
111 aFont.SetTransparent( false );
112 Color aColor( pParent->GetBackground().GetColor() );
113 aFont.SetFillColor(aColor );
114 pEdit->SetFont( aFont );
115 pEdit->SetBackground( pParent->GetBackground() );
116 pEdit->SetPosPixel( rPos );
117 pEdit->SetSizePixel( rSize );
118 pEdit->SetText( rData );
119 pEdit->SetSelection( rSelection );
120 pEdit->SaveValue();
121
122 aAccReturn.InsertItem( SVLBOX_ACC_RETURN, vcl::KeyCode(KEY_RETURN) );
123 aAccEscape.InsertItem( SVLBOX_ACC_ESCAPE, vcl::KeyCode(KEY_ESCAPE) );
124
125 aAccReturn.SetActivateHdl( LINK( this, SvInplaceEdit2, ReturnHdl_Impl) );
126 aAccEscape.SetActivateHdl( LINK( this, SvInplaceEdit2, EscapeHdl_Impl) );
127 Application::InsertAccel( &aAccReturn );
128 Application::InsertAccel( &aAccEscape );
129
130 pEdit->Show();
131 pEdit->GrabFocus();
132 }
133
~SvInplaceEdit2()134 SvInplaceEdit2::~SvInplaceEdit2()
135 {
136 if( !bAlreadyInCallBack )
137 {
138 Application::RemoveAccel( &aAccReturn );
139 Application::RemoveAccel( &aAccEscape );
140 }
141 pEdit.disposeAndClear();
142 }
143
GetSavedValue() const144 OUString const & SvInplaceEdit2::GetSavedValue() const
145 {
146 return pEdit->GetSavedValue();
147 }
148
Hide()149 void SvInplaceEdit2::Hide()
150 {
151 pEdit->Hide();
152 }
153
154
IMPL_LINK_NOARG(SvInplaceEdit2,ReturnHdl_Impl,Accelerator &,void)155 IMPL_LINK_NOARG(SvInplaceEdit2, ReturnHdl_Impl, Accelerator&, void)
156 {
157 bCanceled = false;
158 CallCallBackHdl_Impl();
159 }
160
IMPL_LINK_NOARG(SvInplaceEdit2,EscapeHdl_Impl,Accelerator &,void)161 IMPL_LINK_NOARG(SvInplaceEdit2, EscapeHdl_Impl, Accelerator&, void)
162 {
163 bCanceled = true;
164 CallCallBackHdl_Impl();
165 }
166
KeyInput(const KeyEvent & rKEvt)167 bool SvInplaceEdit2::KeyInput( const KeyEvent& rKEvt )
168 {
169 vcl::KeyCode aCode = rKEvt.GetKeyCode();
170 sal_uInt16 nCode = aCode.GetCode();
171
172 switch ( nCode )
173 {
174 case KEY_ESCAPE:
175 bCanceled = true;
176 CallCallBackHdl_Impl();
177 return true;
178
179 case KEY_RETURN:
180 bCanceled = false;
181 CallCallBackHdl_Impl();
182 return true;
183 }
184 return false;
185 }
186
StopEditing(bool bCancel)187 void SvInplaceEdit2::StopEditing( bool bCancel )
188 {
189 if ( !bAlreadyInCallBack )
190 {
191 bCanceled = bCancel;
192 CallCallBackHdl_Impl();
193 }
194 }
195
LoseFocus()196 void SvInplaceEdit2::LoseFocus()
197 {
198 if ( !bAlreadyInCallBack
199 && ((!Application::GetFocusWindow()) || !pEdit->IsChild( Application::GetFocusWindow()) )
200 )
201 {
202 bCanceled = false;
203 aIdle.SetPriority(TaskPriority::REPAINT);
204 aIdle.SetInvokeHandler(LINK(this,SvInplaceEdit2,Timeout_Impl));
205 aIdle.SetDebugName( "svtools::SvInplaceEdit2 aIdle" );
206 aIdle.Start();
207 }
208 }
209
IMPL_LINK_NOARG(SvInplaceEdit2,Timeout_Impl,Timer *,void)210 IMPL_LINK_NOARG(SvInplaceEdit2, Timeout_Impl, Timer *, void)
211 {
212 CallCallBackHdl_Impl();
213 }
214
CallCallBackHdl_Impl()215 void SvInplaceEdit2::CallCallBackHdl_Impl()
216 {
217 aIdle.Stop();
218 if ( !bAlreadyInCallBack )
219 {
220 bAlreadyInCallBack = true;
221 Application::RemoveAccel( &aAccReturn );
222 Application::RemoveAccel( &aAccEscape );
223 pEdit->Hide();
224 aCallBackHdl.Call( *this );
225 }
226 }
227
GetText() const228 OUString SvInplaceEdit2::GetText() const
229 {
230 return pEdit->GetText();
231 }
232
233 // ***************************************************************
234 // class SvLBoxTab
235 // ***************************************************************
236
237
SvLBoxTab()238 SvLBoxTab::SvLBoxTab()
239 {
240 nPos = 0;
241 nFlags = SvLBoxTabFlags::NONE;
242 }
243
SvLBoxTab(long nPosition,SvLBoxTabFlags nTabFlags)244 SvLBoxTab::SvLBoxTab( long nPosition, SvLBoxTabFlags nTabFlags )
245 {
246 nPos = nPosition;
247 nFlags = nTabFlags;
248 }
249
SvLBoxTab(const SvLBoxTab & rTab)250 SvLBoxTab::SvLBoxTab( const SvLBoxTab& rTab )
251 {
252 nPos = rTab.nPos;
253 nFlags = rTab.nFlags;
254 }
255
~SvLBoxTab()256 SvLBoxTab::~SvLBoxTab()
257 {
258 }
259
260
CalcOffset(long nItemWidth,long nTabWidth)261 long SvLBoxTab::CalcOffset( long nItemWidth, long nTabWidth )
262 {
263 long nOffset = 0;
264 if ( nFlags & SvLBoxTabFlags::ADJUST_RIGHT )
265 {
266 nOffset = nTabWidth - nItemWidth;
267 if( nOffset < 0 )
268 nOffset = 0;
269 }
270 else if ( nFlags & SvLBoxTabFlags::ADJUST_CENTER )
271 {
272 if( nFlags & SvLBoxTabFlags::FORCE )
273 {
274 // correct implementation of centering
275 nOffset = ( nTabWidth - nItemWidth ) / 2;
276 if( nOffset < 0 )
277 nOffset = 0;
278 }
279 else
280 {
281 // historically grown, wrong calculation of tabs which is needed by
282 // Abo-Tabbox, Tools/Options/Customize etc.
283 nItemWidth++;
284 nOffset = -( nItemWidth / 2 );
285 }
286 }
287 return nOffset;
288 }
289
290 // ***************************************************************
291 // class SvLBoxItem
292 // ***************************************************************
293
294
SvLBoxItem()295 SvLBoxItem::SvLBoxItem()
296 : mbDisabled(false)
297 {
298 }
299
~SvLBoxItem()300 SvLBoxItem::~SvLBoxItem()
301 {
302 }
303
GetWidth(const SvTreeListBox * pView,const SvTreeListEntry * pEntry) const304 int SvLBoxItem::GetWidth(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
305 {
306 const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
307 int nWidth = pViewData->mnWidth;
308 if (nWidth == -1)
309 {
310 nWidth = CalcWidth(pView);
311 const_cast<SvViewDataItem*>(pViewData)->mnWidth = nWidth;
312 }
313 return nWidth;
314 }
315
GetHeight(const SvTreeListBox * pView,const SvTreeListEntry * pEntry) const316 int SvLBoxItem::GetHeight(const SvTreeListBox* pView, const SvTreeListEntry* pEntry) const
317 {
318 const SvViewDataItem* pViewData = pView->GetViewDataItem( pEntry, this );
319 return pViewData->mnHeight;
320 }
321
GetWidth(const SvTreeListBox * pView,const SvViewDataEntry * pData,sal_uInt16 nItemPos)322 int SvLBoxItem::GetWidth(const SvTreeListBox* pView, const SvViewDataEntry* pData, sal_uInt16 nItemPos)
323 {
324 const SvViewDataItem& rIData = pData->GetItem(nItemPos);
325 int nWidth = rIData.mnWidth;
326 if (nWidth == -1)
327 {
328 nWidth = CalcWidth(pView);
329 const_cast<SvViewDataItem&>(rIData).mnWidth = nWidth;
330 }
331 return nWidth;
332 }
333
GetHeight(const SvViewDataEntry * pData,sal_uInt16 nItemPos)334 int SvLBoxItem::GetHeight(const SvViewDataEntry* pData, sal_uInt16 nItemPos)
335 {
336 const SvViewDataItem& rIData = pData->GetItem(nItemPos);
337 return rIData.mnHeight;
338 }
339
CalcWidth(const SvTreeListBox *) const340 int SvLBoxItem::CalcWidth(const SvTreeListBox* /*pView*/) const
341 {
342 return 0;
343 }
344
345 struct SvTreeListBoxImpl
346 {
347 bool m_bIsEmptyTextAllowed:1;
348 bool m_bEntryMnemonicsEnabled:1;
349 bool m_bDoingQuickSelection:1;
350
351 vcl::MnemonicEngine m_aMnemonicEngine;
352 vcl::QuickSelectionEngine m_aQuickSelectionEngine;
353
SvTreeListBoxImplSvTreeListBoxImpl354 explicit SvTreeListBoxImpl(SvTreeListBox& _rBox) :
355 m_bIsEmptyTextAllowed(true),
356 m_bEntryMnemonicsEnabled(false),
357 m_bDoingQuickSelection(false),
358 m_aMnemonicEngine(_rBox),
359 m_aQuickSelectionEngine(_rBox) {}
360 };
361
362
SvTreeListBox(vcl::Window * pParent,WinBits nWinStyle)363 SvTreeListBox::SvTreeListBox(vcl::Window* pParent, WinBits nWinStyle) :
364 Control(pParent, nWinStyle | WB_CLIPCHILDREN),
365 DropTargetHelper(this),
366 DragSourceHelper(this),
367 mpImpl(new SvTreeListBoxImpl(*this)),
368 mbContextBmpExpanded(false),
369 mbAlternatingRowColors(false),
370 mbUpdateAlternatingRows(false),
371 mbQuickSearch(false),
372 eSelMode(SelectionMode::NONE),
373 nMinWidthInChars(0),
374 mbCenterAndClipText(false)
375 {
376 nImpFlags = SvTreeListBoxFlags::NONE;
377 pTargetEntry = nullptr;
378 nDragDropMode = DragDropMode::NONE;
379 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
380 pHdlEntry = nullptr;
381 eSelMode = SelectionMode::Single;
382 nDragDropMode = DragDropMode::NONE;
383 SetType(WindowType::TREELISTBOX);
384
385 InitTreeView();
386 pImpl->SetModel( pModel.get() );
387
388 SetSublistOpenWithLeftRight();
389 }
390
Clear()391 void SvTreeListBox::Clear()
392 {
393 if (pModel)
394 pModel->Clear(); // Model calls SvTreeListBox::ModelHasCleared()
395 }
396
EnableEntryMnemonics()397 void SvTreeListBox::EnableEntryMnemonics()
398 {
399 if ( IsEntryMnemonicsEnabled() )
400 return;
401
402 mpImpl->m_bEntryMnemonicsEnabled = true;
403 Invalidate();
404 }
405
IsEntryMnemonicsEnabled() const406 bool SvTreeListBox::IsEntryMnemonicsEnabled() const
407 {
408 return mpImpl->m_bEntryMnemonicsEnabled;
409 }
410
IMPL_LINK(SvTreeListBox,CloneHdl_Impl,SvTreeListEntry *,pEntry,SvTreeListEntry *)411 IMPL_LINK( SvTreeListBox, CloneHdl_Impl, SvTreeListEntry*, pEntry, SvTreeListEntry* )
412 {
413 return CloneEntry(pEntry);
414 }
415
Insert(SvTreeListEntry * pEntry,SvTreeListEntry * pParent,sal_uLong nPos)416 sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry, SvTreeListEntry* pParent, sal_uLong nPos )
417 {
418 sal_uLong nInsPos = pModel->Insert( pEntry, pParent, nPos );
419 pEntry->SetBackColor( GetBackground().GetColor() );
420 SetAlternatingRowColors( mbAlternatingRowColors );
421 return nInsPos;
422 }
423
Insert(SvTreeListEntry * pEntry,sal_uLong nRootPos)424 sal_uLong SvTreeListBox::Insert( SvTreeListEntry* pEntry,sal_uLong nRootPos )
425 {
426 sal_uLong nInsPos = pModel->Insert( pEntry, nRootPos );
427 pEntry->SetBackColor( GetBackground().GetColor() );
428 SetAlternatingRowColors( mbAlternatingRowColors );
429 return nInsPos;
430 }
431
ExpandingHdl()432 bool SvTreeListBox::ExpandingHdl()
433 {
434 return !aExpandingHdl.IsSet() || aExpandingHdl.Call( this );
435 }
436
ExpandedHdl()437 void SvTreeListBox::ExpandedHdl()
438 {
439 aExpandedHdl.Call( this );
440 }
441
SelectHdl()442 void SvTreeListBox::SelectHdl()
443 {
444 aSelectHdl.Call( this );
445 }
446
DeselectHdl()447 void SvTreeListBox::DeselectHdl()
448 {
449 aDeselectHdl.Call( this );
450 }
451
DoubleClickHdl()452 bool SvTreeListBox::DoubleClickHdl()
453 {
454 return !aDoubleClickHdl.IsSet() || aDoubleClickHdl.Call(this);
455 }
456
457
CheckDragAndDropMode(SvTreeListBox const * pSource,sal_Int8 nAction)458 bool SvTreeListBox::CheckDragAndDropMode( SvTreeListBox const * pSource, sal_Int8 nAction )
459 {
460 if ( pSource == this )
461 {
462 if ( !(nDragDropMode & (DragDropMode::CTRL_MOVE | DragDropMode::CTRL_COPY) ) )
463 return false; // D&D locked within list
464 if( DND_ACTION_MOVE == nAction )
465 {
466 if ( !(nDragDropMode & DragDropMode::CTRL_MOVE) )
467 return false; // no local move
468 }
469 else
470 {
471 if ( !(nDragDropMode & DragDropMode::CTRL_COPY))
472 return false; // no local copy
473 }
474 }
475 else
476 {
477 if ( !(nDragDropMode & DragDropMode::APP_DROP ) )
478 return false; // no drop
479 if ( DND_ACTION_MOVE == nAction )
480 {
481 if ( !(nDragDropMode & DragDropMode::APP_MOVE) )
482 return false; // no global move
483 }
484 else
485 {
486 if ( !(nDragDropMode & DragDropMode::APP_COPY))
487 return false; // no global copy
488 }
489 }
490 return true;
491 }
492
493
494 /*
495 NotifyMoving/Copying
496 ====================
497
498 default behavior:
499
500 1. target doesn't have children
501 - entry becomes sibling of target. entry comes after target
502 (->Window: below the target)
503 2. target is an expanded parent
504 - entry inserted at the beginning of the target childlist
505 3. target is a collapsed parent
506 - entry is inserted at the end of the target childlist
507 */
NotifyMoving(SvTreeListEntry * pTarget,SvTreeListEntry * pEntry,SvTreeListEntry * & rpNewParent,sal_uLong & rNewChildPos)508 TriState SvTreeListBox::NotifyMoving(
509 SvTreeListEntry* pTarget, // D&D dropping position in GetModel()
510 SvTreeListEntry* pEntry, // entry that we want to move, from
511 // GetSourceListBox()->GetModel()
512 SvTreeListEntry*& rpNewParent, // new target parent
513 sal_uLong& rNewChildPos) // position in childlist of target parent
514 {
515 DBG_ASSERT(pEntry,"NotifyMoving:SourceEntry?");
516 if( !pTarget )
517 {
518 rpNewParent = nullptr;
519 rNewChildPos = 0;
520 return TRISTATE_TRUE;
521 }
522 if ( !pTarget->HasChildren() && !pTarget->HasChildrenOnDemand() )
523 {
524 // case 1
525 rpNewParent = GetParent( pTarget );
526 rNewChildPos = SvTreeList::GetRelPos( pTarget ) + 1;
527 rNewChildPos += nCurEntrySelPos;
528 nCurEntrySelPos++;
529 }
530 else
531 {
532 // cases 2 & 3
533 rpNewParent = pTarget;
534 if( IsExpanded(pTarget))
535 rNewChildPos = 0;
536 else
537 rNewChildPos = TREELIST_APPEND;
538 }
539 return TRISTATE_TRUE;
540 }
541
NotifyCopying(SvTreeListEntry * pTarget,SvTreeListEntry * pEntry,SvTreeListEntry * & rpNewParent,sal_uLong & rNewChildPos)542 TriState SvTreeListBox::NotifyCopying(
543 SvTreeListEntry* pTarget, // D&D dropping position in GetModel()
544 SvTreeListEntry* pEntry, // entry that we want to move, from
545 // GetSourceListBox()->GetModel()
546 SvTreeListEntry*& rpNewParent, // new target parent
547 sal_uLong& rNewChildPos) // position in childlist of target parent
548 {
549 return NotifyMoving(pTarget,pEntry,rpNewParent,rNewChildPos);
550 }
551
FirstChild(SvTreeListEntry * pParent) const552 SvTreeListEntry* SvTreeListBox::FirstChild( SvTreeListEntry* pParent ) const
553 {
554 return pModel->FirstChild(pParent);
555 }
556
557 // return: all entries copied
CopySelection(SvTreeListBox * pSource,SvTreeListEntry * pTarget)558 bool SvTreeListBox::CopySelection( SvTreeListBox* pSource, SvTreeListEntry* pTarget )
559 {
560 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
561 bool bSuccess = true;
562 std::vector<SvTreeListEntry*> aList;
563 bool bClone = ( pSource->GetModel() != GetModel() );
564 Link<SvTreeListEntry*,SvTreeListEntry*> aCloneLink( pModel->GetCloneLink() );
565 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
566
567 // cache selection to simplify iterating over the selection when doing a D&D
568 // exchange within the same listbox
569 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
570 while ( pSourceEntry )
571 {
572 // children are copied automatically
573 pSource->SelectChildren( pSourceEntry, false );
574 aList.push_back( pSourceEntry );
575 pSourceEntry = pSource->NextSelected( pSourceEntry );
576 }
577
578 for (auto const& elem : aList)
579 {
580 pSourceEntry = elem;
581 SvTreeListEntry* pNewParent = nullptr;
582 sal_uLong nInsertionPos = TREELIST_APPEND;
583 TriState nOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
584 if ( nOk )
585 {
586 if ( bClone )
587 {
588 sal_uLong nCloneCount = 0;
589 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
590 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
591 }
592 else
593 {
594 sal_uLong nListPos = pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
595 pSourceEntry = GetEntry( pNewParent, nListPos );
596 }
597 }
598 else
599 bSuccess = false;
600
601 if (nOk == TRISTATE_INDET) // HACK: make visible moved entry
602 MakeVisible( pSourceEntry );
603 }
604 pModel->SetCloneLink( aCloneLink );
605 return bSuccess;
606 }
607
608 // return: all entries were moved
MoveSelectionCopyFallbackPossible(SvTreeListBox * pSource,SvTreeListEntry * pTarget,bool bAllowCopyFallback)609 bool SvTreeListBox::MoveSelectionCopyFallbackPossible( SvTreeListBox* pSource, SvTreeListEntry* pTarget, bool bAllowCopyFallback )
610 {
611 nCurEntrySelPos = 0; // selection counter for NotifyMoving/Copying
612 bool bSuccess = true;
613 std::vector<SvTreeListEntry*> aList;
614 bool bClone = ( pSource->GetModel() != GetModel() );
615 Link<SvTreeListEntry*,SvTreeListEntry*> aCloneLink( pModel->GetCloneLink() );
616 if ( bClone )
617 pModel->SetCloneLink( LINK(this, SvTreeListBox, CloneHdl_Impl ));
618
619 SvTreeListEntry* pSourceEntry = pSource->FirstSelected();
620 while ( pSourceEntry )
621 {
622 // children are automatically moved
623 pSource->SelectChildren( pSourceEntry, false );
624 aList.push_back( pSourceEntry );
625 pSourceEntry = pSource->NextSelected( pSourceEntry );
626 }
627
628 for (auto const& elem : aList)
629 {
630 pSourceEntry = elem;
631 SvTreeListEntry* pNewParent = nullptr;
632 sal_uLong nInsertionPos = TREELIST_APPEND;
633 TriState nOk = NotifyMoving(pTarget,pSourceEntry,pNewParent,nInsertionPos);
634 TriState nCopyOk = nOk;
635 if ( !nOk && bAllowCopyFallback )
636 {
637 nInsertionPos = TREELIST_APPEND;
638 nCopyOk = NotifyCopying(pTarget,pSourceEntry,pNewParent,nInsertionPos);
639 }
640
641 if ( nOk || nCopyOk )
642 {
643 if ( bClone )
644 {
645 sal_uLong nCloneCount = 0;
646 pSourceEntry = pModel->Clone(pSourceEntry, nCloneCount);
647 pModel->InsertTree(pSourceEntry, pNewParent, nInsertionPos);
648 }
649 else
650 {
651 if ( nOk )
652 pModel->Move(pSourceEntry, pNewParent, nInsertionPos);
653 else
654 pModel->Copy(pSourceEntry, pNewParent, nInsertionPos);
655 }
656 }
657 else
658 bSuccess = false;
659
660 if (nOk == TRISTATE_INDET) // HACK: make moved entry visible
661 MakeVisible( pSourceEntry );
662 }
663 pModel->SetCloneLink( aCloneLink );
664 return bSuccess;
665 }
666
RemoveSelection()667 void SvTreeListBox::RemoveSelection()
668 {
669 std::vector<const SvTreeListEntry*> aList;
670 // cache selection, as the implementation deselects everything on the first
671 // remove
672 SvTreeListEntry* pEntry = FirstSelected();
673 while ( pEntry )
674 {
675 aList.push_back( pEntry );
676 if ( pEntry->HasChildren() )
677 // remove deletes all children automatically
678 SelectChildren(pEntry, false);
679 pEntry = NextSelected( pEntry );
680 }
681
682 for (auto const& elem : aList)
683 pModel->Remove(elem);
684 }
685
RemoveEntry(SvTreeListEntry const * pEntry)686 void SvTreeListBox::RemoveEntry(SvTreeListEntry const * pEntry)
687 {
688 pModel->Remove(pEntry);
689 }
690
RecalcViewData()691 void SvTreeListBox::RecalcViewData()
692 {
693 SvTreeListEntry* pEntry = First();
694 while( pEntry )
695 {
696 sal_uInt16 nCount = pEntry->ItemCount();
697 sal_uInt16 nCurPos = 0;
698 while ( nCurPos < nCount )
699 {
700 SvLBoxItem& rItem = pEntry->GetItem( nCurPos );
701 rItem.InitViewData( this, pEntry );
702 nCurPos++;
703 }
704 pEntry = Next( pEntry );
705 }
706 }
707
ImplShowTargetEmphasis(SvTreeListEntry * pEntry,bool bShow)708 void SvTreeListBox::ImplShowTargetEmphasis( SvTreeListEntry* pEntry, bool bShow)
709 {
710 if ( bShow && (nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
711 return;
712 if ( !bShow && !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
713 return;
714 pImpl->PaintDDCursor( pEntry, bShow);
715 if( bShow )
716 nImpFlags |= SvTreeListBoxFlags::TARGEMPH_VIS;
717 else
718 nImpFlags &= ~SvTreeListBoxFlags::TARGEMPH_VIS;
719 }
720
OnCurrentEntryChanged()721 void SvTreeListBox::OnCurrentEntryChanged()
722 {
723 if ( !mpImpl->m_bDoingQuickSelection )
724 mpImpl->m_aQuickSelectionEngine.Reset();
725 }
726
GetEntry(SvTreeListEntry * pParent,sal_uLong nPos) const727 SvTreeListEntry* SvTreeListBox::GetEntry( SvTreeListEntry* pParent, sal_uLong nPos ) const
728 {
729 return pModel->GetEntry(pParent, nPos);
730 }
731
GetEntry(sal_uLong nRootPos) const732 SvTreeListEntry* SvTreeListBox::GetEntry( sal_uLong nRootPos ) const
733 {
734 return pModel->GetEntry(nRootPos);
735 }
736
GetEntryFromPath(const::std::deque<sal_Int32> & _rPath) const737 SvTreeListEntry* SvTreeListBox::GetEntryFromPath( const ::std::deque< sal_Int32 >& _rPath ) const
738 {
739
740 SvTreeListEntry* pEntry = nullptr;
741 SvTreeListEntry* pParent = nullptr;
742 for (auto const& elem : _rPath)
743 {
744 pEntry = GetEntry( pParent, elem );
745 if ( !pEntry )
746 break;
747 pParent = pEntry;
748 }
749
750 return pEntry;
751 }
752
FillEntryPath(SvTreeListEntry * pEntry,::std::deque<sal_Int32> & _rPath) const753 void SvTreeListBox::FillEntryPath( SvTreeListEntry* pEntry, ::std::deque< sal_Int32 >& _rPath ) const
754 {
755
756 if ( !pEntry )
757 return;
758
759 SvTreeListEntry* pParentEntry = GetParent( pEntry );
760 while ( true )
761 {
762 sal_uLong i, nCount = GetLevelChildCount( pParentEntry );
763 for ( i = 0; i < nCount; ++i )
764 {
765 SvTreeListEntry* pTemp = GetEntry( pParentEntry, i );
766 DBG_ASSERT( pEntry, "invalid entry" );
767 if ( pEntry == pTemp )
768 {
769 _rPath.push_front( static_cast<sal_Int32>(i) );
770 break;
771 }
772 }
773
774 if ( pParentEntry )
775 {
776 pEntry = pParentEntry;
777 pParentEntry = GetParent( pParentEntry );
778 }
779 else
780 break;
781 }
782 }
783
GetParent(const SvTreeListEntry * pEntry) const784 const SvTreeListEntry* SvTreeListBox::GetParent( const SvTreeListEntry* pEntry ) const
785 {
786 return pModel->GetParent(pEntry);
787 }
788
GetParent(SvTreeListEntry * pEntry) const789 SvTreeListEntry* SvTreeListBox::GetParent( SvTreeListEntry* pEntry ) const
790 {
791 return pModel->GetParent(pEntry);
792 }
793
GetRootLevelParent(SvTreeListEntry * pEntry) const794 SvTreeListEntry* SvTreeListBox::GetRootLevelParent( SvTreeListEntry* pEntry ) const
795 {
796 return pModel->GetRootLevelParent(pEntry);
797 }
798
GetChildCount(SvTreeListEntry const * pParent) const799 sal_uLong SvTreeListBox::GetChildCount( SvTreeListEntry const * pParent ) const
800 {
801 return pModel->GetChildCount(pParent);
802 }
803
GetLevelChildCount(SvTreeListEntry * _pParent) const804 sal_uLong SvTreeListBox::GetLevelChildCount( SvTreeListEntry* _pParent ) const
805 {
806
807 //if _pParent is 0, then pEntry is the first child of the root.
808 SvTreeListEntry* pEntry = FirstChild( _pParent );
809
810 if( !pEntry )//there is only root, root don't have children
811 return 0;
812
813 if( !_pParent )//root and children of root
814 return pEntry->pParent->m_Children.size();
815
816 return _pParent->m_Children.size();
817 }
818
GetViewDataEntry(SvTreeListEntry const * pEntry) const819 SvViewDataEntry* SvTreeListBox::GetViewDataEntry( SvTreeListEntry const * pEntry ) const
820 {
821 return const_cast<SvViewDataEntry*>(SvListView::GetViewData(pEntry));
822 }
823
GetViewDataItem(SvTreeListEntry const * pEntry,SvLBoxItem const * pItem)824 SvViewDataItem* SvTreeListBox::GetViewDataItem(SvTreeListEntry const * pEntry, SvLBoxItem const * pItem)
825 {
826 return const_cast<SvViewDataItem*>(static_cast<const SvTreeListBox*>(this)->GetViewDataItem(pEntry, pItem));
827 }
828
GetViewDataItem(const SvTreeListEntry * pEntry,const SvLBoxItem * pItem) const829 const SvViewDataItem* SvTreeListBox::GetViewDataItem(const SvTreeListEntry* pEntry, const SvLBoxItem* pItem) const
830 {
831 const SvViewDataEntry* pEntryData = SvListView::GetViewData(pEntry);
832 assert(pEntryData && "Entry not in View");
833 sal_uInt16 nItemPos = pEntry->GetPos(pItem);
834 return &pEntryData->GetItem(nItemPos);
835 }
836
InitViewData(SvViewDataEntry * pData,SvTreeListEntry * pEntry)837 void SvTreeListBox::InitViewData( SvViewDataEntry* pData, SvTreeListEntry* pEntry )
838 {
839 SvTreeListEntry* pInhEntry = pEntry;
840 SvViewDataEntry* pEntryData = pData;
841
842 pEntryData->Init(pInhEntry->ItemCount());
843 sal_uInt16 nCount = pInhEntry->ItemCount();
844 sal_uInt16 nCurPos = 0;
845 while( nCurPos < nCount )
846 {
847 SvLBoxItem& rItem = pInhEntry->GetItem( nCurPos );
848 SvViewDataItem& rItemData = pEntryData->GetItem(nCurPos);
849 rItem.InitViewData( this, pInhEntry, &rItemData );
850 nCurPos++;
851 }
852 }
853
EnableSelectionAsDropTarget(bool bEnable)854 void SvTreeListBox::EnableSelectionAsDropTarget( bool bEnable )
855 {
856 sal_uInt16 nRefDepth;
857 SvTreeListEntry* pTemp;
858
859 SvTreeListEntry* pSelEntry = FirstSelected();
860 while( pSelEntry )
861 {
862 if ( !bEnable )
863 {
864 pSelEntry->nEntryFlags |= SvTLEntryFlags::DISABLE_DROP;
865 nRefDepth = pModel->GetDepth( pSelEntry );
866 pTemp = Next( pSelEntry );
867 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
868 {
869 pTemp->nEntryFlags |= SvTLEntryFlags::DISABLE_DROP;
870 pTemp = Next( pTemp );
871 }
872 }
873 else
874 {
875 pSelEntry->nEntryFlags &= ~SvTLEntryFlags::DISABLE_DROP;
876 nRefDepth = pModel->GetDepth( pSelEntry );
877 pTemp = Next( pSelEntry );
878 while( pTemp && pModel->GetDepth( pTemp ) > nRefDepth )
879 {
880 pTemp->nEntryFlags &= ~SvTLEntryFlags::DISABLE_DROP;
881 pTemp = Next( pTemp );
882 }
883 }
884 pSelEntry = NextSelected( pSelEntry );
885 }
886 }
887
888 // ******************************************************************
889 // InplaceEditing
890 // ******************************************************************
891
EditText(const OUString & rStr,const tools::Rectangle & rRect,const Selection & rSel)892 void SvTreeListBox::EditText( const OUString& rStr, const tools::Rectangle& rRect,
893 const Selection& rSel )
894 {
895 pEdCtrl.reset();
896 nImpFlags |= SvTreeListBoxFlags::IN_EDT;
897 nImpFlags &= ~SvTreeListBoxFlags::EDTEND_CALLED;
898 HideFocus();
899 pEdCtrl.reset( new SvInplaceEdit2(
900 this, rRect.TopLeft(), rRect.GetSize(), rStr,
901 LINK( this, SvTreeListBox, TextEditEndedHdl_Impl ),
902 rSel ) );
903 }
904
IMPL_LINK_NOARG(SvTreeListBox,TextEditEndedHdl_Impl,SvInplaceEdit2 &,void)905 IMPL_LINK_NOARG(SvTreeListBox, TextEditEndedHdl_Impl, SvInplaceEdit2&, void)
906 {
907 if ( nImpFlags & SvTreeListBoxFlags::EDTEND_CALLED ) // avoid nesting
908 return;
909 nImpFlags |= SvTreeListBoxFlags::EDTEND_CALLED;
910 OUString aStr;
911 if ( !pEdCtrl->EditingCanceled() )
912 aStr = pEdCtrl->GetText();
913 else
914 aStr = pEdCtrl->GetSavedValue();
915 if ( mpImpl->m_bIsEmptyTextAllowed || !aStr.isEmpty() )
916 EditedText( aStr );
917 // Hide may only be called after the new text was put into the entry, so
918 // that we don't call the selection handler in the GetFocus of the listbox
919 // with the old entry text.
920 pEdCtrl->Hide();
921 nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
922 GrabFocus();
923 }
924
CancelTextEditing()925 void SvTreeListBox::CancelTextEditing()
926 {
927 if ( pEdCtrl )
928 pEdCtrl->StopEditing( true );
929 nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
930 }
931
EndEditing(bool bCancel)932 void SvTreeListBox::EndEditing( bool bCancel )
933 {
934 if( pEdCtrl )
935 pEdCtrl->StopEditing( bCancel );
936 nImpFlags &= ~SvTreeListBoxFlags::IN_EDT;
937 }
938
939
FirstSearchEntry(OUString & _rEntryText) const940 const void* SvTreeListBox::FirstSearchEntry( OUString& _rEntryText ) const
941 {
942 SvTreeListEntry* pEntry = GetCurEntry();
943 if ( pEntry )
944 pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( NextSearchEntry( pEntry, _rEntryText ) ) );
945 else
946 {
947 pEntry = FirstSelected();
948 if ( !pEntry )
949 pEntry = First();
950 }
951
952 if ( pEntry )
953 _rEntryText = GetEntryText( pEntry );
954
955 return pEntry;
956 }
957
NextSearchEntry(const void * _pCurrentSearchEntry,OUString & _rEntryText) const958 const void* SvTreeListBox::NextSearchEntry( const void* _pCurrentSearchEntry, OUString& _rEntryText ) const
959 {
960 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pCurrentSearchEntry ) );
961
962 if ( ( ( GetChildCount( pEntry ) > 0 )
963 || ( pEntry->HasChildrenOnDemand() )
964 )
965 && !IsExpanded( pEntry )
966 )
967 {
968 pEntry = pEntry->NextSibling();
969 }
970 else
971 {
972 pEntry = Next( pEntry );
973 }
974
975 if ( !pEntry )
976 pEntry = First();
977
978 if ( pEntry )
979 _rEntryText = GetEntryText( pEntry );
980
981 return pEntry;
982 }
983
SelectSearchEntry(const void * _pEntry)984 void SvTreeListBox::SelectSearchEntry( const void* _pEntry )
985 {
986 SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) );
987 DBG_ASSERT( pEntry, "SvTreeListBox::SelectSearchEntry: invalid entry!" );
988 if ( !pEntry )
989 return;
990
991 SelectAll( false );
992 SetCurEntry( pEntry );
993 Select( pEntry );
994 }
995
ExecuteSearchEntry(const void *) const996 void SvTreeListBox::ExecuteSearchEntry( const void* /*_pEntry*/ ) const
997 {
998 // nothing to do here, we have no "execution"
999 }
1000
CurrentEntry(OUString & _out_entryText) const1001 vcl::StringEntryIdentifier SvTreeListBox::CurrentEntry( OUString& _out_entryText ) const
1002 {
1003 // always accept the current entry if there is one
1004 SvTreeListEntry* pCurrentEntry( GetCurEntry() );
1005 if ( pCurrentEntry )
1006 {
1007 _out_entryText = GetEntryText( pCurrentEntry );
1008 return pCurrentEntry;
1009 }
1010 return FirstSearchEntry( _out_entryText );
1011 }
1012
NextEntry(vcl::StringEntryIdentifier _currentEntry,OUString & _out_entryText) const1013 vcl::StringEntryIdentifier SvTreeListBox::NextEntry( vcl::StringEntryIdentifier _currentEntry, OUString& _out_entryText ) const
1014 {
1015 return NextSearchEntry( _currentEntry, _out_entryText );
1016 }
1017
SelectEntry(vcl::StringEntryIdentifier _entry)1018 void SvTreeListBox::SelectEntry( vcl::StringEntryIdentifier _entry )
1019 {
1020 SelectSearchEntry( _entry );
1021 }
1022
HandleKeyInput(const KeyEvent & _rKEvt)1023 bool SvTreeListBox::HandleKeyInput( const KeyEvent& _rKEvt )
1024 {
1025 if ( _rKEvt.GetKeyCode().IsMod1() )
1026 return false;
1027
1028 if ( IsEntryMnemonicsEnabled()
1029 && mpImpl->m_aMnemonicEngine.HandleKeyEvent( _rKEvt )
1030 )
1031 return true;
1032
1033 if (mbQuickSearch)
1034 {
1035 mpImpl->m_bDoingQuickSelection = true;
1036 const bool bHandled = mpImpl->m_aQuickSelectionEngine.HandleKeyEvent( _rKEvt );
1037 mpImpl->m_bDoingQuickSelection = false;
1038 if ( bHandled )
1039 return true;
1040 }
1041
1042 return false;
1043 }
1044
EditingCanceled() const1045 bool SvTreeListBox::EditingCanceled() const
1046 {
1047 return pEdCtrl && pEdCtrl->EditingCanceled();
1048 }
1049
1050
1051 //JP 28.3.2001: new Drag & Drop API
AcceptDrop(const AcceptDropEvent & rEvt)1052 sal_Int8 SvTreeListBox::AcceptDrop( const AcceptDropEvent& rEvt )
1053 {
1054 sal_Int8 nRet = DND_ACTION_NONE;
1055
1056 if (rEvt.mbLeaving || !CheckDragAndDropMode(g_pDDSource, rEvt.mnAction))
1057 {
1058 ImplShowTargetEmphasis( pTargetEntry, false );
1059 }
1060 else if( nDragDropMode == DragDropMode::NONE )
1061 {
1062 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no target" );
1063 }
1064 else
1065 {
1066 SvTreeListEntry* pEntry = GetDropTarget( rEvt.maPosPixel );
1067 if( !IsDropFormatSupported( SotClipboardFormatId::TREELISTBOX ) )
1068 {
1069 SAL_WARN( "svtools.contnr", "SvTreeListBox::QueryDrop(): no format" );
1070 }
1071 else
1072 {
1073 DBG_ASSERT(g_pDDSource, "SvTreeListBox::QueryDrop(): SourceBox == 0");
1074 if (!( pEntry && g_pDDSource->GetModel() == GetModel()
1075 && DND_ACTION_MOVE == rEvt.mnAction
1076 && (pEntry->nEntryFlags & SvTLEntryFlags::DISABLE_DROP)))
1077 {
1078 if( NotifyAcceptDrop( pEntry ))
1079 nRet = rEvt.mnAction;
1080 }
1081 }
1082
1083 // **** draw emphasis ****
1084 if( DND_ACTION_NONE == nRet )
1085 ImplShowTargetEmphasis( pTargetEntry, false );
1086 else if( pEntry != pTargetEntry || !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS) )
1087 {
1088 ImplShowTargetEmphasis( pTargetEntry, false );
1089 pTargetEntry = pEntry;
1090 ImplShowTargetEmphasis( pTargetEntry, true );
1091 }
1092 }
1093 return nRet;
1094 }
1095
ExecuteDrop(const ExecuteDropEvent & rEvt,SvTreeListBox * pSourceView)1096 sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt, SvTreeListBox* pSourceView )
1097 {
1098 assert(pSourceView);
1099 pSourceView->EnableSelectionAsDropTarget();
1100
1101 ImplShowTargetEmphasis( pTargetEntry, false );
1102 g_pDDTarget = this;
1103
1104 TransferableDataHelper aData( rEvt.maDropEvent.Transferable );
1105
1106 sal_Int8 nRet;
1107 if( aData.HasFormat( SotClipboardFormatId::TREELISTBOX ))
1108 nRet = rEvt.mnAction;
1109 else
1110 nRet = DND_ACTION_NONE;
1111
1112 if( DND_ACTION_NONE != nRet )
1113 {
1114 nRet = DND_ACTION_NONE;
1115
1116 SvTreeListEntry* pTarget = pTargetEntry; // may be 0!
1117
1118 if( DND_ACTION_COPY == rEvt.mnAction )
1119 {
1120 if (CopySelection(g_pDDSource, pTarget))
1121 nRet = rEvt.mnAction;
1122 }
1123 else if( DND_ACTION_MOVE == rEvt.mnAction )
1124 {
1125 if (MoveSelectionCopyFallbackPossible( g_pDDSource, pTarget, false ))
1126 nRet = rEvt.mnAction;
1127 }
1128 else if( DND_ACTION_COPYMOVE == rEvt.mnAction )
1129 {
1130 if (MoveSelectionCopyFallbackPossible(g_pDDSource, pTarget, true))
1131 nRet = rEvt.mnAction;
1132 }
1133 }
1134 return nRet;
1135 }
1136
ExecuteDrop(const ExecuteDropEvent & rEvt)1137 sal_Int8 SvTreeListBox::ExecuteDrop( const ExecuteDropEvent& rEvt )
1138 {
1139 return ExecuteDrop( rEvt, g_pDDSource );
1140 }
1141
1142 /**
1143 * This sets the global variables used to determine the
1144 * in-process drag source.
1145 */
SetupDragOrigin()1146 void SvTreeListBox::SetupDragOrigin()
1147 {
1148 g_pDDSource = this;
1149 g_pDDTarget = nullptr;
1150 }
1151
StartDrag(sal_Int8,const Point & rPosPixel)1152 void SvTreeListBox::StartDrag( sal_Int8, const Point& rPosPixel )
1153 {
1154
1155 Point aEventPos( rPosPixel );
1156 MouseEvent aMouseEvt( aEventPos, 1, MouseEventModifiers::SELECT, MOUSE_LEFT );
1157 MouseButtonUp( aMouseEvt );
1158
1159 nOldDragMode = GetDragDropMode();
1160 if ( nOldDragMode == DragDropMode::NONE )
1161 return;
1162
1163 ReleaseMouse();
1164
1165 SvTreeListEntry* pEntry = GetEntry( rPosPixel ); // GetDropTarget( rPos );
1166 if( !pEntry )
1167 {
1168 DragFinished( DND_ACTION_NONE );
1169 return;
1170 }
1171
1172 rtl::Reference<TransferDataContainer> pContainer = new TransferDataContainer;
1173 nDragDropMode = NotifyStartDrag( *pContainer, pEntry );
1174 if( nDragDropMode == DragDropMode::NONE || 0 == GetSelectionCount() )
1175 {
1176 nDragDropMode = nOldDragMode;
1177 DragFinished( DND_ACTION_NONE );
1178 return;
1179 }
1180
1181 SetupDragOrigin();
1182
1183 // apparently some (unused) content is needed
1184 pContainer->CopyAnyData( SotClipboardFormatId::TREELISTBOX,
1185 "unused", SAL_N_ELEMENTS("unused") );
1186
1187 bool bOldUpdateMode = Control::IsUpdateMode();
1188 Control::SetUpdateMode( true );
1189 Update();
1190 Control::SetUpdateMode( bOldUpdateMode );
1191
1192 // Disallow using the selection and its children as drop targets.
1193 // Important: If the selection of the SourceListBox is changed in the
1194 // DropHandler, the entries have to be allowed as drop targets again:
1195 // (GetSourceListBox()->EnableSelectionAsDropTarget( true, true );)
1196 EnableSelectionAsDropTarget( false );
1197
1198 pContainer->StartDrag( this, DND_ACTION_COPYMOVE | DND_ACTION_LINK, GetDragFinishedHdl() );
1199 }
1200
DragFinished(sal_Int8 nAction)1201 void SvTreeListBox::DragFinished( sal_Int8
1202 #ifndef UNX
1203 nAction
1204 #endif
1205 )
1206 {
1207 EnableSelectionAsDropTarget();
1208
1209 #ifndef UNX
1210 if ( (nAction == DND_ACTION_MOVE)
1211 && ( (g_pDDTarget && (g_pDDTarget->GetModel() != GetModel()))
1212 || !g_pDDTarget))
1213 {
1214 RemoveSelection();
1215 }
1216 #endif
1217
1218 ImplShowTargetEmphasis( pTargetEntry, false );
1219 g_pDDSource = nullptr;
1220 g_pDDTarget = nullptr;
1221 pTargetEntry = nullptr;
1222 nDragDropMode = nOldDragMode;
1223 }
1224
NotifyStartDrag(TransferDataContainer &,SvTreeListEntry *)1225 DragDropMode SvTreeListBox::NotifyStartDrag( TransferDataContainer&, SvTreeListEntry* )
1226 {
1227 return DragDropMode(0xffff);
1228 }
1229
NotifyAcceptDrop(SvTreeListEntry *)1230 bool SvTreeListBox::NotifyAcceptDrop( SvTreeListEntry* )
1231 {
1232 return true;
1233 }
1234
1235 // Handler and methods for Drag - finished handler.
1236 // The with get GetDragFinishedHdl() get link can set on the
1237 // TransferDataContainer. This link is a callback for the DragFinished
1238 // call. AddBox method is called from the GetDragFinishedHdl() and the
1239 // remove is called in link callback and in the destructor. So it can't
1240 // called to a deleted object.
1241
1242 namespace
1243 {
1244 struct SortLBoxes : public rtl::Static<std::set<sal_uLong>, SortLBoxes> {};
1245 }
1246
AddBoxToDDList_Impl(const SvTreeListBox & rB)1247 void SvTreeListBox::AddBoxToDDList_Impl( const SvTreeListBox& rB )
1248 {
1249 sal_uLong nVal = reinterpret_cast<sal_uLong>(&rB);
1250 SortLBoxes::get().insert( nVal );
1251 }
1252
RemoveBoxFromDDList_Impl(const SvTreeListBox & rB)1253 void SvTreeListBox::RemoveBoxFromDDList_Impl( const SvTreeListBox& rB )
1254 {
1255 sal_uLong nVal = reinterpret_cast<sal_uLong>(&rB);
1256 SortLBoxes::get().erase( nVal );
1257 }
1258
IMPL_LINK(SvTreeListBox,DragFinishHdl_Impl,sal_Int8,nAction,void)1259 IMPL_LINK( SvTreeListBox, DragFinishHdl_Impl, sal_Int8, nAction, void )
1260 {
1261 sal_uLong nVal = reinterpret_cast<sal_uLong>(this);
1262 std::set<sal_uLong> &rSortLBoxes = SortLBoxes::get();
1263 std::set<sal_uLong>::const_iterator it = rSortLBoxes.find(nVal);
1264 if( it != rSortLBoxes.end() )
1265 {
1266 DragFinished( nAction );
1267 rSortLBoxes.erase( it );
1268 }
1269 }
1270
GetDragFinishedHdl() const1271 Link<sal_Int8,void> SvTreeListBox::GetDragFinishedHdl() const
1272 {
1273 AddBoxToDDList_Impl( *this );
1274 return LINK( const_cast<SvTreeListBox*>(this), SvTreeListBox, DragFinishHdl_Impl );
1275 }
1276
1277 /*
1278 Bugs/TODO
1279
1280 - calculate rectangle when editing in-place (bug with some fonts)
1281 - SetSpaceBetweenEntries: offset is not taken into account in SetEntryHeight
1282 */
1283
1284 #define SV_LBOX_DEFAULT_INDENT_PIXEL 20
1285
InitTreeView()1286 void SvTreeListBox::InitTreeView()
1287 {
1288 pCheckButtonData = nullptr;
1289 pEdEntry = nullptr;
1290 pEdItem = nullptr;
1291 nEntryHeight = 0;
1292 pEdCtrl = nullptr;
1293 nFirstSelTab = 0;
1294 nLastSelTab = 0;
1295 nFocusWidth = -1;
1296 mnCheckboxItemWidth = 0;
1297
1298 nTreeFlags = SvTreeFlags::RECALCTABS;
1299 nIndent = SV_LBOX_DEFAULT_INDENT_PIXEL;
1300 nEntryHeightOffs = SV_ENTRYHEIGHTOFFS_PIXEL;
1301 pImpl.reset( new SvImpLBox( this, GetModel(), GetStyle() ) );
1302
1303 mbContextBmpExpanded = true;
1304 nContextBmpWidthMax = 0;
1305
1306 SetFont( GetFont() );
1307 AdjustEntryHeightAndRecalc();
1308
1309 SetSpaceBetweenEntries( 0 );
1310 SetLineColor();
1311 InitSettings();
1312 ImplInitStyle();
1313 SetTabs();
1314 }
1315
GetEntryAltText(SvTreeListEntry *) const1316 OUString SvTreeListBox::GetEntryAltText( SvTreeListEntry* ) const
1317 {
1318 return OUString();
1319 }
1320
GetEntryLongDescription(SvTreeListEntry *) const1321 OUString SvTreeListBox::GetEntryLongDescription( SvTreeListEntry* ) const
1322 {
1323 return OUString();
1324 }
1325
SearchEntryTextWithHeadTitle(SvTreeListEntry * pEntry)1326 OUString SvTreeListBox::SearchEntryTextWithHeadTitle( SvTreeListEntry* pEntry )
1327 {
1328 assert(pEntry);
1329 OUStringBuffer sRet;
1330
1331 sal_uInt16 nCount = pEntry->ItemCount();
1332 sal_uInt16 nCur = 0;
1333 while( nCur < nCount )
1334 {
1335 SvLBoxItem& rItem = pEntry->GetItem( nCur );
1336 if ( (rItem.GetType() == SvLBoxItemType::String) &&
1337 !static_cast<SvLBoxString&>( rItem ).GetText().isEmpty() )
1338 {
1339 sRet.append(static_cast<SvLBoxString&>( rItem ).GetText()).append(",");
1340 }
1341 nCur++;
1342 }
1343
1344 if (!sRet.isEmpty())
1345 sRet = sRet.copy(0, sRet.getLength() - 1);
1346 return sRet.makeStringAndClear();
1347 }
1348
~SvTreeListBox()1349 SvTreeListBox::~SvTreeListBox()
1350 {
1351 disposeOnce();
1352 }
1353
dispose()1354 void SvTreeListBox::dispose()
1355 {
1356 if( pImpl )
1357 {
1358 pImpl->CallEventListeners( VclEventId::ObjectDying );
1359 pImpl.reset();
1360 }
1361 if( mpImpl )
1362 {
1363 ClearTabList();
1364
1365 pEdCtrl.reset();
1366
1367 SvListView::dispose();
1368
1369 SvTreeListBox::RemoveBoxFromDDList_Impl( *this );
1370
1371 if (this == g_pDDSource)
1372 g_pDDSource = nullptr;
1373 if (this == g_pDDTarget)
1374 g_pDDTarget = nullptr;
1375 mpImpl.reset();
1376 }
1377
1378 DropTargetHelper::dispose();
1379 DragSourceHelper::dispose();
1380 Control::dispose();
1381 }
1382
SetNoAutoCurEntry(bool b)1383 void SvTreeListBox::SetNoAutoCurEntry( bool b )
1384 {
1385 pImpl->SetNoAutoCurEntry( b );
1386 }
1387
SetSublistOpenWithReturn()1388 void SvTreeListBox::SetSublistOpenWithReturn()
1389 {
1390 pImpl->m_bSubLstOpRet = true;
1391 }
1392
SetSublistOpenWithLeftRight()1393 void SvTreeListBox::SetSublistOpenWithLeftRight()
1394 {
1395 pImpl->m_bSubLstOpLR = true;
1396 }
1397
SetSublistDontOpenWithDoubleClick(bool bDontOpen)1398 void SvTreeListBox::SetSublistDontOpenWithDoubleClick(bool bDontOpen)
1399 {
1400 pImpl->m_bSubLstOpDblClick = !bDontOpen;
1401 }
1402
Resize()1403 void SvTreeListBox::Resize()
1404 {
1405 if( IsEditingActive() )
1406 EndEditing( true );
1407
1408 Control::Resize();
1409
1410 pImpl->Resize();
1411 nFocusWidth = -1;
1412 pImpl->ShowCursor( false );
1413 pImpl->ShowCursor( true );
1414 }
1415
1416 /* Cases:
1417
1418 A) entries have bitmaps
1419 0. no buttons
1420 1. node buttons (can optionally also be on root items)
1421 2. node buttons (can optionally also be on root items) + CheckButton
1422 3. CheckButton
1423 B) entries don't have bitmaps (=>via WindowBits because of D&D!)
1424 0. no buttons
1425 1. node buttons (can optionally also be on root items)
1426 2. node buttons (can optionally also be on root items) + CheckButton
1427 3. CheckButton
1428 */
1429
1430 #define NO_BUTTONS 0
1431 #define NODE_BUTTONS 1
1432 #define NODE_AND_CHECK_BUTTONS 2
1433 #define CHECK_BUTTONS 3
1434
1435 #define TABFLAGS_TEXT (SvLBoxTabFlags::DYNAMIC | \
1436 SvLBoxTabFlags::ADJUST_LEFT | \
1437 SvLBoxTabFlags::EDITABLE | \
1438 SvLBoxTabFlags::SHOW_SELECTION)
1439
1440 #define TABFLAGS_CONTEXTBMP (SvLBoxTabFlags::DYNAMIC | SvLBoxTabFlags::ADJUST_CENTER)
1441
1442 #define TABFLAGS_CHECKBTN (SvLBoxTabFlags::DYNAMIC | \
1443 SvLBoxTabFlags::ADJUST_CENTER)
1444
1445 #define TAB_STARTPOS 2
1446
1447 // take care of GetTextOffset when doing changes
SetTabs()1448 void SvTreeListBox::SetTabs()
1449 {
1450 if( IsEditingActive() )
1451 EndEditing( true );
1452 nTreeFlags &= ~SvTreeFlags::RECALCTABS;
1453 nFocusWidth = -1;
1454 const WinBits nStyle( GetStyle() );
1455 bool bHasButtons = (nStyle & WB_HASBUTTONS)!=0;
1456 bool bHasButtonsAtRoot = (nStyle & (WB_HASLINESATROOT |
1457 WB_HASBUTTONSATROOT))!=0;
1458 long nStartPos = TAB_STARTPOS;
1459 long nNodeWidthPixel = GetExpandedNodeBmp().GetSizePixel().Width();
1460
1461 // pCheckButtonData->Width() knows nothing about the native checkbox width,
1462 // so we have mnCheckboxItemWidth which becomes valid when something is added.
1463 long nCheckWidth = 0;
1464 if( nTreeFlags & SvTreeFlags::CHKBTN )
1465 nCheckWidth = mnCheckboxItemWidth;
1466 long nCheckWidthDIV2 = nCheckWidth / 2;
1467
1468 long nContextWidth = nContextBmpWidthMax;
1469 long nContextWidthDIV2 = nContextWidth / 2;
1470
1471 ClearTabList();
1472
1473 int nCase = NO_BUTTONS;
1474 if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
1475 {
1476 if( bHasButtons )
1477 nCase = NODE_BUTTONS;
1478 }
1479 else
1480 {
1481 if( bHasButtons )
1482 nCase = NODE_AND_CHECK_BUTTONS;
1483 else
1484 nCase = CHECK_BUTTONS;
1485 }
1486
1487 switch( nCase )
1488 {
1489 case NO_BUTTONS :
1490 nStartPos += nContextWidthDIV2; // because of centering
1491 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1492 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1493 // only set a distance if there are bitmaps
1494 if( nContextBmpWidthMax )
1495 nStartPos += 5; // distance context bitmap to text
1496 AddTab( nStartPos, TABFLAGS_TEXT );
1497 break;
1498
1499 case NODE_BUTTONS :
1500 if( bHasButtonsAtRoot )
1501 nStartPos += ( nIndent + (nNodeWidthPixel/2) );
1502 else
1503 nStartPos += nContextWidthDIV2;
1504 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1505 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1506 // only set a distance if there are bitmaps
1507 if( nContextBmpWidthMax )
1508 nStartPos += 5; // distance context bitmap to text
1509 AddTab( nStartPos, TABFLAGS_TEXT );
1510 break;
1511
1512 case NODE_AND_CHECK_BUTTONS :
1513 if( bHasButtonsAtRoot )
1514 nStartPos += ( nIndent + nNodeWidthPixel );
1515 else
1516 nStartPos += nCheckWidthDIV2;
1517 AddTab( nStartPos, TABFLAGS_CHECKBTN );
1518 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1519 nStartPos += 3; // distance CheckButton to context bitmap
1520 nStartPos += nContextWidthDIV2; // center of context bitmap
1521 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1522 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1523 // only set a distance if there are bitmaps
1524 if( nContextBmpWidthMax )
1525 nStartPos += 5; // distance context bitmap to text
1526 AddTab( nStartPos, TABFLAGS_TEXT );
1527 break;
1528
1529 case CHECK_BUTTONS :
1530 nStartPos += nCheckWidthDIV2;
1531 AddTab( nStartPos, TABFLAGS_CHECKBTN );
1532 nStartPos += nCheckWidthDIV2; // right edge of CheckButton
1533 nStartPos += 3; // distance CheckButton to context bitmap
1534 nStartPos += nContextWidthDIV2; // center of context bitmap
1535 AddTab( nStartPos, TABFLAGS_CONTEXTBMP );
1536 nStartPos += nContextWidthDIV2; // right edge of context bitmap
1537 // only set a distance if there are bitmaps
1538 if( nContextBmpWidthMax )
1539 nStartPos += 5; // distance context bitmap to text
1540 AddTab( nStartPos, TABFLAGS_TEXT );
1541 break;
1542 }
1543 pImpl->NotifyTabsChanged();
1544 }
1545
InitEntry(SvTreeListEntry * pEntry,const OUString & aStr,const Image & aCollEntryBmp,const Image & aExpEntryBmp)1546 void SvTreeListBox::InitEntry(SvTreeListEntry* pEntry,
1547 const OUString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp)
1548 {
1549 if( nTreeFlags & SvTreeFlags::CHKBTN )
1550 {
1551 pEntry->AddItem(std::make_unique<SvLBoxButton>(pCheckButtonData));
1552 }
1553
1554 pEntry->AddItem(std::make_unique<SvLBoxContextBmp>( aCollEntryBmp,aExpEntryBmp, mbContextBmpExpanded));
1555
1556 pEntry->AddItem(std::make_unique<SvLBoxString>(aStr));
1557 }
1558
GetEntryText(SvTreeListEntry * pEntry) const1559 OUString SvTreeListBox::GetEntryText(SvTreeListEntry* pEntry) const
1560 {
1561 assert(pEntry);
1562 SvLBoxString* pItem = static_cast<SvLBoxString*>(pEntry->GetFirstItem(SvLBoxItemType::String));
1563 assert(pItem);
1564 return pItem->GetText();
1565 }
1566
GetExpandedEntryBmp(const SvTreeListEntry * pEntry)1567 const Image& SvTreeListBox::GetExpandedEntryBmp(const SvTreeListEntry* pEntry)
1568 {
1569 assert(pEntry);
1570 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
1571 assert(pItem);
1572 return pItem->GetBitmap2( );
1573 }
1574
GetCollapsedEntryBmp(const SvTreeListEntry * pEntry)1575 const Image& SvTreeListBox::GetCollapsedEntryBmp( const SvTreeListEntry* pEntry )
1576 {
1577 assert(pEntry);
1578 const SvLBoxContextBmp* pItem = static_cast<const SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
1579 assert(pItem);
1580 return pItem->GetBitmap1( );
1581 }
1582
IMPL_LINK(SvTreeListBox,CheckButtonClick,SvLBoxButtonData *,pData,void)1583 IMPL_LINK( SvTreeListBox, CheckButtonClick, SvLBoxButtonData *, pData, void )
1584 {
1585 pHdlEntry = pData->GetActEntry();
1586 CheckButtonHdl();
1587 }
1588
InsertEntry(const OUString & rText,SvTreeListEntry * pParent,bool bChildrenOnDemand,sal_uLong nPos,void * pUser)1589 SvTreeListEntry* SvTreeListBox::InsertEntry(
1590 const OUString& rText,
1591 SvTreeListEntry* pParent,
1592 bool bChildrenOnDemand, sal_uLong nPos,
1593 void* pUser
1594 )
1595 {
1596 nTreeFlags |= SvTreeFlags::MANINS;
1597
1598 const Image& rDefExpBmp = pImpl->GetDefaultEntryExpBmp( );
1599 const Image& rDefColBmp = pImpl->GetDefaultEntryColBmp( );
1600
1601 aCurInsertedExpBmp = rDefExpBmp;
1602 aCurInsertedColBmp = rDefColBmp;
1603
1604 SvTreeListEntry* pEntry = new SvTreeListEntry;
1605 pEntry->SetUserData( pUser );
1606 InitEntry( pEntry, rText, rDefColBmp, rDefExpBmp );
1607 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1608
1609 if( !pParent )
1610 Insert( pEntry, nPos );
1611 else
1612 Insert( pEntry, pParent, nPos );
1613
1614 aPrevInsertedExpBmp = rDefExpBmp;
1615 aPrevInsertedColBmp = rDefColBmp;
1616
1617 nTreeFlags &= ~SvTreeFlags::MANINS;
1618
1619 return pEntry;
1620 }
1621
InsertEntry(const OUString & rText,const Image & aExpEntryBmp,const Image & aCollEntryBmp,SvTreeListEntry * pParent,bool bChildrenOnDemand,sal_uLong nPos,void * pUser)1622 SvTreeListEntry* SvTreeListBox::InsertEntry( const OUString& rText,
1623 const Image& aExpEntryBmp, const Image& aCollEntryBmp,
1624 SvTreeListEntry* pParent, bool bChildrenOnDemand, sal_uLong nPos, void* pUser )
1625 {
1626 nTreeFlags |= SvTreeFlags::MANINS;
1627
1628 aCurInsertedExpBmp = aExpEntryBmp;
1629 aCurInsertedColBmp = aCollEntryBmp;
1630
1631 SvTreeListEntry* pEntry = new SvTreeListEntry;
1632 pEntry->SetUserData( pUser );
1633 InitEntry( pEntry, rText, aCollEntryBmp, aExpEntryBmp );
1634
1635 pEntry->EnableChildrenOnDemand( bChildrenOnDemand );
1636
1637 if( !pParent )
1638 Insert( pEntry, nPos );
1639 else
1640 Insert( pEntry, pParent, nPos );
1641
1642 aPrevInsertedExpBmp = aExpEntryBmp;
1643 aPrevInsertedColBmp = aCollEntryBmp;
1644
1645 nTreeFlags &= ~SvTreeFlags::MANINS;
1646
1647 return pEntry;
1648 }
1649
SetEntryText(SvTreeListEntry * pEntry,const OUString & rStr)1650 void SvTreeListBox::SetEntryText(SvTreeListEntry* pEntry, const OUString& rStr)
1651 {
1652 SvLBoxString* pItem = static_cast<SvLBoxString*>(pEntry->GetFirstItem(SvLBoxItemType::String));
1653 assert(pItem);
1654 pItem->SetText(rStr);
1655 pItem->InitViewData( this, pEntry );
1656 GetModel()->InvalidateEntry( pEntry );
1657 }
1658
SetExpandedEntryBmp(SvTreeListEntry * pEntry,const Image & aBmp)1659 void SvTreeListBox::SetExpandedEntryBmp( SvTreeListEntry* pEntry, const Image& aBmp )
1660 {
1661 SvLBoxContextBmp* pItem = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
1662
1663 assert(pItem);
1664 pItem->SetBitmap2( aBmp );
1665
1666 GetModel()->InvalidateEntry( pEntry );
1667 SetEntryHeight( pEntry );
1668 Size aSize = aBmp.GetSizePixel();
1669 short nWidth = pImpl->UpdateContextBmpWidthVector( pEntry, static_cast<short>(aSize.Width()) );
1670 if( nWidth > nContextBmpWidthMax )
1671 {
1672 nContextBmpWidthMax = nWidth;
1673 SetTabs();
1674 }
1675 }
1676
SetCollapsedEntryBmp(SvTreeListEntry * pEntry,const Image & aBmp)1677 void SvTreeListBox::SetCollapsedEntryBmp(SvTreeListEntry* pEntry,const Image& aBmp )
1678 {
1679 SvLBoxContextBmp* pItem = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp));
1680
1681 assert(pItem);
1682 pItem->SetBitmap1( aBmp );
1683
1684 GetModel()->InvalidateEntry( pEntry );
1685 SetEntryHeight( pEntry );
1686 Size aSize = aBmp.GetSizePixel();
1687 short nWidth = pImpl->UpdateContextBmpWidthVector( pEntry, static_cast<short>(aSize.Width()) );
1688 if( nWidth > nContextBmpWidthMax )
1689 {
1690 nContextBmpWidthMax = nWidth;
1691 SetTabs();
1692 }
1693 }
1694
CheckBoxInserted(SvTreeListEntry * pEntry)1695 void SvTreeListBox::CheckBoxInserted(SvTreeListEntry* pEntry)
1696 {
1697 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
1698 if( pItem )
1699 {
1700 auto nWidth = pItem->GetWidth(this, pEntry);
1701 if( mnCheckboxItemWidth < nWidth )
1702 {
1703 mnCheckboxItemWidth = nWidth;
1704 nTreeFlags |= SvTreeFlags::RECALCTABS;
1705 }
1706 }
1707 }
1708
ImpEntryInserted(SvTreeListEntry * pEntry)1709 void SvTreeListBox::ImpEntryInserted( SvTreeListEntry* pEntry )
1710 {
1711
1712 SvTreeListEntry* pParent = pModel->GetParent( pEntry );
1713 if( pParent )
1714 {
1715 SvTLEntryFlags nFlags = pParent->GetFlags();
1716 nFlags &= ~SvTLEntryFlags::NO_NODEBMP;
1717 pParent->SetFlags( nFlags );
1718 }
1719
1720 if(!((nTreeFlags & SvTreeFlags::MANINS) &&
1721 (aPrevInsertedExpBmp == aCurInsertedExpBmp) &&
1722 (aPrevInsertedColBmp == aCurInsertedColBmp) ))
1723 {
1724 Size aSize = GetCollapsedEntryBmp( pEntry ).GetSizePixel();
1725 if( aSize.Width() > nContextBmpWidthMax )
1726 {
1727 nContextBmpWidthMax = static_cast<short>(aSize.Width());
1728 nTreeFlags |= SvTreeFlags::RECALCTABS;
1729 }
1730 aSize = GetExpandedEntryBmp( pEntry ).GetSizePixel();
1731 if( aSize.Width() > nContextBmpWidthMax )
1732 {
1733 nContextBmpWidthMax = static_cast<short>(aSize.Width());
1734 nTreeFlags |= SvTreeFlags::RECALCTABS;
1735 }
1736 }
1737 SetEntryHeight( pEntry );
1738
1739 if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
1740 return;
1741
1742 CheckBoxInserted(pEntry);
1743 }
1744
SetCheckButtonState(SvTreeListEntry * pEntry,SvButtonState eState)1745 void SvTreeListBox::SetCheckButtonState( SvTreeListEntry* pEntry, SvButtonState eState)
1746 {
1747 if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
1748 return;
1749
1750 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
1751 if(!pItem)
1752 return ;
1753 switch( eState )
1754 {
1755 case SvButtonState::Checked:
1756 pItem->SetStateChecked();
1757 break;
1758
1759 case SvButtonState::Unchecked:
1760 pItem->SetStateUnchecked();
1761 break;
1762
1763 case SvButtonState::Tristate:
1764 pItem->SetStateTristate();
1765 break;
1766 }
1767 InvalidateEntry( pEntry );
1768 }
1769
GetCheckButtonState(SvTreeListEntry * pEntry) const1770 SvButtonState SvTreeListBox::GetCheckButtonState( SvTreeListEntry* pEntry ) const
1771 {
1772 SvButtonState eState = SvButtonState::Unchecked;
1773 if( pEntry && ( nTreeFlags & SvTreeFlags::CHKBTN ) )
1774 {
1775 SvLBoxButton* pItem = static_cast<SvLBoxButton*>(pEntry->GetFirstItem(SvLBoxItemType::Button));
1776 if(!pItem)
1777 return SvButtonState::Tristate;
1778 SvItemStateFlags nButtonFlags = pItem->GetButtonFlags();
1779 eState = SvLBoxButtonData::ConvertToButtonState( nButtonFlags );
1780 }
1781 return eState;
1782 }
1783
CheckButtonHdl()1784 void SvTreeListBox::CheckButtonHdl()
1785 {
1786 aCheckButtonHdl.Call( this );
1787 if ( pCheckButtonData )
1788 pImpl->CallEventListeners( VclEventId::CheckboxToggle, static_cast<void*>(pCheckButtonData->GetActEntry()) );
1789 }
1790
1791
1792 // TODO: Currently all data is cloned so that they conform to the default tree
1793 // view format. Actually, the model should be used as a reference here. This
1794 // leads to us _not_ calling SvTreeListEntry::Clone, but only its base class
1795 // SvTreeListEntry.
1796
1797
CloneEntry(SvTreeListEntry * pSource)1798 SvTreeListEntry* SvTreeListBox::CloneEntry( SvTreeListEntry* pSource )
1799 {
1800 OUString aStr;
1801 Image aCollEntryBmp;
1802 Image aExpEntryBmp;
1803
1804 SvLBoxString* pStringItem = static_cast<SvLBoxString*>(pSource->GetFirstItem(SvLBoxItemType::String));
1805 if( pStringItem )
1806 aStr = pStringItem->GetText();
1807 SvLBoxContextBmp* pBmpItem = static_cast<SvLBoxContextBmp*>(pSource->GetFirstItem(SvLBoxItemType::ContextBmp));
1808 if( pBmpItem )
1809 {
1810 aCollEntryBmp = pBmpItem->GetBitmap1( );
1811 aExpEntryBmp = pBmpItem->GetBitmap2( );
1812 }
1813 SvTreeListEntry* pClone = new SvTreeListEntry;
1814 InitEntry( pClone, aStr, aCollEntryBmp, aExpEntryBmp );
1815 pClone->SvTreeListEntry::Clone( pSource );
1816 pClone->EnableChildrenOnDemand( pSource->HasChildrenOnDemand() );
1817 pClone->SetUserData( pSource->GetUserData() );
1818
1819 return pClone;
1820 }
1821
SetIndent(short nNewIndent)1822 void SvTreeListBox::SetIndent( short nNewIndent )
1823 {
1824 nIndent = nNewIndent;
1825 SetTabs();
1826 if( IsUpdateMode() )
1827 Invalidate();
1828 }
1829
GetDefaultExpandedEntryBmp() const1830 const Image& SvTreeListBox::GetDefaultExpandedEntryBmp( ) const
1831 {
1832 return pImpl->GetDefaultEntryExpBmp( );
1833 }
1834
GetDefaultCollapsedEntryBmp() const1835 const Image& SvTreeListBox::GetDefaultCollapsedEntryBmp( ) const
1836 {
1837 return pImpl->GetDefaultEntryColBmp( );
1838 }
1839
SetDefaultExpandedEntryBmp(const Image & aBmp)1840 void SvTreeListBox::SetDefaultExpandedEntryBmp( const Image& aBmp )
1841 {
1842 Size aSize = aBmp.GetSizePixel();
1843 if( aSize.Width() > nContextBmpWidthMax )
1844 nContextBmpWidthMax = static_cast<short>(aSize.Width());
1845 SetTabs();
1846
1847 pImpl->SetDefaultEntryExpBmp( aBmp );
1848 }
1849
SetDefaultCollapsedEntryBmp(const Image & aBmp)1850 void SvTreeListBox::SetDefaultCollapsedEntryBmp( const Image& aBmp )
1851 {
1852 Size aSize = aBmp.GetSizePixel();
1853 if( aSize.Width() > nContextBmpWidthMax )
1854 nContextBmpWidthMax = static_cast<short>(aSize.Width());
1855 SetTabs();
1856
1857 pImpl->SetDefaultEntryColBmp( aBmp );
1858 }
1859
EnableCheckButton(SvLBoxButtonData * pData)1860 void SvTreeListBox::EnableCheckButton( SvLBoxButtonData* pData )
1861 {
1862 if( !pData )
1863 nTreeFlags &= ~SvTreeFlags::CHKBTN;
1864 else
1865 {
1866 SetCheckButtonData( pData );
1867 nTreeFlags |= SvTreeFlags::CHKBTN;
1868 pData->SetLink( LINK(this, SvTreeListBox, CheckButtonClick));
1869 }
1870
1871 SetTabs();
1872 if( IsUpdateMode() )
1873 Invalidate();
1874 }
1875
SetCheckButtonData(SvLBoxButtonData * pData)1876 void SvTreeListBox::SetCheckButtonData( SvLBoxButtonData* pData )
1877 {
1878 if ( pData )
1879 pCheckButtonData = pData;
1880 }
1881
GetDefaultExpandedNodeImage()1882 const Image& SvTreeListBox::GetDefaultExpandedNodeImage( )
1883 {
1884 return SvImpLBox::GetDefaultExpandedNodeImage( );
1885 }
1886
GetDefaultCollapsedNodeImage()1887 const Image& SvTreeListBox::GetDefaultCollapsedNodeImage( )
1888 {
1889 return SvImpLBox::GetDefaultCollapsedNodeImage( );
1890 }
1891
SetNodeBitmaps(const Image & rCollapsedNodeBmp,const Image & rExpandedNodeBmp)1892 void SvTreeListBox::SetNodeBitmaps( const Image& rCollapsedNodeBmp, const Image& rExpandedNodeBmp )
1893 {
1894 SetExpandedNodeBmp( rExpandedNodeBmp );
1895 SetCollapsedNodeBmp( rCollapsedNodeBmp );
1896 SetTabs();
1897 }
1898
EditingEntry(SvTreeListEntry *,Selection &)1899 bool SvTreeListBox::EditingEntry( SvTreeListEntry*, Selection& )
1900 {
1901 return true;
1902 }
1903
EditedEntry(SvTreeListEntry *,const OUString &)1904 bool SvTreeListBox::EditedEntry( SvTreeListEntry* /*pEntry*/,const OUString& /*rNewText*/)
1905 {
1906 return true;
1907 }
1908
EnableInplaceEditing(bool bOn)1909 void SvTreeListBox::EnableInplaceEditing( bool bOn )
1910 {
1911 if (bOn)
1912 nImpFlags |= SvTreeListBoxFlags::EDT_ENABLED;
1913 else
1914 nImpFlags &= ~SvTreeListBoxFlags::EDT_ENABLED;
1915 }
1916
KeyInput(const KeyEvent & rKEvt)1917 void SvTreeListBox::KeyInput( const KeyEvent& rKEvt )
1918 {
1919 // under OS/2, we get key up/down even while editing
1920 if( IsEditingActive() )
1921 return;
1922
1923 if( !pImpl->KeyInput( rKEvt ) )
1924 {
1925 bool bHandled = HandleKeyInput( rKEvt );
1926 if ( !bHandled )
1927 Control::KeyInput( rKEvt );
1928 }
1929 }
1930
RequestingChildren(SvTreeListEntry * pParent)1931 void SvTreeListBox::RequestingChildren( SvTreeListEntry* pParent )
1932 {
1933 if( !pParent->HasChildren() )
1934 InsertEntry( "<dummy>", pParent );
1935 }
1936
GetFocus()1937 void SvTreeListBox::GetFocus()
1938 {
1939 //If there is no item in the tree, draw focus.
1940 if( !First())
1941 {
1942 Invalidate();
1943 }
1944 pImpl->GetFocus();
1945 Control::GetFocus();
1946
1947 SvTreeListEntry* pEntry = FirstSelected();
1948 if ( !pEntry )
1949 {
1950 pEntry = pImpl->GetCurrentEntry();
1951 }
1952 if (pImpl->m_pCursor)
1953 {
1954 if (pEntry != pImpl->m_pCursor)
1955 pEntry = pImpl->m_pCursor;
1956 }
1957 if ( pEntry )
1958 pImpl->CallEventListeners( VclEventId::ListboxTreeFocus, pEntry );
1959
1960 }
1961
LoseFocus()1962 void SvTreeListBox::LoseFocus()
1963 {
1964 // If there is no item in the tree, delete visual focus.
1965 if ( !First() )
1966 Invalidate();
1967 if ( pImpl )
1968 pImpl->LoseFocus();
1969 Control::LoseFocus();
1970 }
1971
ModelHasCleared()1972 void SvTreeListBox::ModelHasCleared()
1973 {
1974 pImpl->m_pCursor = nullptr; // else we crash in GetFocus when editing in-place
1975 pEdCtrl.reset();
1976 pImpl->Clear();
1977 nFocusWidth = -1;
1978
1979 nContextBmpWidthMax = 0;
1980 SetDefaultExpandedEntryBmp( GetDefaultExpandedEntryBmp() );
1981 SetDefaultCollapsedEntryBmp( GetDefaultCollapsedEntryBmp() );
1982
1983 if( !(nTreeFlags & SvTreeFlags::FIXEDHEIGHT ))
1984 nEntryHeight = 0;
1985 AdjustEntryHeight();
1986 AdjustEntryHeight( GetDefaultExpandedEntryBmp() );
1987 AdjustEntryHeight( GetDefaultCollapsedEntryBmp() );
1988
1989 SvListView::ModelHasCleared();
1990 }
1991
ScrollOutputArea(short nDeltaEntries)1992 void SvTreeListBox::ScrollOutputArea( short nDeltaEntries )
1993 {
1994 if( !nDeltaEntries || !pImpl->m_aVerSBar->IsVisible() )
1995 return;
1996
1997 long nThumb = pImpl->m_aVerSBar->GetThumbPos();
1998 long nMax = pImpl->m_aVerSBar->GetRange().Max();
1999
2000 if( nDeltaEntries < 0 )
2001 {
2002 // move window up
2003 nDeltaEntries *= -1;
2004 long nVis = pImpl->m_aVerSBar->GetVisibleSize();
2005 long nTemp = nThumb + nVis;
2006 if( nDeltaEntries > (nMax - nTemp) )
2007 nDeltaEntries = static_cast<short>(nMax - nTemp);
2008 pImpl->PageDown( static_cast<sal_uInt16>(nDeltaEntries) );
2009 }
2010 else
2011 {
2012 if( nDeltaEntries > nThumb )
2013 nDeltaEntries = static_cast<short>(nThumb);
2014 pImpl->PageUp( static_cast<sal_uInt16>(nDeltaEntries) );
2015 }
2016 pImpl->SyncVerThumb();
2017 NotifyEndScroll();
2018 }
2019
ScrollToAbsPos(long nPos)2020 void SvTreeListBox::ScrollToAbsPos( long nPos )
2021 {
2022 pImpl->ScrollToAbsPos( nPos );
2023 }
2024
SetSelectionMode(SelectionMode eSelectMode)2025 void SvTreeListBox::SetSelectionMode( SelectionMode eSelectMode )
2026 {
2027 eSelMode = eSelectMode;
2028 pImpl->SetSelectionMode( eSelectMode );
2029 }
2030
SetDragDropMode(DragDropMode nDDMode)2031 void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode )
2032 {
2033 nDragDropMode = nDDMode;
2034 pImpl->SetDragDropMode( nDDMode );
2035 }
2036
SetEntryHeight(SvTreeListEntry const * pEntry)2037 void SvTreeListBox::SetEntryHeight( SvTreeListEntry const * pEntry )
2038 {
2039 short nHeightMax=0;
2040 sal_uInt16 nCount = pEntry->ItemCount();
2041 sal_uInt16 nCur = 0;
2042 SvViewDataEntry* pViewData = GetViewDataEntry( pEntry );
2043 while( nCur < nCount )
2044 {
2045 auto nHeight = SvLBoxItem::GetHeight(pViewData, nCur);
2046 if( nHeight > nHeightMax )
2047 nHeightMax = nHeight;
2048 nCur++;
2049 }
2050
2051 if( nHeightMax > nEntryHeight )
2052 {
2053 nEntryHeight = nHeightMax;
2054 Control::SetFont( GetFont() );
2055 pImpl->SetEntryHeight();
2056 }
2057 }
2058
SetEntryHeight(short nHeight,bool bForce)2059 void SvTreeListBox::SetEntryHeight( short nHeight, bool bForce )
2060 {
2061 if( nHeight > nEntryHeight || bForce )
2062 {
2063 nEntryHeight = nHeight;
2064 if( nEntryHeight )
2065 nTreeFlags |= SvTreeFlags::FIXEDHEIGHT;
2066 else
2067 nTreeFlags &= ~SvTreeFlags::FIXEDHEIGHT;
2068 Control::SetFont( GetFont() );
2069 pImpl->SetEntryHeight();
2070 }
2071 }
2072
SetEntryWidth(short nWidth)2073 void SvTreeListBox::SetEntryWidth( short nWidth )
2074 {
2075 nEntryWidth = nWidth;
2076 }
2077
AdjustEntryHeight(const Image & rBmp)2078 void SvTreeListBox::AdjustEntryHeight( const Image& rBmp )
2079 {
2080 const Size aSize( rBmp.GetSizePixel() );
2081 if( aSize.Height() > nEntryHeight )
2082 {
2083 nEntryHeight = static_cast<short>(aSize.Height()) + nEntryHeightOffs;
2084 pImpl->SetEntryHeight();
2085 }
2086 }
2087
AdjustEntryHeight()2088 void SvTreeListBox::AdjustEntryHeight()
2089 {
2090 Size aSize( GetTextWidth(OUString('X')), GetTextHeight() );
2091 if( aSize.Height() > nEntryHeight )
2092 {
2093 nEntryHeight = static_cast<short>(aSize.Height()) + nEntryHeightOffs;
2094 pImpl->SetEntryHeight();
2095 }
2096 }
2097
Expand(SvTreeListEntry * pParent)2098 bool SvTreeListBox::Expand( SvTreeListEntry* pParent )
2099 {
2100 pHdlEntry = pParent;
2101 bool bExpanded = false;
2102 SvTLEntryFlags nFlags;
2103
2104 if( pParent->HasChildrenOnDemand() )
2105 RequestingChildren( pParent );
2106 bool bExpandAllowed = pParent->HasChildren() && ExpandingHdl();
2107 // double check if the expander callback ended up removing all children
2108 if (pParent->HasChildren())
2109 {
2110 if (bExpandAllowed)
2111 {
2112 bExpanded = true;
2113 ExpandListEntry( pParent );
2114 pImpl->EntryExpanded( pParent );
2115 pHdlEntry = pParent;
2116 ExpandedHdl();
2117 SetAlternatingRowColors( mbAlternatingRowColors );
2118 }
2119 nFlags = pParent->GetFlags();
2120 nFlags &= ~SvTLEntryFlags::NO_NODEBMP;
2121 nFlags |= SvTLEntryFlags::HAD_CHILDREN;
2122 pParent->SetFlags( nFlags );
2123 }
2124 else
2125 {
2126 nFlags = pParent->GetFlags();
2127 nFlags |= SvTLEntryFlags::NO_NODEBMP;
2128 pParent->SetFlags( nFlags );
2129 GetModel()->InvalidateEntry( pParent ); // repaint
2130 }
2131
2132 // #i92103#
2133 if ( bExpanded )
2134 {
2135 pImpl->CallEventListeners( VclEventId::ItemExpanded, pParent );
2136 }
2137
2138 return bExpanded;
2139 }
2140
Collapse(SvTreeListEntry * pParent)2141 bool SvTreeListBox::Collapse( SvTreeListEntry* pParent )
2142 {
2143 pHdlEntry = pParent;
2144 bool bCollapsed = false;
2145
2146 if( ExpandingHdl() )
2147 {
2148 bCollapsed = true;
2149 pImpl->CollapsingEntry( pParent );
2150 CollapseListEntry( pParent );
2151 pImpl->EntryCollapsed( pParent );
2152 pHdlEntry = pParent;
2153 ExpandedHdl();
2154 SetAlternatingRowColors( mbAlternatingRowColors );
2155 }
2156
2157 // #i92103#
2158 if ( bCollapsed )
2159 {
2160 pImpl->CallEventListeners( VclEventId::ItemCollapsed, pParent );
2161 }
2162
2163 return bCollapsed;
2164 }
2165
Select(SvTreeListEntry * pEntry,bool bSelect)2166 bool SvTreeListBox::Select( SvTreeListEntry* pEntry, bool bSelect )
2167 {
2168 DBG_ASSERT(pEntry,"Select: Null-Ptr");
2169 bool bRetVal = SelectListEntry( pEntry, bSelect );
2170 DBG_ASSERT(IsSelected(pEntry)==bSelect,"Select failed");
2171 if( bRetVal )
2172 {
2173 pImpl->EntrySelected( pEntry, bSelect );
2174 pHdlEntry = pEntry;
2175 if( bSelect )
2176 {
2177 SelectHdl();
2178 CallEventListeners( VclEventId::ListboxTreeSelect, pEntry);
2179 }
2180 else
2181 DeselectHdl();
2182 }
2183 return bRetVal;
2184 }
2185
SelectChildren(SvTreeListEntry * pParent,bool bSelect)2186 sal_uLong SvTreeListBox::SelectChildren( SvTreeListEntry* pParent, bool bSelect )
2187 {
2188 pImpl->DestroyAnchor();
2189 sal_uLong nRet = 0;
2190 if( !pParent->HasChildren() )
2191 return 0;
2192 sal_uInt16 nRefDepth = pModel->GetDepth( pParent );
2193 SvTreeListEntry* pChild = FirstChild( pParent );
2194 do {
2195 nRet++;
2196 Select( pChild, bSelect );
2197 pChild = Next( pChild );
2198 } while( pChild && pModel->GetDepth( pChild ) > nRefDepth );
2199 return nRet;
2200 }
2201
SelectAll(bool bSelect,bool)2202 void SvTreeListBox::SelectAll( bool bSelect, bool )
2203 {
2204 pImpl->SelAllDestrAnch(
2205 bSelect,
2206 true, // delete anchor,
2207 true ); // even when using SelectionMode::Single, deselect the cursor
2208 }
2209
ModelHasInsertedTree(SvTreeListEntry * pEntry)2210 void SvTreeListBox::ModelHasInsertedTree( SvTreeListEntry* pEntry )
2211 {
2212 sal_uInt16 nRefDepth = pModel->GetDepth( pEntry );
2213 SvTreeListEntry* pTmp = pEntry;
2214 do
2215 {
2216 ImpEntryInserted( pTmp );
2217 pTmp = Next( pTmp );
2218 } while( pTmp && nRefDepth < pModel->GetDepth( pTmp ) );
2219 pImpl->TreeInserted( pEntry );
2220 }
2221
ModelHasInserted(SvTreeListEntry * pEntry)2222 void SvTreeListBox::ModelHasInserted( SvTreeListEntry* pEntry )
2223 {
2224 ImpEntryInserted( pEntry );
2225 pImpl->EntryInserted( pEntry );
2226 }
2227
ModelIsMoving(SvTreeListEntry * pSource)2228 void SvTreeListBox::ModelIsMoving(SvTreeListEntry* pSource )
2229 {
2230 pImpl->MovingEntry( pSource );
2231 }
2232
ModelHasMoved(SvTreeListEntry * pSource)2233 void SvTreeListBox::ModelHasMoved( SvTreeListEntry* pSource )
2234 {
2235 pImpl->EntryMoved( pSource );
2236 }
2237
ModelIsRemoving(SvTreeListEntry * pEntry)2238 void SvTreeListBox::ModelIsRemoving( SvTreeListEntry* pEntry )
2239 {
2240 if(pEdEntry == pEntry)
2241 pEdEntry = nullptr;
2242
2243 pImpl->RemovingEntry( pEntry );
2244 }
2245
ModelHasRemoved(SvTreeListEntry * pEntry)2246 void SvTreeListBox::ModelHasRemoved( SvTreeListEntry* pEntry )
2247 {
2248 if ( pEntry == pHdlEntry)
2249 pHdlEntry = nullptr;
2250 pImpl->EntryRemoved();
2251 }
2252
SetCollapsedNodeBmp(const Image & rBmp)2253 void SvTreeListBox::SetCollapsedNodeBmp( const Image& rBmp)
2254 {
2255 AdjustEntryHeight( rBmp );
2256 pImpl->SetCollapsedNodeBmp( rBmp );
2257 }
2258
SetExpandedNodeBmp(const Image & rBmp)2259 void SvTreeListBox::SetExpandedNodeBmp( const Image& rBmp )
2260 {
2261 AdjustEntryHeight( rBmp );
2262 pImpl->SetExpandedNodeBmp( rBmp );
2263 }
2264
2265
SetFont(const vcl::Font & rFont)2266 void SvTreeListBox::SetFont( const vcl::Font& rFont )
2267 {
2268 vcl::Font aTempFont( rFont );
2269 vcl::Font aOrigFont( GetFont() );
2270 aTempFont.SetTransparent( true );
2271 if (aTempFont == aOrigFont)
2272 return;
2273 Control::SetFont( aTempFont );
2274
2275 aTempFont.SetColor(aOrigFont.GetColor());
2276 aTempFont.SetFillColor(aOrigFont.GetFillColor());
2277 aTempFont.SetTransparent(aOrigFont.IsTransparent());
2278
2279 if (aTempFont == aOrigFont)
2280 return;
2281
2282 AdjustEntryHeightAndRecalc();
2283 }
2284
AdjustEntryHeightAndRecalc()2285 void SvTreeListBox::AdjustEntryHeightAndRecalc()
2286 {
2287 AdjustEntryHeight();
2288 // always invalidate, else things go wrong in SetEntryHeight
2289 RecalcViewData();
2290 }
2291
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rRect)2292 void SvTreeListBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
2293 {
2294 Control::Paint(rRenderContext, rRect);
2295 if (nTreeFlags & SvTreeFlags::RECALCTABS)
2296 SetTabs();
2297 pImpl->Paint(rRenderContext, rRect);
2298
2299 //Add visual focus draw
2300 if (First())
2301 return;
2302
2303 if (HasFocus())
2304 {
2305 long nHeight = rRenderContext.GetTextHeight();
2306 tools::Rectangle aRect(Point(0, 0), Size(GetSizePixel().Width(), nHeight));
2307 ShowFocus(aRect);
2308 }
2309 else
2310 {
2311 HideFocus();
2312 }
2313 }
2314
MouseButtonDown(const MouseEvent & rMEvt)2315 void SvTreeListBox::MouseButtonDown( const MouseEvent& rMEvt )
2316 {
2317 pImpl->MouseButtonDown( rMEvt );
2318 }
2319
MouseButtonUp(const MouseEvent & rMEvt)2320 void SvTreeListBox::MouseButtonUp( const MouseEvent& rMEvt )
2321 {
2322 pImpl->MouseButtonUp( rMEvt );
2323 }
2324
MouseMove(const MouseEvent & rMEvt)2325 void SvTreeListBox::MouseMove( const MouseEvent& rMEvt )
2326 {
2327 pImpl->MouseMove( rMEvt );
2328 }
2329
2330
SetUpdateMode(bool bUpdate)2331 void SvTreeListBox::SetUpdateMode( bool bUpdate )
2332 {
2333 pImpl->SetUpdateMode( bUpdate );
2334 mbUpdateAlternatingRows = bUpdate;
2335 SetAlternatingRowColors( mbAlternatingRowColors );
2336 }
2337
SetSpaceBetweenEntries(short nOffsLogic)2338 void SvTreeListBox::SetSpaceBetweenEntries( short nOffsLogic )
2339 {
2340 if( nOffsLogic != nEntryHeightOffs )
2341 {
2342 nEntryHeight = nEntryHeight - nEntryHeightOffs;
2343 nEntryHeightOffs = nOffsLogic;
2344 nEntryHeight = nEntryHeight + nOffsLogic;
2345 AdjustEntryHeightAndRecalc();
2346 pImpl->SetEntryHeight();
2347 }
2348 }
2349
SetCursor(SvTreeListEntry * pEntry,bool bForceNoSelect)2350 void SvTreeListBox::SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect )
2351 {
2352 pImpl->SetCursor(pEntry, bForceNoSelect);
2353 }
2354
SetCurEntry(SvTreeListEntry * pEntry)2355 void SvTreeListBox::SetCurEntry( SvTreeListEntry* pEntry )
2356 {
2357 pImpl->SetCurEntry( pEntry );
2358 }
2359
GetExpandedNodeBmp() const2360 Image const & SvTreeListBox::GetExpandedNodeBmp( ) const
2361 {
2362 return pImpl->GetExpandedNodeBmp( );
2363 }
2364
GetEntryPosition(SvTreeListEntry * pEntry) const2365 Point SvTreeListBox::GetEntryPosition( SvTreeListEntry* pEntry ) const
2366 {
2367 return pImpl->GetEntryPosition( pEntry );
2368 }
2369
MakeVisible(SvTreeListEntry * pEntry)2370 void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry )
2371 {
2372 pImpl->MakeVisible(pEntry);
2373 }
2374
MakeVisible(SvTreeListEntry * pEntry,bool bMoveToTop)2375 void SvTreeListBox::MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop )
2376 {
2377 pImpl->MakeVisible( pEntry, bMoveToTop );
2378 }
2379
ModelHasEntryInvalidated(SvTreeListEntry * pEntry)2380 void SvTreeListBox::ModelHasEntryInvalidated( SvTreeListEntry* pEntry )
2381 {
2382
2383 // reinitialize the separate items of the entries
2384 sal_uInt16 nCount = pEntry->ItemCount();
2385 for( sal_uInt16 nIdx = 0; nIdx < nCount; nIdx++ )
2386 {
2387 SvLBoxItem& rItem = pEntry->GetItem( nIdx );
2388 rItem.InitViewData( this, pEntry );
2389 }
2390
2391 // repaint
2392 pImpl->InvalidateEntry( pEntry );
2393 }
2394
EditItemText(SvTreeListEntry * pEntry,SvLBoxString * pItem,const Selection & rSelection)2395 void SvTreeListBox::EditItemText(SvTreeListEntry* pEntry, SvLBoxString* pItem, const Selection& rSelection)
2396 {
2397 assert(pEntry && pItem);
2398 if( IsSelected( pEntry ))
2399 {
2400 pImpl->ShowCursor( false );
2401 SelectListEntry( pEntry, false );
2402 pImpl->InvalidateEntry(pEntry);
2403 SelectListEntry( pEntry, true );
2404 pImpl->ShowCursor( true );
2405 }
2406 pEdEntry = pEntry;
2407 pEdItem = pItem;
2408 SvLBoxTab* pTab = GetTab( pEntry, pItem );
2409 DBG_ASSERT(pTab,"EditItemText:Tab not found");
2410
2411 auto nItemHeight( pItem->GetHeight(this, pEntry) );
2412 Point aPos = GetEntryPosition( pEntry );
2413 aPos.AdjustY(( nEntryHeight - nItemHeight ) / 2 );
2414 aPos.setX( GetTabPos( pEntry, pTab ) );
2415 long nOutputWidth = pImpl->GetOutputSize().Width();
2416 Size aSize( nOutputWidth - aPos.X(), nItemHeight );
2417 sal_uInt16 nPos = std::find_if( aTabs.begin(), aTabs.end(),
2418 [pTab](const std::unique_ptr<SvLBoxTab>& p) { return p.get() == pTab; })
2419 - aTabs.begin();
2420 if( nPos+1 < static_cast<sal_uInt16>(aTabs.size()) )
2421 {
2422 SvLBoxTab* pRightTab = aTabs[ nPos + 1 ].get();
2423 long nRight = GetTabPos( pEntry, pRightTab );
2424 if( nRight <= nOutputWidth )
2425 aSize.setWidth( nRight - aPos.X() );
2426 }
2427 Point aOrigin( GetMapMode().GetOrigin() );
2428 aPos += aOrigin; // convert to win coordinates
2429 aSize.AdjustWidth( -(aOrigin.X()) );
2430 tools::Rectangle aRect( aPos, aSize );
2431 EditText( pItem->GetText(), aRect, rSelection );
2432 }
2433
EditEntry(SvTreeListEntry * pEntry)2434 void SvTreeListBox::EditEntry( SvTreeListEntry* pEntry )
2435 {
2436 pImpl->m_aEditClickPos = Point( -1, -1 );
2437 ImplEditEntry( pEntry );
2438 }
2439
ImplEditEntry(SvTreeListEntry * pEntry)2440 void SvTreeListBox::ImplEditEntry( SvTreeListEntry* pEntry )
2441 {
2442 if( IsEditingActive() )
2443 EndEditing();
2444 if( !pEntry )
2445 pEntry = GetCurEntry();
2446 if( !pEntry )
2447 return;
2448
2449 long nClickX = pImpl->m_aEditClickPos.X();
2450 bool bIsMouseTriggered = nClickX >= 0;
2451
2452 SvLBoxString* pItem = nullptr;
2453 sal_uInt16 nCount = pEntry->ItemCount();
2454 long nTabPos, nNextTabPos = 0;
2455 for( sal_uInt16 i = 0 ; i < nCount ; i++ )
2456 {
2457 SvLBoxItem& rTmpItem = pEntry->GetItem( i );
2458 if (rTmpItem.GetType() != SvLBoxItemType::String)
2459 continue;
2460
2461 SvLBoxTab* pTab = GetTab( pEntry, &rTmpItem );
2462 nNextTabPos = -1;
2463 if( i < nCount - 1 )
2464 {
2465 SvLBoxItem& rNextItem = pEntry->GetItem( i + 1 );
2466 SvLBoxTab* pNextTab = GetTab( pEntry, &rNextItem );
2467 nNextTabPos = pNextTab->GetPos();
2468 }
2469
2470 if( pTab && pTab->IsEditable() )
2471 {
2472 nTabPos = pTab->GetPos();
2473 if( !bIsMouseTriggered || (nClickX > nTabPos && (nNextTabPos == -1 || nClickX < nNextTabPos ) ) )
2474 {
2475 pItem = static_cast<SvLBoxString*>( &rTmpItem );
2476 break;
2477 }
2478 }
2479 }
2480
2481 Selection aSel( SELECTION_MIN, SELECTION_MAX );
2482 if( pItem && EditingEntry( pEntry, aSel ) )
2483 {
2484 SelectAll( false );
2485 MakeVisible( pEntry );
2486 EditItemText( pEntry, pItem, aSel );
2487 }
2488 }
2489
AreChildrenTransient() const2490 bool SvTreeListBox::AreChildrenTransient() const
2491 {
2492 return pImpl->AreChildrenTransient();
2493 }
2494
EditedText(const OUString & rStr)2495 void SvTreeListBox::EditedText( const OUString& rStr )
2496
2497 {
2498 if(pEdEntry) // we have to check if this entry is null that means that it is removed while editing
2499 {
2500 if( EditedEntry( pEdEntry, rStr ) )
2501 {
2502 static_cast<SvLBoxString*>(pEdItem)->SetText( rStr );
2503 pModel->InvalidateEntry( pEdEntry );
2504 }
2505 if( GetSelectionCount() == 0 )
2506 Select( pEdEntry );
2507 if( GetSelectionMode() == SelectionMode::Multiple && !GetCurEntry() )
2508 SetCurEntry( pEdEntry );
2509 }
2510 }
2511
GetDropTarget(const Point & rPos)2512 SvTreeListEntry* SvTreeListBox::GetDropTarget( const Point& rPos )
2513 {
2514 // scroll
2515 if( rPos.Y() < 12 )
2516 {
2517 ImplShowTargetEmphasis(pTargetEntry, false);
2518 ScrollOutputArea( +1 );
2519 }
2520 else
2521 {
2522 Size aSize( pImpl->GetOutputSize() );
2523 if( rPos.Y() > aSize.Height() - 12 )
2524 {
2525 ImplShowTargetEmphasis(pTargetEntry, false);
2526 ScrollOutputArea( -1 );
2527 }
2528 }
2529
2530 SvTreeListEntry* pTarget = pImpl->GetEntry( rPos );
2531 // when dropping in a vacant space, use the last entry
2532 if( !pTarget )
2533 return LastVisible();
2534 else if( (GetDragDropMode() & DragDropMode::ENABLE_TOP) &&
2535 pTarget == First() && rPos.Y() < 6 )
2536 return nullptr;
2537
2538 return pTarget;
2539 }
2540
2541
GetEntry(const Point & rPos,bool bHit) const2542 SvTreeListEntry* SvTreeListBox::GetEntry( const Point& rPos, bool bHit ) const
2543 {
2544 SvTreeListEntry* pEntry = pImpl->GetEntry( rPos );
2545 if( pEntry && bHit )
2546 {
2547 long nLine = pImpl->GetEntryLine( pEntry );
2548 if( !(pImpl->EntryReallyHit( pEntry, rPos, nLine)) )
2549 return nullptr;
2550 }
2551 return pEntry;
2552 }
2553
GetCurEntry() const2554 SvTreeListEntry* SvTreeListBox::GetCurEntry() const
2555 {
2556 return pImpl ? pImpl->GetCurEntry() : nullptr;
2557 }
2558
ImplInitStyle()2559 void SvTreeListBox::ImplInitStyle()
2560 {
2561 const WinBits nWindowStyle = GetStyle();
2562
2563 nTreeFlags |= SvTreeFlags::RECALCTABS;
2564 if (nWindowStyle & WB_SORT)
2565 {
2566 GetModel()->SetSortMode(SortAscending);
2567 GetModel()->SetCompareHdl(LINK(this, SvTreeListBox, DefaultCompare));
2568 }
2569 else
2570 {
2571 GetModel()->SetSortMode(SortNone);
2572 GetModel()->SetCompareHdl(Link<const SvSortData&,sal_Int32>());
2573 }
2574 pImpl->SetStyle(nWindowStyle);
2575 pImpl->Resize();
2576 Invalidate();
2577 }
2578
InvalidateEntry(SvTreeListEntry * pEntry)2579 void SvTreeListBox::InvalidateEntry(SvTreeListEntry* pEntry)
2580 {
2581 DBG_ASSERT(pEntry,"InvalidateEntry:No Entry");
2582 if (pEntry)
2583 {
2584 GetModel()->InvalidateEntry(pEntry);
2585 }
2586 }
2587
PaintEntry1(SvTreeListEntry & rEntry,long nLine,vcl::RenderContext & rRenderContext)2588 void SvTreeListBox::PaintEntry1(SvTreeListEntry& rEntry, long nLine, vcl::RenderContext& rRenderContext)
2589 {
2590 tools::Rectangle aRect; // multi purpose
2591
2592 bool bHorSBar = pImpl->HasHorScrollBar();
2593 PreparePaint(rRenderContext, rEntry);
2594
2595 pImpl->UpdateContextBmpWidthMax(&rEntry);
2596
2597 if (nTreeFlags & SvTreeFlags::RECALCTABS)
2598 SetTabs();
2599
2600 short nTempEntryHeight = GetEntryHeight();
2601 long nWidth = pImpl->GetOutputSize().Width();
2602
2603 // Did we turn on the scrollbar within PreparePaints? If yes, we have to set
2604 // the ClipRegion anew.
2605 if (!bHorSBar && pImpl->HasHorScrollBar())
2606 rRenderContext.SetClipRegion(vcl::Region(pImpl->GetClipRegionRect()));
2607
2608 Point aEntryPos(rRenderContext.GetMapMode().GetOrigin());
2609 aEntryPos.setX( aEntryPos.X() * -1 ); // conversion document coordinates
2610 long nMaxRight = nWidth + aEntryPos.X() - 1;
2611
2612 Color aBackupTextColor(rRenderContext.GetTextColor());
2613 vcl::Font aBackupFont(rRenderContext.GetFont());
2614 Color aBackupColor = rRenderContext.GetFillColor();
2615
2616 bool bCurFontIsSel = false;
2617 // if a ClipRegion was set from outside, we don't have to reset it
2618 const WinBits nWindowStyle = GetStyle();
2619 const bool bHideSelection = (nWindowStyle & WB_HIDESELECTION) !=0 && !HasFocus();
2620 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
2621
2622 vcl::Font aHighlightFont(rRenderContext.GetFont());
2623 const Color aHighlightTextColor(rSettings.GetHighlightTextColor());
2624 aHighlightFont.SetColor(aHighlightTextColor);
2625
2626 Size aRectSize(0, nTempEntryHeight);
2627
2628 SvViewDataEntry* pViewDataEntry = GetViewDataEntry( &rEntry );
2629
2630 const size_t nTabCount = aTabs.size();
2631 const size_t nItemCount = rEntry.ItemCount();
2632 size_t nCurTab = 0;
2633 size_t nCurItem = 0;
2634
2635 while (nCurTab < nTabCount && nCurItem < nItemCount)
2636 {
2637 SvLBoxTab* pTab = aTabs[nCurTab].get();
2638 const size_t nNextTab = nCurTab + 1;
2639 SvLBoxTab* pNextTab = nNextTab < nTabCount ? aTabs[nNextTab].get() : nullptr;
2640 SvLBoxItem& rItem = rEntry.GetItem(nCurItem);
2641
2642 SvLBoxTabFlags nFlags = pTab->nFlags;
2643 Size aSize(rItem.GetWidth(this, pViewDataEntry, nCurItem),
2644 SvLBoxItem::GetHeight(pViewDataEntry, nCurItem));
2645 long nTabPos = GetTabPos(&rEntry, pTab);
2646
2647 long nNextTabPos;
2648 if (pNextTab)
2649 nNextTabPos = GetTabPos(&rEntry, pNextTab);
2650 else
2651 {
2652 nNextTabPos = nMaxRight;
2653 if (nTabPos > nMaxRight)
2654 nNextTabPos += 50;
2655 }
2656
2657 long nX;
2658 if( pTab->nFlags & SvLBoxTabFlags::ADJUST_RIGHT )
2659 // avoid cutting the right edge off the tab separation
2660 nX = nTabPos + pTab->CalcOffset(aSize.Width(), (nNextTabPos - SV_TAB_BORDER - 1) - nTabPos);
2661 else
2662 nX = nTabPos + pTab->CalcOffset(aSize.Width(), nNextTabPos - nTabPos);
2663
2664 aEntryPos.setX( nX );
2665 aEntryPos.setY( nLine );
2666
2667 // set background pattern/color
2668
2669 Wallpaper aWallpaper = rRenderContext.GetBackground();
2670
2671 bool bSelTab = bool(nFlags & SvLBoxTabFlags::SHOW_SELECTION);
2672
2673 if (pViewDataEntry->IsHighlighted() && bSelTab)
2674 {
2675 Color aNewWallColor = rSettings.GetHighlightColor();
2676 // if the face color is bright then the deactivate color is also bright
2677 // -> so you can't see any deactivate selection
2678 if (bHideSelection && !rSettings.GetFaceColor().IsBright()
2679 && aWallpaper.GetColor().IsBright() != rSettings.GetDeactiveColor().IsBright())
2680 {
2681 aNewWallColor = rSettings.GetDeactiveColor();
2682 }
2683 // set font color to highlight
2684 if (!bCurFontIsSel)
2685 {
2686 rRenderContext.SetTextColor(aHighlightTextColor);
2687 rRenderContext.SetFont(aHighlightFont);
2688 bCurFontIsSel = true;
2689 }
2690 aWallpaper.SetColor(aNewWallColor);
2691 }
2692 else // no selection
2693 {
2694 if (bCurFontIsSel || rEntry.GetTextColor())
2695 {
2696 bCurFontIsSel = false;
2697 if (const auto & xCustomTextColor = rEntry.GetTextColor())
2698 rRenderContext.SetTextColor(*xCustomTextColor);
2699 else
2700 rRenderContext.SetTextColor(aBackupTextColor);
2701 rRenderContext.SetFont(aBackupFont);
2702 }
2703 else
2704 {
2705 aWallpaper.SetColor(rEntry.GetBackColor());
2706 }
2707 }
2708
2709 // draw background
2710 if (!(nTreeFlags & SvTreeFlags::USESEL))
2711 {
2712 // only draw the area that is used by the item
2713 aRectSize.setWidth( aSize.Width() );
2714 aRect.SetPos(aEntryPos);
2715 aRect.SetSize(aRectSize);
2716 }
2717 else
2718 {
2719 // draw from the current to the next tab
2720 if (nCurTab != 0)
2721 aRect.SetLeft( nTabPos );
2722 else
2723 // if we're in the 0th tab, always draw from column 0 --
2724 // else we get problems with centered tabs
2725 aRect.SetLeft( 0 );
2726 aRect.SetTop( nLine );
2727 aRect.SetBottom( nLine + nTempEntryHeight - 1 );
2728 if (pNextTab)
2729 {
2730 long nRight;
2731 nRight = GetTabPos(&rEntry, pNextTab) - 1;
2732 if (nRight > nMaxRight)
2733 nRight = nMaxRight;
2734 aRect.SetRight( nRight );
2735 }
2736 else
2737 {
2738 aRect.SetRight( nMaxRight );
2739 }
2740 }
2741 // A custom selection that starts at a tab position > 0, do not fill
2742 // the background of the 0th item, else e.g. we might not be able to
2743 // realize tab listboxes with lines.
2744 if (!(nCurTab == 0 && (nTreeFlags & SvTreeFlags::USESEL) && nFirstSelTab))
2745 {
2746 Color aBackgroundColor = aWallpaper.GetColor();
2747 if (aBackgroundColor != COL_TRANSPARENT)
2748 {
2749 rRenderContext.SetFillColor(aBackgroundColor);
2750 // this case may occur for smaller horizontal resizes
2751 if (aRect.Left() < aRect.Right())
2752 rRenderContext.DrawRect(aRect);
2753 }
2754 }
2755 // draw item
2756 // center vertically
2757 aEntryPos.AdjustY((nTempEntryHeight - aSize.Height()) / 2 );
2758 pViewDataEntry->SetPaintRectangle(aRect);
2759
2760 rItem.Paint(aEntryPos, *this, rRenderContext, pViewDataEntry, rEntry);
2761
2762 // division line between tabs
2763 if (pNextTab && rItem.GetType() == SvLBoxItemType::String &&
2764 // not at the right edge of the window!
2765 aRect.Right() < nMaxRight)
2766 {
2767 aRect.SetLeft( aRect.Right() - SV_TAB_BORDER );
2768 rRenderContext.DrawRect(aRect);
2769 }
2770
2771 rRenderContext.SetFillColor(aBackupColor);
2772
2773 nCurItem++;
2774 nCurTab++;
2775 }
2776
2777 if (pViewDataEntry->IsDragTarget())
2778 {
2779 rRenderContext.Push();
2780 rRenderContext.SetLineColor(rSettings.GetDeactiveColor());
2781 rRenderContext.SetFillColor(rSettings.GetDeactiveColor());
2782 rRenderContext.DrawRect(tools::Rectangle(Point(0, nLine + nTempEntryHeight - 2), Size(nWidth, 2)));
2783 rRenderContext.Pop();
2784 }
2785
2786 if (bCurFontIsSel || rEntry.GetTextColor())
2787 {
2788 rRenderContext.SetTextColor(aBackupTextColor);
2789 rRenderContext.SetFont(aBackupFont);
2790 }
2791
2792 sal_uInt16 nFirstDynTabPos(0);
2793 SvLBoxTab* pFirstDynamicTab = GetFirstDynamicTab(nFirstDynTabPos);
2794 long nDynTabPos = GetTabPos(&rEntry, pFirstDynamicTab);
2795 nDynTabPos += pImpl->m_nNodeBmpTabDistance;
2796 nDynTabPos += pImpl->m_nNodeBmpWidth / 2;
2797 nDynTabPos += 4; // 4 pixels of buffer, so the node bitmap is not too close
2798 // to the next tab
2799
2800 if( !((!(rEntry.GetFlags() & SvTLEntryFlags::NO_NODEBMP)) &&
2801 (nWindowStyle & WB_HASBUTTONS) && pFirstDynamicTab &&
2802 (rEntry.HasChildren() || rEntry.HasChildrenOnDemand())))
2803 return;
2804
2805 // find first tab and check if the node bitmap extends into it
2806 sal_uInt16 nNextTab = nFirstDynTabPos;
2807 SvLBoxTab* pNextTab;
2808 do
2809 {
2810 nNextTab++;
2811 pNextTab = nNextTab < nTabCount ? aTabs[nNextTab].get() : nullptr;
2812 } while (pNextTab && pNextTab->IsDynamic());
2813
2814 if (!(!pNextTab || (GetTabPos( &rEntry, pNextTab ) > nDynTabPos)))
2815 return;
2816
2817 if (!((nWindowStyle & WB_HASBUTTONSATROOT) || pModel->GetDepth(&rEntry) > 0))
2818 return;
2819
2820 Point aPos(GetTabPos(&rEntry, pFirstDynamicTab), nLine);
2821 aPos.AdjustX(pImpl->m_nNodeBmpTabDistance );
2822
2823 const Image* pImg = nullptr;
2824
2825 if (IsExpanded(&rEntry))
2826 pImg = &pImpl->GetExpandedNodeBmp();
2827 else
2828 {
2829 if ((!rEntry.HasChildren()) && rEntry.HasChildrenOnDemand() &&
2830 (!(rEntry.GetFlags() & SvTLEntryFlags::HAD_CHILDREN)) &&
2831 pImpl->GetDontKnowNodeBmp().GetSizePixel().Width())
2832 {
2833 pImg = &pImpl->GetDontKnowNodeBmp( );
2834 }
2835 else
2836 {
2837 pImg = &pImpl->GetCollapsedNodeBmp( );
2838 }
2839 }
2840 aPos.AdjustY((nTempEntryHeight - pImg->GetSizePixel().Height()) / 2 );
2841
2842 DrawImageFlags nStyle = DrawImageFlags::NONE;
2843 if (!IsEnabled())
2844 nStyle |= DrawImageFlags::Disable;
2845
2846 //native
2847 bool bNativeOK = false;
2848 if (rRenderContext.IsNativeControlSupported(ControlType::ListNode, ControlPart::Entire))
2849 {
2850 ImplControlValue aControlValue;
2851 tools::Rectangle aCtrlRegion(aPos, pImg->GetSizePixel());
2852 ControlState nState = ControlState::NONE;
2853
2854 if (IsEnabled())
2855 nState |= ControlState::ENABLED;
2856
2857 if (IsExpanded(&rEntry))
2858 aControlValue.setTristateVal(ButtonValue::On); //expanded node
2859 else
2860 {
2861 if ((!rEntry.HasChildren()) && rEntry.HasChildrenOnDemand() &&
2862 (!(rEntry.GetFlags() & SvTLEntryFlags::HAD_CHILDREN)) &&
2863 pImpl->GetDontKnowNodeBmp().GetSizePixel().Width())
2864 {
2865 aControlValue.setTristateVal( ButtonValue::DontKnow ); //don't know
2866 }
2867 else
2868 {
2869 aControlValue.setTristateVal( ButtonValue::Off ); //collapsed node
2870 }
2871 }
2872
2873 bNativeOK = rRenderContext.DrawNativeControl(ControlType::ListNode, ControlPart::Entire, aCtrlRegion, nState, aControlValue, OUString());
2874 }
2875
2876 if (!bNativeOK)
2877 {
2878 rRenderContext.DrawImage(aPos, *pImg ,nStyle);
2879 }
2880 }
2881
PreparePaint(vcl::RenderContext &,SvTreeListEntry &)2882 void SvTreeListBox::PreparePaint(vcl::RenderContext& /*rRenderContext*/, SvTreeListEntry& /*rEntry*/)
2883 {
2884 }
2885
GetFocusRect(SvTreeListEntry * pEntry,long nLine)2886 tools::Rectangle SvTreeListBox::GetFocusRect( SvTreeListEntry* pEntry, long nLine )
2887 {
2888 pImpl->UpdateContextBmpWidthMax( pEntry );
2889
2890 Size aSize;
2891 tools::Rectangle aRect;
2892 aRect.SetTop( nLine );
2893 aSize.setHeight( GetEntryHeight() );
2894
2895 long nRealWidth = pImpl->GetOutputSize().Width();
2896 nRealWidth -= GetMapMode().GetOrigin().X();
2897
2898 sal_uInt16 nCurTab;
2899 SvLBoxTab* pTab = GetFirstTab( SvLBoxTabFlags::SHOW_SELECTION, nCurTab );
2900 long nTabPos = 0;
2901 if( pTab )
2902 nTabPos = GetTabPos( pEntry, pTab );
2903 long nNextTabPos;
2904 if( pTab && nCurTab < aTabs.size() - 1 )
2905 {
2906 SvLBoxTab* pNextTab = aTabs[ nCurTab + 1 ].get();
2907 nNextTabPos = GetTabPos( pEntry, pNextTab );
2908 }
2909 else
2910 {
2911 nNextTabPos = nRealWidth;
2912 if( nTabPos > nRealWidth )
2913 nNextTabPos += 50;
2914 }
2915
2916 bool bUserSelection = bool( nTreeFlags & SvTreeFlags::USESEL );
2917 if( !bUserSelection )
2918 {
2919 if( pTab && nCurTab < pEntry->ItemCount() )
2920 {
2921 SvLBoxItem& rItem = pEntry->GetItem( nCurTab );
2922 aSize.setWidth(rItem.GetWidth(this, pEntry));
2923 if( !aSize.Width() )
2924 aSize.setWidth( 15 );
2925 long nX = nTabPos; //GetTabPos( pEntry, pTab );
2926 // alignment
2927 nX += pTab->CalcOffset( aSize.Width(), nNextTabPos - nTabPos );
2928 aRect.SetLeft( nX );
2929 // make sure that first and last letter aren't cut off slightly
2930 aRect.SetSize( aSize );
2931 if( aRect.Left() > 0 )
2932 aRect.AdjustLeft( -1 );
2933 aRect.AdjustRight( 1 );
2934 }
2935 }
2936 else
2937 {
2938 // if SelTab != 0, we have to calculate also
2939 if( nFocusWidth == -1 || nFirstSelTab )
2940 {
2941 SvLBoxTab* pLastTab = nullptr; // default to select whole width
2942
2943 sal_uInt16 nLastTab;
2944 GetLastTab(SvLBoxTabFlags::SHOW_SELECTION,nLastTab);
2945 nLastTab++;
2946 if( nLastTab < aTabs.size() ) // is there another one?
2947 pLastTab = aTabs[ nLastTab ].get();
2948
2949 aSize.setWidth( pLastTab ? pLastTab->GetPos() : 0x0fffffff );
2950 nFocusWidth = static_cast<short>(aSize.Width());
2951 if( pTab )
2952 nFocusWidth = nFocusWidth - static_cast<short>(nTabPos); //pTab->GetPos();
2953 }
2954 else
2955 {
2956 aSize.setWidth( nFocusWidth );
2957 if( pTab )
2958 {
2959 if( nCurTab )
2960 aSize.AdjustWidth(nTabPos );
2961 else
2962 aSize.AdjustWidth(pTab->GetPos() ); // Tab0 always from the leftmost position
2963 }
2964 }
2965 // if selection starts with 0th tab, draw from column 0 on
2966 if( nCurTab != 0 )
2967 {
2968 aRect.SetLeft( nTabPos );
2969 aSize.AdjustWidth( -nTabPos );
2970 }
2971 aRect.SetSize( aSize );
2972 }
2973 // adjust right edge because of clipping
2974 if( aRect.Right() >= nRealWidth )
2975 {
2976 aRect.SetRight( nRealWidth-1 );
2977 nFocusWidth = static_cast<short>(aRect.GetWidth());
2978 }
2979 return aRect;
2980 }
2981
2982
GetTabPos(SvTreeListEntry * pEntry,SvLBoxTab * pTab)2983 sal_IntPtr SvTreeListBox::GetTabPos( SvTreeListEntry* pEntry, SvLBoxTab* pTab)
2984 {
2985 assert(pTab);
2986 sal_IntPtr nPos = pTab->GetPos();
2987 if( pTab->IsDynamic() )
2988 {
2989 sal_uInt16 nDepth = pModel->GetDepth( pEntry );
2990 nDepth = nDepth * static_cast<sal_uInt16>(nIndent);
2991 nPos += static_cast<sal_IntPtr>(nDepth);
2992 }
2993 return nPos;
2994 }
2995
GetItem_Impl(SvTreeListEntry * pEntry,long nX,SvLBoxTab ** ppTab)2996 SvLBoxItem* SvTreeListBox::GetItem_Impl( SvTreeListEntry* pEntry, long nX,
2997 SvLBoxTab** ppTab )
2998 {
2999 SvLBoxItem* pItemClicked = nullptr;
3000 sal_uInt16 nTabCount = aTabs.size();
3001 sal_uInt16 nItemCount = pEntry->ItemCount();
3002 SvLBoxTab* pTab = aTabs.front().get();
3003 SvLBoxItem* pItem = &pEntry->GetItem(0);
3004 sal_uInt16 nNextItem = 1;
3005 nX -= GetMapMode().GetOrigin().X();
3006 long nRealWidth = pImpl->GetOutputSize().Width();
3007 nRealWidth -= GetMapMode().GetOrigin().X();
3008
3009 while( true )
3010 {
3011 SvLBoxTab* pNextTab=nNextItem<nTabCount ? aTabs[nNextItem].get() : nullptr;
3012 long nStart = GetTabPos( pEntry, pTab );
3013
3014 long nNextTabPos;
3015 if( pNextTab )
3016 nNextTabPos = GetTabPos( pEntry, pNextTab );
3017 else
3018 {
3019 nNextTabPos = nRealWidth;
3020 if( nStart > nRealWidth )
3021 nNextTabPos += 50;
3022 }
3023
3024 auto nItemWidth(pItem->GetWidth(this, pEntry));
3025 nStart += pTab->CalcOffset(nItemWidth, nNextTabPos - nStart);
3026 auto nLen = nItemWidth;
3027 if( pNextTab )
3028 {
3029 long nTabWidth = GetTabPos( pEntry, pNextTab ) - nStart;
3030 if( nTabWidth < nLen )
3031 nLen = nTabWidth;
3032 }
3033
3034 if( nX >= nStart && nX < (nStart+nLen ) )
3035 {
3036 pItemClicked = pItem;
3037 if( ppTab )
3038 {
3039 *ppTab = pTab;
3040 break;
3041 }
3042 }
3043 if( nNextItem >= nItemCount || nNextItem >= nTabCount)
3044 break;
3045 pTab = aTabs[ nNextItem ].get();
3046 pItem = &pEntry->GetItem( nNextItem );
3047 nNextItem++;
3048 }
3049 return pItemClicked;
3050 }
3051
getPreferredDimensions(std::vector<long> & rWidths) const3052 long SvTreeListBox::getPreferredDimensions(std::vector<long> &rWidths) const
3053 {
3054 long nHeight = 0;
3055 rWidths.clear();
3056 SvTreeListEntry* pEntry = First();
3057 while (pEntry)
3058 {
3059 sal_uInt16 nCount = pEntry->ItemCount();
3060 sal_uInt16 nCurPos = 0;
3061 if (nCount > rWidths.size())
3062 rWidths.resize(nCount);
3063 while (nCurPos < nCount)
3064 {
3065 SvLBoxItem& rItem = pEntry->GetItem( nCurPos );
3066 auto nWidth = rItem.GetWidth(this, pEntry);
3067 if (nWidth)
3068 {
3069 nWidth += SV_TAB_BORDER * 2;
3070 if (nWidth > rWidths[nCurPos])
3071 rWidths[nCurPos] = nWidth;
3072 }
3073 ++nCurPos;
3074 }
3075 pEntry = Next( pEntry );
3076 nHeight += GetEntryHeight();
3077 }
3078 return nHeight;
3079 }
3080
GetOptimalSize() const3081 Size SvTreeListBox::GetOptimalSize() const
3082 {
3083 std::vector<long> aWidths;
3084 Size aRet(0, getPreferredDimensions(aWidths));
3085 for (long aWidth : aWidths)
3086 aRet.AdjustWidth(aWidth );
3087 if (GetStyle() & WB_BORDER)
3088 {
3089 aRet.AdjustWidth(StyleSettings::GetBorderSize() * 2 );
3090 aRet.AdjustHeight(StyleSettings::GetBorderSize() * 2 );
3091 }
3092 long nMinWidth = nMinWidthInChars * approximate_char_width();
3093 aRet.setWidth( std::max(aRet.Width(), nMinWidth) );
3094
3095 if (GetStyle() & WB_VSCROLL)
3096 aRet.AdjustWidth(GetSettings().GetStyleSettings().GetScrollBarSize());
3097
3098 return aRet;
3099 }
3100
SetAlternatingRowColors(bool bEnable)3101 void SvTreeListBox::SetAlternatingRowColors( bool bEnable )
3102 {
3103 if( !mbUpdateAlternatingRows )
3104 {
3105 mbAlternatingRowColors = bEnable;
3106 return;
3107 }
3108
3109 if( bEnable )
3110 {
3111 SvTreeListEntry* pEntry = pModel->First();
3112 for(size_t i = 0; pEntry; ++i)
3113 {
3114 pEntry->SetBackColor( i % 2 == 0 ? GetBackground().GetColor() : GetSettings().GetStyleSettings().GetAlternatingRowColor());
3115 SvTreeListEntry *pNextEntry = nullptr;
3116 if( IsExpanded( pEntry ) )
3117 pNextEntry = pModel->FirstChild( pEntry );
3118 else
3119 pNextEntry = pEntry->NextSibling();
3120
3121 if( !pNextEntry )
3122 pEntry = pModel->Next( pEntry );
3123 else
3124 pEntry = pNextEntry;
3125 }
3126 }
3127 else if( mbAlternatingRowColors )
3128 for(SvTreeListEntry* pEntry = pModel->First(); pEntry; pEntry = pModel->Next(pEntry))
3129 pEntry->SetBackColor( GetBackground().GetColor() );
3130
3131 mbAlternatingRowColors = bEnable;
3132 pImpl->UpdateAll(true);
3133 }
3134
SetForceMakeVisible(bool bEnable)3135 void SvTreeListBox::SetForceMakeVisible( bool bEnable )
3136 {
3137 pImpl->SetForceMakeVisible(bEnable);
3138 }
3139
GetItem(SvTreeListEntry * pEntry,long nX,SvLBoxTab ** ppTab)3140 SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX,SvLBoxTab** ppTab)
3141 {
3142 return GetItem_Impl( pEntry, nX, ppTab );
3143 }
3144
GetItem(SvTreeListEntry * pEntry,long nX)3145 SvLBoxItem* SvTreeListBox::GetItem(SvTreeListEntry* pEntry,long nX )
3146 {
3147 SvLBoxTab* pDummyTab;
3148 return GetItem_Impl( pEntry, nX, &pDummyTab );
3149 }
3150
AddTab(long nTabPos,SvLBoxTabFlags nFlags)3151 void SvTreeListBox::AddTab(long nTabPos, SvLBoxTabFlags nFlags )
3152 {
3153 nFocusWidth = -1;
3154 SvLBoxTab* pTab = new SvLBoxTab( nTabPos, nFlags );
3155 aTabs.emplace_back( pTab );
3156 if( nTreeFlags & SvTreeFlags::USESEL )
3157 {
3158 sal_uInt16 nPos = aTabs.size() - 1;
3159 if( nPos >= nFirstSelTab && nPos <= nLastSelTab )
3160 pTab->nFlags |= SvLBoxTabFlags::SHOW_SELECTION;
3161 else
3162 // string items usually have to be selected -- turn this off
3163 // explicitly
3164 pTab->nFlags &= ~SvLBoxTabFlags::SHOW_SELECTION;
3165 }
3166 }
3167
3168
GetFirstDynamicTab(sal_uInt16 & rPos) const3169 SvLBoxTab* SvTreeListBox::GetFirstDynamicTab( sal_uInt16& rPos ) const
3170 {
3171 sal_uInt16 nCurTab = 0;
3172 sal_uInt16 nTabCount = aTabs.size();
3173 while( nCurTab < nTabCount )
3174 {
3175 SvLBoxTab* pTab = aTabs[nCurTab].get();
3176 if( pTab->nFlags & SvLBoxTabFlags::DYNAMIC )
3177 {
3178 rPos = nCurTab;
3179 return pTab;
3180 }
3181 nCurTab++;
3182 }
3183 return nullptr;
3184 }
3185
GetFirstDynamicTab() const3186 SvLBoxTab* SvTreeListBox::GetFirstDynamicTab() const
3187 {
3188 sal_uInt16 nDummy;
3189 return GetFirstDynamicTab( nDummy );
3190 }
3191
GetTab(SvTreeListEntry const * pEntry,SvLBoxItem const * pItem) const3192 SvLBoxTab* SvTreeListBox::GetTab( SvTreeListEntry const * pEntry, SvLBoxItem const * pItem) const
3193 {
3194 sal_uInt16 nPos = pEntry->GetPos( pItem );
3195 return aTabs[ nPos ].get();
3196 }
3197
ClearTabList()3198 void SvTreeListBox::ClearTabList()
3199 {
3200 aTabs.clear();
3201 }
3202
3203
GetOutputSizePixel() const3204 Size SvTreeListBox::GetOutputSizePixel() const
3205 {
3206 Size aSize = pImpl->GetOutputSize();
3207 return aSize;
3208 }
3209
NotifyEndScroll()3210 void SvTreeListBox::NotifyEndScroll()
3211 {
3212 }
3213
NotifyScrolled()3214 void SvTreeListBox::NotifyScrolled()
3215 {
3216 aScrolledHdl.Call( this );
3217 }
3218
Invalidate(InvalidateFlags nInvalidateFlags)3219 void SvTreeListBox::Invalidate( InvalidateFlags nInvalidateFlags )
3220 {
3221 if (!pImpl)
3222 return;
3223 if( nFocusWidth == -1 )
3224 // to make sure that the control doesn't show the wrong focus rectangle
3225 // after painting
3226 pImpl->RecalcFocusRect();
3227 Control::Invalidate( nInvalidateFlags );
3228 pImpl->Invalidate();
3229 }
3230
Invalidate(const tools::Rectangle & rRect,InvalidateFlags nInvalidateFlags)3231 void SvTreeListBox::Invalidate( const tools::Rectangle& rRect, InvalidateFlags nInvalidateFlags )
3232 {
3233 if( nFocusWidth == -1 )
3234 // to make sure that the control doesn't show the wrong focus rectangle
3235 // after painting
3236 pImpl->RecalcFocusRect();
3237 Control::Invalidate( rRect, nInvalidateFlags );
3238 }
3239
3240
SetHighlightRange(sal_uInt16 nStart,sal_uInt16 nEnd)3241 void SvTreeListBox::SetHighlightRange( sal_uInt16 nStart, sal_uInt16 nEnd)
3242 {
3243
3244 sal_uInt16 nTemp;
3245 nTreeFlags |= SvTreeFlags::USESEL;
3246 if( nStart > nEnd )
3247 {
3248 nTemp = nStart;
3249 nStart = nEnd;
3250 nEnd = nTemp;
3251 }
3252 // select all tabs that lie within the area
3253 nTreeFlags |= SvTreeFlags::RECALCTABS;
3254 nFirstSelTab = nStart;
3255 nLastSelTab = nEnd;
3256 pImpl->RecalcFocusRect();
3257 }
3258
Command(const CommandEvent & rCEvt)3259 void SvTreeListBox::Command(const CommandEvent& rCEvt)
3260 {
3261 if (!aPopupMenuHdl.Call(rCEvt))
3262 pImpl->Command(rCEvt);
3263 //pass at least alt press/release to parent impl
3264 if (rCEvt.GetCommand() == CommandEventId::ModKeyChange)
3265 Control::Command(rCEvt);
3266 }
3267
RemoveParentKeepChildren(SvTreeListEntry * pParent)3268 void SvTreeListBox::RemoveParentKeepChildren( SvTreeListEntry* pParent )
3269 {
3270 assert(pParent);
3271 SvTreeListEntry* pNewParent = GetParent( pParent );
3272 if( pParent->HasChildren())
3273 {
3274 SvTreeListEntry* pChild = FirstChild( pParent );
3275 while( pChild )
3276 {
3277 pModel->Move( pChild, pNewParent, TREELIST_APPEND );
3278 pChild = FirstChild( pParent );
3279 }
3280 }
3281 pModel->Remove( pParent );
3282 }
3283
GetFirstTab(SvLBoxTabFlags nFlagMask,sal_uInt16 & rPos)3284 SvLBoxTab* SvTreeListBox::GetFirstTab( SvLBoxTabFlags nFlagMask, sal_uInt16& rPos )
3285 {
3286 sal_uInt16 nTabCount = aTabs.size();
3287 for( sal_uInt16 nPos = 0; nPos < nTabCount; nPos++ )
3288 {
3289 SvLBoxTab* pTab = aTabs[ nPos ].get();
3290 if( pTab->nFlags & nFlagMask )
3291 {
3292 rPos = nPos;
3293 return pTab;
3294 }
3295 }
3296 rPos = 0xffff;
3297 return nullptr;
3298 }
3299
GetLastTab(SvLBoxTabFlags nFlagMask,sal_uInt16 & rTabPos)3300 void SvTreeListBox::GetLastTab( SvLBoxTabFlags nFlagMask, sal_uInt16& rTabPos )
3301 {
3302 sal_uInt16 nPos = static_cast<sal_uInt16>(aTabs.size());
3303 while( nPos )
3304 {
3305 --nPos;
3306 SvLBoxTab* pTab = aTabs[ nPos ].get();
3307 if( pTab->nFlags & nFlagMask )
3308 {
3309 rTabPos = nPos;
3310 return;
3311 }
3312 }
3313 rTabPos = 0xffff;
3314 }
3315
RequestHelp(const HelpEvent & rHEvt)3316 void SvTreeListBox::RequestHelp( const HelpEvent& rHEvt )
3317 {
3318 if( !pImpl->RequestHelp( rHEvt ) )
3319 Control::RequestHelp( rHEvt );
3320 }
3321
DefaultCompare(const SvLBoxString * pLeftText,const SvLBoxString * pRightText)3322 sal_Int32 SvTreeListBox::DefaultCompare(const SvLBoxString* pLeftText, const SvLBoxString* pRightText)
3323 {
3324 OUString aLeft = pLeftText ? pLeftText->GetText() : OUString();
3325 OUString aRight = pRightText ? pRightText->GetText() : OUString();
3326 pImpl->UpdateStringSorter();
3327 return pImpl->m_pStringSorter->compare(aLeft, aRight);
3328 }
3329
IMPL_LINK(SvTreeListBox,DefaultCompare,const SvSortData &,rData,sal_Int32)3330 IMPL_LINK( SvTreeListBox, DefaultCompare, const SvSortData&, rData, sal_Int32 )
3331 {
3332 const SvTreeListEntry* pLeft = rData.pLeft;
3333 const SvTreeListEntry* pRight = rData.pRight;
3334 const SvLBoxString* pLeftText = static_cast<const SvLBoxString*>(pLeft->GetFirstItem(SvLBoxItemType::String));
3335 const SvLBoxString* pRightText = static_cast<const SvLBoxString*>(pRight->GetFirstItem(SvLBoxItemType::String));
3336 return DefaultCompare(pLeftText, pRightText);
3337 }
3338
ModelNotification(SvListAction nActionId,SvTreeListEntry * pEntry1,SvTreeListEntry * pEntry2,sal_uLong nPos)3339 void SvTreeListBox::ModelNotification( SvListAction nActionId, SvTreeListEntry* pEntry1,
3340 SvTreeListEntry* pEntry2, sal_uLong nPos )
3341 {
3342 SolarMutexGuard aSolarGuard;
3343
3344 if( nActionId == SvListAction::CLEARING )
3345 CancelTextEditing();
3346
3347 SvListView::ModelNotification( nActionId, pEntry1, pEntry2, nPos );
3348 switch( nActionId )
3349 {
3350 case SvListAction::INSERTED:
3351 {
3352 SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry1->GetFirstItem( SvLBoxItemType::ContextBmp ) );
3353 if ( !pBmpItem )
3354 break;
3355 const Image& rBitmap1( pBmpItem->GetBitmap1() );
3356 const Image& rBitmap2( pBmpItem->GetBitmap2() );
3357 short nMaxWidth = short( std::max( rBitmap1.GetSizePixel().Width(), rBitmap2.GetSizePixel().Width() ) );
3358 nMaxWidth = pImpl->UpdateContextBmpWidthVector( pEntry1, nMaxWidth );
3359 if( nMaxWidth > nContextBmpWidthMax )
3360 {
3361 nContextBmpWidthMax = nMaxWidth;
3362 SetTabs();
3363 }
3364 if (get_width_request() == -1)
3365 queue_resize();
3366 }
3367 break;
3368
3369 case SvListAction::RESORTING:
3370 SetUpdateMode( false );
3371 break;
3372
3373 case SvListAction::RESORTED:
3374 // after a selection: show first entry and also keep the selection
3375 MakeVisible( pModel->First(), true );
3376 SetUpdateMode( true );
3377 break;
3378
3379 case SvListAction::CLEARED:
3380 if( IsUpdateMode() )
3381 Update();
3382 break;
3383
3384 default: break;
3385 }
3386 }
3387
EndSelection()3388 void SvTreeListBox::EndSelection()
3389 {
3390 pImpl->EndSelection();
3391 }
3392
GetVScroll()3393 ScrollBar *SvTreeListBox::GetVScroll()
3394 {
3395 return pImpl->m_aVerSBar.get();
3396 }
3397
GetHScroll()3398 ScrollBar *SvTreeListBox::GetHScroll()
3399 {
3400 return pImpl->m_aHorSBar.get();
3401 }
3402
EnableAsyncDrag(bool b)3403 void SvTreeListBox::EnableAsyncDrag( bool b )
3404 {
3405 pImpl->EnableAsyncDrag( b );
3406 }
3407
GetFirstEntryInView() const3408 SvTreeListEntry* SvTreeListBox::GetFirstEntryInView() const
3409 {
3410 return GetEntry( Point() );
3411 }
3412
GetNextEntryInView(SvTreeListEntry * pEntry) const3413 SvTreeListEntry* SvTreeListBox::GetNextEntryInView(SvTreeListEntry* pEntry ) const
3414 {
3415 SvTreeListEntry* pNext = NextVisible( pEntry );
3416 if( pNext )
3417 {
3418 Point aPos( GetEntryPosition(pNext) );
3419 const Size& rSize = pImpl->GetOutputSize();
3420 if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() )
3421 return nullptr;
3422 }
3423 return pNext;
3424 }
3425
GetPrevEntryInView(SvTreeListEntry * pEntry) const3426 SvTreeListEntry* SvTreeListBox::GetPrevEntryInView(SvTreeListEntry* pEntry ) const
3427 {
3428 SvTreeListEntry* pPrev = PrevVisible( pEntry );
3429 if( pPrev )
3430 {
3431 Point aPos( GetEntryPosition(pPrev) );
3432 const Size& rSize = pImpl->GetOutputSize();
3433 if( aPos.Y() < 0 || aPos.Y() >= rSize.Height() )
3434 return nullptr;
3435 }
3436 return pPrev;
3437 }
3438
GetLastEntryInView() const3439 SvTreeListEntry* SvTreeListBox::GetLastEntryInView() const
3440 {
3441 SvTreeListEntry* pEntry = GetFirstEntryInView();
3442 SvTreeListEntry* pNext = nullptr;
3443 while( pEntry )
3444 {
3445 pNext = NextVisible( pEntry );
3446 if( pNext )
3447 {
3448 Point aPos( GetEntryPosition(pNext) );
3449 const Size& rSize = pImpl->GetOutputSize();
3450 if( aPos.Y() < 0 || aPos.Y() + GetEntryHeight() >= rSize.Height() )
3451 break;
3452 else
3453 pEntry = pNext;
3454 }
3455 else
3456 break;
3457 }
3458 return pEntry;
3459 }
3460
ShowFocusRect(const SvTreeListEntry * pEntry)3461 void SvTreeListBox::ShowFocusRect( const SvTreeListEntry* pEntry )
3462 {
3463 pImpl->ShowFocusRect( pEntry );
3464 }
3465
DataChanged(const DataChangedEvent & rDCEvt)3466 void SvTreeListBox::DataChanged( const DataChangedEvent& rDCEvt )
3467 {
3468 if( (rDCEvt.GetType()==DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
3469 {
3470 nEntryHeight = 0; // _together_ with true of 1. par (bFont) of InitSettings() a zero-height
3471 // forces complete recalc of heights!
3472 InitSettings();
3473 Invalidate();
3474 }
3475 else
3476 Control::DataChanged( rDCEvt );
3477 }
3478
StateChanged(StateChangedType eType)3479 void SvTreeListBox::StateChanged( StateChangedType eType )
3480 {
3481 if( eType == StateChangedType::Enable )
3482 Invalidate( InvalidateFlags::Children );
3483
3484 Control::StateChanged( eType );
3485
3486 if ( eType == StateChangedType::Style )
3487 ImplInitStyle();
3488 }
3489
ApplySettings(vcl::RenderContext & rRenderContext)3490 void SvTreeListBox::ApplySettings(vcl::RenderContext& rRenderContext)
3491 {
3492 SetPointFont(rRenderContext, GetPointFont(*this));
3493
3494 const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
3495 rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor());
3496 rRenderContext.SetTextFillColor();
3497 rRenderContext.SetBackground(rStyleSettings.GetFieldColor());
3498
3499 // always try to re-create default-SvLBoxButtonData
3500 if (pCheckButtonData && pCheckButtonData->HasDefaultImages())
3501 pCheckButtonData->SetDefaultImages(this);
3502 }
3503
InitSettings()3504 void SvTreeListBox::InitSettings()
3505 {
3506 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
3507 vcl::Font aFont = rStyleSettings.GetFieldFont();
3508 aFont.SetColor(rStyleSettings.GetWindowTextColor());
3509 SetPointFont(*this, aFont);
3510 AdjustEntryHeightAndRecalc();
3511
3512 SetTextColor(rStyleSettings.GetFieldTextColor());
3513 SetTextFillColor();
3514
3515 SetBackground(rStyleSettings.GetFieldColor());
3516
3517 // always try to re-create default-SvLBoxButtonData
3518 if( pCheckButtonData && pCheckButtonData->HasDefaultImages() )
3519 pCheckButtonData->SetDefaultImages(this);
3520 }
3521
IsCellFocusEnabled() const3522 bool SvTreeListBox::IsCellFocusEnabled() const
3523 {
3524 return pImpl->IsCellFocusEnabled();
3525 }
3526
SetCurrentTabPos(sal_uInt16 _nNewPos)3527 bool SvTreeListBox::SetCurrentTabPos( sal_uInt16 _nNewPos )
3528 {
3529 return pImpl->SetCurrentTabPos( _nNewPos );
3530 }
3531
GetCurrentTabPos() const3532 sal_uInt16 SvTreeListBox::GetCurrentTabPos() const
3533 {
3534 return pImpl->GetCurrentTabPos();
3535 }
3536
CreateContextMenu()3537 VclPtr<PopupMenu> SvTreeListBox::CreateContextMenu()
3538 {
3539 return nullptr;
3540 }
3541
ExecuteContextMenuAction(sal_uInt16)3542 void SvTreeListBox::ExecuteContextMenuAction( sal_uInt16 )
3543 {
3544 SAL_INFO( "svtools.contnr", "SvTreeListBox::ExecuteContextMenuAction(): now there's happening nothing!" );
3545 }
3546
EnableContextMenuHandling()3547 void SvTreeListBox::EnableContextMenuHandling()
3548 {
3549 assert(pImpl && "-SvTreeListBox::EnableContextMenuHandling(): No implementation!");
3550 pImpl->m_bContextMenuHandling = true;
3551 }
3552
CreateAccessible()3553 css::uno::Reference< XAccessible > SvTreeListBox::CreateAccessible()
3554 {
3555 vcl::Window* pParent = GetAccessibleParentWindow();
3556 DBG_ASSERT( pParent, "SvTreeListBox::CreateAccessible - accessible parent not found" );
3557
3558 css::uno::Reference< XAccessible > xAccessible;
3559 if ( pParent )
3560 {
3561 css::uno::Reference< XAccessible > xAccParent = pParent->GetAccessible();
3562 if ( xAccParent.is() )
3563 {
3564 // need to be done here to get the vclxwindow later on in the accessible
3565 css::uno::Reference< css::awt::XWindowPeer > xTemp(GetComponentInterface());
3566 xAccessible = pImpl->m_aFactoryAccess.getFactory().createAccessibleTreeListBox( *this, xAccParent );
3567 }
3568 }
3569 return xAccessible;
3570 }
3571
FillAccessibleEntryStateSet(SvTreeListEntry * pEntry,::utl::AccessibleStateSetHelper & rStateSet) const3572 void SvTreeListBox::FillAccessibleEntryStateSet( SvTreeListEntry* pEntry, ::utl::AccessibleStateSetHelper& rStateSet ) const
3573 {
3574 assert(pEntry && "SvTreeListBox::FillAccessibleEntryStateSet: invalid entry");
3575
3576 if ( pEntry->HasChildrenOnDemand() || pEntry->HasChildren() )
3577 {
3578 rStateSet.AddState( AccessibleStateType::EXPANDABLE );
3579 if ( IsExpanded( pEntry ) )
3580 rStateSet.AddState( sal_Int16(AccessibleStateType::EXPANDED) );
3581 }
3582
3583 if ( GetCheckButtonState( pEntry ) == SvButtonState::Checked )
3584 rStateSet.AddState( AccessibleStateType::CHECKED );
3585 if ( IsEntryVisible( pEntry ) )
3586 rStateSet.AddState( AccessibleStateType::VISIBLE );
3587 if ( IsSelected( pEntry ) )
3588 rStateSet.AddState( AccessibleStateType::SELECTED );
3589 if ( IsEnabled() )
3590 {
3591 rStateSet.AddState( AccessibleStateType::ENABLED );
3592 rStateSet.AddState( AccessibleStateType::FOCUSABLE );
3593 rStateSet.AddState( AccessibleStateType::SELECTABLE );
3594 SvViewDataEntry* pViewDataNewCur = GetViewDataEntry(pEntry);
3595 if (pViewDataNewCur && pViewDataNewCur->HasFocus())
3596 rStateSet.AddState( AccessibleStateType::FOCUSED );
3597 }
3598 }
3599
GetBoundingRect(SvTreeListEntry * pEntry)3600 tools::Rectangle SvTreeListBox::GetBoundingRect( SvTreeListEntry* pEntry )
3601 {
3602 Point aPos = GetEntryPosition( pEntry );
3603 tools::Rectangle aRect = GetFocusRect( pEntry, aPos.Y() );
3604 return aRect;
3605 }
3606
CallImplEventListeners(VclEventId nEvent,void * pData)3607 void SvTreeListBox::CallImplEventListeners(VclEventId nEvent, void* pData)
3608 {
3609 CallEventListeners(nEvent, pData);
3610 }
3611
set_min_width_in_chars(sal_Int32 nChars)3612 void SvTreeListBox::set_min_width_in_chars(sal_Int32 nChars)
3613 {
3614 nMinWidthInChars = nChars;
3615 queue_resize();
3616 }
3617
set_property(const OString & rKey,const OUString & rValue)3618 bool SvTreeListBox::set_property(const OString &rKey, const OUString &rValue)
3619 {
3620 if (rKey == "min-width-chars")
3621 {
3622 set_min_width_in_chars(rValue.toInt32());
3623 }
3624 else if (rKey == "enable-tree-lines")
3625 {
3626 auto nStyle = GetStyle();
3627 nStyle &= ~(WB_HASLINES | WB_HASLINESATROOT);
3628 if (toBool(rValue))
3629 nStyle |= (WB_HASLINES | WB_HASLINESATROOT);
3630 SetStyle(nStyle);
3631 }
3632 else if (rKey == "show-expanders")
3633 {
3634 auto nStyle = GetStyle();
3635 nStyle &= ~(WB_HASBUTTONS | WB_HASBUTTONSATROOT);
3636 if (toBool(rValue))
3637 nStyle |= (WB_HASBUTTONS | WB_HASBUTTONSATROOT);
3638 SetStyle(nStyle);
3639 }
3640 else if (rKey == "rules-hint")
3641 {
3642 SetAlternatingRowColors(toBool(rValue));
3643 }
3644 else if (rKey == "enable-search")
3645 {
3646 SetQuickSearch(toBool(rValue));
3647 }
3648 else if (rKey == "reorderable")
3649 {
3650 if (toBool(rValue))
3651 SetDragDropMode(DragDropMode::CTRL_MOVE | DragDropMode::ENABLE_TOP);
3652 }
3653 else
3654 return Control::set_property(rKey, rValue);
3655 return true;
3656 }
3657
GetUITestFactory() const3658 FactoryFunction SvTreeListBox::GetUITestFactory() const
3659 {
3660 return TreeListUIObject::create;
3661 }
3662
3663 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3664