bump product version to 6.4.0.3
[LibreOffice.git] / vcl / source / treelist / iconviewimpl.cxx
blobc9c5e530592f1acdb5a5bb5e8473755b5050cdd1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/svapp.hxx>
21 #include <tools/debug.hxx>
22 #include <iconview.hxx>
23 #include "iconviewimpl.hxx"
25 IconViewImpl::IconViewImpl( SvTreeListBox* pTreeListBox, SvTreeList* pTreeList, WinBits nWinStyle )
26 : SvImpLBox( pTreeListBox, pTreeList, nWinStyle )
30 void IconViewImpl::CursorUp()
32 if (!m_pStartEntry)
33 return;
35 SvTreeListEntry* pPrevFirstToDraw = m_pStartEntry;
37 for(short i = 0; i < m_pView->GetColumnsCount() && pPrevFirstToDraw; i++)
38 pPrevFirstToDraw = m_pView->PrevVisible(pPrevFirstToDraw);
40 if( !pPrevFirstToDraw )
41 return;
43 m_nFlags &= ~LBoxFlags::Filling;
44 long nEntryHeight = m_pView->GetEntryHeight();
45 ShowCursor( false );
46 m_pView->Update();
47 m_pStartEntry = pPrevFirstToDraw;
48 tools::Rectangle aArea( GetVisibleArea() );
49 aArea.AdjustBottom( -nEntryHeight );
50 m_pView->Scroll( 0, nEntryHeight, aArea, ScrollFlags::NoChildren );
51 m_pView->Update();
52 ShowCursor( true );
53 m_pView->NotifyScrolled();
56 void IconViewImpl::CursorDown()
58 if (!m_pStartEntry)
59 return;
61 SvTreeListEntry* pNextFirstToDraw = m_pStartEntry;
63 for(short i = 0; i < m_pView->GetColumnsCount(); i++)
64 pNextFirstToDraw = m_pView->NextVisible(pNextFirstToDraw);
66 if( pNextFirstToDraw )
68 m_nFlags &= ~LBoxFlags::Filling;
69 ShowCursor( false );
70 m_pView->Update();
71 m_pStartEntry = pNextFirstToDraw;
72 tools::Rectangle aArea( GetVisibleArea() );
73 m_pView->Scroll( 0, -(m_pView->GetEntryHeight()), aArea, ScrollFlags::NoChildren );
74 m_pView->Update();
75 ShowCursor( true );
76 m_pView->NotifyScrolled();
80 void IconViewImpl::PageDown( sal_uInt16 nDelta )
82 sal_uInt16 nRealDelta = nDelta * m_pView->GetColumnsCount();
84 if( !nDelta )
85 return;
87 if (!m_pStartEntry)
88 return;
90 SvTreeListEntry* pNext = m_pView->NextVisible(m_pStartEntry, nRealDelta);
91 if( pNext == m_pStartEntry )
92 return;
94 ShowCursor( false );
96 m_nFlags &= ~LBoxFlags::Filling;
97 m_pView->Update();
98 m_pStartEntry = pNext;
100 if( nRealDelta >= m_nVisibleCount )
102 m_pView->Invalidate( GetVisibleArea() );
103 m_pView->Update();
105 else
107 tools::Rectangle aArea( GetVisibleArea() );
108 long nScroll = m_pView->GetEntryHeight() * static_cast<long>(nRealDelta);
109 nScroll = -nScroll;
110 m_pView->Update();
111 m_pView->Scroll( 0, nScroll, aArea, ScrollFlags::NoChildren );
112 m_pView->Update();
113 m_pView->NotifyScrolled();
116 ShowCursor( true );
119 void IconViewImpl::PageUp( sal_uInt16 nDelta )
121 sal_uInt16 nRealDelta = nDelta * m_pView->GetColumnsCount();
122 if( !nDelta )
123 return;
125 if (!m_pStartEntry)
126 return;
128 SvTreeListEntry* pPrev = m_pView->PrevVisible(m_pStartEntry, nRealDelta);
129 if( pPrev == m_pStartEntry )
130 return;
132 m_nFlags &= ~LBoxFlags::Filling;
133 ShowCursor( false );
135 m_pView->Update();
136 m_pStartEntry = pPrev;
137 if( nRealDelta >= m_nVisibleCount )
139 m_pView->Invalidate( GetVisibleArea() );
140 m_pView->Update();
142 else
144 long nEntryHeight = m_pView->GetEntryHeight();
145 tools::Rectangle aArea( GetVisibleArea() );
146 m_pView->Update();
147 m_pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, ScrollFlags::NoChildren );
148 m_pView->Update();
149 m_pView->NotifyScrolled();
152 ShowCursor( true );
155 void IconViewImpl::KeyDown( bool bPageDown )
157 if( !m_aVerSBar->IsVisible() )
158 return;
160 long nDelta;
161 if( bPageDown )
162 nDelta = m_aVerSBar->GetPageSize();
163 else
164 nDelta = 1;
166 long nThumbPos = m_aVerSBar->GetThumbPos();
168 if( nDelta <= 0 )
169 return;
171 m_nFlags &= ~LBoxFlags::Filling;
172 BeginScroll();
174 m_aVerSBar->SetThumbPos( nThumbPos+nDelta );
175 if( bPageDown )
176 PageDown( static_cast<short>(nDelta) );
177 else
178 CursorDown();
180 EndScroll();
183 void IconViewImpl::KeyUp( bool bPageUp )
185 if( !m_aVerSBar->IsVisible() )
186 return;
188 long nDelta;
189 if( bPageUp )
190 nDelta = m_aVerSBar->GetPageSize();
191 else
192 nDelta = 1;
194 long nThumbPos = m_aVerSBar->GetThumbPos();
196 if( nThumbPos < nDelta )
197 nDelta = nThumbPos;
199 if( nDelta < 0 )
200 return;
202 m_nFlags &= ~LBoxFlags::Filling;
203 BeginScroll();
205 m_aVerSBar->SetThumbPos( nThumbPos - nDelta );
206 if( bPageUp )
207 PageUp( static_cast<short>(nDelta) );
208 else
209 CursorUp();
211 EndScroll();
214 long IconViewImpl::GetEntryLine( SvTreeListEntry* pEntry ) const
216 if(!m_pStartEntry )
217 return -1; // invisible position
219 long nFirstVisPos = m_pView->GetVisiblePos( m_pStartEntry );
220 long nEntryVisPos = m_pView->GetVisiblePos( pEntry );
221 nFirstVisPos = nEntryVisPos - nFirstVisPos;
223 return nFirstVisPos;
226 Point IconViewImpl::GetEntryPosition( SvTreeListEntry* pEntry ) const
228 const int pos = m_pView->GetAbsPos( pEntry );
230 return Point( ( pos % m_pView->GetColumnsCount() ) * m_pView->GetEntryWidth(),
231 ( pos / m_pView->GetColumnsCount() ) * m_pView->GetEntryHeight() );
234 SvTreeListEntry* IconViewImpl::GetClickedEntry( const Point& rPoint ) const
236 DBG_ASSERT( m_pView->GetModel(), "IconViewImpl::GetClickedEntry: how can this ever happen?" );
237 if ( !m_pView->GetModel() )
238 return nullptr;
239 if( m_pView->GetEntryCount() == 0 || !m_pStartEntry || !m_pView->GetEntryHeight() || !m_pView->GetEntryWidth())
240 return nullptr;
242 sal_uInt16 nY = static_cast<sal_uInt16>(rPoint.Y() / m_pView->GetEntryHeight() );
243 sal_uInt16 nX = static_cast<sal_uInt16>(rPoint.X() / m_pView->GetEntryWidth() );
244 sal_uInt16 nTemp = nY * m_pView->GetColumnsCount() + nX;
246 SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp);
248 return pEntry;
251 bool IconViewImpl::IsEntryInView( SvTreeListEntry* pEntry ) const
253 // parent collapsed
254 if( !m_pView->IsEntryVisible(pEntry) )
255 return false;
257 long nY = GetEntryLine( pEntry ) / m_pView->GetColumnsCount() * m_pView->GetEntryHeight();
258 if( nY < 0 )
259 return false;
261 long nMax = m_nVisibleCount / m_pView->GetColumnsCount() * m_pView->GetEntryHeight();
262 if( nY >= nMax )
263 return false;
265 long nStart = GetEntryLine( pEntry ) - GetEntryLine( m_pStartEntry );
266 return nStart >= 0;
269 void IconViewImpl::AdjustScrollBars( Size& rSize )
271 long nEntryHeight = m_pView->GetEntryHeight();
272 if( !nEntryHeight )
273 return;
275 sal_uInt16 nResult = 0;
277 Size aOSize( m_pView->Control::GetOutputSizePixel() );
279 const WinBits nWindowStyle = m_pView->GetStyle();
280 bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0;
282 // number of entries that are not collapsed
283 sal_uLong nTotalCount = m_pView->GetVisibleCount();
285 // number of entries visible within the view
286 m_nVisibleCount = aOSize.Height() / nEntryHeight * m_pView->GetColumnsCount();
288 long nRows = ( nTotalCount / m_pView->GetColumnsCount() ) + 1;
290 // do we need a vertical scrollbar?
291 if( bVerSBar || nTotalCount > m_nVisibleCount )
293 nResult = 1;
296 PositionScrollBars( aOSize, nResult );
298 // adapt Range, VisibleRange etc.
300 // refresh output size, in case we have to scroll
301 tools::Rectangle aRect;
302 aRect.SetSize( aOSize );
303 m_aSelEng.SetVisibleArea( aRect );
305 // vertical scrollbar
306 if( !m_bInVScrollHdl )
308 m_aVerSBar->SetPageSize( nTotalCount );
309 m_aVerSBar->SetVisibleSize( nTotalCount - nRows );
311 else
313 m_nFlags |= LBoxFlags::EndScrollSetVisSize;
316 if( nResult & 0x0001 )
317 m_aVerSBar->Show();
318 else
319 m_aVerSBar->Hide();
321 rSize = aOSize;
324 // returns 0 if position is just past the last entry
325 SvTreeListEntry* IconViewImpl::GetEntry( const Point& rPoint ) const
327 if( (m_pView->GetEntryCount() == 0) || !m_pStartEntry ||
328 (rPoint.Y() > m_aOutputSize.Height())
329 || !m_pView->GetEntryHeight()
330 || !m_pView->GetEntryWidth())
331 return nullptr;
333 sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / m_pView->GetEntryHeight() * m_pView->GetColumnsCount() + rPoint.X() / m_pView->GetEntryWidth() );
334 sal_uInt16 nTemp = nClickedEntry;
335 SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp);
336 if( nTemp != nClickedEntry )
337 pEntry = nullptr;
338 return pEntry;
341 void IconViewImpl::SyncVerThumb()
343 if( m_pStartEntry )
345 long nEntryPos = m_pView->GetVisiblePos( m_pStartEntry );
346 m_aVerSBar->SetThumbPos( nEntryPos );
348 else
349 m_aVerSBar->SetThumbPos( 0 );
352 void IconViewImpl::UpdateAll( bool bInvalidateCompleteView )
354 FindMostRight( nullptr );
355 m_aVerSBar->SetRange( Range( 0, m_pView->GetVisibleCount() ) );
356 SyncVerThumb();
357 FillView();
358 ShowVerSBar();
359 if( m_bSimpleTravel && m_pCursor && m_pView->HasFocus() )
360 m_pView->Select( m_pCursor );
361 ShowCursor( true );
362 if( bInvalidateCompleteView )
363 m_pView->Invalidate();
364 else
365 m_pView->Invalidate( GetVisibleArea() );
368 void IconViewImpl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
370 if (!m_pView->GetVisibleCount())
371 return;
373 m_nFlags |= LBoxFlags::InPaint;
375 if (m_nFlags & LBoxFlags::Filling)
377 SvTreeListEntry* pFirst = m_pView->First();
378 if (pFirst != m_pStartEntry)
380 ShowCursor(false);
381 m_pStartEntry = m_pView->First();
382 m_aVerSBar->SetThumbPos( 0 );
383 StopUserEvent();
384 ShowCursor(true);
385 m_nCurUserEvent = Application::PostUserEvent(LINK(this, SvImpLBox, MyUserEvent),
386 reinterpret_cast<void*>(1));
387 return;
391 if (!m_pStartEntry)
393 m_pStartEntry = m_pView->First();
396 long nRectHeight = rRect.GetHeight();
397 long nRectWidth = rRect.GetWidth();
398 long nEntryHeight = m_pView->GetEntryHeight();
399 long nEntryWidth = m_pView->GetEntryWidth();
401 // calculate area for the entries we want to draw
402 sal_uInt16 nStartId = static_cast<sal_uInt16>(rRect.Top() / nEntryHeight * m_pView->GetColumnsCount() + (rRect.Left() / nEntryWidth));
403 sal_uInt16 nCount = static_cast<sal_uInt16>(( nRectHeight / nEntryHeight + 1 ) * nRectWidth / nEntryWidth);
404 nCount += 2; // don't miss an entry
406 long nY = nStartId / m_pView->GetColumnsCount() * nEntryHeight;
407 long nX = 0;
408 SvTreeListEntry* pEntry = m_pStartEntry;
409 while (nStartId && pEntry)
411 pEntry = m_pView->NextVisible(pEntry);
412 nStartId--;
415 vcl::Region aClipRegion(GetClipRegionRect());
417 if (!m_pCursor && !mbNoAutoCurEntry)
419 // do not select if multiselection or explicit set
420 bool bNotSelect = (m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) || ((m_nStyle & WB_NOINITIALSELECTION) == WB_NOINITIALSELECTION);
421 SetCursor(m_pStartEntry, bNotSelect);
424 for(sal_uInt16 n = 0; n< nCount && pEntry; n++)
426 static_cast<IconView*>(m_pView.get())->PaintEntry(*pEntry, nX, nY, rRenderContext);
427 nX += nEntryWidth;
429 if(nX + m_pView->GetEntryWidth() > nEntryWidth * m_pView->GetColumnsCount())
431 nY += nEntryHeight;
432 nX = 0;
434 pEntry = m_pView->NextVisible(pEntry);
437 m_nFlags &= ~LBoxFlags::DeselectAll;
438 rRenderContext.SetClipRegion();
439 m_nFlags &= ~LBoxFlags::InPaint;
442 void IconViewImpl::InvalidateEntry( long nId ) const
444 if( m_nFlags & LBoxFlags::InPaint )
445 return;
447 tools::Rectangle aRect( GetVisibleArea() );
448 long nMaxBottom = aRect.Bottom();
449 aRect.SetTop( nId / m_pView->GetColumnsCount() * m_pView->GetEntryHeight() );
450 aRect.SetBottom( aRect.Top() ); aRect.AdjustBottom(m_pView->GetEntryHeight() );
452 if( aRect.Top() > nMaxBottom )
453 return;
454 if( aRect.Bottom() > nMaxBottom )
455 aRect.SetBottom( nMaxBottom );
456 m_pView->Invalidate( aRect );
459 bool IconViewImpl::KeyInput( const KeyEvent& rKEvt )
461 const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
463 if( rKeyCode.IsMod2() )
464 return false; // don't evaluate Alt key
466 m_nFlags &= ~LBoxFlags::Filling;
468 if( !m_pCursor )
469 m_pCursor = m_pStartEntry;
470 if( !m_pCursor )
471 return false;
473 sal_uInt16 aCode = rKeyCode.GetCode();
475 bool bShift = rKeyCode.IsShift();
476 bool bMod1 = rKeyCode.IsMod1();
478 SvTreeListEntry* pNewCursor;
480 bool bHandled = true;
482 long i;
483 long nColumns = m_pView->GetColumnsCount();
485 switch( aCode )
487 case KEY_LEFT:
488 if( !IsEntryInView( m_pCursor ) )
489 MakeVisible( m_pCursor );
491 pNewCursor = m_pCursor;
494 pNewCursor = m_pView->PrevVisible(pNewCursor);
495 } while( pNewCursor && !IsSelectable(pNewCursor) );
497 // if there is no next entry, take the current one
498 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
499 // the cursor key
500 if (!pNewCursor)
501 pNewCursor = m_pCursor;
503 m_aSelEng.CursorPosChanging( bShift, bMod1 );
504 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
505 if( !IsEntryInView( pNewCursor ) )
506 KeyUp( false );
507 break;
509 case KEY_RIGHT:
510 if( !IsEntryInView( m_pCursor ) )
511 MakeVisible( m_pCursor );
513 pNewCursor = m_pCursor;
516 pNewCursor = m_pView->NextVisible(pNewCursor);
517 } while( pNewCursor && !IsSelectable(pNewCursor) );
519 // if there is no next entry, take the current one
520 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
521 // the cursor key
522 if ( !pNewCursor && m_pCursor )
523 pNewCursor = m_pCursor;
525 if( pNewCursor )
527 m_aSelEng.CursorPosChanging( bShift, bMod1 );
528 if( IsEntryInView( pNewCursor ) )
529 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
530 else
532 if( m_pCursor )
533 m_pView->Select( m_pCursor, false );
534 KeyDown( false );
535 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
538 else
539 KeyDown( false ); // because scrollbar range might still
540 // allow scrolling
541 break;
543 case KEY_UP:
545 if( !IsEntryInView( m_pCursor ) )
546 MakeVisible( m_pCursor );
548 pNewCursor = m_pCursor;
549 for( i = 0; i < nColumns && pNewCursor; i++)
553 pNewCursor = m_pView->PrevVisible(pNewCursor);
554 } while( pNewCursor && !IsSelectable(pNewCursor) );
557 // if there is no next entry, take the current one
558 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
559 // the cursor key
560 if ( !pNewCursor && m_pCursor )
561 pNewCursor = m_pCursor;
563 if( pNewCursor )
565 m_aSelEng.CursorPosChanging( bShift, bMod1 );
566 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
567 if( !IsEntryInView( pNewCursor ) )
568 KeyUp( false );
570 break;
573 case KEY_DOWN:
575 if( !IsEntryInView( m_pCursor ) )
576 MakeVisible( m_pCursor );
578 pNewCursor = m_pCursor;
579 for( i = 0; i < nColumns && pNewCursor; i++)
583 pNewCursor = m_pView->NextVisible(pNewCursor);
584 } while( pNewCursor && !IsSelectable(pNewCursor) );
587 // if there is no next entry, take the current one
588 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
589 // the cursor key
590 if ( !pNewCursor && m_pCursor )
591 pNewCursor = m_pCursor;
593 if( pNewCursor )
595 m_aSelEng.CursorPosChanging( bShift, bMod1 );
596 if( IsEntryInView( pNewCursor ) )
597 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
598 else
600 if( m_pCursor )
601 m_pView->Select( m_pCursor, false );
602 KeyDown( false );
603 SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
606 else
607 KeyDown( false ); // because scrollbar range might still
608 // allow scrolling
609 break;
612 case KEY_RETURN:
614 m_pView->aDoubleClickHdl.Call( m_pView );
615 bHandled = true;
617 break;
620 case KEY_END:
622 pNewCursor = m_pView->GetModel()->Last();
624 while( pNewCursor && !IsSelectable(pNewCursor) )
626 pNewCursor = m_pView->PrevVisible(pNewCursor);
629 m_pStartEntry = pNewCursor;
631 while( m_pStartEntry && m_pView->GetAbsPos( m_pStartEntry ) % m_pView->GetColumnsCount() != 0 )
633 m_pStartEntry = m_pView->PrevVisible(m_pStartEntry);
636 if( pNewCursor && pNewCursor != m_pCursor)
638 // SelAllDestrAnch( false );
639 m_aSelEng.CursorPosChanging( bShift, bMod1 );
640 SetCursor( pNewCursor );
641 SyncVerThumb();
644 bHandled = true;
646 break;
649 default:
651 bHandled = false;
652 break;
656 if(!bHandled)
657 return SvImpLBox::KeyInput( rKEvt );
659 return true;
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */