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