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