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