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