File: | home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx |
Warning: | line 1715, column 10 Called C++ object pointer is null |
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 | #include <sal/config.h> | |||
21 | ||||
22 | #include <o3tl/safeint.hxx> | |||
23 | #include <vcl/svapp.hxx> | |||
24 | #include <vcl/salnativewidgets.hxx> | |||
25 | #include <vcl/help.hxx> | |||
26 | #include <vcl/settings.hxx> | |||
27 | #include <vcl/commandevent.hxx> | |||
28 | ||||
29 | #include <cstdlib> | |||
30 | #include <memory> | |||
31 | #include <stack> | |||
32 | ||||
33 | #include <vcl/toolkit/treelistbox.hxx> | |||
34 | #include <vcl/toolkit/svlbitm.hxx> | |||
35 | #include <tools/wintypes.hxx> | |||
36 | #include <bitmaps.hlst> | |||
37 | #include <svimpbox.hxx> | |||
38 | #include <comphelper/processfactory.hxx> | |||
39 | #include <comphelper/string.hxx> | |||
40 | #include <i18nlangtag/languagetag.hxx> | |||
41 | #include <tools/debug.hxx> | |||
42 | ||||
43 | #include <vcl/toolkit/treelistentry.hxx> | |||
44 | #include <vcl/toolkit/viewdataentry.hxx> | |||
45 | ||||
46 | // #i27063# (pl), #i32300# (pb) never access VCL after DeInitVCL - also no destructors | |||
47 | Image* SvImpLBox::s_pDefCollapsed = nullptr; | |||
48 | Image* SvImpLBox::s_pDefExpanded = nullptr; | |||
49 | oslInterlockedCount SvImpLBox::s_nImageRefCount = 0; | |||
50 | ||||
51 | SvImpLBox::SvImpLBox( SvTreeListBox* pLBView, SvTreeList* pLBTree, WinBits nWinStyle) | |||
52 | : m_aHorSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_HSCROLL)) | |||
53 | , m_aScrBarBox(VclPtr<ScrollBarBox>::Create(pLBView)) | |||
54 | , m_aFctSet(this, pLBView) | |||
55 | , mbForceMakeVisible (false) | |||
56 | , m_aVerSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_VSCROLL)) | |||
57 | , m_aOutputSize(0, 0) | |||
58 | , mbNoAutoCurEntry(false) | |||
59 | , m_aSelEng(pLBView, nullptr) | |||
60 | , m_nNextVerVisSize(0) | |||
61 | { | |||
62 | osl_atomic_increment(&s_nImageRefCount)__sync_add_and_fetch((&s_nImageRefCount), 1); | |||
63 | m_pView = pLBView; | |||
64 | m_pTree = pLBTree; | |||
65 | m_aSelEng.SetFunctionSet( static_cast<FunctionSet*>(&m_aFctSet) ); | |||
66 | m_aSelEng.ExpandSelectionOnMouseMove( false ); | |||
67 | SetStyle( nWinStyle ); | |||
68 | SetSelectionMode( SelectionMode::Single ); | |||
69 | SetDragDropMode( DragDropMode::NONE ); | |||
70 | ||||
71 | m_aVerSBar->SetScrollHdl( LINK( this, SvImpLBox, ScrollUpDownHdl )::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox *>(this), &SvImpLBox::LinkStubScrollUpDownHdl) ); | |||
72 | m_aHorSBar->SetScrollHdl( LINK( this, SvImpLBox, ScrollLeftRightHdl )::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox *>(this), &SvImpLBox::LinkStubScrollLeftRightHdl) ); | |||
73 | m_aHorSBar->SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl )::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox *>(this), &SvImpLBox::LinkStubEndScrollHdl) ); | |||
74 | m_aVerSBar->SetEndScrollHdl( LINK( this, SvImpLBox, EndScrollHdl )::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox *>(this), &SvImpLBox::LinkStubEndScrollHdl) ); | |||
75 | m_aVerSBar->SetRange( Range(0,0) ); | |||
76 | m_aVerSBar->Hide(); | |||
77 | m_aHorSBar->SetRange( Range(0,0) ); | |||
78 | m_aHorSBar->SetPageSize( 24 ); // pixels | |||
79 | m_aHorSBar->SetLineSize( 8 ); // pixels | |||
80 | ||||
81 | m_nHorSBarHeight = static_cast<short>(m_aHorSBar->GetSizePixel().Height()); | |||
82 | m_nVerSBarWidth = static_cast<short>(m_aVerSBar->GetSizePixel().Width()); | |||
83 | ||||
84 | m_pStartEntry = nullptr; | |||
85 | m_pCursor = nullptr; | |||
86 | m_pAnchor = nullptr; | |||
87 | m_nVisibleCount = 0; // number of rows of data in control | |||
88 | m_nNodeBmpTabDistance = NODE_BMP_TABDIST_NOTVALID-2000000; | |||
89 | m_nNodeBmpWidth = 0; | |||
90 | ||||
91 | // button animation in listbox | |||
92 | m_pActiveButton = nullptr; | |||
93 | m_pActiveEntry = nullptr; | |||
94 | m_pActiveTab = nullptr; | |||
95 | ||||
96 | m_nFlags = LBoxFlags::NONE; | |||
97 | ||||
98 | m_aEditIdle.SetPriority( TaskPriority::LOWEST ); | |||
99 | m_aEditIdle.SetInvokeHandler( LINK(this,SvImpLBox,EditTimerCall)::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox *>(this), &SvImpLBox::LinkStubEditTimerCall) ); | |||
100 | ||||
101 | m_nMostRight = -1; | |||
102 | m_pMostRightEntry = nullptr; | |||
103 | m_nCurUserEvent = nullptr; | |||
104 | ||||
105 | m_bUpdateMode = true; | |||
106 | m_bInVScrollHdl = false; | |||
107 | m_nFlags |= LBoxFlags::Filling; | |||
108 | ||||
109 | m_bSubLstOpLR = false; | |||
110 | } | |||
111 | ||||
112 | SvImpLBox::~SvImpLBox() | |||
113 | { | |||
114 | m_aEditIdle.Stop(); | |||
115 | StopUserEvent(); | |||
116 | ||||
117 | if ( osl_atomic_decrement(&s_nImageRefCount)__sync_sub_and_fetch((&s_nImageRefCount), 1) == 0 ) | |||
118 | { | |||
119 | delete s_pDefCollapsed; | |||
120 | s_pDefCollapsed = nullptr; | |||
121 | delete s_pDefExpanded; | |||
122 | s_pDefExpanded = nullptr; | |||
123 | } | |||
124 | m_aVerSBar.disposeAndClear(); | |||
125 | m_aHorSBar.disposeAndClear(); | |||
126 | m_aScrBarBox.disposeAndClear(); | |||
127 | } | |||
128 | ||||
129 | void SvImpLBox::UpdateStringSorter() | |||
130 | { | |||
131 | const css::lang::Locale& rNewLocale = Application::GetSettings().GetLanguageTag().getLocale(); | |||
132 | ||||
133 | if( m_pStringSorter ) | |||
134 | { | |||
135 | // different Locale from the older one, drop it and force recreate | |||
136 | const css::lang::Locale &aLocale = m_pStringSorter->getLocale(); | |||
137 | if( aLocale.Language != rNewLocale.Language || | |||
138 | aLocale.Country != rNewLocale.Country || | |||
139 | aLocale.Variant != rNewLocale.Variant ) | |||
140 | m_pStringSorter.reset(); | |||
141 | } | |||
142 | ||||
143 | if( !m_pStringSorter ) | |||
144 | { | |||
145 | m_pStringSorter.reset(new comphelper::string::NaturalStringSorter( | |||
146 | ::comphelper::getProcessComponentContext(), | |||
147 | rNewLocale)); | |||
148 | } | |||
149 | } | |||
150 | ||||
151 | short SvImpLBox::UpdateContextBmpWidthVector( SvTreeListEntry const * pEntry, short nWidth ) | |||
152 | { | |||
153 | DBG_ASSERT( m_pView->pModel, "View and Model aren't valid!" )do { if (true && (!(m_pView->pModel))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "153" ": "), "%s", "View and Model aren't valid!"); } } while (false); | |||
154 | ||||
155 | sal_uInt16 nDepth = m_pView->pModel->GetDepth( pEntry ); | |||
156 | // initialize vector if necessary | |||
157 | std::vector< short >::size_type nSize = m_aContextBmpWidthVector.size(); | |||
158 | while ( nDepth > nSize ) | |||
159 | { | |||
160 | m_aContextBmpWidthVector.resize( nSize + 1 ); | |||
161 | m_aContextBmpWidthVector.at( nSize ) = nWidth; | |||
162 | ++nSize; | |||
163 | } | |||
164 | if( m_aContextBmpWidthVector.size() == nDepth ) | |||
165 | { | |||
166 | m_aContextBmpWidthVector.resize( nDepth + 1 ); | |||
167 | m_aContextBmpWidthVector.at( nDepth ) = 0; | |||
168 | } | |||
169 | short nContextBmpWidth = m_aContextBmpWidthVector[ nDepth ]; | |||
170 | if( nContextBmpWidth < nWidth ) | |||
171 | { | |||
172 | m_aContextBmpWidthVector.at( nDepth ) = nWidth; | |||
173 | return nWidth; | |||
174 | } | |||
175 | else | |||
176 | return nContextBmpWidth; | |||
177 | } | |||
178 | ||||
179 | void SvImpLBox::UpdateContextBmpWidthVectorFromMovedEntry( SvTreeListEntry* pEntry ) | |||
180 | { | |||
181 | DBG_ASSERT( pEntry, "Moved Entry is invalid!" )do { if (true && (!(pEntry))) { sal_detail_logFormat( (SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "181" ": "), "%s", "Moved Entry is invalid!"); } } while (false); | |||
182 | ||||
183 | SvLBoxContextBmp* pBmpItem = static_cast< SvLBoxContextBmp* >( pEntry->GetFirstItem(SvLBoxItemType::ContextBmp) ); | |||
184 | short nExpWidth = static_cast<short>(pBmpItem->GetBitmap1().GetSizePixel().Width()); | |||
185 | short nColWidth = static_cast<short>(pBmpItem->GetBitmap2().GetSizePixel().Width()); | |||
186 | short nMax = std::max(nExpWidth, nColWidth); | |||
187 | UpdateContextBmpWidthVector( pEntry, nMax ); | |||
188 | ||||
189 | if( pEntry->HasChildren() ) // recursive call, whether expanded or not | |||
190 | { | |||
191 | SvTreeListEntry* pChild = m_pView->FirstChild( pEntry ); | |||
192 | DBG_ASSERT( pChild, "The first child is invalid!" )do { if (true && (!(pChild))) { sal_detail_logFormat( (SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "192" ": "), "%s", "The first child is invalid!"); } } while (false); | |||
193 | do | |||
194 | { | |||
195 | UpdateContextBmpWidthVectorFromMovedEntry( pChild ); | |||
196 | pChild = m_pView->Next( pChild ); | |||
197 | } while ( pChild ); | |||
198 | } | |||
199 | } | |||
200 | ||||
201 | void SvImpLBox::UpdateContextBmpWidthMax( SvTreeListEntry const * pEntry ) | |||
202 | { | |||
203 | sal_uInt16 nDepth = m_pView->pModel->GetDepth( pEntry ); | |||
204 | if( m_aContextBmpWidthVector.empty() ) | |||
205 | return; | |||
206 | short nWidth = m_aContextBmpWidthVector[ nDepth ]; | |||
207 | if( nWidth != m_pView->nContextBmpWidthMax ) { | |||
208 | m_pView->nContextBmpWidthMax = nWidth; | |||
209 | m_nFlags |= LBoxFlags::IgnoreChangedTabs; | |||
210 | m_pView->SetTabs(); | |||
211 | m_nFlags &= ~LBoxFlags::IgnoreChangedTabs; | |||
212 | } | |||
213 | } | |||
214 | ||||
215 | void SvImpLBox::SetStyle( WinBits i_nWinStyle ) | |||
216 | { | |||
217 | m_nStyle = i_nWinStyle; | |||
218 | if ( ( m_nStyle & WB_SIMPLEMODE) && ( m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) ) | |||
219 | m_aSelEng.AddAlways( true ); | |||
220 | } | |||
221 | ||||
222 | void SvImpLBox::SetNoAutoCurEntry( bool b ) | |||
223 | { | |||
224 | mbNoAutoCurEntry = b; | |||
225 | } | |||
226 | ||||
227 | // don't touch the model any more | |||
228 | void SvImpLBox::Clear() | |||
229 | { | |||
230 | StopUserEvent(); | |||
231 | m_pStartEntry = nullptr; | |||
232 | m_pAnchor = nullptr; | |||
233 | ||||
234 | m_pActiveButton = nullptr; | |||
235 | m_pActiveEntry = nullptr; | |||
236 | m_pActiveTab = nullptr; | |||
237 | ||||
238 | m_nMostRight = -1; | |||
239 | m_pMostRightEntry = nullptr; | |||
240 | ||||
241 | // don't touch the cursor any more | |||
242 | if( m_pCursor ) | |||
243 | { | |||
244 | if( m_pView->HasFocus() ) | |||
245 | m_pView->HideFocus(); | |||
246 | m_pCursor = nullptr; | |||
247 | } | |||
248 | m_aVerSBar->Hide(); | |||
249 | m_aVerSBar->SetThumbPos( 0 ); | |||
250 | Range aRange( 0, 0 ); | |||
251 | m_aVerSBar->SetRange( aRange ); | |||
252 | m_aOutputSize = m_pView->Control::GetOutputSizePixel(); | |||
253 | m_aHorSBar->Hide(); | |||
254 | m_aHorSBar->SetThumbPos( 0 ); | |||
255 | MapMode aMapMode( m_pView->GetMapMode()); | |||
256 | aMapMode.SetOrigin( Point(0,0) ); | |||
257 | m_pView->Control::SetMapMode( aMapMode ); | |||
258 | m_aHorSBar->SetRange( aRange ); | |||
259 | m_aHorSBar->SetSizePixel(Size(m_aOutputSize.Width(),m_nHorSBarHeight)); | |||
260 | m_pView->SetClipRegion(); | |||
261 | if( GetUpdateMode() ) | |||
262 | m_pView->Invalidate( GetVisibleArea() ); | |||
263 | m_nFlags |= LBoxFlags::Filling; | |||
264 | if( !m_aHorSBar->IsVisible() && !m_aVerSBar->IsVisible() ) | |||
265 | m_aScrBarBox->Hide(); | |||
266 | ||||
267 | m_aContextBmpWidthVector.clear(); | |||
268 | ||||
269 | CallEventListeners( VclEventId::ListboxItemRemoved ); | |||
270 | } | |||
271 | ||||
272 | // ********************************************************************* | |||
273 | // Paint, navigate, scroll | |||
274 | // ********************************************************************* | |||
275 | ||||
276 | IMPL_LINK_NOARG(SvImpLBox, EndScrollHdl, ScrollBar*, void)void SvImpLBox::LinkStubEndScrollHdl(void * instance, ScrollBar * data) { return static_cast<SvImpLBox *>(instance)-> EndScrollHdl(data); } void SvImpLBox::EndScrollHdl(__attribute__ ((unused)) ScrollBar*) | |||
277 | { | |||
278 | if( m_nFlags & LBoxFlags::EndScrollSetVisSize ) | |||
279 | { | |||
280 | m_aVerSBar->SetVisibleSize( m_nNextVerVisSize ); | |||
281 | m_nFlags &= ~LBoxFlags::EndScrollSetVisSize; | |||
282 | } | |||
283 | } | |||
284 | ||||
285 | // handler for vertical scrollbar | |||
286 | ||||
287 | IMPL_LINK( SvImpLBox, ScrollUpDownHdl, ScrollBar *, pScrollBar, void )void SvImpLBox::LinkStubScrollUpDownHdl(void * instance, ScrollBar * data) { return static_cast<SvImpLBox *>(instance)-> ScrollUpDownHdl(data); } void SvImpLBox::ScrollUpDownHdl(ScrollBar * pScrollBar) | |||
288 | { | |||
289 | DBG_ASSERT(!m_bInVScrollHdl,"Scroll handler out-paces itself!")do { if (true && (!(!m_bInVScrollHdl))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "289" ": "), "%s", "Scroll handler out-paces itself!"); } } while (false); | |||
290 | long nDelta = pScrollBar->GetDelta(); | |||
291 | if( !nDelta ) | |||
292 | return; | |||
293 | ||||
294 | m_nFlags &= ~LBoxFlags::Filling; | |||
295 | ||||
296 | m_bInVScrollHdl = true; | |||
297 | ||||
298 | if( m_pView->IsEditingActive() ) | |||
299 | { | |||
300 | m_pView->EndEditing( true ); // Cancel | |||
301 | m_pView->PaintImmediately(); | |||
302 | } | |||
303 | ||||
304 | if( nDelta > 0 ) | |||
305 | { | |||
306 | if( nDelta == 1 ) | |||
307 | CursorDown(); | |||
308 | else | |||
309 | PageDown( static_cast<sal_uInt16>(nDelta) ); | |||
310 | } | |||
311 | else | |||
312 | { | |||
313 | nDelta *= -1; | |||
314 | if( nDelta == 1 ) | |||
315 | CursorUp(); | |||
316 | else | |||
317 | PageUp( static_cast<sal_uInt16>(nDelta) ); | |||
318 | } | |||
319 | m_bInVScrollHdl = false; | |||
320 | } | |||
321 | ||||
322 | ||||
323 | void SvImpLBox::CursorDown() | |||
324 | { | |||
325 | if (!m_pStartEntry) | |||
326 | return; | |||
327 | ||||
328 | SvTreeListEntry* pNextFirstToDraw = m_pView->NextVisible(m_pStartEntry); | |||
329 | if( pNextFirstToDraw ) | |||
330 | { | |||
331 | m_nFlags &= ~LBoxFlags::Filling; | |||
332 | ShowCursor( false ); | |||
333 | m_pView->PaintImmediately(); | |||
334 | m_pStartEntry = pNextFirstToDraw; | |||
335 | tools::Rectangle aArea( GetVisibleArea() ); | |||
336 | m_pView->Scroll( 0, -(m_pView->GetEntryHeight()), aArea, ScrollFlags::NoChildren ); | |||
337 | m_pView->PaintImmediately(); | |||
338 | ShowCursor( true ); | |||
339 | m_pView->NotifyScrolled(); | |||
340 | } | |||
341 | } | |||
342 | ||||
343 | void SvImpLBox::CursorUp() | |||
344 | { | |||
345 | if (!m_pStartEntry) | |||
346 | return; | |||
347 | ||||
348 | SvTreeListEntry* pPrevFirstToDraw = m_pView->PrevVisible(m_pStartEntry); | |||
349 | if( !pPrevFirstToDraw ) | |||
350 | return; | |||
351 | ||||
352 | m_nFlags &= ~LBoxFlags::Filling; | |||
353 | long nEntryHeight = m_pView->GetEntryHeight(); | |||
354 | ShowCursor( false ); | |||
355 | m_pView->PaintImmediately(); | |||
356 | m_pStartEntry = pPrevFirstToDraw; | |||
357 | tools::Rectangle aArea( GetVisibleArea() ); | |||
358 | aArea.AdjustBottom( -nEntryHeight ); | |||
359 | m_pView->Scroll( 0, nEntryHeight, aArea, ScrollFlags::NoChildren ); | |||
360 | m_pView->PaintImmediately(); | |||
361 | ShowCursor( true ); | |||
362 | m_pView->NotifyScrolled(); | |||
363 | } | |||
364 | ||||
365 | void SvImpLBox::PageDown( sal_uInt16 nDelta ) | |||
366 | { | |||
367 | sal_uInt16 nRealDelta = nDelta; | |||
368 | ||||
369 | if( !nDelta ) | |||
370 | return; | |||
371 | ||||
372 | if (!m_pStartEntry) | |||
373 | return; | |||
374 | ||||
375 | SvTreeListEntry* pNext = m_pView->NextVisible(m_pStartEntry, nRealDelta); | |||
376 | if( pNext == m_pStartEntry ) | |||
377 | return; | |||
378 | ||||
379 | ShowCursor( false ); | |||
380 | ||||
381 | m_nFlags &= ~LBoxFlags::Filling; | |||
382 | m_pStartEntry = pNext; | |||
383 | ||||
384 | if( nRealDelta >= m_nVisibleCount ) | |||
385 | { | |||
386 | m_pView->Invalidate( GetVisibleArea() ); | |||
387 | m_pView->PaintImmediately(); | |||
388 | } | |||
389 | else | |||
390 | { | |||
391 | tools::Rectangle aArea( GetVisibleArea() ); | |||
392 | long nScroll = m_pView->GetEntryHeight() * static_cast<long>(nRealDelta); | |||
393 | nScroll = -nScroll; | |||
394 | m_pView->PaintImmediately(); | |||
395 | m_pView->Scroll( 0, nScroll, aArea, ScrollFlags::NoChildren ); | |||
396 | m_pView->PaintImmediately(); | |||
397 | m_pView->NotifyScrolled(); | |||
398 | } | |||
399 | ||||
400 | ShowCursor( true ); | |||
401 | } | |||
402 | ||||
403 | void SvImpLBox::PageUp( sal_uInt16 nDelta ) | |||
404 | { | |||
405 | sal_uInt16 nRealDelta = nDelta; | |||
406 | if( !nDelta ) | |||
407 | return; | |||
408 | ||||
409 | if (!m_pStartEntry) | |||
410 | return; | |||
411 | ||||
412 | SvTreeListEntry* pPrev = m_pView->PrevVisible(m_pStartEntry, nRealDelta); | |||
413 | if( pPrev == m_pStartEntry ) | |||
414 | return; | |||
415 | ||||
416 | m_nFlags &= ~LBoxFlags::Filling; | |||
417 | ShowCursor( false ); | |||
418 | ||||
419 | m_pStartEntry = pPrev; | |||
420 | if( nRealDelta >= m_nVisibleCount ) | |||
421 | { | |||
422 | m_pView->Invalidate( GetVisibleArea() ); | |||
423 | m_pView->PaintImmediately(); | |||
424 | } | |||
425 | else | |||
426 | { | |||
427 | long nEntryHeight = m_pView->GetEntryHeight(); | |||
428 | tools::Rectangle aArea( GetVisibleArea() ); | |||
429 | m_pView->PaintImmediately(); | |||
430 | m_pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, ScrollFlags::NoChildren ); | |||
431 | m_pView->PaintImmediately(); | |||
432 | m_pView->NotifyScrolled(); | |||
433 | } | |||
434 | ||||
435 | ShowCursor( true ); | |||
436 | } | |||
437 | ||||
438 | void SvImpLBox::KeyUp( bool bPageUp ) | |||
439 | { | |||
440 | if( !m_aVerSBar->IsVisible() ) | |||
441 | return; | |||
442 | ||||
443 | long nDelta; | |||
444 | if( bPageUp ) | |||
445 | nDelta = m_aVerSBar->GetPageSize(); | |||
446 | else | |||
447 | nDelta = 1; | |||
448 | ||||
449 | long nThumbPos = m_aVerSBar->GetThumbPos(); | |||
450 | ||||
451 | if( nThumbPos < nDelta ) | |||
452 | nDelta = nThumbPos; | |||
453 | ||||
454 | if( nDelta <= 0 ) | |||
455 | return; | |||
456 | ||||
457 | m_nFlags &= ~LBoxFlags::Filling; | |||
458 | ||||
459 | m_aVerSBar->SetThumbPos( nThumbPos - nDelta ); | |||
460 | if( bPageUp ) | |||
461 | PageUp( static_cast<short>(nDelta) ); | |||
462 | else | |||
463 | CursorUp(); | |||
464 | } | |||
465 | ||||
466 | ||||
467 | void SvImpLBox::KeyDown( bool bPageDown ) | |||
468 | { | |||
469 | if( !m_aVerSBar->IsVisible() ) | |||
470 | return; | |||
471 | ||||
472 | long nDelta; | |||
473 | if( bPageDown ) | |||
474 | nDelta = m_aVerSBar->GetPageSize(); | |||
475 | else | |||
476 | nDelta = 1; | |||
477 | ||||
478 | long nThumbPos = m_aVerSBar->GetThumbPos(); | |||
479 | long nVisibleSize = m_aVerSBar->GetVisibleSize(); | |||
480 | long nRange = m_aVerSBar->GetRange().Len(); | |||
481 | ||||
482 | long nTmp = nThumbPos+nVisibleSize; | |||
483 | while( (nDelta > 0) && (nTmp+nDelta) >= nRange ) | |||
484 | nDelta--; | |||
485 | ||||
486 | if( nDelta <= 0 ) | |||
487 | return; | |||
488 | ||||
489 | m_nFlags &= ~LBoxFlags::Filling; | |||
490 | ||||
491 | m_aVerSBar->SetThumbPos( nThumbPos+nDelta ); | |||
492 | if( bPageDown ) | |||
493 | PageDown( static_cast<short>(nDelta) ); | |||
494 | else | |||
495 | CursorDown(); | |||
496 | } | |||
497 | ||||
498 | ||||
499 | void SvImpLBox::InvalidateEntriesFrom( long nY ) const | |||
500 | { | |||
501 | if( !(m_nFlags & LBoxFlags::InPaint )) | |||
502 | { | |||
503 | tools::Rectangle aRect( GetVisibleArea() ); | |||
504 | aRect.SetTop( nY ); | |||
505 | m_pView->Invalidate( aRect ); | |||
506 | } | |||
507 | } | |||
508 | ||||
509 | void SvImpLBox::InvalidateEntry( long nY ) const | |||
510 | { | |||
511 | if( m_nFlags & LBoxFlags::InPaint ) | |||
512 | return; | |||
513 | ||||
514 | tools::Rectangle aRect( GetVisibleArea() ); | |||
515 | long nMaxBottom = aRect.Bottom(); | |||
516 | aRect.SetTop( nY ); | |||
517 | aRect.SetBottom( nY ); aRect.AdjustBottom(m_pView->GetEntryHeight() ); | |||
518 | if( aRect.Top() > nMaxBottom ) | |||
519 | return; | |||
520 | if( aRect.Bottom() > nMaxBottom ) | |||
521 | aRect.SetBottom( nMaxBottom ); | |||
522 | if (m_pView->SupportsDoubleBuffering()) | |||
523 | // Perform full paint when flicker is to be avoided explicitly. | |||
524 | m_pView->Invalidate(); | |||
525 | else | |||
526 | m_pView->Invalidate(aRect); | |||
527 | } | |||
528 | ||||
529 | void SvImpLBox::InvalidateEntry( SvTreeListEntry* pEntry ) | |||
530 | { | |||
531 | if( GetUpdateMode() ) | |||
532 | { | |||
533 | long nPrev = m_nMostRight; | |||
534 | SetMostRight( pEntry ); | |||
535 | if( nPrev < m_nMostRight ) | |||
536 | ShowVerSBar(); | |||
537 | } | |||
538 | if( !(m_nFlags & LBoxFlags::InPaint )) | |||
539 | { | |||
540 | bool bHasFocusRect = false; | |||
541 | if( pEntry==m_pCursor && m_pView->HasFocus() ) | |||
542 | { | |||
543 | bHasFocusRect = true; | |||
544 | ShowCursor( false ); | |||
545 | } | |||
546 | InvalidateEntry( GetEntryLine( pEntry ) ); | |||
547 | if( bHasFocusRect ) | |||
548 | ShowCursor( true ); | |||
549 | } | |||
550 | } | |||
551 | ||||
552 | ||||
553 | void SvImpLBox::RecalcFocusRect() | |||
554 | { | |||
555 | if( m_pView->HasFocus() && m_pCursor ) | |||
556 | { | |||
557 | m_pView->HideFocus(); | |||
558 | long nY = GetEntryLine( m_pCursor ); | |||
559 | tools::Rectangle aRect = m_pView->GetFocusRect( m_pCursor, nY ); | |||
560 | vcl::Region aOldClip( m_pView->GetClipRegion()); | |||
561 | vcl::Region aClipRegion( GetClipRegionRect() ); | |||
562 | m_pView->SetClipRegion( aClipRegion ); | |||
563 | m_pView->ShowFocus( aRect ); | |||
564 | m_pView->SetClipRegion( aOldClip ); | |||
565 | } | |||
566 | } | |||
567 | ||||
568 | ||||
569 | // Sets cursor. When using SingleSelection, the selection is adjusted. | |||
570 | void SvImpLBox::SetCursor( SvTreeListEntry* pEntry, bool bForceNoSelect ) | |||
571 | { | |||
572 | SvViewDataEntry* pViewDataNewCur = nullptr; | |||
573 | if( pEntry ) | |||
574 | pViewDataNewCur= m_pView->GetViewDataEntry(pEntry); | |||
575 | if( pEntry && | |||
576 | pEntry == m_pCursor && | |||
577 | pViewDataNewCur && | |||
578 | pViewDataNewCur->HasFocus() && | |||
579 | pViewDataNewCur->IsSelected()) | |||
580 | { | |||
581 | return; | |||
582 | } | |||
583 | ||||
584 | // if this cursor is not selectable, find first visible that is and use it | |||
585 | while( pEntry && pViewDataNewCur && !pViewDataNewCur->IsSelectable() ) | |||
586 | { | |||
587 | pEntry = m_pView->NextVisible(pEntry); | |||
588 | pViewDataNewCur = pEntry ? m_pView->GetViewDataEntry(pEntry) : nullptr; | |||
589 | } | |||
590 | ||||
591 | SvTreeListEntry* pOldCursor = m_pCursor; | |||
592 | if( m_pCursor && pEntry != m_pCursor ) | |||
593 | { | |||
594 | m_pView->SetEntryFocus( m_pCursor, false ); | |||
595 | if( m_bSimpleTravel ) | |||
596 | m_pView->Select( m_pCursor, false ); | |||
597 | m_pView->HideFocus(); | |||
598 | } | |||
599 | m_pCursor = pEntry; | |||
600 | if( m_pCursor ) | |||
601 | { | |||
602 | if (pViewDataNewCur) | |||
603 | pViewDataNewCur->SetFocus( true ); | |||
604 | if(!bForceNoSelect && m_bSimpleTravel && !(m_nFlags & LBoxFlags::DeselectAll) && GetUpdateMode()) | |||
605 | { | |||
606 | m_pView->Select( m_pCursor ); | |||
607 | CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor ); | |||
608 | } | |||
609 | // multiple selection: select in cursor move if we're not in | |||
610 | // Add mode (Ctrl-F8) | |||
611 | else if( GetUpdateMode() && | |||
612 | m_pView->GetSelectionMode() == SelectionMode::Multiple && | |||
613 | !(m_nFlags & LBoxFlags::DeselectAll) && !m_aSelEng.IsAddMode() && | |||
614 | !bForceNoSelect ) | |||
615 | { | |||
616 | m_pView->Select( m_pCursor ); | |||
617 | CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor ); | |||
618 | } | |||
619 | else | |||
620 | { | |||
621 | ShowCursor( true ); | |||
622 | if (bForceNoSelect && GetUpdateMode()) | |||
623 | { | |||
624 | CallEventListeners( VclEventId::ListboxTreeFocus, m_pCursor); | |||
625 | } | |||
626 | } | |||
627 | ||||
628 | if( m_pAnchor ) | |||
629 | { | |||
630 | DBG_ASSERT(m_aSelEng.GetSelectionMode() != SelectionMode::Single,"Mode?")do { if (true && (!(m_aSelEng.GetSelectionMode() != SelectionMode ::Single))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "630" ": "), "%s", "Mode?"); } } while (false); | |||
631 | SetAnchorSelection( pOldCursor, m_pCursor ); | |||
632 | } | |||
633 | } | |||
634 | m_nFlags &= ~LBoxFlags::DeselectAll; | |||
635 | ||||
636 | m_pView->OnCurrentEntryChanged(); | |||
637 | } | |||
638 | ||||
639 | void SvImpLBox::ShowCursor( bool bShow ) | |||
640 | { | |||
641 | if( !bShow || !m_pCursor || !m_pView->HasFocus() ) | |||
642 | { | |||
643 | vcl::Region aOldClip( m_pView->GetClipRegion()); | |||
644 | vcl::Region aClipRegion( GetClipRegionRect() ); | |||
645 | m_pView->SetClipRegion( aClipRegion ); | |||
646 | m_pView->HideFocus(); | |||
647 | m_pView->SetClipRegion( aOldClip ); | |||
648 | } | |||
649 | else | |||
650 | { | |||
651 | long nY = GetEntryLine( m_pCursor ); | |||
652 | tools::Rectangle aRect = m_pView->GetFocusRect( m_pCursor, nY ); | |||
653 | vcl::Region aOldClip( m_pView->GetClipRegion()); | |||
654 | vcl::Region aClipRegion( GetClipRegionRect() ); | |||
655 | m_pView->SetClipRegion( aClipRegion ); | |||
656 | m_pView->ShowFocus( aRect ); | |||
657 | m_pView->SetClipRegion( aOldClip ); | |||
658 | } | |||
659 | } | |||
660 | ||||
661 | ||||
662 | void SvImpLBox::UpdateAll( bool bInvalidateCompleteView ) | |||
663 | { | |||
664 | FindMostRight(); | |||
665 | m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) ); | |||
666 | SyncVerThumb(); | |||
667 | FillView(); | |||
668 | ShowVerSBar(); | |||
669 | if( m_bSimpleTravel && m_pCursor && m_pView->HasFocus() ) | |||
670 | m_pView->Select( m_pCursor ); | |||
671 | ShowCursor( true ); | |||
672 | if( bInvalidateCompleteView ) | |||
673 | m_pView->Invalidate(); | |||
674 | else | |||
675 | m_pView->Invalidate( GetVisibleArea() ); | |||
676 | } | |||
677 | ||||
678 | IMPL_LINK( SvImpLBox, ScrollLeftRightHdl, ScrollBar *, pScrollBar, void )void SvImpLBox::LinkStubScrollLeftRightHdl(void * instance, ScrollBar * data) { return static_cast<SvImpLBox *>(instance)-> ScrollLeftRightHdl(data); } void SvImpLBox::ScrollLeftRightHdl (ScrollBar * pScrollBar) | |||
679 | { | |||
680 | long nDelta = pScrollBar->GetDelta(); | |||
681 | if( nDelta ) | |||
682 | { | |||
683 | if( m_pView->IsEditingActive() ) | |||
684 | { | |||
685 | m_pView->EndEditing( true ); // Cancel | |||
686 | m_pView->PaintImmediately(); | |||
687 | } | |||
688 | m_pView->nFocusWidth = -1; | |||
689 | KeyLeftRight( nDelta ); | |||
690 | } | |||
691 | } | |||
692 | ||||
693 | void SvImpLBox::KeyLeftRight( long nDelta ) | |||
694 | { | |||
695 | if( !(m_nFlags & LBoxFlags::InResize) ) | |||
696 | m_pView->PaintImmediately(); | |||
697 | m_nFlags &= ~LBoxFlags::Filling; | |||
698 | ShowCursor( false ); | |||
699 | ||||
700 | // calculate new origin | |||
701 | long nPos = m_aHorSBar->GetThumbPos(); | |||
702 | Point aOrigin( -nPos, 0 ); | |||
703 | ||||
704 | MapMode aMapMode( m_pView->GetMapMode() ); | |||
705 | aMapMode.SetOrigin( aOrigin ); | |||
706 | m_pView->SetMapMode( aMapMode ); | |||
707 | ||||
708 | if( !(m_nFlags & LBoxFlags::InResize) ) | |||
709 | { | |||
710 | tools::Rectangle aRect( GetVisibleArea() ); | |||
711 | m_pView->Scroll( -nDelta, 0, aRect, ScrollFlags::NoChildren ); | |||
712 | } | |||
713 | else | |||
714 | m_pView->Invalidate(); | |||
715 | RecalcFocusRect(); | |||
716 | ShowCursor( true ); | |||
717 | m_pView->NotifyScrolled(); | |||
718 | } | |||
719 | ||||
720 | ||||
721 | // returns the last entry if position is just past the last entry | |||
722 | SvTreeListEntry* SvImpLBox::GetClickedEntry( const Point& rPoint ) const | |||
723 | { | |||
724 | DBG_ASSERT( m_pView->GetModel(), "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" )do { if (true && (!(m_pView->GetModel()))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "724" ": "), "%s", "SvImpLBox::GetClickedEntry: how can this ever happen? Please tell me (frank.schoenheit@sun.com) how to reproduce!" ); } } while (false); | |||
725 | if ( !m_pView->GetModel() ) | |||
726 | // this is quite impossible. Nevertheless, stack traces from the crash reporter | |||
727 | // suggest it isn't. Okay, make it safe, and wait for somebody to reproduce it | |||
728 | // reliably :-\ ... | |||
729 | // #122359# / 2005-05-23 / frank.schoenheit@sun.com | |||
730 | return nullptr; | |||
731 | if( m_pView->GetEntryCount() == 0 || !m_pStartEntry || !m_pView->GetEntryHeight()) | |||
732 | return nullptr; | |||
733 | ||||
734 | sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_pView->GetEntryHeight() ); | |||
735 | sal_uInt16 nTemp = nClickedEntry; | |||
736 | SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp); | |||
737 | return pEntry; | |||
738 | } | |||
739 | ||||
740 | ||||
741 | // checks if the entry was hit "the right way" | |||
742 | // (Focusrect+ ContextBitmap at TreeListBox) | |||
743 | ||||
744 | bool SvImpLBox::EntryReallyHit(SvTreeListEntry* pEntry, const Point& rPosPixel, long nLine) | |||
745 | { | |||
746 | bool bRet; | |||
747 | // we are not too exact when it comes to "special" entries | |||
748 | // (with CheckButtons etc.) | |||
749 | if( pEntry->ItemCount() >= 3 ) | |||
750 | return true; | |||
751 | ||||
752 | tools::Rectangle aRect( m_pView->GetFocusRect( pEntry, nLine )); | |||
753 | aRect.SetRight( GetOutputSize().Width() - m_pView->GetMapMode().GetOrigin().X() ); | |||
754 | ||||
755 | SvLBoxContextBmp* pBmp = static_cast<SvLBoxContextBmp*>(pEntry->GetFirstItem(SvLBoxItemType::ContextBmp)); | |||
756 | aRect.AdjustLeft( -pBmp->GetWidth(m_pView,pEntry) ); | |||
757 | aRect.AdjustLeft( -4 ); // a little tolerance | |||
758 | ||||
759 | Point aPos( rPosPixel ); | |||
760 | aPos -= m_pView->GetMapMode().GetOrigin(); | |||
761 | bRet = aRect.IsInside( aPos ); | |||
762 | return bRet; | |||
763 | } | |||
764 | ||||
765 | ||||
766 | // returns 0 if position is just past the last entry | |||
767 | SvTreeListEntry* SvImpLBox::GetEntry( const Point& rPoint ) const | |||
768 | { | |||
769 | if( (m_pView->GetEntryCount() == 0) || !m_pStartEntry || | |||
770 | (rPoint.Y() > m_aOutputSize.Height()) | |||
771 | || !m_pView->GetEntryHeight()) | |||
772 | return nullptr; | |||
773 | ||||
774 | sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_pView->GetEntryHeight() ); | |||
775 | sal_uInt16 nTemp = nClickedEntry; | |||
776 | SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp); | |||
777 | if( nTemp != nClickedEntry ) | |||
778 | pEntry = nullptr; | |||
779 | return pEntry; | |||
780 | } | |||
781 | ||||
782 | ||||
783 | SvTreeListEntry* SvImpLBox::MakePointVisible(const Point& rPoint) | |||
784 | { | |||
785 | if( !m_pCursor ) | |||
786 | return nullptr; | |||
787 | long nY = rPoint.Y(); | |||
788 | SvTreeListEntry* pEntry = nullptr; | |||
789 | long nMax = m_aOutputSize.Height(); | |||
790 | if( nY < 0 || nY >= nMax ) // aOutputSize.Height() ) | |||
791 | { | |||
792 | if( nY < 0 ) | |||
793 | pEntry = m_pView->PrevVisible(m_pCursor); | |||
794 | else | |||
795 | pEntry = m_pView->NextVisible(m_pCursor); | |||
796 | ||||
797 | if( pEntry && pEntry != m_pCursor ) | |||
798 | m_pView->SetEntryFocus( m_pCursor, false ); | |||
799 | ||||
800 | if( nY < 0 ) | |||
801 | KeyUp( false ); | |||
802 | else | |||
803 | KeyDown( false ); | |||
804 | } | |||
805 | else | |||
806 | { | |||
807 | pEntry = GetClickedEntry( rPoint ); | |||
808 | if( !pEntry ) | |||
809 | { | |||
810 | sal_uInt16 nSteps = 0xFFFF; | |||
811 | // TODO: LastVisible is not yet implemented! | |||
812 | pEntry = m_pView->NextVisible(m_pStartEntry, nSteps); | |||
813 | } | |||
814 | if( pEntry ) | |||
815 | { | |||
816 | if( pEntry != m_pCursor && | |||
817 | m_aSelEng.GetSelectionMode() == SelectionMode::Single | |||
818 | ) | |||
819 | m_pView->Select( m_pCursor, false ); | |||
820 | } | |||
821 | } | |||
822 | return pEntry; | |||
823 | } | |||
824 | ||||
825 | tools::Rectangle SvImpLBox::GetClipRegionRect() const | |||
826 | { | |||
827 | Point aOrigin( m_pView->GetMapMode().GetOrigin() ); | |||
828 | aOrigin.setX( aOrigin.X() * -1 ); // conversion document coordinates | |||
829 | tools::Rectangle aClipRect( aOrigin, m_aOutputSize ); | |||
830 | aClipRect.AdjustBottom( 1 ); | |||
831 | return aClipRect; | |||
832 | } | |||
833 | ||||
834 | ||||
835 | void SvImpLBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) | |||
836 | { | |||
837 | if (!m_pView->GetVisibleCount()) | |||
838 | return; | |||
839 | ||||
840 | m_nFlags |= LBoxFlags::InPaint; | |||
841 | ||||
842 | if (m_nFlags & LBoxFlags::Filling) | |||
843 | { | |||
844 | SvTreeListEntry* pFirst = m_pView->First(); | |||
845 | if (pFirst != m_pStartEntry) | |||
846 | { | |||
847 | ShowCursor(false); | |||
848 | m_pStartEntry = m_pView->First(); | |||
849 | m_aVerSBar->SetThumbPos( 0 ); | |||
850 | StopUserEvent(); | |||
851 | ShowCursor(true); | |||
852 | m_nCurUserEvent = Application::PostUserEvent(LINK(this, SvImpLBox, MyUserEvent)::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox *>(this), &SvImpLBox::LinkStubMyUserEvent), | |||
853 | reinterpret_cast<void*>(1)); | |||
854 | return; | |||
855 | } | |||
856 | } | |||
857 | ||||
858 | if (!m_pStartEntry) | |||
859 | { | |||
860 | m_pStartEntry = m_pView->First(); | |||
861 | } | |||
862 | ||||
863 | if (m_nNodeBmpTabDistance == NODE_BMP_TABDIST_NOTVALID-2000000) | |||
864 | SetNodeBmpTabDistance(); | |||
865 | ||||
866 | long nRectHeight = rRect.GetHeight(); | |||
867 | long nEntryHeight = m_pView->GetEntryHeight(); | |||
868 | ||||
869 | // calculate area for the entries we want to draw | |||
870 | sal_uInt16 nStartLine = static_cast<sal_uInt16>(rRect.Top() / nEntryHeight); | |||
871 | sal_uInt16 nCount = static_cast<sal_uInt16>(nRectHeight / nEntryHeight); | |||
872 | nCount += 2; // don't miss a row | |||
873 | ||||
874 | long nY = nStartLine * nEntryHeight; | |||
875 | SvTreeListEntry* pEntry = m_pStartEntry; | |||
876 | while (nStartLine && pEntry) | |||
877 | { | |||
878 | pEntry = m_pView->NextVisible(pEntry); | |||
879 | nStartLine--; | |||
880 | } | |||
881 | ||||
882 | vcl::Region aClipRegion(GetClipRegionRect()); | |||
883 | ||||
884 | // first draw the lines, then clip them! | |||
885 | rRenderContext.SetClipRegion(); | |||
886 | if (m_nStyle & (WB_HASLINES | WB_HASLINESATROOT)) | |||
887 | DrawNet(rRenderContext); | |||
888 | ||||
889 | rRenderContext.SetClipRegion(aClipRegion); | |||
890 | ||||
891 | if (!m_pCursor && !mbNoAutoCurEntry) | |||
892 | { | |||
893 | // do not select if multiselection or explicit set | |||
894 | bool bNotSelect = (m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) || ((m_nStyle & WB_NOINITIALSELECTION) == WB_NOINITIALSELECTION); | |||
895 | SetCursor(m_pStartEntry, bNotSelect); | |||
896 | } | |||
897 | ||||
898 | for(sal_uInt16 n=0; n< nCount && pEntry; n++) | |||
899 | { | |||
900 | /*long nMaxRight=*/ | |||
901 | m_pView->PaintEntry1(*pEntry, nY, rRenderContext ); | |||
902 | nY += nEntryHeight; | |||
903 | pEntry = m_pView->NextVisible(pEntry); | |||
904 | } | |||
905 | ||||
906 | m_nFlags &= ~LBoxFlags::DeselectAll; | |||
907 | rRenderContext.SetClipRegion(); | |||
908 | m_nFlags &= ~LBoxFlags::InPaint; | |||
909 | } | |||
910 | ||||
911 | void SvImpLBox::MakeVisible( SvTreeListEntry* pEntry, bool bMoveToTop ) | |||
912 | { | |||
913 | if( !pEntry ) | |||
914 | return; | |||
915 | ||||
916 | bool bInView = IsEntryInView( pEntry ); | |||
917 | ||||
918 | if( bInView && (!bMoveToTop || m_pStartEntry == pEntry) ) | |||
919 | return; // is already visible | |||
920 | ||||
921 | if( m_pStartEntry || mbForceMakeVisible ) | |||
922 | m_nFlags &= ~LBoxFlags::Filling; | |||
923 | if( !bInView ) | |||
924 | { | |||
925 | if( !m_pView->IsEntryVisible(pEntry) ) // Parent(s) collapsed? | |||
926 | { | |||
927 | SvTreeListEntry* pParent = m_pView->GetParent( pEntry ); | |||
928 | while( pParent ) | |||
929 | { | |||
930 | if( !m_pView->IsExpanded( pParent ) ) | |||
931 | { | |||
932 | bool bRet = m_pView->Expand( pParent ); | |||
933 | DBG_ASSERT(bRet,"Not expanded!")do { if (true && (!(bRet))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "933" ": "), "%s", "Not expanded!"); } } while (false); | |||
934 | } | |||
935 | pParent = m_pView->GetParent( pParent ); | |||
936 | } | |||
937 | // do the parent's children fit into the view or do we have to scroll? | |||
938 | if( IsEntryInView( pEntry ) && !bMoveToTop ) | |||
939 | return; // no need to scroll | |||
940 | } | |||
941 | } | |||
942 | ||||
943 | m_pStartEntry = pEntry; | |||
944 | ShowCursor( false ); | |||
945 | FillView(); | |||
946 | m_aVerSBar->SetThumbPos( static_cast<long>(m_pView->GetVisiblePos( m_pStartEntry )) ); | |||
947 | ShowCursor( true ); | |||
948 | m_pView->Invalidate(); | |||
949 | } | |||
950 | ||||
951 | void SvImpLBox::ScrollToAbsPos( long nPos ) | |||
952 | { | |||
953 | if( m_pView->GetVisibleCount() == 0 ) | |||
954 | return; | |||
955 | long nLastEntryPos = m_pView->GetAbsPos( m_pView->Last() ); | |||
956 | ||||
957 | if( nPos < 0 ) | |||
958 | nPos = 0; | |||
959 | else if( nPos > nLastEntryPos ) | |||
960 | nPos = nLastEntryPos; | |||
961 | ||||
962 | SvTreeListEntry* pEntry = m_pView->GetEntryAtAbsPos( nPos ); | |||
963 | if( !pEntry || pEntry == m_pStartEntry ) | |||
964 | return; | |||
965 | ||||
966 | if( m_pStartEntry || mbForceMakeVisible ) | |||
967 | m_nFlags &= ~LBoxFlags::Filling; | |||
968 | ||||
969 | if( m_pView->IsEntryVisible(pEntry) ) | |||
970 | { | |||
971 | m_pStartEntry = pEntry; | |||
972 | ShowCursor( false ); | |||
973 | m_aVerSBar->SetThumbPos( nPos ); | |||
974 | ShowCursor( true ); | |||
975 | if (GetUpdateMode()) | |||
976 | m_pView->Invalidate(); | |||
977 | } | |||
978 | } | |||
979 | ||||
980 | void SvImpLBox::DrawNet(vcl::RenderContext& rRenderContext) | |||
981 | { | |||
982 | if (m_pView->GetVisibleCount() < 2 && !m_pStartEntry->HasChildrenOnDemand() && | |||
983 | !m_pStartEntry->HasChildren()) | |||
984 | { | |||
985 | return; | |||
986 | } | |||
987 | ||||
988 | // for platforms that don't have nets, DrawNativeControl does nothing and returns true | |||
989 | // so that SvImpLBox::DrawNet() doesn't draw anything either | |||
990 | if (rRenderContext.IsNativeControlSupported(ControlType::ListNet, ControlPart::Entire)) | |||
991 | { | |||
992 | ImplControlValue aControlValue; | |||
993 | if (rRenderContext.DrawNativeControl(ControlType::ListNet, ControlPart::Entire, | |||
994 | tools::Rectangle(), ControlState::ENABLED, aControlValue, OUString())) | |||
995 | { | |||
996 | return; | |||
997 | } | |||
998 | } | |||
999 | ||||
1000 | long nEntryHeight = m_pView->GetEntryHeight(); | |||
1001 | long nEntryHeightDIV2 = nEntryHeight / 2; | |||
1002 | if( nEntryHeightDIV2 && !(nEntryHeight & 0x0001)) | |||
1003 | nEntryHeightDIV2--; | |||
1004 | ||||
1005 | SvTreeListEntry* pChild; | |||
1006 | SvTreeListEntry* pEntry = m_pStartEntry; | |||
1007 | ||||
1008 | SvLBoxTab* pFirstDynamicTab = m_pView->GetFirstDynamicTab(); | |||
1009 | while (m_pTree->GetDepth( pEntry ) > 0) | |||
1010 | { | |||
1011 | pEntry = m_pView->GetParent(pEntry); | |||
1012 | } | |||
1013 | sal_uInt16 nOffs = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pStartEntry) - m_pView->GetVisiblePos(pEntry)); | |||
1014 | long nY = 0; | |||
1015 | nY -= (nOffs * nEntryHeight); | |||
1016 | ||||
1017 | DBG_ASSERT(pFirstDynamicTab,"No Tree!")do { if (true && (!(pFirstDynamicTab))) { sal_detail_logFormat ((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "1017" ": "), "%s", "No Tree!"); } } while (false); | |||
1018 | ||||
1019 | rRenderContext.Push(PushFlags::LINECOLOR); | |||
1020 | ||||
1021 | const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); | |||
1022 | Color aCol = rStyleSettings.GetFaceColor(); | |||
1023 | ||||
1024 | if (aCol.IsRGBEqual(rRenderContext.GetBackground().GetColor())) | |||
1025 | aCol = rStyleSettings.GetShadowColor(); | |||
1026 | rRenderContext.SetLineColor(aCol); | |||
1027 | Point aPos1, aPos2; | |||
1028 | sal_uInt16 nDistance; | |||
1029 | sal_uLong nMax = m_nVisibleCount + nOffs + 1; | |||
1030 | ||||
1031 | const Image& rExpandedNodeBitmap = GetExpandedNodeBmp(); | |||
1032 | ||||
1033 | for (sal_uLong n=0; n< nMax && pEntry; n++) | |||
1034 | { | |||
1035 | if (m_pView->IsExpanded(pEntry)) | |||
1036 | { | |||
1037 | aPos1.setX( m_pView->GetTabPos(pEntry, pFirstDynamicTab) ); | |||
1038 | // if it is not a context bitmap, go a little to the right below the | |||
1039 | // first text (node bitmap, too) | |||
1040 | if (!m_pView->nContextBmpWidthMax) | |||
1041 | aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 ); | |||
1042 | ||||
1043 | aPos1.setY( nY ); | |||
1044 | aPos1.AdjustY(nEntryHeightDIV2 ); | |||
1045 | ||||
1046 | pChild = m_pView->FirstChild( pEntry ); | |||
1047 | assert(pChild && "Child?")(static_cast <bool> (pChild && "Child?") ? void (0) : __assert_fail ("pChild && \"Child?\"", "/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" , 1047, __extension__ __PRETTY_FUNCTION__)); | |||
1048 | pChild = pChild->LastSibling(); | |||
1049 | nDistance = static_cast<sal_uInt16>(m_pView->GetVisiblePos(pChild) - m_pView->GetVisiblePos(pEntry)); | |||
1050 | aPos2 = aPos1; | |||
1051 | aPos2.AdjustY(nDistance * nEntryHeight ); | |||
1052 | rRenderContext.DrawLine(aPos1, aPos2); | |||
1053 | } | |||
1054 | // visible in control? | |||
1055 | if (n >= nOffs && ((m_nStyle & WB_HASLINESATROOT) || !m_pTree->IsAtRootDepth(pEntry))) | |||
1056 | { | |||
1057 | // can we recycle aPos1? | |||
1058 | if (!m_pView->IsExpanded(pEntry)) | |||
1059 | { | |||
1060 | // nope | |||
1061 | aPos1.setX( m_pView->GetTabPos(pEntry, pFirstDynamicTab) ); | |||
1062 | // if it is not a context bitmap, go a little to the right below | |||
1063 | // the first text (node bitmap, too) | |||
1064 | if (!m_pView->nContextBmpWidthMax) | |||
1065 | aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 ); | |||
1066 | aPos1.setY( nY ); | |||
1067 | aPos1.AdjustY(nEntryHeightDIV2 ); | |||
1068 | aPos2.setX( aPos1.X() ); | |||
1069 | } | |||
1070 | aPos2.setY( aPos1.Y() ); | |||
1071 | aPos2.AdjustX( -(m_pView->GetIndent()) ); | |||
1072 | rRenderContext.DrawLine(aPos1, aPos2); | |||
1073 | } | |||
1074 | nY += nEntryHeight; | |||
1075 | pEntry = m_pView->NextVisible(pEntry); | |||
1076 | } | |||
1077 | if (m_nStyle & WB_HASLINESATROOT) | |||
1078 | { | |||
1079 | pEntry = m_pView->First(); | |||
1080 | aPos1.setX( m_pView->GetTabPos(pEntry, pFirstDynamicTab) ); | |||
1081 | // if it is not a context bitmap, go a little to the right below the | |||
1082 | // first text (node bitmap, too) | |||
1083 | if (!m_pView->nContextBmpWidthMax) | |||
1084 | aPos1.AdjustX(rExpandedNodeBitmap.GetSizePixel().Width() / 2 ); | |||
1085 | aPos1.AdjustX( -(m_pView->GetIndent()) ); | |||
1086 | aPos1.setY( GetEntryLine( pEntry ) ); | |||
1087 | aPos1.AdjustY(nEntryHeightDIV2 ); | |||
1088 | pChild = pEntry->LastSibling(); | |||
1089 | aPos2.setX( aPos1.X() ); | |||
1090 | aPos2.setY( GetEntryLine( pChild ) ); | |||
1091 | aPos2.AdjustY(nEntryHeightDIV2 ); | |||
1092 | rRenderContext.DrawLine(aPos1, aPos2); | |||
1093 | } | |||
1094 | rRenderContext.Pop(); | |||
1095 | } | |||
1096 | ||||
1097 | void SvImpLBox::PositionScrollBars( Size& rSize, sal_uInt16 nMask ) | |||
1098 | { | |||
1099 | long nOverlap = 0; | |||
1100 | ||||
1101 | Size aVerSize( m_nVerSBarWidth, rSize.Height() ); | |||
1102 | Size aHorSize( rSize.Width(), m_nHorSBarHeight ); | |||
1103 | ||||
1104 | if( nMask & 0x0001 ) | |||
1105 | aHorSize.AdjustWidth( -m_nVerSBarWidth ); | |||
1106 | if( nMask & 0x0002 ) | |||
1107 | aVerSize.AdjustHeight( -m_nHorSBarHeight ); | |||
1108 | ||||
1109 | aVerSize.AdjustHeight(2 * nOverlap ); | |||
1110 | Point aVerPos( rSize.Width() - aVerSize.Width() + nOverlap, -nOverlap ); | |||
1111 | m_aVerSBar->SetPosSizePixel( aVerPos, aVerSize ); | |||
1112 | ||||
1113 | aHorSize.AdjustWidth(2 * nOverlap ); | |||
1114 | Point aHorPos( -nOverlap, rSize.Height() - aHorSize.Height() + nOverlap ); | |||
1115 | ||||
1116 | m_aHorSBar->SetPosSizePixel( aHorPos, aHorSize ); | |||
1117 | ||||
1118 | if( nMask & 0x0001 ) | |||
1119 | rSize.setWidth( aVerPos.X() ); | |||
1120 | if( nMask & 0x0002 ) | |||
1121 | rSize.setHeight( aHorPos.Y() ); | |||
1122 | ||||
1123 | if( (nMask & (0x0001|0x0002)) == (0x0001|0x0002) ) | |||
1124 | m_aScrBarBox->Show(); | |||
1125 | else | |||
1126 | m_aScrBarBox->Hide(); | |||
1127 | } | |||
1128 | ||||
1129 | void SvImpLBox::AdjustScrollBars( Size& rSize ) | |||
1130 | { | |||
1131 | long nEntryHeight = m_pView->GetEntryHeight(); | |||
1132 | if( !nEntryHeight ) | |||
1133 | return; | |||
1134 | ||||
1135 | sal_uInt16 nResult = 0; | |||
1136 | ||||
1137 | Size aOSize( m_pView->Control::GetOutputSizePixel() ); | |||
1138 | ||||
1139 | const WinBits nWindowStyle = m_pView->GetStyle(); | |||
1140 | bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0; | |||
1141 | bool bHorBar = false; | |||
1142 | long nMaxRight = aOSize.Width(); //GetOutputSize().Width(); | |||
1143 | Point aOrigin( m_pView->GetMapMode().GetOrigin() ); | |||
1144 | aOrigin.setX( aOrigin.X() * -1 ); | |||
1145 | nMaxRight += aOrigin.X() - 1; | |||
1146 | long nVis = m_nMostRight - aOrigin.X(); | |||
1147 | if( (nWindowStyle & (WB_AUTOHSCROLL|WB_HSCROLL)) && | |||
1148 | (nVis < m_nMostRight || nMaxRight < m_nMostRight) ) | |||
1149 | { | |||
1150 | bHorBar = true; | |||
1151 | } | |||
1152 | ||||
1153 | // number of entries that are not collapsed | |||
1154 | sal_uLong nTotalCount = m_pView->GetVisibleCount(); | |||
1155 | ||||
1156 | // number of entries visible within the view | |||
1157 | m_nVisibleCount = aOSize.Height() / nEntryHeight; | |||
1158 | ||||
1159 | // do we need a vertical scrollbar? | |||
1160 | if( bVerSBar || nTotalCount > m_nVisibleCount ) | |||
1161 | { | |||
1162 | nResult = 1; | |||
1163 | nMaxRight -= m_nVerSBarWidth; | |||
1164 | if( !bHorBar ) | |||
1165 | { | |||
1166 | if( (nWindowStyle & (WB_AUTOHSCROLL|WB_HSCROLL)) && | |||
1167 | (nVis < m_nMostRight || nMaxRight < m_nMostRight) ) | |||
1168 | bHorBar = true; | |||
1169 | } | |||
1170 | } | |||
1171 | ||||
1172 | // do we need a horizontal scrollbar? | |||
1173 | if( bHorBar ) | |||
1174 | { | |||
1175 | nResult |= 0x0002; | |||
1176 | // the number of entries visible within the view has to be recalculated | |||
1177 | // because the horizontal scrollbar is now visible. | |||
1178 | m_nVisibleCount = (aOSize.Height() - m_nHorSBarHeight) / nEntryHeight; | |||
1179 | // we might actually need a vertical scrollbar now | |||
1180 | if( !(nResult & 0x0001) && | |||
1181 | ((nTotalCount > m_nVisibleCount) || bVerSBar) ) | |||
1182 | { | |||
1183 | nResult = 3; | |||
1184 | } | |||
1185 | } | |||
1186 | ||||
1187 | PositionScrollBars( aOSize, nResult ); | |||
1188 | ||||
1189 | // adapt Range, VisibleRange etc. | |||
1190 | ||||
1191 | // refresh output size, in case we have to scroll | |||
1192 | tools::Rectangle aRect; | |||
1193 | aRect.SetSize( aOSize ); | |||
1194 | m_aSelEng.SetVisibleArea( aRect ); | |||
1195 | ||||
1196 | // vertical scrollbar | |||
1197 | long nTemp = static_cast<long>(m_nVisibleCount); | |||
1198 | nTemp--; | |||
1199 | if( nTemp != m_aVerSBar->GetVisibleSize() ) | |||
1200 | { | |||
1201 | if( !m_bInVScrollHdl ) | |||
1202 | { | |||
1203 | m_aVerSBar->SetPageSize( nTemp - 1 ); | |||
1204 | m_aVerSBar->SetVisibleSize( nTemp ); | |||
1205 | } | |||
1206 | else | |||
1207 | { | |||
1208 | m_nFlags |= LBoxFlags::EndScrollSetVisSize; | |||
1209 | m_nNextVerVisSize = nTemp; | |||
1210 | } | |||
1211 | } | |||
1212 | ||||
1213 | // horizontal scrollbar | |||
1214 | nTemp = m_aHorSBar->GetThumbPos(); | |||
1215 | m_aHorSBar->SetVisibleSize( aOSize.Width() ); | |||
1216 | long nNewThumbPos = m_aHorSBar->GetThumbPos(); | |||
1217 | Range aRange( m_aHorSBar->GetRange() ); | |||
1218 | if( aRange.Max() < m_nMostRight+25 ) | |||
1219 | { | |||
1220 | aRange.Max() = m_nMostRight+25; | |||
1221 | m_aHorSBar->SetRange( aRange ); | |||
1222 | } | |||
1223 | ||||
1224 | if( nTemp != nNewThumbPos ) | |||
1225 | { | |||
1226 | nTemp = nNewThumbPos - nTemp; | |||
1227 | if( m_pView->IsEditingActive() ) | |||
1228 | { | |||
1229 | m_pView->EndEditing( true ); // Cancel | |||
1230 | m_pView->PaintImmediately(); | |||
1231 | } | |||
1232 | m_pView->nFocusWidth = -1; | |||
1233 | KeyLeftRight( nTemp ); | |||
1234 | } | |||
1235 | ||||
1236 | if( nResult & 0x0001 ) | |||
1237 | m_aVerSBar->Show(); | |||
1238 | else | |||
1239 | m_aVerSBar->Hide(); | |||
1240 | ||||
1241 | if( nResult & 0x0002 ) | |||
1242 | m_aHorSBar->Show(); | |||
1243 | else | |||
1244 | { | |||
1245 | m_aHorSBar->Hide(); | |||
1246 | } | |||
1247 | rSize = aOSize; | |||
1248 | } | |||
1249 | ||||
1250 | void SvImpLBox::InitScrollBarBox() | |||
1251 | { | |||
1252 | m_aScrBarBox->SetSizePixel( Size(m_nVerSBarWidth, m_nHorSBarHeight) ); | |||
1253 | Size aSize( m_pView->Control::GetOutputSizePixel() ); | |||
1254 | m_aScrBarBox->SetPosPixel( Point(aSize.Width()-m_nVerSBarWidth, aSize.Height()-m_nHorSBarHeight)); | |||
1255 | } | |||
1256 | ||||
1257 | void SvImpLBox::Resize() | |||
1258 | { | |||
1259 | m_aOutputSize = m_pView->Control::GetOutputSizePixel(); | |||
1260 | if( m_aOutputSize.IsEmpty() ) | |||
1261 | return; | |||
1262 | m_nFlags |= LBoxFlags::InResize; | |||
1263 | InitScrollBarBox(); | |||
1264 | ||||
1265 | if( m_pView->GetEntryHeight()) | |||
1266 | { | |||
1267 | AdjustScrollBars( m_aOutputSize ); | |||
1268 | UpdateAll(false); | |||
1269 | } | |||
1270 | // HACK, as in floating and docked windows the scrollbars might not be drawn | |||
1271 | // correctly/not be drawn at all after resizing! | |||
1272 | if( m_aHorSBar->IsVisible()) | |||
1273 | m_aHorSBar->Invalidate(); | |||
1274 | if( m_aVerSBar->IsVisible()) | |||
1275 | m_aVerSBar->Invalidate(); | |||
1276 | m_nFlags &= ~LBoxFlags::InResize; | |||
1277 | } | |||
1278 | ||||
1279 | void SvImpLBox::FillView() | |||
1280 | { | |||
1281 | if( !m_pStartEntry ) | |||
1282 | { | |||
1283 | sal_uLong nVisibleViewCount = m_pView->GetVisibleCount(); | |||
1284 | long nTempThumb = m_aVerSBar->GetThumbPos(); | |||
1285 | if( nTempThumb < 0 ) | |||
1286 | nTempThumb = 0; | |||
1287 | else if( o3tl::make_unsigned(nTempThumb) >= nVisibleViewCount ) | |||
1288 | nTempThumb = nVisibleViewCount == 0 ? 0 : nVisibleViewCount - 1; | |||
1289 | m_pStartEntry = m_pView->GetEntryAtVisPos(nTempThumb); | |||
1290 | } | |||
1291 | if( !m_pStartEntry ) | |||
1292 | return; | |||
1293 | ||||
1294 | sal_uInt16 nLast = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pView->LastVisible())); | |||
1295 | sal_uInt16 nThumb = static_cast<sal_uInt16>(m_pView->GetVisiblePos( m_pStartEntry )); | |||
1296 | sal_uLong nCurDispEntries = nLast-nThumb+1; | |||
1297 | if( nCurDispEntries >= m_nVisibleCount ) | |||
1298 | return; | |||
1299 | ||||
1300 | ShowCursor( false ); | |||
1301 | // fill window by moving the thumb up incrementally | |||
1302 | bool bFound = false; | |||
1303 | SvTreeListEntry* pTemp = m_pStartEntry; | |||
1304 | while( nCurDispEntries < m_nVisibleCount && pTemp ) | |||
1305 | { | |||
1306 | pTemp = m_pView->PrevVisible(m_pStartEntry); | |||
1307 | if( pTemp ) | |||
1308 | { | |||
1309 | nThumb--; | |||
1310 | m_pStartEntry = pTemp; | |||
1311 | nCurDispEntries++; | |||
1312 | bFound = true; | |||
1313 | } | |||
1314 | } | |||
1315 | if( bFound ) | |||
1316 | { | |||
1317 | m_aVerSBar->SetThumbPos( nThumb ); | |||
1318 | ShowCursor( true ); // recalculate focus rectangle | |||
1319 | m_pView->Invalidate(); | |||
1320 | } | |||
1321 | } | |||
1322 | ||||
1323 | ||||
1324 | void SvImpLBox::ShowVerSBar() | |||
1325 | { | |||
1326 | bool bVerBar = ( m_pView->GetStyle() & WB_VSCROLL ) != 0; | |||
1327 | sal_uLong nVis = 0; | |||
1328 | if( !bVerBar ) | |||
1329 | nVis = m_pView->GetVisibleCount(); | |||
1330 | if( bVerBar || (m_nVisibleCount && nVis > static_cast<sal_uLong>(m_nVisibleCount-1)) ) | |||
1331 | { | |||
1332 | if( !m_aVerSBar->IsVisible() ) | |||
1333 | { | |||
1334 | m_pView->nFocusWidth = -1; | |||
1335 | AdjustScrollBars( m_aOutputSize ); | |||
1336 | if( GetUpdateMode() ) | |||
1337 | m_aVerSBar->Invalidate(); | |||
1338 | } | |||
1339 | } | |||
1340 | else | |||
1341 | { | |||
1342 | if( m_aVerSBar->IsVisible() ) | |||
1343 | { | |||
1344 | m_pView->nFocusWidth = -1; | |||
1345 | AdjustScrollBars( m_aOutputSize ); | |||
1346 | } | |||
1347 | } | |||
1348 | ||||
1349 | long nMaxRight = GetOutputSize().Width(); | |||
1350 | Point aPos( m_pView->GetMapMode().GetOrigin() ); | |||
1351 | aPos.setX( aPos.X() * -1 ); // convert document coordinates | |||
1352 | nMaxRight = nMaxRight + aPos.X() - 1; | |||
1353 | if( nMaxRight < m_nMostRight ) | |||
1354 | { | |||
1355 | if( !m_aHorSBar->IsVisible() ) | |||
1356 | { | |||
1357 | m_pView->nFocusWidth = -1; | |||
1358 | AdjustScrollBars( m_aOutputSize ); | |||
1359 | if( GetUpdateMode() ) | |||
1360 | m_aHorSBar->Invalidate(); | |||
1361 | } | |||
1362 | else | |||
1363 | { | |||
1364 | Range aRange( m_aHorSBar->GetRange() ); | |||
1365 | if( aRange.Max() < m_nMostRight+25 ) | |||
1366 | { | |||
1367 | aRange.Max() = m_nMostRight+25; | |||
1368 | m_aHorSBar->SetRange( aRange ); | |||
1369 | } | |||
1370 | else | |||
1371 | { | |||
1372 | m_pView->nFocusWidth = -1; | |||
1373 | AdjustScrollBars( m_aOutputSize ); | |||
1374 | } | |||
1375 | } | |||
1376 | } | |||
1377 | else | |||
1378 | { | |||
1379 | if( m_aHorSBar->IsVisible() ) | |||
1380 | { | |||
1381 | m_pView->nFocusWidth = -1; | |||
1382 | AdjustScrollBars( m_aOutputSize ); | |||
1383 | } | |||
1384 | } | |||
1385 | } | |||
1386 | ||||
1387 | ||||
1388 | void SvImpLBox::SyncVerThumb() | |||
1389 | { | |||
1390 | if( m_pStartEntry ) | |||
1391 | { | |||
1392 | long nEntryPos = m_pView->GetVisiblePos( m_pStartEntry ); | |||
1393 | m_aVerSBar->SetThumbPos( nEntryPos ); | |||
1394 | } | |||
1395 | else | |||
1396 | m_aVerSBar->SetThumbPos( 0 ); | |||
1397 | } | |||
1398 | ||||
1399 | bool SvImpLBox::IsEntryInView( SvTreeListEntry* pEntry ) const | |||
1400 | { | |||
1401 | // parent collapsed | |||
1402 | if( !m_pView->IsEntryVisible(pEntry) ) | |||
1403 | return false; | |||
1404 | long nY = GetEntryLine( pEntry ); | |||
1405 | if( nY < 0 ) | |||
1406 | return false; | |||
1407 | long nMax = m_nVisibleCount * m_pView->GetEntryHeight(); | |||
1408 | return nY < nMax; | |||
1409 | } | |||
1410 | ||||
1411 | ||||
1412 | long SvImpLBox::GetEntryLine(const SvTreeListEntry* pEntry) const | |||
1413 | { | |||
1414 | if(!m_pStartEntry ) | |||
1415 | return -1; // invisible position | |||
1416 | ||||
1417 | long nFirstVisPos = m_pView->GetVisiblePos( m_pStartEntry ); | |||
1418 | long nEntryVisPos = m_pView->GetVisiblePos( pEntry ); | |||
1419 | nFirstVisPos = nEntryVisPos - nFirstVisPos; | |||
1420 | nFirstVisPos *= m_pView->GetEntryHeight(); | |||
1421 | return nFirstVisPos; | |||
1422 | } | |||
1423 | ||||
1424 | void SvImpLBox::SetEntryHeight() | |||
1425 | { | |||
1426 | SetNodeBmpWidth( GetExpandedNodeBmp() ); | |||
1427 | SetNodeBmpWidth( GetCollapsedNodeBmp() ); | |||
1428 | if(!m_pView->HasViewData()) // are we within the Clear? | |||
1429 | { | |||
1430 | Size aSize = m_pView->Control::GetOutputSizePixel(); | |||
1431 | AdjustScrollBars( aSize ); | |||
1432 | } | |||
1433 | else | |||
1434 | { | |||
1435 | Resize(); | |||
1436 | if( GetUpdateMode() ) | |||
1437 | m_pView->Invalidate(); | |||
1438 | } | |||
1439 | } | |||
1440 | ||||
1441 | ||||
1442 | // *********************************************************************** | |||
1443 | // Callback Functions | |||
1444 | // *********************************************************************** | |||
1445 | ||||
1446 | void SvImpLBox::EntryExpanded( SvTreeListEntry* pEntry ) | |||
1447 | { | |||
1448 | // SelAllDestrAnch( false, true ); //DeselectAll(); | |||
1449 | if( !GetUpdateMode() ) | |||
1450 | return; | |||
1451 | ||||
1452 | ShowCursor( false ); | |||
1453 | long nY = GetEntryLine( pEntry ); | |||
1454 | if( IsLineVisible(nY) ) | |||
1455 | { | |||
1456 | InvalidateEntriesFrom( nY ); | |||
1457 | FindMostRight( pEntry ); | |||
1458 | } | |||
1459 | m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) ); | |||
1460 | // if we expanded before the thumb, the thumb's position has to be | |||
1461 | // corrected | |||
1462 | SyncVerThumb(); | |||
1463 | ShowVerSBar(); | |||
1464 | ShowCursor( true ); | |||
1465 | } | |||
1466 | ||||
1467 | void SvImpLBox::EntryCollapsed( SvTreeListEntry* pEntry ) | |||
1468 | { | |||
1469 | if( !m_pView->IsEntryVisible( pEntry ) ) | |||
1470 | return; | |||
1471 | ||||
1472 | ShowCursor( false ); | |||
1473 | ||||
1474 | if( !m_pMostRightEntry || m_pTree->IsChild( pEntry,m_pMostRightEntry ) ) | |||
1475 | { | |||
1476 | FindMostRight(); | |||
1477 | } | |||
1478 | ||||
1479 | if( m_pStartEntry ) | |||
1480 | { | |||
1481 | long nOldThumbPos = m_aVerSBar->GetThumbPos(); | |||
1482 | sal_uLong nVisList = m_pView->GetVisibleCount(); | |||
1483 | m_aVerSBar->SetRange( Range(0, nVisList-1) ); | |||
1484 | long nNewThumbPos = m_aVerSBar->GetThumbPos(); | |||
1485 | if( nNewThumbPos != nOldThumbPos ) | |||
1486 | { | |||
1487 | m_pStartEntry = m_pView->First(); | |||
1488 | sal_uInt16 nDistance = static_cast<sal_uInt16>(nNewThumbPos); | |||
1489 | if( nDistance ) | |||
1490 | m_pStartEntry = m_pView->NextVisible(m_pStartEntry, nDistance); | |||
1491 | if( GetUpdateMode() ) | |||
1492 | m_pView->Invalidate(); | |||
1493 | } | |||
1494 | else | |||
1495 | SyncVerThumb(); | |||
1496 | ShowVerSBar(); | |||
1497 | } | |||
1498 | // has the cursor been collapsed? | |||
1499 | if( m_pTree->IsChild( pEntry, m_pCursor ) ) | |||
1500 | SetCursor( pEntry ); | |||
1501 | if( GetUpdateMode() ) | |||
1502 | ShowVerSBar(); | |||
1503 | ShowCursor( true ); | |||
1504 | if( GetUpdateMode() && m_pCursor ) | |||
1505 | m_pView->Select( m_pCursor ); | |||
1506 | } | |||
1507 | ||||
1508 | void SvImpLBox::CollapsingEntry( SvTreeListEntry* pEntry ) | |||
1509 | { | |||
1510 | if( !m_pView->IsEntryVisible( pEntry ) || !m_pStartEntry ) | |||
1511 | return; | |||
1512 | ||||
1513 | SelAllDestrAnch( false ); // deselect all | |||
1514 | ||||
1515 | // is the collapsed cursor visible? | |||
1516 | long nY = GetEntryLine( pEntry ); | |||
1517 | if( IsLineVisible(nY) ) | |||
1518 | { | |||
1519 | if( GetUpdateMode() ) | |||
1520 | InvalidateEntriesFrom( nY ); | |||
1521 | } | |||
1522 | else | |||
1523 | { | |||
1524 | if( m_pTree->IsChild(pEntry, m_pStartEntry) ) | |||
1525 | { | |||
1526 | m_pStartEntry = pEntry; | |||
1527 | if( GetUpdateMode() ) | |||
1528 | m_pView->Invalidate(); | |||
1529 | } | |||
1530 | } | |||
1531 | } | |||
1532 | ||||
1533 | ||||
1534 | void SvImpLBox::SetNodeBmpWidth( const Image& rBmp ) | |||
1535 | { | |||
1536 | const Size aSize( rBmp.GetSizePixel() ); | |||
1537 | m_nNodeBmpWidth = aSize.Width(); | |||
1538 | } | |||
1539 | ||||
1540 | void SvImpLBox::SetNodeBmpTabDistance() | |||
1541 | { | |||
1542 | m_nNodeBmpTabDistance = -m_pView->GetIndent(); | |||
1543 | if( m_pView->nContextBmpWidthMax ) | |||
1544 | { | |||
1545 | // only if the first dynamic tab is centered (we currently assume that) | |||
1546 | Size aSize = GetExpandedNodeBmp().GetSizePixel(); | |||
1547 | m_nNodeBmpTabDistance -= aSize.Width() / 2; | |||
1548 | } | |||
1549 | } | |||
1550 | ||||
1551 | ||||
1552 | // corrects the cursor when using SingleSelection | |||
1553 | ||||
1554 | void SvImpLBox::EntrySelected( SvTreeListEntry* pEntry, bool bSelect ) | |||
1555 | { | |||
1556 | if( m_nFlags & LBoxFlags::IgnoreSelect ) | |||
1557 | return; | |||
1558 | ||||
1559 | m_nFlags &= ~LBoxFlags::DeselectAll; | |||
1560 | if( bSelect && | |||
1561 | m_aSelEng.GetSelectionMode() == SelectionMode::Single && | |||
1562 | pEntry != m_pCursor ) | |||
1563 | { | |||
1564 | SetCursor( pEntry ); | |||
1565 | DBG_ASSERT(m_pView->GetSelectionCount()==1,"selection count?")do { if (true && (!(m_pView->GetSelectionCount()== 1))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "1565" ": "), "%s", "selection count?"); } } while (false ); | |||
1566 | } | |||
1567 | ||||
1568 | if( GetUpdateMode() && m_pView->IsEntryVisible(pEntry) ) | |||
1569 | { | |||
1570 | long nY = GetEntryLine( pEntry ); | |||
1571 | if( IsLineVisible( nY ) ) | |||
1572 | { | |||
1573 | ShowCursor(false); | |||
1574 | InvalidateEntry(pEntry); | |||
1575 | ShowCursor(true); | |||
1576 | } | |||
1577 | } | |||
1578 | } | |||
1579 | ||||
1580 | ||||
1581 | void SvImpLBox::RemovingEntry( SvTreeListEntry* pEntry ) | |||
1582 | { | |||
1583 | CallEventListeners( VclEventId::ListboxItemRemoved , pEntry ); | |||
1584 | ||||
1585 | DestroyAnchor(); | |||
1586 | ||||
1587 | if( !m_pView->IsEntryVisible( pEntry ) ) | |||
1588 | { | |||
1589 | // if parent is collapsed => bye! | |||
1590 | m_nFlags |= LBoxFlags::RemovedEntryInvisible; | |||
1591 | return; | |||
1592 | } | |||
1593 | ||||
1594 | if( pEntry == m_pMostRightEntry || ( | |||
1595 | pEntry->HasChildren() && m_pView->IsExpanded(pEntry) && | |||
1596 | m_pTree->IsChild(pEntry, m_pMostRightEntry))) | |||
1597 | { | |||
1598 | m_nFlags |= LBoxFlags::RemovedRecalcMostRight; | |||
1599 | } | |||
1600 | ||||
1601 | SvTreeListEntry* pOldStartEntry = m_pStartEntry; | |||
1602 | ||||
1603 | SvTreeListEntry* pParent = m_pView->GetModel()->GetParent(pEntry); | |||
1604 | ||||
1605 | if (pParent && m_pView->GetModel()->GetChildList(pParent).size() == 1) | |||
1606 | { | |||
1607 | DBG_ASSERT( m_pView->IsExpanded( pParent ), "Parent not expanded")do { if (true && (!(m_pView->IsExpanded( pParent ) ))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.tools" ), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "1607" ": "), "%s", "Parent not expanded"); } } while (false ); | |||
1608 | pParent->SetFlags( pParent->GetFlags() | SvTLEntryFlags::NO_NODEBMP); | |||
1609 | InvalidateEntry( pParent ); | |||
1610 | } | |||
1611 | ||||
1612 | if( m_pCursor && m_pTree->IsChild( pEntry, m_pCursor) ) | |||
1613 | m_pCursor = pEntry; | |||
1614 | if( m_pStartEntry && m_pTree->IsChild(pEntry,m_pStartEntry) ) | |||
1615 | m_pStartEntry = pEntry; | |||
1616 | ||||
1617 | SvTreeListEntry* pTemp; | |||
1618 | if( m_pCursor && m_pCursor == pEntry ) | |||
1619 | { | |||
1620 | if( m_bSimpleTravel ) | |||
1621 | m_pView->Select( m_pCursor, false ); | |||
1622 | ShowCursor( false ); // focus rectangle gone | |||
1623 | // NextSibling, because we also delete the children of the cursor | |||
1624 | pTemp = m_pCursor->NextSibling(); | |||
1625 | if( !pTemp ) | |||
1626 | pTemp = m_pView->PrevVisible(m_pCursor); | |||
1627 | ||||
1628 | SetCursor( pTemp, true ); | |||
1629 | } | |||
1630 | if( m_pStartEntry && m_pStartEntry == pEntry ) | |||
1631 | { | |||
1632 | pTemp = m_pStartEntry->NextSibling(); | |||
1633 | if( !pTemp ) | |||
1634 | pTemp = m_pView->PrevVisible(m_pStartEntry); | |||
1635 | m_pStartEntry = pTemp; | |||
1636 | } | |||
1637 | if( GetUpdateMode()) | |||
1638 | { | |||
1639 | // if it is the last one, we have to invalidate it, so the lines are | |||
1640 | // drawn correctly (in this case they're deleted) | |||
1641 | if( m_pStartEntry && (m_pStartEntry != pOldStartEntry || pEntry == m_pView->GetModel()->Last()) ) | |||
1642 | { | |||
1643 | m_aVerSBar->SetThumbPos( m_pView->GetVisiblePos( m_pStartEntry )); | |||
1644 | m_pView->Invalidate( GetVisibleArea() ); | |||
1645 | } | |||
1646 | else | |||
1647 | InvalidateEntriesFrom( GetEntryLine( pEntry ) ); | |||
1648 | } | |||
1649 | } | |||
1650 | ||||
1651 | void SvImpLBox::EntryRemoved() | |||
1652 | { | |||
1653 | if( m_nFlags & LBoxFlags::RemovedEntryInvisible ) | |||
1654 | { | |||
1655 | m_nFlags &= ~LBoxFlags::RemovedEntryInvisible; | |||
1656 | return; | |||
1657 | } | |||
1658 | if( !m_pStartEntry ) | |||
1659 | m_pStartEntry = m_pTree->First(); | |||
1660 | if( !m_pCursor ) | |||
1661 | SetCursor( m_pStartEntry, true ); | |||
1662 | ||||
1663 | if( m_pCursor && (m_bSimpleTravel || !m_pView->GetSelectionCount() )) | |||
1664 | m_pView->Select( m_pCursor ); | |||
1665 | ||||
1666 | if( GetUpdateMode()) | |||
1667 | { | |||
1668 | if( m_nFlags & LBoxFlags::RemovedRecalcMostRight ) | |||
1669 | FindMostRight(); | |||
1670 | m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1 ) ); | |||
1671 | FillView(); | |||
1672 | if( m_pStartEntry ) | |||
1673 | // if something above the thumb was deleted | |||
1674 | m_aVerSBar->SetThumbPos( m_pView->GetVisiblePos( m_pStartEntry) ); | |||
1675 | ||||
1676 | ShowVerSBar(); | |||
1677 | if( m_pCursor && m_pView->HasFocus() && !m_pView->IsSelected(m_pCursor) ) | |||
1678 | { | |||
1679 | if( m_pView->GetSelectionCount() ) | |||
1680 | { | |||
1681 | // is a neighboring entry selected? | |||
1682 | SvTreeListEntry* pNextCursor = m_pView->PrevVisible( m_pCursor ); | |||
1683 | if( !pNextCursor || !m_pView->IsSelected( pNextCursor )) | |||
1684 | pNextCursor = m_pView->NextVisible( m_pCursor ); | |||
1685 | if( !pNextCursor || !m_pView->IsSelected( pNextCursor )) | |||
1686 | // no neighbor selected: use first selected | |||
1687 | pNextCursor = m_pView->FirstSelected(); | |||
1688 | SetCursor( pNextCursor ); | |||
1689 | MakeVisible( m_pCursor ); | |||
1690 | } | |||
1691 | else | |||
1692 | m_pView->Select( m_pCursor ); | |||
1693 | } | |||
1694 | ShowCursor( true ); | |||
1695 | } | |||
1696 | m_nFlags &= ~LBoxFlags::RemovedRecalcMostRight; | |||
1697 | } | |||
1698 | ||||
1699 | ||||
1700 | void SvImpLBox::MovingEntry( SvTreeListEntry* pEntry ) | |||
1701 | { | |||
1702 | bool bDeselAll(m_nFlags & LBoxFlags::DeselectAll); | |||
1703 | SelAllDestrAnch( false ); // DeselectAll(); | |||
1704 | if( !bDeselAll
| |||
| ||||
1705 | m_nFlags &= ~LBoxFlags::DeselectAll; | |||
1706 | ||||
1707 | if( pEntry == m_pCursor ) | |||
1708 | ShowCursor( false ); | |||
1709 | if( IsEntryInView( pEntry ) ) | |||
1710 | m_pView->Invalidate(); | |||
1711 | if( pEntry != m_pStartEntry ) | |||
1712 | return; | |||
1713 | ||||
1714 | SvTreeListEntry* pNew = nullptr; | |||
1715 | if( !pEntry->HasChildren() ) | |||
| ||||
1716 | { | |||
1717 | pNew = m_pView->NextVisible(m_pStartEntry); | |||
1718 | if( !pNew ) | |||
1719 | pNew = m_pView->PrevVisible(m_pStartEntry); | |||
1720 | } | |||
1721 | else | |||
1722 | { | |||
1723 | pNew = pEntry->NextSibling(); | |||
1724 | if( !pNew ) | |||
1725 | pNew = pEntry->PrevSibling(); | |||
1726 | } | |||
1727 | m_pStartEntry = pNew; | |||
1728 | } | |||
1729 | ||||
1730 | void SvImpLBox::EntryMoved( SvTreeListEntry* pEntry ) | |||
1731 | { | |||
1732 | UpdateContextBmpWidthVectorFromMovedEntry( pEntry ); | |||
1733 | ||||
1734 | if ( !m_pStartEntry ) | |||
1735 | // this might happen if the only entry in the view is moved to its very same position | |||
1736 | // #i97346# | |||
1737 | m_pStartEntry = m_pView->First(); | |||
1738 | ||||
1739 | m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1)); | |||
1740 | sal_uInt16 nFirstPos = static_cast<sal_uInt16>(m_pTree->GetAbsPos( m_pStartEntry )); | |||
1741 | sal_uInt16 nNewPos = static_cast<sal_uInt16>(m_pTree->GetAbsPos( pEntry )); | |||
1742 | FindMostRight(); | |||
1743 | if( nNewPos < nFirstPos ) // HACK! | |||
1744 | m_pStartEntry = pEntry; | |||
1745 | SyncVerThumb(); | |||
1746 | if( pEntry == m_pCursor ) | |||
1747 | { | |||
1748 | if( m_pView->IsEntryVisible( m_pCursor ) ) | |||
1749 | ShowCursor( true ); | |||
1750 | else | |||
1751 | { | |||
1752 | SvTreeListEntry* pParent = pEntry; | |||
1753 | do { | |||
1754 | pParent = m_pTree->GetParent( pParent ); | |||
1755 | } | |||
1756 | while( !m_pView->IsEntryVisible( pParent ) ); | |||
1757 | SetCursor( pParent ); | |||
1758 | } | |||
1759 | } | |||
1760 | if( IsEntryInView( pEntry ) ) | |||
1761 | m_pView->Invalidate(); | |||
1762 | } | |||
1763 | ||||
1764 | ||||
1765 | void SvImpLBox::EntryInserted( SvTreeListEntry* pEntry ) | |||
1766 | { | |||
1767 | if( !GetUpdateMode() ) | |||
1768 | return; | |||
1769 | ||||
1770 | SvTreeListEntry* pParent = m_pTree->GetParent(pEntry); | |||
1771 | if (pParent && m_pTree->GetChildList(pParent).size() == 1) | |||
1772 | // draw plus sign | |||
1773 | m_pTree->InvalidateEntry( pParent ); | |||
1774 | ||||
1775 | if( !m_pView->IsEntryVisible( pEntry ) ) | |||
1776 | return; | |||
1777 | bool bDeselAll(m_nFlags & LBoxFlags::DeselectAll); | |||
1778 | if( bDeselAll ) | |||
1779 | SelAllDestrAnch( false ); | |||
1780 | else | |||
1781 | DestroyAnchor(); | |||
1782 | // nFlags &= (~LBoxFlags::DeselectAll); | |||
1783 | // ShowCursor( false ); // if cursor is moved lower | |||
1784 | long nY = GetEntryLine( pEntry ); | |||
1785 | bool bEntryVisible = IsLineVisible( nY ); | |||
1786 | if( bEntryVisible ) | |||
1787 | { | |||
1788 | ShowCursor( false ); // if cursor is moved lower | |||
1789 | nY -= m_pView->GetEntryHeight(); // because of lines | |||
1790 | InvalidateEntriesFrom( nY ); | |||
1791 | } | |||
1792 | else if( m_pStartEntry && nY < GetEntryLine(m_pStartEntry) ) | |||
1793 | { | |||
1794 | // Check if the view is filled completely. If not, then adjust | |||
1795 | // pStartEntry and the Cursor (automatic scrolling). | |||
1796 | sal_uInt16 nLast = static_cast<sal_uInt16>(m_pView->GetVisiblePos(m_pView->LastVisible())); | |||
1797 | sal_uInt16 nThumb = static_cast<sal_uInt16>(m_pView->GetVisiblePos( m_pStartEntry )); | |||
1798 | sal_uInt16 nCurDispEntries = nLast-nThumb+1; | |||
1799 | if( nCurDispEntries < m_nVisibleCount ) | |||
1800 | { | |||
1801 | // set at the next paint event | |||
1802 | m_pStartEntry = nullptr; | |||
1803 | SetCursor( nullptr ); | |||
1804 | m_pView->Invalidate(); | |||
1805 | } | |||
1806 | } | |||
1807 | else if( !m_pStartEntry ) | |||
1808 | m_pView->Invalidate(); | |||
1809 | ||||
1810 | SetMostRight( pEntry ); | |||
1811 | m_aVerSBar->SetRange( Range(0, m_pView->GetVisibleCount()-1)); | |||
1812 | SyncVerThumb(); // if something was inserted before the thumb | |||
1813 | ShowVerSBar(); | |||
1814 | ShowCursor( true ); | |||
1815 | if( m_pStartEntry != m_pView->First() && (m_nFlags & LBoxFlags::Filling) ) | |||
1816 | m_pView->PaintImmediately(); | |||
1817 | } | |||
1818 | ||||
1819 | ||||
1820 | // ******************************************************************** | |||
1821 | // Event handler | |||
1822 | // ******************************************************************** | |||
1823 | ||||
1824 | ||||
1825 | // ****** Control the control animation | |||
1826 | ||||
1827 | bool SvImpLBox::ButtonDownCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry* pEntry) | |||
1828 | { | |||
1829 | SvLBoxItem* pItem = m_pView->GetItem(pEntry,rMEvt.GetPosPixel().X(),&m_pActiveTab); | |||
1830 | if (pItem && pItem->GetType() == SvLBoxItemType::Button) | |||
1831 | { | |||
1832 | m_pActiveButton = static_cast<SvLBoxButton*>(pItem); | |||
1833 | m_pActiveEntry = pEntry; | |||
1834 | if( m_pCursor == m_pActiveEntry ) | |||
1835 | m_pView->HideFocus(); | |||
1836 | m_pView->CaptureMouse(); | |||
1837 | m_pActiveButton->SetStateHilighted( true ); | |||
1838 | InvalidateEntry(m_pActiveEntry); | |||
1839 | return true; | |||
1840 | } | |||
1841 | else | |||
1842 | m_pActiveButton = nullptr; | |||
1843 | return false; | |||
1844 | } | |||
1845 | ||||
1846 | bool SvImpLBox::MouseMoveCheckCtrl(const MouseEvent& rMEvt, SvTreeListEntry const * pEntry) | |||
1847 | { | |||
1848 | if( m_pActiveButton ) | |||
1849 | { | |||
1850 | long nMouseX = rMEvt.GetPosPixel().X(); | |||
1851 | if( pEntry == m_pActiveEntry && | |||
1852 | m_pView->GetItem(m_pActiveEntry, nMouseX) == m_pActiveButton ) | |||
1853 | { | |||
1854 | if( !m_pActiveButton->IsStateHilighted() ) | |||
1855 | { | |||
1856 | m_pActiveButton->SetStateHilighted(true ); | |||
1857 | InvalidateEntry(m_pActiveEntry); | |||
1858 | } | |||
1859 | } | |||
1860 | else | |||
1861 | { | |||
1862 | if( m_pActiveButton->IsStateHilighted() ) | |||
1863 | { | |||
1864 | m_pActiveButton->SetStateHilighted(false ); | |||
1865 | InvalidateEntry(m_pActiveEntry); | |||
1866 | } | |||
1867 | } | |||
1868 | return true; | |||
1869 | } | |||
1870 | return false; | |||
1871 | } | |||
1872 | ||||
1873 | bool SvImpLBox::ButtonUpCheckCtrl( const MouseEvent& rMEvt ) | |||
1874 | { | |||
1875 | if( m_pActiveButton ) | |||
1876 | { | |||
1877 | m_pView->ReleaseMouse(); | |||
1878 | SvTreeListEntry* pEntry = GetClickedEntry( rMEvt.GetPosPixel() ); | |||
1879 | m_pActiveButton->SetStateHilighted( false ); | |||
1880 | long nMouseX = rMEvt.GetPosPixel().X(); | |||
1881 | if (pEntry == m_pActiveEntry && m_pView->GetItem(m_pActiveEntry, nMouseX) == m_pActiveButton) | |||
1882 | m_pActiveButton->ClickHdl(m_pActiveEntry); | |||
1883 | InvalidateEntry(m_pActiveEntry); | |||
1884 | if (m_pCursor == m_pActiveEntry) | |||
1885 | ShowCursor(true); | |||
1886 | m_pActiveButton = nullptr; | |||
1887 | m_pActiveEntry = nullptr; | |||
1888 | m_pActiveTab = nullptr; | |||
1889 | return true; | |||
1890 | } | |||
1891 | return false; | |||
1892 | } | |||
1893 | ||||
1894 | // ******* Control plus/minus button for expanding/collapsing | |||
1895 | ||||
1896 | // false == no expand/collapse button hit | |||
1897 | bool SvImpLBox::IsNodeButton( const Point& rPosPixel, const SvTreeListEntry* pEntry ) const | |||
1898 | { | |||
1899 | if( !pEntry->HasChildren() && !pEntry->HasChildrenOnDemand() ) | |||
1900 | return false; | |||
1901 | ||||
1902 | SvLBoxTab* pFirstDynamicTab = m_pView->GetFirstDynamicTab(); | |||
1903 | if( !pFirstDynamicTab ) | |||
1904 | return false; | |||
1905 | ||||
1906 | long nMouseX = rPosPixel.X(); | |||
1907 | // convert to document coordinates | |||
1908 | Point aOrigin( m_pView->GetMapMode().GetOrigin() ); | |||
1909 | nMouseX -= aOrigin.X(); | |||
1910 | ||||
1911 | long nX = m_pView->GetTabPos( pEntry, pFirstDynamicTab); | |||
1912 | nX += m_nNodeBmpTabDistance; | |||
1913 | if( nMouseX < nX ) | |||
1914 | return false; | |||
1915 | nX += m_nNodeBmpWidth; | |||
1916 | return nMouseX <= nX; | |||
1917 | } | |||
1918 | ||||
1919 | // false == hit no node button | |||
1920 | bool SvImpLBox::ButtonDownCheckExpand( const MouseEvent& rMEvt, SvTreeListEntry* pEntry ) | |||
1921 | { | |||
1922 | bool bRet = false; | |||
1923 | ||||
1924 | if ( m_pView->IsEditingActive() && pEntry == m_pView->pEdEntry ) | |||
1925 | // inplace editing -> nothing to do | |||
1926 | bRet = true; | |||
1927 | else if ( IsNodeButton( rMEvt.GetPosPixel(), pEntry ) ) | |||
1928 | { | |||
1929 | if ( m_pView->IsExpanded( pEntry ) ) | |||
1930 | { | |||
1931 | m_pView->EndEditing( true ); | |||
1932 | m_pView->Collapse( pEntry ); | |||
1933 | } | |||
1934 | else | |||
1935 | { | |||
1936 | // you can expand an entry, which is in editing | |||
1937 | m_pView->Expand( pEntry ); | |||
1938 | } | |||
1939 | bRet = true; | |||
1940 | } | |||
1941 | ||||
1942 | return bRet; | |||
1943 | } | |||
1944 | ||||
1945 | void SvImpLBox::MouseButtonDown( const MouseEvent& rMEvt ) | |||
1946 | { | |||
1947 | if ( !rMEvt.IsLeft() && !rMEvt.IsRight()) | |||
1948 | return; | |||
1949 | ||||
1950 | m_aEditIdle.Stop(); | |||
1951 | Point aPos( rMEvt.GetPosPixel()); | |||
1952 | ||||
1953 | if( aPos.X() > m_aOutputSize.Width() || aPos.Y() > m_aOutputSize.Height() ) | |||
1954 | return; | |||
1955 | ||||
1956 | if( !m_pCursor ) | |||
1957 | m_pCursor = m_pStartEntry; | |||
1958 | m_nFlags &= ~LBoxFlags::Filling; | |||
1959 | m_pView->GrabFocus(); | |||
1960 | //fdo#82270 Grabbing focus can invalidate the entries, re-fetch | |||
1961 | SvTreeListEntry* pEntry = GetEntry(aPos); | |||
1962 | // the entry can still be invalid! | |||
1963 | if( !pEntry || !m_pView->GetViewData( pEntry )) | |||
1964 | return; | |||
1965 | ||||
1966 | long nY = GetEntryLine( pEntry ); | |||
1967 | // Node-Button? | |||
1968 | if( ButtonDownCheckExpand( rMEvt, pEntry ) ) | |||
1969 | return; | |||
1970 | ||||
1971 | if( !EntryReallyHit(pEntry,aPos,nY)) | |||
1972 | return; | |||
1973 | ||||
1974 | SvLBoxItem* pXItem = m_pView->GetItem( pEntry, aPos.X() ); | |||
1975 | if( pXItem ) | |||
1976 | { | |||
1977 | SvLBoxTab* pXTab = m_pView->GetTab( pEntry, pXItem ); | |||
1978 | if ( !rMEvt.IsMod1() && !rMEvt.IsMod2() && rMEvt.IsLeft() && pXTab->IsEditable() | |||
1979 | && pEntry == m_pView->FirstSelected() && nullptr == m_pView->NextSelected( pEntry ) ) | |||
1980 | // #i8234# FirstSelected() and NextSelected() ensures, that inplace editing is only triggered, when only one entry is selected | |||
1981 | m_nFlags |= LBoxFlags::StartEditTimer; | |||
1982 | if ( !m_pView->IsSelected( pEntry ) ) | |||
1983 | m_nFlags &= ~LBoxFlags::StartEditTimer; | |||
1984 | } | |||
1985 | ||||
1986 | ||||
1987 | if( (rMEvt.GetClicks() % 2) == 0) | |||
1988 | { | |||
1989 | m_nFlags &= ~LBoxFlags::StartEditTimer; | |||
1990 | m_pView->pHdlEntry = pEntry; | |||
1991 | if( !m_pView->DoubleClickHdl() ) | |||
1992 | { | |||
1993 | // Handler signals nothing to be done anymore, bail out, 'this' may | |||
1994 | // even be dead and destroyed. | |||
1995 | return; | |||
1996 | } | |||
1997 | else | |||
1998 | { | |||
1999 | // if the entry was deleted within the handler | |||
2000 | pEntry = GetClickedEntry( aPos ); | |||
2001 | if( !pEntry ) | |||
2002 | return; | |||
2003 | if( pEntry != m_pView->pHdlEntry ) | |||
2004 | { | |||
2005 | // select anew & bye | |||
2006 | if( !m_bSimpleTravel && !m_aSelEng.IsAlwaysAdding()) | |||
2007 | SelAllDestrAnch( false ); // DeselectAll(); | |||
2008 | SetCursor( pEntry ); | |||
2009 | ||||
2010 | return; | |||
2011 | } | |||
2012 | if( pEntry->HasChildren() || pEntry->HasChildrenOnDemand() ) | |||
2013 | { | |||
2014 | if( m_pView->IsExpanded(pEntry) ) | |||
2015 | m_pView->Collapse( pEntry ); | |||
2016 | else | |||
2017 | m_pView->Expand( pEntry ); | |||
2018 | if( pEntry == m_pCursor ) // only if Entryitem was clicked | |||
2019 | // (Nodebutton is not an Entryitem!) | |||
2020 | m_pView->Select( m_pCursor ); | |||
2021 | return; | |||
2022 | } | |||
2023 | } | |||
2024 | } | |||
2025 | else | |||
2026 | { | |||
2027 | // CheckButton? (TreeListBox: Check + Info) | |||
2028 | if( ButtonDownCheckCtrl(rMEvt, pEntry) ) | |||
2029 | return; | |||
2030 | // Inplace-Editing? | |||
2031 | } | |||
2032 | if ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE | |||
2033 | && !rMEvt.IsRight() ) // tdf#128824 | |||
2034 | m_aSelEng.SelMouseButtonDown( rMEvt ); | |||
2035 | } | |||
2036 | ||||
2037 | void SvImpLBox::MouseButtonUp( const MouseEvent& rMEvt) | |||
2038 | { | |||
2039 | if ( !ButtonUpCheckCtrl( rMEvt ) && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) ) | |||
2040 | m_aSelEng.SelMouseButtonUp( rMEvt ); | |||
2041 | if( m_nFlags & LBoxFlags::StartEditTimer ) | |||
2042 | { | |||
2043 | m_nFlags &= ~LBoxFlags::StartEditTimer; | |||
2044 | m_aEditClickPos = rMEvt.GetPosPixel(); | |||
2045 | m_aEditIdle.Start(); | |||
2046 | } | |||
2047 | ||||
2048 | if (m_pView->mbActivateOnSingleClick) | |||
2049 | m_pView->DoubleClickHdl(); | |||
2050 | } | |||
2051 | ||||
2052 | void SvImpLBox::MouseMove( const MouseEvent& rMEvt) | |||
2053 | { | |||
2054 | Point aPos = rMEvt.GetPosPixel(); | |||
2055 | SvTreeListEntry* pEntry = GetClickedEntry(aPos); | |||
2056 | if ( !MouseMoveCheckCtrl( rMEvt, pEntry ) && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) ) | |||
2057 | { | |||
2058 | m_aSelEng.SelMouseMove(rMEvt); | |||
2059 | if (m_pView->mbHoverSelection) | |||
2060 | { | |||
2061 | if (aPos.X() < 0 || aPos.Y() < 0 || aPos.X() > m_aOutputSize.Width() || aPos.Y() > m_aOutputSize.Height()) | |||
2062 | pEntry = nullptr; | |||
2063 | else | |||
2064 | pEntry = GetEntry(aPos); | |||
2065 | if (!pEntry) | |||
2066 | m_pView->SelectAll(false); | |||
2067 | else if (!m_pView->IsSelected(pEntry) && IsSelectable(pEntry)) | |||
2068 | m_pView->Select(pEntry); | |||
2069 | } | |||
2070 | } | |||
2071 | } | |||
2072 | ||||
2073 | void SvImpLBox::ExpandAll() | |||
2074 | { | |||
2075 | sal_uInt16 nRefDepth = m_pTree->GetDepth(m_pCursor); | |||
2076 | SvTreeListEntry* pCur = m_pTree->Next(m_pCursor); | |||
2077 | while (pCur && m_pTree->GetDepth(pCur) > nRefDepth) | |||
2078 | { | |||
2079 | if (pCur->HasChildren() && !m_pView->IsExpanded(pCur)) | |||
2080 | m_pView->Expand(pCur); | |||
2081 | pCur = m_pTree->Next(pCur); | |||
2082 | } | |||
2083 | } | |||
2084 | ||||
2085 | void SvImpLBox::CollapseTo(SvTreeListEntry* pParentToCollapse) | |||
2086 | { | |||
2087 | // collapse all parents until we get to the given parent to collapse | |||
2088 | if (!pParentToCollapse) | |||
2089 | return; | |||
2090 | ||||
2091 | sal_uInt16 nRefDepth; | |||
2092 | // special case explorer: if the root only has a single | |||
2093 | // entry, don't collapse the root entry | |||
2094 | if (m_pTree->GetChildList(nullptr).size() < 2) | |||
2095 | { | |||
2096 | nRefDepth = 1; | |||
2097 | pParentToCollapse = m_pCursor; | |||
2098 | while (m_pTree->GetParent(pParentToCollapse) | |||
2099 | && m_pTree->GetDepth(m_pTree->GetParent(pParentToCollapse)) > 0) | |||
2100 | { | |||
2101 | pParentToCollapse = m_pTree->GetParent(pParentToCollapse); | |||
2102 | } | |||
2103 | } | |||
2104 | else | |||
2105 | nRefDepth = m_pTree->GetDepth(pParentToCollapse); | |||
2106 | ||||
2107 | if (m_pView->IsExpanded(pParentToCollapse)) | |||
2108 | m_pView->Collapse(pParentToCollapse); | |||
2109 | SvTreeListEntry* pCur = m_pTree->Next(pParentToCollapse); | |||
2110 | while (pCur && m_pTree->GetDepth(pCur) > nRefDepth) | |||
2111 | { | |||
2112 | if (pCur->HasChildren() && m_pView->IsExpanded(pCur)) | |||
2113 | m_pView->Collapse(pCur); | |||
2114 | pCur = m_pTree->Next(pCur); | |||
2115 | } | |||
2116 | } | |||
2117 | ||||
2118 | bool SvImpLBox::KeyInput( const KeyEvent& rKEvt) | |||
2119 | { | |||
2120 | m_aEditIdle.Stop(); | |||
2121 | const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); | |||
2122 | ||||
2123 | if( rKeyCode.IsMod2() ) | |||
2124 | return false; // don't evaluate Alt key | |||
2125 | ||||
2126 | m_nFlags &= ~LBoxFlags::Filling; | |||
2127 | ||||
2128 | if( !m_pCursor ) | |||
2129 | m_pCursor = m_pStartEntry; | |||
2130 | if( !m_pCursor ) | |||
2131 | return false; | |||
2132 | ||||
2133 | bool bKeyUsed = true; | |||
2134 | ||||
2135 | sal_uInt16 nDelta = static_cast<sal_uInt16>(m_aVerSBar->GetPageSize()); | |||
2136 | sal_uInt16 aCode = rKeyCode.GetCode(); | |||
2137 | ||||
2138 | bool bShift = rKeyCode.IsShift(); | |||
2139 | bool bMod1 = rKeyCode.IsMod1(); | |||
2140 | ||||
2141 | SvTreeListEntry* pNewCursor; | |||
2142 | ||||
2143 | switch( aCode ) | |||
2144 | { | |||
2145 | case KEY_UP: | |||
2146 | if( !IsEntryInView( m_pCursor ) ) | |||
2147 | MakeVisible( m_pCursor ); | |||
2148 | ||||
2149 | pNewCursor = m_pCursor; | |||
2150 | do | |||
2151 | { | |||
2152 | pNewCursor = m_pView->PrevVisible(pNewCursor); | |||
2153 | } while( pNewCursor && !IsSelectable(pNewCursor) ); | |||
2154 | ||||
2155 | // if there is no next entry, take the current one | |||
2156 | // this ensures that in case of _one_ entry in the list, this entry is selected when pressing | |||
2157 | // the cursor key | |||
2158 | if (!pNewCursor) | |||
2159 | pNewCursor = m_pCursor; | |||
2160 | ||||
2161 | m_aSelEng.CursorPosChanging( bShift, bMod1 ); | |||
2162 | SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on | |||
2163 | if( !IsEntryInView( pNewCursor ) ) | |||
2164 | KeyUp( false ); | |||
2165 | break; | |||
2166 | ||||
2167 | case KEY_DOWN: | |||
2168 | if( !IsEntryInView( m_pCursor ) ) | |||
2169 | MakeVisible( m_pCursor ); | |||
2170 | ||||
2171 | pNewCursor = m_pCursor; | |||
2172 | do | |||
2173 | { | |||
2174 | pNewCursor = m_pView->NextVisible(pNewCursor); | |||
2175 | } while( pNewCursor && !IsSelectable(pNewCursor) ); | |||
2176 | ||||
2177 | // if there is no next entry, take the current one | |||
2178 | // this ensures that in case of _one_ entry in the list, this entry is selected when pressing | |||
2179 | // the cursor key | |||
2180 | // 06.09.20001 - 83416 - frank.schoenheit@sun.com | |||
2181 | if ( !pNewCursor && m_pCursor ) | |||
2182 | pNewCursor = m_pCursor; | |||
2183 | ||||
2184 | if( pNewCursor ) | |||
2185 | { | |||
2186 | m_aSelEng.CursorPosChanging( bShift, bMod1 ); | |||
2187 | if( IsEntryInView( pNewCursor ) ) | |||
2188 | SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on | |||
2189 | else | |||
2190 | { | |||
2191 | if( m_pCursor ) | |||
2192 | m_pView->Select( m_pCursor, false ); | |||
2193 | KeyDown( false ); | |||
2194 | SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on | |||
2195 | } | |||
2196 | } | |||
2197 | else | |||
2198 | KeyDown( false ); // because scrollbar range might still | |||
2199 | // allow scrolling | |||
2200 | break; | |||
2201 | ||||
2202 | case KEY_RIGHT: | |||
2203 | { | |||
2204 | if( m_bSubLstOpLR ) | |||
2205 | { | |||
2206 | // only try to expand if sublist is expandable, | |||
2207 | // otherwise ignore the key press | |||
2208 | if( IsExpandable() && !m_pView->IsExpanded( m_pCursor ) ) | |||
2209 | m_pView->Expand( m_pCursor ); | |||
2210 | } | |||
2211 | else if (m_aHorSBar->IsVisible()) | |||
2212 | { | |||
2213 | long nThumb = m_aHorSBar->GetThumbPos(); | |||
2214 | nThumb += m_aHorSBar->GetLineSize(); | |||
2215 | long nOldThumb = m_aHorSBar->GetThumbPos(); | |||
2216 | m_aHorSBar->SetThumbPos( nThumb ); | |||
2217 | nThumb = nOldThumb; | |||
2218 | nThumb -= m_aHorSBar->GetThumbPos(); | |||
2219 | nThumb *= -1; | |||
2220 | if( nThumb ) | |||
2221 | { | |||
2222 | KeyLeftRight( nThumb ); | |||
2223 | } | |||
2224 | } | |||
2225 | else | |||
2226 | bKeyUsed = false; | |||
2227 | break; | |||
2228 | } | |||
2229 | ||||
2230 | case KEY_LEFT: | |||
2231 | { | |||
2232 | if (m_aHorSBar->IsVisible()) | |||
2233 | { | |||
2234 | long nThumb = m_aHorSBar->GetThumbPos(); | |||
2235 | nThumb -= m_aHorSBar->GetLineSize(); | |||
2236 | long nOldThumb = m_aHorSBar->GetThumbPos(); | |||
2237 | m_aHorSBar->SetThumbPos( nThumb ); | |||
2238 | nThumb = nOldThumb; | |||
2239 | nThumb -= m_aHorSBar->GetThumbPos(); | |||
2240 | if( nThumb ) | |||
2241 | { | |||
2242 | KeyLeftRight( -nThumb ); | |||
2243 | } | |||
2244 | else if( m_bSubLstOpLR ) | |||
2245 | { | |||
2246 | if( IsExpandable() && m_pView->IsExpanded( m_pCursor ) ) | |||
2247 | m_pView->Collapse( m_pCursor ); | |||
2248 | else | |||
2249 | { | |||
2250 | pNewCursor = m_pView->GetParent( m_pCursor ); | |||
2251 | if( pNewCursor ) | |||
2252 | SetCursor( pNewCursor ); | |||
2253 | } | |||
2254 | } | |||
2255 | } | |||
2256 | else if( m_bSubLstOpLR ) | |||
2257 | { | |||
2258 | if( IsExpandable() && m_pView->IsExpanded( m_pCursor ) ) | |||
2259 | m_pView->Collapse( m_pCursor ); | |||
2260 | else | |||
2261 | { | |||
2262 | pNewCursor = m_pView->GetParent( m_pCursor ); | |||
2263 | if( pNewCursor ) | |||
2264 | SetCursor( pNewCursor ); | |||
2265 | } | |||
2266 | } | |||
2267 | else | |||
2268 | bKeyUsed = false; | |||
2269 | break; | |||
2270 | } | |||
2271 | ||||
2272 | case KEY_PAGEUP: | |||
2273 | if( !bMod1 ) | |||
2274 | { | |||
2275 | pNewCursor = m_pView->PrevVisible(m_pCursor, nDelta); | |||
2276 | ||||
2277 | while( nDelta && pNewCursor && !IsSelectable(pNewCursor) ) | |||
2278 | { | |||
2279 | pNewCursor = m_pView->NextVisible(pNewCursor); | |||
2280 | nDelta--; | |||
2281 | } | |||
2282 | ||||
2283 | if( nDelta ) | |||
2284 | { | |||
2285 | DBG_ASSERT(pNewCursor && pNewCursor!=m_pCursor, "Cursor?")do { if (true && (!(pNewCursor && pNewCursor!= m_pCursor))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "2285" ": "), "%s", "Cursor?"); } } while (false); | |||
2286 | m_aSelEng.CursorPosChanging( bShift, bMod1 ); | |||
2287 | if( IsEntryInView( pNewCursor ) ) | |||
2288 | SetCursor( pNewCursor ); | |||
2289 | else | |||
2290 | { | |||
2291 | SetCursor( pNewCursor ); | |||
2292 | KeyUp( true ); | |||
2293 | } | |||
2294 | } | |||
2295 | } | |||
2296 | else | |||
2297 | bKeyUsed = false; | |||
2298 | break; | |||
2299 | ||||
2300 | case KEY_PAGEDOWN: | |||
2301 | if( !bMod1 ) | |||
2302 | { | |||
2303 | pNewCursor= m_pView->NextVisible(m_pCursor, nDelta); | |||
2304 | ||||
2305 | while( nDelta && pNewCursor && !IsSelectable(pNewCursor) ) | |||
2306 | { | |||
2307 | pNewCursor = m_pView->PrevVisible(pNewCursor); | |||
2308 | nDelta--; | |||
2309 | } | |||
2310 | ||||
2311 | if( nDelta && pNewCursor ) | |||
2312 | { | |||
2313 | DBG_ASSERT(pNewCursor && pNewCursor!=m_pCursor, "Cursor?")do { if (true && (!(pNewCursor && pNewCursor!= m_pCursor))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN ), ("legacy.tools"), ("/home/maarten/src/libreoffice/core/vcl/source/treelist/svimpbox.cxx" ":" "2313" ": "), "%s", "Cursor?"); } } while (false); | |||
2314 | m_aSelEng.CursorPosChanging( bShift, bMod1 ); | |||
2315 | if( IsEntryInView( pNewCursor ) ) | |||
2316 | SetCursor( pNewCursor ); | |||
2317 | else | |||
2318 | { | |||
2319 | SetCursor( pNewCursor ); | |||
2320 | KeyDown( true ); | |||
2321 | } | |||
2322 | } | |||
2323 | else | |||
2324 | KeyDown( false ); // see also: KEY_DOWN | |||
2325 | } | |||
2326 | else | |||
2327 | bKeyUsed = false; | |||
2328 | break; | |||
2329 | ||||
2330 | case KEY_SPACE: | |||
2331 | if ( m_pView->GetSelectionMode() != SelectionMode::NONE ) | |||
2332 | { | |||
2333 | if ( bMod1 ) | |||
2334 | { | |||
2335 | if ( m_pView->GetSelectionMode() == SelectionMode::Multiple && !bShift ) | |||
2336 | // toggle selection | |||
2337 | m_pView->Select( m_pCursor, !m_pView->IsSelected( m_pCursor ) ); | |||
2338 | } | |||
2339 | else if ( !bShift /*&& !bMod1*/ ) | |||
2340 | { | |||
2341 | if ( m_aSelEng.IsAddMode() ) | |||
2342 | { | |||
2343 | // toggle selection | |||
2344 | m_pView->Select( m_pCursor, !m_pView->IsSelected( m_pCursor ) ); | |||
2345 | } | |||
2346 | else if ( !m_pView->IsSelected( m_pCursor ) ) | |||
2347 | { | |||
2348 | SelAllDestrAnch( false ); | |||
2349 | m_pView->Select( m_pCursor ); | |||
2350 | } | |||
2351 | else | |||
2352 | bKeyUsed = false; | |||
2353 | } | |||
2354 | else | |||
2355 | bKeyUsed = false; | |||
2356 | } | |||
2357 | else | |||
2358 | bKeyUsed = false; | |||
2359 | break; | |||
2360 | ||||
2361 | case KEY_RETURN: | |||
2362 | bKeyUsed = !m_pView->DoubleClickHdl(); | |||
2363 | break; | |||
2364 | ||||
2365 | case KEY_F2: | |||
2366 | if( !bShift && !bMod1 ) | |||
2367 | { | |||
2368 | m_aEditClickPos = Point( -1, -1 ); | |||
2369 | EditTimerCall( nullptr ); | |||
2370 | } | |||
2371 | else | |||
2372 | bKeyUsed = false; | |||
2373 | break; | |||
2374 | ||||
2375 | case KEY_F8: | |||
2376 | if( bShift && m_pView->GetSelectionMode()==SelectionMode::Multiple && | |||
2377 | !(m_nStyle & WB_SIMPLEMODE)) | |||
2378 | { | |||
2379 | if( m_aSelEng.IsAlwaysAdding() ) | |||
2380 | m_aSelEng.AddAlways( false ); | |||
2381 | else | |||
2382 | m_aSelEng.AddAlways( true ); | |||
2383 | } | |||
2384 | else | |||
2385 | bKeyUsed = false; | |||
2386 | break; | |||
2387 | ||||
2388 | case KEY_ADD: | |||
2389 | if (!m_pView->IsExpanded(m_pCursor)) | |||
2390 | m_pView->Expand(m_pCursor); | |||
2391 | if (bMod1) | |||
2392 | ExpandAll(); | |||
2393 | break; | |||
2394 | ||||
2395 | case KEY_A: | |||
2396 | if( bMod1 ) | |||
2397 | SelAllDestrAnch( true ); | |||
2398 | else | |||
2399 | bKeyUsed = false; | |||
2400 | break; | |||
2401 | ||||
2402 | case KEY_SUBTRACT: | |||
2403 | if (m_pView->IsExpanded(m_pCursor)) | |||
2404 | m_pView->Collapse(m_pCursor); | |||
2405 | if (bMod1) | |||
2406 | CollapseTo(m_pTree->GetRootLevelParent(m_pCursor)); | |||
2407 | break; | |||
2408 | ||||
2409 | case KEY_MULTIPLY: | |||
2410 | if( bMod1 ) | |||
2411 | { | |||
2412 | // only try to expand/collapse if sublist is expandable, | |||
2413 | // otherwise ignore the key press | |||
2414 | if( IsExpandable() ) | |||
2415 | { | |||
2416 | if (!m_pView->IsAllExpanded(m_pCursor)) | |||
2417 | { | |||
2418 | m_pView->Expand(m_pCursor); | |||
2419 | ExpandAll(); | |||
2420 | } | |||
2421 | else | |||
2422 | CollapseTo(m_pCursor); | |||
2423 | } | |||
2424 | } | |||
2425 | else | |||
2426 | bKeyUsed = false; | |||
2427 | break; | |||
2428 | ||||
2429 | case KEY_DIVIDE : | |||
2430 | if( bMod1 ) | |||
2431 | SelAllDestrAnch( true ); | |||
2432 | else | |||
2433 | bKeyUsed = false; | |||
2434 | break; | |||
2435 | ||||
2436 | case KEY_COMMA : | |||
2437 | if( bMod1 ) | |||
2438 | SelAllDestrAnch( false ); | |||
2439 | else | |||
2440 | bKeyUsed = false; | |||
2441 | break; | |||
2442 | ||||
2443 | case KEY_HOME : | |||
2444 | pNewCursor = m_pView->GetModel()->First(); | |||
2445 | ||||
2446 | while( pNewCursor && !IsSelectable(pNewCursor) ) | |||
2447 | { | |||
2448 | pNewCursor = m_pView->NextVisible(pNewCursor); | |||
2449 | } | |||
2450 | ||||
2451 | if( pNewCursor && pNewCursor != m_pCursor ) | |||
2452 | { | |||
2453 | // SelAllDestrAnch( false ); | |||
2454 | m_aSelEng.CursorPosChanging( bShift, bMod1 ); | |||
2455 | SetCursor( pNewCursor ); | |||
2456 | if( !IsEntryInView( pNewCursor ) ) | |||
2457 | MakeVisible( pNewCursor ); | |||
2458 | } | |||
2459 | else | |||
2460 | bKeyUsed = false; | |||
2461 | break; | |||
2462 | ||||
2463 | case KEY_END : | |||
2464 | pNewCursor = m_pView->GetModel()->Last(); | |||
2465 | ||||
2466 | while( pNewCursor && !IsSelectable(pNewCursor) ) | |||
2467 | { | |||
2468 | pNewCursor = m_pView->PrevVisible(pNewCursor); | |||
2469 | } | |||
2470 | ||||
2471 | if( pNewCursor && pNewCursor != m_pCursor) | |||
2472 | { | |||
2473 | // SelAllDestrAnch( false ); | |||
2474 | m_aSelEng.CursorPosChanging( bShift, bMod1 ); | |||
2475 | SetCursor( pNewCursor ); | |||
2476 | if( !IsEntryInView( pNewCursor ) ) | |||
2477 | MakeVisible( pNewCursor ); | |||
2478 | } | |||
2479 | else | |||
2480 | bKeyUsed = false; | |||
2481 | break; | |||
2482 | ||||
2483 | case KEY_ESCAPE: | |||
2484 | case KEY_TAB: | |||
2485 | case KEY_DELETE: | |||
2486 | case KEY_BACKSPACE: | |||
2487 | // must not be handled because this quits dialogs and does other magic things... | |||
2488 | // if there are other single keys which should not be handled, they can be added here | |||
2489 | bKeyUsed = false; | |||
2490 | break; | |||
2491 | ||||
2492 | default: | |||
2493 | // is there any reason why we should eat the events here? The only place where this is called | |||
2494 | // is from SvTreeListBox::KeyInput. If we set bKeyUsed to true here, then the key input | |||
2495 | // is just silenced. However, we want SvLBox::KeyInput to get a chance, to do the QuickSelection | |||
2496 | // handling. | |||
2497 | // (The old code here which intentionally set bKeyUsed to sal_True said this was because of "quick search" | |||
2498 | // handling, but actually there was no quick search handling anymore. We just re-implemented it.) | |||
2499 | // #i31275# / 2009-06-16 / frank.schoenheit@sun.com | |||
2500 | bKeyUsed = false; | |||
2501 | break; | |||
2502 | } | |||
2503 | return bKeyUsed; | |||
2504 | } | |||
2505 | ||||
2506 | void SvImpLBox::GetFocus() | |||
2507 | { | |||
2508 | if( m_pCursor ) | |||
2509 | { | |||
2510 | m_pView->SetEntryFocus( m_pCursor, true ); | |||
2511 | ShowCursor( true ); | |||
2512 | // auskommentiert wg. deselectall | |||
2513 | // if( bSimpleTravel && !pView->IsSelected(pCursor) ) | |||
2514 | // pView->Select( pCursor, true ); | |||
2515 | } | |||
2516 | if( m_nStyle & WB_HIDESELECTION ) | |||
2517 | { | |||
2518 | SvTreeListEntry* pEntry = m_pView->FirstSelected(); | |||
2519 | while( pEntry ) | |||
2520 | { | |||
2521 | InvalidateEntry( pEntry ); | |||
2522 | pEntry = m_pView->NextSelected( pEntry ); | |||
2523 | } | |||
2524 | } | |||
2525 | } | |||
2526 | ||||
2527 | void SvImpLBox::LoseFocus() | |||
2528 | { | |||
2529 | m_aEditIdle.Stop(); | |||
2530 | if( m_pCursor ) | |||
2531 | m_pView->SetEntryFocus( m_pCursor,false ); | |||
2532 | ShowCursor( false ); | |||
2533 | ||||
2534 | if( m_nStyle & WB_HIDESELECTION ) | |||
2535 | { | |||
2536 | SvTreeListEntry* pEntry = m_pView ? m_pView->FirstSelected() : nullptr; | |||
2537 | while( pEntry ) | |||
2538 | { | |||
2539 | InvalidateEntry( pEntry ); | |||
2540 | pEntry = m_pView->NextSelected( pEntry ); | |||
2541 | } | |||
2542 | } | |||
2543 | } | |||
2544 | ||||
2545 | ||||
2546 | // ******************************************************************** | |||
2547 | // SelectionEngine | |||
2548 | // ******************************************************************** | |||
2549 | ||||
2550 | void SvImpLBox::SelectEntry( SvTreeListEntry* pEntry, bool bSelect ) | |||
2551 | { | |||
2552 | m_pView->Select( pEntry, bSelect ); | |||
2553 | } | |||
2554 | ||||
2555 | ImpLBSelEng::ImpLBSelEng( SvImpLBox* pImpl, SvTreeListBox* pV ) | |||
2556 | { | |||
2557 | pImp = pImpl; | |||
2558 | pView = pV; | |||
2559 | } | |||
2560 | ||||
2561 | ImpLBSelEng::~ImpLBSelEng() | |||
2562 | { | |||
2563 | } | |||
2564 | ||||
2565 | void ImpLBSelEng::BeginDrag() | |||
2566 | { | |||
2567 | pImp->BeginDrag(); | |||
2568 | } | |||
2569 | ||||
2570 | void ImpLBSelEng::CreateAnchor() | |||
2571 | { | |||
2572 | pImp->m_pAnchor = pImp->m_pCursor; | |||
2573 | } | |||
2574 | ||||
2575 | void ImpLBSelEng::DestroyAnchor() | |||
2576 | { | |||
2577 | pImp->m_pAnchor = nullptr; | |||
2578 | } | |||
2579 | ||||
2580 | void ImpLBSelEng::SetCursorAtPoint(const Point& rPoint, bool bDontSelectAtCursor) | |||
2581 | { | |||
2582 | SvTreeListEntry* pNewCursor = pImp->MakePointVisible( rPoint ); | |||
2583 | if( pNewCursor ) | |||
2584 | { | |||
2585 | // at SimpleTravel, the SetCursor is selected and the select handler is | |||
2586 | // called | |||
2587 | //if( !bDontSelectAtCursor && !pImp->bSimpleTravel ) | |||
2588 | // pImp->SelectEntry( pNewCursor, true ); | |||
2589 | pImp->SetCursor( pNewCursor, bDontSelectAtCursor ); | |||
2590 | } | |||
2591 | } | |||
2592 | ||||
2593 | bool ImpLBSelEng::IsSelectionAtPoint( const Point& rPoint ) | |||
2594 | { | |||
2595 | SvTreeListEntry* pEntry = pImp->MakePointVisible( rPoint ); | |||
2596 | if( pEntry ) | |||
2597 | return pView->IsSelected(pEntry); | |||
2598 | return false; | |||
2599 | } | |||
2600 | ||||
2601 | void ImpLBSelEng::DeselectAtPoint( const Point& rPoint ) | |||
2602 | { | |||
2603 | SvTreeListEntry* pEntry = pImp->MakePointVisible( rPoint ); | |||
2604 | if( !pEntry ) | |||
2605 | return; | |||
2606 | pImp->SelectEntry( pEntry, false ); | |||
2607 | } | |||
2608 | ||||
2609 | void ImpLBSelEng::DeselectAll() | |||
2610 | { | |||
2611 | pImp->SelAllDestrAnch( false, false ); // don't reset SelectionEngine! | |||
2612 | pImp->m_nFlags &= ~LBoxFlags::DeselectAll; | |||
2613 | } | |||
2614 | ||||
2615 | // *********************************************************************** | |||
2616 | // Selection | |||
2617 | // *********************************************************************** | |||
2618 | ||||
2619 | void SvImpLBox::SetAnchorSelection(SvTreeListEntry* pOldCursor,SvTreeListEntry* pNewCursor) | |||
2620 | { | |||
2621 | SvTreeListEntry* pEntry; | |||
2622 | sal_uLong nAnchorVisPos = m_pView->GetVisiblePos( m_pAnchor ); | |||
2623 | sal_uLong nOldVisPos = m_pView->GetVisiblePos( pOldCursor ); | |||
2624 | sal_uLong nNewVisPos = m_pView->GetVisiblePos( pNewCursor ); | |||
2625 | ||||
2626 | if( nOldVisPos > nAnchorVisPos || | |||
2627 | ( nAnchorVisPos==nOldVisPos && nNewVisPos > nAnchorVisPos) ) | |||
2628 | { | |||
2629 | if( nNewVisPos > nOldVisPos ) | |||
2630 | { | |||
2631 | pEntry = pOldCursor; | |||
2632 | while( pEntry && pEntry != pNewCursor ) | |||
2633 | { | |||
2634 | m_pView->Select( pEntry ); | |||
2635 | pEntry = m_pView->NextVisible(pEntry); | |||
2636 | } | |||
2637 | if( pEntry ) | |||
2638 | m_pView->Select( pEntry ); | |||
2639 | return; | |||
2640 | } | |||
2641 | ||||
2642 | if( nNewVisPos < nAnchorVisPos ) | |||
2643 | { | |||
2644 | pEntry = m_pAnchor; | |||
2645 | while( pEntry && pEntry != pOldCursor ) | |||
2646 | { | |||
2647 | m_pView->Select( pEntry, false ); | |||
2648 | pEntry = m_pView->NextVisible(pEntry); | |||
2649 | } | |||
2650 | if( pEntry ) | |||
2651 | m_pView->Select( pEntry, false ); | |||
2652 | ||||
2653 | pEntry = pNewCursor; | |||
2654 | while( pEntry && pEntry != m_pAnchor ) | |||
2655 | { | |||
2656 | m_pView->Select( pEntry ); | |||
2657 | pEntry = m_pView->NextVisible(pEntry); | |||
2658 | } | |||
2659 | if( pEntry ) | |||
2660 | m_pView->Select( pEntry ); | |||
2661 | return; | |||
2662 | } | |||
2663 | ||||
2664 | if( nNewVisPos < nOldVisPos ) | |||
2665 | { | |||
2666 | pEntry = m_pView->NextVisible(pNewCursor); | |||
2667 | while( pEntry && pEntry != pOldCursor ) | |||
2668 | { | |||
2669 | m_pView->Select( pEntry, false ); | |||
2670 | pEntry = m_pView->NextVisible(pEntry); | |||
2671 | } | |||
2672 | if( pEntry ) | |||
2673 | m_pView->Select( pEntry, false ); | |||
2674 | return; | |||
2675 | } | |||
2676 | } | |||
2677 | else | |||
2678 | { | |||
2679 | if( nNewVisPos < nOldVisPos ) // enlarge selection | |||
2680 | { | |||
2681 | pEntry = pNewCursor; | |||
2682 | while( pEntry && pEntry != pOldCursor ) | |||
2683 | { | |||
2684 | m_pView->Select( pEntry ); | |||
2685 | pEntry = m_pView->NextVisible(pEntry); | |||
2686 | } | |||
2687 | if( pEntry ) | |||
2688 | m_pView->Select( pEntry ); | |||
2689 | return; | |||
2690 | } | |||
2691 | ||||
2692 | if( nNewVisPos > nAnchorVisPos ) | |||
2693 | { | |||
2694 | pEntry = pOldCursor; | |||
2695 | while( pEntry && pEntry != m_pAnchor ) | |||
2696 | { | |||
2697 | m_pView->Select( pEntry, false ); | |||
2698 | pEntry = m_pView->NextVisible(pEntry); | |||
2699 | } | |||
2700 | if( pEntry ) | |||
2701 | m_pView->Select( pEntry, false ); | |||
2702 | pEntry = m_pAnchor; | |||
2703 | while( pEntry && pEntry != pNewCursor ) | |||
2704 | { | |||
2705 | m_pView->Select( pEntry ); | |||
2706 | pEntry = m_pView->NextVisible(pEntry); | |||
2707 | } | |||
2708 | if( pEntry ) | |||
2709 | m_pView->Select( pEntry ); | |||
2710 | return; | |||
2711 | } | |||
2712 | ||||
2713 | if( nNewVisPos > nOldVisPos ) | |||
2714 | { | |||
2715 | pEntry = pOldCursor; | |||
2716 | while( pEntry && pEntry != pNewCursor ) | |||
2717 | { | |||
2718 | m_pView->Select( pEntry, false ); | |||
2719 | pEntry = m_pView->NextVisible(pEntry); | |||
2720 | } | |||
2721 | return; | |||
2722 | } | |||
2723 | } | |||
2724 | } | |||
2725 | ||||
2726 | void SvImpLBox::SelAllDestrAnch( | |||
2727 | bool bSelect, bool bDestroyAnchor, bool bSingleSelToo ) | |||
2728 | { | |||
2729 | SvTreeListEntry* pEntry; | |||
2730 | m_nFlags &= ~LBoxFlags::DeselectAll; | |||
2731 | if( bSelect && m_bSimpleTravel ) | |||
2732 | { | |||
2733 | if( m_pCursor && !m_pView->IsSelected( m_pCursor )) | |||
2734 | { | |||
2735 | m_pView->Select( m_pCursor ); | |||
2736 | } | |||
2737 | return; | |||
2738 | } | |||
2739 | if( !bSelect && m_pView->GetSelectionCount() == 0 ) | |||
2740 | { | |||
2741 | if( m_bSimpleTravel && ( !GetUpdateMode() || !m_pCursor) ) | |||
2742 | m_nFlags |= LBoxFlags::DeselectAll; | |||
2743 | return; | |||
2744 | } | |||
2745 | if( bSelect && m_pView->GetSelectionCount() == m_pView->GetEntryCount()) | |||
2746 | return; | |||
2747 | if( !bSingleSelToo && m_bSimpleTravel ) | |||
2748 | return; | |||
2749 | ||||
2750 | if( !bSelect && m_pView->GetSelectionCount()==1 && m_pCursor && | |||
2751 | m_pView->IsSelected( m_pCursor )) | |||
2752 | { | |||
2753 | m_pView->Select( m_pCursor, false ); | |||
2754 | if( bDestroyAnchor ) | |||
2755 | DestroyAnchor(); // delete anchor & reset SelectionEngine | |||
2756 | else | |||
2757 | m_pAnchor = nullptr; // always delete internal anchor | |||
2758 | return; | |||
2759 | } | |||
2760 | ||||
2761 | if( m_bSimpleTravel && !m_pCursor && !GetUpdateMode() ) | |||
2762 | m_nFlags |= LBoxFlags::DeselectAll; | |||
2763 | ||||
2764 | ShowCursor( false ); | |||
2765 | bool bUpdate = GetUpdateMode(); | |||
2766 | ||||
2767 | m_nFlags |= LBoxFlags::IgnoreSelect; // EntryInserted should not do anything | |||
2768 | pEntry = m_pTree->First(); | |||
2769 | while( pEntry ) | |||
2770 | { | |||
2771 | if( m_pView->Select( pEntry, bSelect ) ) | |||
2772 | { | |||
2773 | if( bUpdate && m_pView->IsEntryVisible(pEntry) ) | |||
2774 | { | |||
2775 | long nY = GetEntryLine( pEntry ); | |||
2776 | if( IsLineVisible( nY ) ) | |||
2777 | InvalidateEntry(pEntry); | |||
2778 | } | |||
2779 | } | |||
2780 | pEntry = m_pTree->Next( pEntry ); | |||
2781 | } | |||
2782 | m_nFlags &= ~LBoxFlags::IgnoreSelect; | |||
2783 | ||||
2784 | if( bDestroyAnchor ) | |||
2785 | DestroyAnchor(); // delete anchor & reset SelectionEngine | |||
2786 | else | |||
2787 | m_pAnchor = nullptr; // always delete internal anchor | |||
2788 | ShowCursor( true ); | |||
2789 | } | |||
2790 | ||||
2791 | void SvImpLBox::SetSelectionMode( SelectionMode eSelMode ) | |||
2792 | { | |||
2793 | m_aSelEng.SetSelectionMode( eSelMode); | |||
2794 | if( eSelMode == SelectionMode::Single ) | |||
2795 | m_bSimpleTravel = true; | |||
2796 | else | |||
2797 | m_bSimpleTravel = false; | |||
2798 | if( (m_nStyle & WB_SIMPLEMODE) && (eSelMode == SelectionMode::Multiple) ) | |||
2799 | m_aSelEng.AddAlways( true ); | |||
2800 | } | |||
2801 | ||||
2802 | // *********************************************************************** | |||
2803 | // Drag & Drop | |||
2804 | // *********************************************************************** | |||
2805 | ||||
2806 | void SvImpLBox::SetDragDropMode( DragDropMode eDDMode ) | |||
2807 | { | |||
2808 | if( eDDMode != DragDropMode::NONE ) | |||
2809 | { | |||
2810 | m_aSelEng.ExpandSelectionOnMouseMove( false ); | |||
2811 | m_aSelEng.EnableDrag( true ); | |||
2812 | } | |||
2813 | else | |||
2814 | { | |||
2815 | m_aSelEng.ExpandSelectionOnMouseMove(); | |||
2816 | m_aSelEng.EnableDrag( false ); | |||
2817 | } | |||
2818 | } | |||
2819 | ||||
2820 | void SvImpLBox::BeginDrag() | |||
2821 | { | |||
2822 | m_nFlags &= ~LBoxFlags::Filling; | |||
2823 | m_pView->StartDrag( 0, m_aSelEng.GetMousePosPixel() ); | |||
2824 | } | |||
2825 | ||||
2826 | void SvImpLBox::PaintDDCursor(SvTreeListEntry* pEntry, bool bShow) | |||
2827 | { | |||
2828 | if (pEntry) | |||
2829 | { | |||
2830 | ||||
2831 | SvViewDataEntry* pViewData = m_pView->GetViewData(pEntry); | |||
2832 | pViewData->SetDragTarget(bShow); | |||
2833 | #ifdef MACOSX | |||
2834 | // in MacOS we need to draw directly (as we are synchronous) or no invalidation happens | |||
2835 | m_pView->PaintEntry1(*pEntry, GetEntryLine(pEntry), *m_pView); | |||
2836 | #else | |||
2837 | InvalidateEntry(pEntry); | |||
2838 | #endif | |||
2839 | } | |||
2840 | } | |||
2841 | ||||
2842 | void SvImpLBox::Command( const CommandEvent& rCEvt ) | |||
2843 | { | |||
2844 | CommandEventId nCommand = rCEvt.GetCommand(); | |||
2845 | ||||
2846 | if( nCommand == CommandEventId::ContextMenu ) | |||
2847 | m_aEditIdle.Stop(); | |||
2848 | ||||
2849 | // scroll mouse event? | |||
2850 | if (nCommand == CommandEventId::Wheel || | |||
2851 | nCommand == CommandEventId::StartAutoScroll || | |||
2852 | nCommand == CommandEventId::AutoScroll || | |||
2853 | nCommand == CommandEventId::Gesture) | |||
2854 | { | |||
2855 | if (m_pView->HandleScrollCommand(rCEvt, m_aHorSBar.get(), m_aVerSBar.get())) | |||
2856 | return; | |||
2857 | } | |||
2858 | ||||
2859 | const Point& rPos = rCEvt.GetMousePosPixel(); | |||
2860 | if( rPos.X() < m_aOutputSize.Width() && rPos.Y() < m_aOutputSize.Height() ) | |||
2861 | m_aSelEng.Command( rCEvt ); | |||
2862 | } | |||
2863 | ||||
2864 | tools::Rectangle SvImpLBox::GetVisibleArea() const | |||
2865 | { | |||
2866 | Point aPos( m_pView->GetMapMode().GetOrigin() ); | |||
2867 | aPos.setX( aPos.X() * -1 ); | |||
2868 | tools::Rectangle aRect( aPos, m_aOutputSize ); | |||
2869 | return aRect; | |||
2870 | } | |||
2871 | ||||
2872 | void SvImpLBox::Invalidate() | |||
2873 | { | |||
2874 | m_pView->SetClipRegion(); | |||
2875 | } | |||
2876 | ||||
2877 | void SvImpLBox::SetCurEntry( SvTreeListEntry* pEntry ) | |||
2878 | { | |||
2879 | if ( ( m_aSelEng.GetSelectionMode() != SelectionMode::Single ) | |||
2880 | && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) | |||
2881 | ) | |||
2882 | SelAllDestrAnch( false ); | |||
2883 | if ( pEntry ) | |||
2884 | MakeVisible( pEntry ); | |||
2885 | SetCursor( pEntry ); | |||
2886 | if ( pEntry && ( m_aSelEng.GetSelectionMode() != SelectionMode::NONE ) ) | |||
2887 | m_pView->Select( pEntry ); | |||
2888 | } | |||
2889 | ||||
2890 | IMPL_LINK_NOARG(SvImpLBox, EditTimerCall, Timer *, void)void SvImpLBox::LinkStubEditTimerCall(void * instance, Timer * data) { return static_cast<SvImpLBox *>(instance)-> EditTimerCall(data); } void SvImpLBox::EditTimerCall(__attribute__ ((unused)) Timer *) | |||
2891 | { | |||
2892 | if( !m_pView->IsInplaceEditingEnabled() ) | |||
2893 | return; | |||
2894 | ||||
2895 | bool bIsMouseTriggered = m_aEditClickPos.X() >= 0; | |||
2896 | if ( bIsMouseTriggered ) | |||
2897 | { | |||
2898 | Point aCurrentMousePos = m_pView->GetPointerPosPixel(); | |||
2899 | if ( ( std::abs( aCurrentMousePos.X() - m_aEditClickPos.X() ) > 5 ) | |||
2900 | || ( std::abs( aCurrentMousePos.Y() - m_aEditClickPos.Y() ) > 5 ) | |||
2901 | ) | |||
2902 | { | |||
2903 | return; | |||
2904 | } | |||
2905 | } | |||
2906 | ||||
2907 | SvTreeListEntry* pEntry = GetCurEntry(); | |||
2908 | if( pEntry ) | |||
2909 | { | |||
2910 | ShowCursor( false ); | |||
2911 | m_pView->ImplEditEntry( pEntry ); | |||
2912 | ShowCursor( true ); | |||
2913 | } | |||
2914 | } | |||
2915 | ||||
2916 | bool SvImpLBox::RequestHelp( const HelpEvent& rHEvt ) | |||
2917 | { | |||
2918 | if( rHEvt.GetMode() & HelpEventMode::QUICK ) | |||
2919 | { | |||
2920 | Point aPos( m_pView->ScreenToOutputPixel( rHEvt.GetMousePosPixel() )); | |||
2921 | if( !GetVisibleArea().IsInside( aPos )) | |||
2922 | return false; | |||
2923 | ||||
2924 | SvTreeListEntry* pEntry = GetEntry( aPos ); | |||
2925 | if( pEntry ) | |||
2926 | { | |||
2927 | // recalculate text rectangle | |||
2928 | SvLBoxTab* pTab; | |||
2929 | SvLBoxItem* pItem = m_pView->GetItem( pEntry, aPos.X(), &pTab ); | |||
2930 | if (!pItem || pItem->GetType() != SvLBoxItemType::String) | |||
2931 | return false; | |||
2932 | ||||
2933 | aPos = GetEntryPosition( pEntry ); | |||
2934 | aPos.setX( m_pView->GetTabPos( pEntry, pTab ) ); //pTab->GetPos(); | |||
2935 | Size aSize(pItem->GetWidth(m_pView, pEntry), pItem->GetHeight(m_pView, pEntry)); | |||
2936 | SvLBoxTab* pNextTab = NextTab( pTab ); | |||
2937 | bool bItemClipped = false; | |||
2938 | // is the item cut off by its right neighbor? | |||
2939 | if( pNextTab && m_pView->GetTabPos(pEntry,pNextTab) < aPos.X()+aSize.Width() ) | |||
2940 | { | |||
2941 | aSize.setWidth( pNextTab->GetPos() - pTab->GetPos() ); | |||
2942 | bItemClipped = true; | |||
2943 | } | |||
2944 | tools::Rectangle aItemRect( aPos, aSize ); | |||
2945 | ||||
2946 | tools::Rectangle aViewRect( GetVisibleArea() ); | |||
2947 | ||||
2948 | if( bItemClipped || !aViewRect.IsInside( aItemRect ) ) | |||
2949 | { | |||
2950 | // clip the right edge of the item at the edge of the view | |||
2951 | //if( aItemRect.Right() > aViewRect.Right() ) | |||
2952 | // aItemRect.Right() = aViewRect.Right(); | |||
2953 | ||||
2954 | Point aPt = m_pView->OutputToScreenPixel( aItemRect.TopLeft() ); | |||
2955 | aItemRect.SetLeft( aPt.X() ); | |||
2956 | aItemRect.SetTop( aPt.Y() ); | |||
2957 | aPt = m_pView->OutputToScreenPixel( aItemRect.BottomRight() ); | |||
2958 | aItemRect.SetRight( aPt.X() ); | |||
2959 | aItemRect.SetBottom( aPt.Y() ); | |||
2960 | ||||
2961 | Help::ShowQuickHelp( m_pView, aItemRect, | |||
2962 | static_cast<SvLBoxString*>(pItem)->GetText(), QuickHelpFlags::Left | QuickHelpFlags::VCenter ); | |||
2963 | return true; | |||
2964 | } | |||
2965 | } | |||
2966 | } | |||
2967 | return false; | |||
2968 | } | |||
2969 | ||||
2970 | SvLBoxTab* SvImpLBox::NextTab( SvLBoxTab const * pTab ) | |||
2971 | { | |||
2972 | sal_uInt16 nTabCount = m_pView->TabCount(); | |||
2973 | if( nTabCount <= 1 ) | |||
2974 | return nullptr; | |||
2975 | for( int nTab=0; nTab < (nTabCount-1); nTab++) | |||
2976 | { | |||
2977 | if( m_pView->aTabs[nTab].get() == pTab ) | |||
2978 | return m_pView->aTabs[nTab+1].get(); | |||
2979 | } | |||
2980 | return nullptr; | |||
2981 | } | |||
2982 | ||||
2983 | void SvImpLBox::SetUpdateMode( bool bMode ) | |||
2984 | { | |||
2985 | if( m_bUpdateMode != bMode ) | |||
2986 | { | |||
2987 | m_bUpdateMode = bMode; | |||
2988 | if( m_bUpdateMode ) | |||
2989 | UpdateAll( false ); | |||
2990 | } | |||
2991 | } | |||
2992 | ||||
2993 | bool SvImpLBox::SetMostRight( SvTreeListEntry* pEntry ) | |||
2994 | { | |||
2995 | if( m_pView->nTreeFlags & SvTreeFlags::RECALCTABS ) | |||
2996 | { | |||
2997 | m_nFlags |= LBoxFlags::IgnoreChangedTabs; | |||
2998 | m_pView->SetTabs(); | |||
2999 | m_nFlags &= ~LBoxFlags::IgnoreChangedTabs; | |||
3000 | } | |||
3001 | ||||
3002 | sal_uInt16 nLastTab = m_pView->aTabs.size() - 1; | |||
3003 | sal_uInt16 nLastItem = pEntry->ItemCount() - 1; | |||
3004 | if( !m_pView->aTabs.empty() && nLastItem != USHRT_MAX(32767 *2 +1) ) | |||
3005 | { | |||
3006 | if( nLastItem < nLastTab ) | |||
3007 | nLastTab = nLastItem; | |||
3008 | ||||
3009 | SvLBoxTab* pTab = m_pView->aTabs[ nLastTab ].get(); | |||
3010 | SvLBoxItem& rItem = pEntry->GetItem( nLastTab ); | |||
3011 | ||||
3012 | long nTabPos = m_pView->GetTabPos( pEntry, pTab ); | |||
3013 | ||||
3014 | long nMaxRight = GetOutputSize().Width(); | |||
3015 | Point aPos( m_pView->GetMapMode().GetOrigin() ); | |||
3016 | aPos.setX( aPos.X() * -1 ); // conversion document coordinates | |||
3017 | nMaxRight = nMaxRight + aPos.X() - 1; | |||
3018 | ||||
3019 | long nNextTab = nTabPos < nMaxRight ? nMaxRight : nMaxRight + 50; | |||
3020 | long nTabWidth = nNextTab - nTabPos + 1; | |||
3021 | auto nItemSize = rItem.GetWidth(m_pView,pEntry); | |||
3022 | long nOffset = pTab->CalcOffset( nItemSize, nTabWidth ); | |||
3023 | ||||
3024 | long nRight = nTabPos + nOffset + nItemSize; | |||
3025 | if( nRight > m_nMostRight ) | |||
3026 | { | |||
3027 | m_nMostRight = nRight; | |||
3028 | m_pMostRightEntry = pEntry; | |||
3029 | return true; | |||
3030 | } | |||
3031 | } | |||
3032 | return false; | |||
3033 | } | |||
3034 | ||||
3035 | void SvImpLBox::FindMostRight() | |||
3036 | { | |||
3037 | m_nMostRight = -1; | |||
3038 | m_pMostRightEntry = nullptr; | |||
3039 | if( !m_pView->GetModel() ) | |||
3040 | return; | |||
3041 | ||||
3042 | SvTreeListEntry* pEntry = m_pView->FirstVisible(); | |||
3043 | while( pEntry ) | |||
3044 | { | |||
3045 | SetMostRight( pEntry ); | |||
3046 | pEntry = m_pView->NextVisible( pEntry ); | |||
3047 | } | |||
3048 | } | |||
3049 | ||||
3050 | void SvImpLBox::FindMostRight( SvTreeListEntry* pParent ) | |||
3051 | { | |||
3052 | if( !pParent ) | |||
3053 | FindMostRight(); | |||
3054 | else | |||
3055 | FindMostRight_Impl( pParent ); | |||
3056 | } | |||
3057 | ||||
3058 | void SvImpLBox::FindMostRight_Impl( SvTreeListEntry* pParent ) | |||
3059 | { | |||
3060 | SvTreeListEntries& rList = m_pTree->GetChildList( pParent ); | |||
3061 | ||||
3062 | size_t nCount = rList.size(); | |||
3063 | for( size_t nCur = 0; nCur < nCount; nCur++ ) | |||
3064 | { | |||
3065 | SvTreeListEntry* pChild = rList[nCur].get(); | |||
3066 | SetMostRight( pChild ); | |||
3067 | if( pChild->HasChildren() && m_pView->IsExpanded( pChild )) | |||
3068 | FindMostRight_Impl( pChild ); | |||
3069 | } | |||
3070 | } | |||
3071 | ||||
3072 | void SvImpLBox::NotifyTabsChanged() | |||
3073 | { | |||
3074 | if( GetUpdateMode() && !(m_nFlags & LBoxFlags::IgnoreChangedTabs ) && | |||
3075 | m_nCurUserEvent == nullptr ) | |||
3076 | { | |||
3077 | m_nCurUserEvent = Application::PostUserEvent(LINK(this,SvImpLBox,MyUserEvent)::tools::detail::makeLink( ::tools::detail::castTo<SvImpLBox *>(this), &SvImpLBox::LinkStubMyUserEvent)); | |||
3078 | } | |||
3079 | } | |||
3080 | ||||
3081 | bool SvImpLBox::IsExpandable() const | |||
3082 | { | |||
3083 | return m_pCursor->HasChildren() || m_pCursor->HasChildrenOnDemand(); | |||
3084 | } | |||
3085 | ||||
3086 | IMPL_LINK(SvImpLBox, MyUserEvent, void*, pArg, void )void SvImpLBox::LinkStubMyUserEvent(void * instance, void* data ) { return static_cast<SvImpLBox *>(instance)->MyUserEvent (data); } void SvImpLBox::MyUserEvent(void* pArg) | |||
3087 | { | |||
3088 | m_nCurUserEvent = nullptr; | |||
3089 | if( !pArg ) | |||
3090 | { | |||
3091 | m_pView->Invalidate(); | |||
3092 | m_pView->PaintImmediately(); | |||
3093 | } | |||
3094 | else | |||
3095 | { | |||
3096 | FindMostRight(); | |||
3097 | ShowVerSBar(); | |||
3098 | m_pView->Invalidate( GetVisibleArea() ); | |||
3099 | } | |||
3100 | } | |||
3101 | ||||
3102 | ||||
3103 | void SvImpLBox::StopUserEvent() | |||
3104 | { | |||
3105 | if( m_nCurUserEvent != nullptr ) | |||
3106 | { | |||
3107 | Application::RemoveUserEvent( m_nCurUserEvent ); | |||
3108 | m_nCurUserEvent = nullptr; | |||
3109 | } | |||
3110 | } | |||
3111 | ||||
3112 | void SvImpLBox::implInitDefaultNodeImages() | |||
3113 | { | |||
3114 | if ( s_pDefCollapsed ) | |||
3115 | // assume that all or nothing is initialized | |||
3116 | return; | |||
3117 | ||||
3118 | s_pDefCollapsed = new Image(StockImage::Yes, RID_BMP_TREENODE_COLLAPSED"res/plus.png"); | |||
3119 | s_pDefExpanded = new Image(StockImage::Yes, RID_BMP_TREENODE_EXPANDED"res/minus.png"); | |||
3120 | } | |||
3121 | ||||
3122 | ||||
3123 | const Image& SvImpLBox::GetDefaultExpandedNodeImage( ) | |||
3124 | { | |||
3125 | implInitDefaultNodeImages(); | |||
3126 | return *s_pDefExpanded; | |||
3127 | } | |||
3128 | ||||
3129 | ||||
3130 | const Image& SvImpLBox::GetDefaultCollapsedNodeImage( ) | |||
3131 | { | |||
3132 | implInitDefaultNodeImages(); | |||
3133 | return *s_pDefCollapsed; | |||
3134 | } | |||
3135 | ||||
3136 | ||||
3137 | void SvImpLBox::CallEventListeners( VclEventId nEvent, void* pData ) | |||
3138 | { | |||
3139 | if ( m_pView ) | |||
3140 | m_pView->CallImplEventListeners( nEvent, pData); | |||
3141 | } | |||
3142 | ||||
3143 | ||||
3144 | bool SvImpLBox::IsSelectable( const SvTreeListEntry* pEntry ) | |||
3145 | { | |||
3146 | if( pEntry ) | |||
3147 | { | |||
3148 | SvViewDataEntry* pViewDataNewCur = m_pView->GetViewDataEntry(pEntry); | |||
3149 | return (pViewDataNewCur == nullptr) || pViewDataNewCur->IsSelectable(); | |||
3150 | } | |||
3151 | else | |||
3152 | { | |||
3153 | return false; | |||
3154 | } | |||
3155 | } | |||
3156 | ||||
3157 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |