summaryrefslogtreecommitdiffstats
path: root/vcl/source/treelist/iconviewimpl.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /vcl/source/treelist/iconviewimpl.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/treelist/iconviewimpl.cxx')
-rw-r--r--vcl/source/treelist/iconviewimpl.cxx741
1 files changed, 741 insertions, 0 deletions
diff --git a/vcl/source/treelist/iconviewimpl.cxx b/vcl/source/treelist/iconviewimpl.cxx
new file mode 100644
index 000000000..6839ff1db
--- /dev/null
+++ b/vcl/source/treelist/iconviewimpl.cxx
@@ -0,0 +1,741 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+#include <vcl/toolkit/treelistentry.hxx>
+#include <tools/debug.hxx>
+#include <iconview.hxx>
+#include "iconviewimpl.hxx"
+
+IconViewImpl::IconViewImpl( SvTreeListBox* pTreeListBox, SvTreeList* pTreeList, WinBits nWinStyle )
+: SvImpLBox( pTreeListBox, pTreeList, nWinStyle )
+{
+}
+
+static bool IsSeparator(const SvTreeListEntry* entry)
+{
+ return entry && entry->GetFlags() & SvTLEntryFlags::IS_SEPARATOR;
+}
+
+Size IconViewImpl::GetEntrySize(const SvTreeListEntry& entry) const
+{
+ return static_cast<const IconView*>(m_pView.get())->GetEntrySize(entry);
+}
+
+void IconViewImpl::IterateVisibleEntryAreas(const IterateEntriesFunc& f, bool fromStartEntry) const
+{
+ tools::Long x = 0, y = 0;
+ short column = 0;
+ const tools::Long rowWidth = m_pView->GetEntryWidth() * m_pView->GetColumnsCount();
+ tools::Long nPrevHeight = 0;
+ for (auto entry = fromStartEntry ? m_pStartEntry : m_pView->FirstVisible(); entry;
+ entry = m_pView->NextVisible(entry))
+ {
+ const Size s = GetEntrySize(*entry);
+ if (x >= rowWidth || IsSeparator(entry))
+ {
+ column = 0;
+ x = 0;
+ y += nPrevHeight;
+ }
+ EntryAreaInfo info{ entry, column, tools::Rectangle{ Point{ x, y }, s } };
+ const auto result = f(info);
+ if (result == CallbackResult::Stop)
+ return;
+ ++column;
+ x += s.Width();
+ nPrevHeight = s.Height();
+ }
+}
+
+tools::Long IconViewImpl::GetEntryRow(const SvTreeListEntry* entry) const
+{
+ tools::Long nEntryRow = -1;
+ auto GetRow = [entry, &nEntryRow, row = -1](const EntryAreaInfo& info) mutable
+ {
+ if (info.column == 0 && !IsSeparator(info.entry))
+ ++row;
+ if (info.entry != entry)
+ return CallbackResult::Continue;
+ nEntryRow = row;
+ return CallbackResult::Stop;
+ };
+ IterateVisibleEntryAreas(GetRow);
+ return nEntryRow;
+}
+
+void IconViewImpl::SetStartEntry(SvTreeListEntry* entry)
+{
+ const tools::Long max = m_aVerSBar->GetRangeMax() - m_aVerSBar->GetVisibleSize();
+ tools::Long row = -1;
+ auto GetEntryAndRow = [&entry, &row, max, found = entry](const EntryAreaInfo& info) mutable
+ {
+ if (info.column == 0 && !IsSeparator(info.entry))
+ {
+ found = info.entry;
+ ++row;
+ }
+ if (row >= max || info.entry == entry)
+ {
+ entry = found;
+ return CallbackResult::Stop;
+ }
+ return CallbackResult::Continue;
+ };
+ IterateVisibleEntryAreas(GetEntryAndRow);
+
+ m_pStartEntry = entry;
+ m_aVerSBar->SetThumbPos(row);
+ m_pView->Invalidate(GetVisibleArea());
+}
+
+void IconViewImpl::ScrollTo(SvTreeListEntry* entry)
+{
+ if (!m_aVerSBar->IsVisible())
+ return;
+ const tools::Long entryRow = GetEntryRow(entry);
+ const tools::Long oldStartRow = m_aVerSBar->GetThumbPos();
+ if (entryRow < oldStartRow)
+ IconViewImpl::SetStartEntry(entry);
+ const tools::Long visibleRows = m_aVerSBar->GetVisibleSize();
+ const tools::Long posRelativeToBottom = entryRow - (oldStartRow + visibleRows) + 1;
+ if (posRelativeToBottom > 0)
+ IconViewImpl::SetStartEntry(GoToNextRow(m_pStartEntry, posRelativeToBottom));
+}
+
+SvTreeListEntry* IconViewImpl::GoToPrevRow(SvTreeListEntry* pEntry, int nRows) const
+{
+ SvTreeListEntry* pPrev = pEntry;
+ auto FindPrev = [this, pEntry, nRows, &pPrev,
+ prevs = std::vector<SvTreeListEntry*>()](const EntryAreaInfo& info) mutable
+ {
+ if (info.column == 0 && !IsSeparator(info.entry))
+ prevs.push_back(info.entry);
+ if (pEntry == info.entry)
+ {
+ if (prevs.size() > 1)
+ {
+ int i = std::max(0, static_cast<int>(prevs.size()) - nRows - 1);
+ pPrev = prevs[i];
+ for (short column = info.column; column; --column)
+ {
+ SvTreeListEntry* pNext = m_pView->NextVisible(pPrev);
+ if (!pNext || IsSeparator(pNext))
+ break;
+ pPrev = pNext;
+ }
+ }
+ return CallbackResult::Stop;
+ }
+ return CallbackResult::Continue;
+ };
+ IterateVisibleEntryAreas(FindPrev);
+
+ return pPrev;
+}
+
+SvTreeListEntry* IconViewImpl::GoToNextRow(SvTreeListEntry* pEntry, int nRows) const
+{
+ SvTreeListEntry* pNext = pEntry;
+ auto FindNext
+ = [pEntry, nRows, &pNext, column = -1](const EntryAreaInfo& info) mutable
+ {
+ if (info.column <= column && !IsSeparator(info.entry))
+ {
+ if (info.column == 0 && --nRows < 0)
+ return CallbackResult::Stop;
+ pNext = info.entry;
+ if (info.column == column && nRows == 0)
+ return CallbackResult::Stop;
+ }
+ else if (pEntry == info.entry)
+ {
+ column = info.column;
+ }
+ return CallbackResult::Continue;
+ };
+ IterateVisibleEntryAreas(FindNext);
+
+ return pNext;
+}
+
+void IconViewImpl::CursorUp()
+{
+ if (!m_pStartEntry)
+ return;
+
+ SvTreeListEntry* pPrevFirstToDraw = GoToPrevRow(m_pStartEntry, 1);
+
+ m_nFlags &= ~LBoxFlags::Filling;
+ ShowCursor( false );
+ SetStartEntry(pPrevFirstToDraw);
+ ShowCursor( true );
+ m_pView->NotifyScrolled();
+}
+
+void IconViewImpl::CursorDown()
+{
+ if (!m_pStartEntry)
+ return;
+
+ SvTreeListEntry* pNextFirstToDraw = GoToNextRow(m_pStartEntry, 1);
+
+ m_nFlags &= ~LBoxFlags::Filling;
+ ShowCursor( false );
+ SetStartEntry(pNextFirstToDraw);
+ ShowCursor( true );
+ m_pView->NotifyScrolled();
+}
+
+void IconViewImpl::PageDown( sal_uInt16 nDelta )
+{
+ if( !nDelta )
+ return;
+
+ if (!m_pStartEntry)
+ return;
+
+ SvTreeListEntry* pNext = GoToNextRow(m_pStartEntry, nDelta);
+
+ ShowCursor( false );
+
+ m_nFlags &= ~LBoxFlags::Filling;
+ SetStartEntry(pNext);
+
+ ShowCursor( true );
+}
+
+void IconViewImpl::PageUp( sal_uInt16 nDelta )
+{
+ if( !nDelta )
+ return;
+
+ if (!m_pStartEntry)
+ return;
+
+ SvTreeListEntry* pPrev = GoToPrevRow(m_pStartEntry, nDelta);
+
+ m_nFlags &= ~LBoxFlags::Filling;
+ ShowCursor( false );
+
+ SetStartEntry(pPrev);
+
+ ShowCursor( true );
+}
+
+void IconViewImpl::KeyDown( bool bPageDown )
+{
+ if( !m_aVerSBar->IsVisible() )
+ return;
+
+ tools::Long nDelta;
+ if( bPageDown )
+ nDelta = m_aVerSBar->GetPageSize();
+ else
+ nDelta = 1;
+
+ if( nDelta <= 0 )
+ return;
+
+ m_nFlags &= ~LBoxFlags::Filling;
+
+ if( bPageDown )
+ PageDown( static_cast<short>(nDelta) );
+ else
+ CursorDown();
+}
+
+void IconViewImpl::KeyUp( bool bPageUp )
+{
+ if( !m_aVerSBar->IsVisible() )
+ return;
+
+ tools::Long nDelta;
+ if( bPageUp )
+ nDelta = m_aVerSBar->GetPageSize();
+ else
+ nDelta = 1;
+
+ m_nFlags &= ~LBoxFlags::Filling;
+
+ if( bPageUp )
+ PageUp( static_cast<short>(nDelta) );
+ else
+ CursorUp();
+}
+
+tools::Long IconViewImpl::GetEntryLine(const SvTreeListEntry* pEntry) const
+{
+ if(!m_pStartEntry )
+ return -1; // invisible position
+
+ return IconViewImpl::GetEntryPosition(pEntry).Y();
+}
+
+Point IconViewImpl::GetEntryPosition(const SvTreeListEntry* pEntry) const
+{
+ Point result{ -m_pView->GetEntryWidth(), -m_pView->GetEntryHeight() }; // invisible
+ auto FindEntryPos = [pEntry, &result](const EntryAreaInfo& info)
+ {
+ if (pEntry == info.entry)
+ {
+ result = info.area.TopLeft();
+ return CallbackResult::Stop;
+ }
+ return CallbackResult::Continue;
+ };
+ IterateVisibleEntryAreas(FindEntryPos, true);
+
+ return result;
+}
+
+// Returns the last entry (in respective row) if position is just past the last entry
+SvTreeListEntry* IconViewImpl::GetClickedEntry( const Point& rPoint ) const
+{
+ DBG_ASSERT( m_pView->GetModel(), "IconViewImpl::GetClickedEntry: how can this ever happen?" );
+ if ( !m_pView->GetModel() )
+ return nullptr;
+ if( m_pView->GetEntryCount() == 0 || !m_pStartEntry || !m_pView->GetEntryHeight() || !m_pView->GetEntryWidth())
+ return nullptr;
+
+ SvTreeListEntry* pEntry = nullptr;
+ auto FindEntryByPos = [&pEntry, &rPoint](const EntryAreaInfo& info)
+ {
+ if (info.area.Contains(rPoint))
+ {
+ pEntry = info.entry;
+ return CallbackResult::Stop;
+ }
+ else if (info.area.Top() > rPoint.Y())
+ {
+ return CallbackResult::Stop; // we are already below the clicked row
+ }
+ else if (info.area.Bottom() > rPoint.Y())
+ {
+ pEntry = info.entry; // Same row; store the entry in case the click is past all entries
+ }
+ return CallbackResult::Continue;
+ };
+ IterateVisibleEntryAreas(FindEntryByPos, true);
+
+ return pEntry;
+}
+
+bool IconViewImpl::IsEntryInView( SvTreeListEntry* pEntry ) const
+{
+ // parent collapsed
+ if( !m_pView->IsEntryVisible(pEntry) )
+ return false;
+
+ tools::Long nY = GetEntryLine( pEntry );
+ if( nY < 0 )
+ return false;
+
+ tools::Long height = GetEntrySize(*pEntry).Height();
+ if (nY + height > m_aOutputSize.Height())
+ return false;
+
+ return true;
+}
+
+void IconViewImpl::AdjustScrollBars( Size& rSize )
+{
+ tools::Long nEntryHeight = m_pView->GetEntryHeight();
+ if( !nEntryHeight )
+ return;
+
+ sal_uInt16 nResult = 0;
+
+ Size aOSize( m_pView->Control::GetOutputSizePixel() );
+
+ const WinBits nWindowStyle = m_pView->GetStyle();
+ bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0;
+
+ // number of entries visible within the view
+ const tools::Long nVisibleRows = aOSize.Height() / nEntryHeight;
+ m_nVisibleCount = nVisibleRows * m_pView->GetColumnsCount();
+
+ tools::Long nTotalRows = 0;
+ tools::Long totalHeight = 0;
+ auto CountRowsAndHeight = [&nTotalRows, &totalHeight](const EntryAreaInfo& info)
+ {
+ totalHeight = std::max(totalHeight, info.area.Bottom());
+ if (info.column == 0 && !IsSeparator(info.entry))
+ ++nTotalRows;
+ return CallbackResult::Continue;
+ };
+ IterateVisibleEntryAreas(CountRowsAndHeight);
+
+ // do we need a vertical scrollbar?
+ if( bVerSBar || totalHeight > aOSize.Height())
+ {
+ nResult = 1;
+ }
+
+ // do we need a Horizontal scrollbar?
+ bool bHorSBar = (nWindowStyle & WB_HSCROLL) != 0;
+ if (bHorSBar || m_pView->GetEntryWidth() > aOSize.Width())
+ {
+ nResult += 2;
+ m_aHorSBar->SetRange(Range(0, m_pView->GetEntryWidth()));
+ m_aHorSBar->SetVisibleSize(aOSize.Width());
+ }
+
+ PositionScrollBars( aOSize, nResult );
+
+ // adapt Range, VisibleRange etc.
+
+ // refresh output size, in case we have to scroll
+ tools::Rectangle aRect;
+ aRect.SetSize( aOSize );
+ m_aSelEng.SetVisibleArea( aRect );
+
+ // vertical scrollbar
+ if( !m_bInVScrollHdl )
+ {
+ m_aVerSBar->SetRange(Range(0, nTotalRows));
+ m_aVerSBar->SetPageSize(nVisibleRows);
+ m_aVerSBar->SetVisibleSize(nVisibleRows);
+ }
+ else
+ {
+ m_nFlags |= LBoxFlags::EndScrollSetVisSize;
+ }
+
+ if( nResult & 0x0001 )
+ m_aVerSBar->Show();
+ else
+ m_aVerSBar->Hide();
+
+ if (nResult & 0x0002)
+ m_aHorSBar->Show();
+ else
+ m_aHorSBar->Hide();
+
+ rSize = aOSize;
+}
+
+// returns 0 if position is just past the last entry
+SvTreeListEntry* IconViewImpl::GetEntry( const Point& rPoint ) const
+{
+ if( (m_pView->GetEntryCount() == 0) || !m_pStartEntry ||
+ (rPoint.Y() > m_aOutputSize.Height())
+ || !m_pView->GetEntryHeight()
+ || !m_pView->GetEntryWidth())
+ return nullptr;
+
+ SvTreeListEntry* pEntry = nullptr;
+ auto FindEntryByPos = [&pEntry, &rPoint](const EntryAreaInfo& info)
+ {
+ if (info.area.Contains(rPoint))
+ {
+ pEntry = info.entry;
+ return CallbackResult::Stop;
+ }
+ else if (info.area.Top() > rPoint.Y())
+ {
+ return CallbackResult::Stop; // we are already below the clicked row
+ }
+ return CallbackResult::Continue;
+ };
+ IterateVisibleEntryAreas(FindEntryByPos, true);
+
+ return pEntry;
+}
+
+void IconViewImpl::SyncVerThumb()
+{
+ m_aVerSBar->SetThumbPos(GetEntryRow(m_pStartEntry));
+}
+
+void IconViewImpl::UpdateAll( bool bInvalidateCompleteView )
+{
+ FindMostRight();
+ SyncVerThumb();
+ FillView();
+ ShowVerSBar();
+ if( m_bSimpleTravel && m_pCursor && m_pView->HasFocus() )
+ m_pView->Select( m_pCursor );
+ ShowCursor( true );
+ if( bInvalidateCompleteView )
+ m_pView->Invalidate();
+ else
+ m_pView->Invalidate( GetVisibleArea() );
+}
+
+void IconViewImpl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ if (!m_pView->GetVisibleCount())
+ return;
+
+ m_nFlags |= LBoxFlags::InPaint;
+
+ if (m_nFlags & LBoxFlags::Filling)
+ {
+ SvTreeListEntry* pFirst = m_pView->First();
+ if (pFirst != m_pStartEntry)
+ {
+ ShowCursor(false);
+ m_pStartEntry = m_pView->First();
+ m_aVerSBar->SetThumbPos( 0 );
+ StopUserEvent();
+ ShowCursor(true);
+ m_nCurUserEvent = Application::PostUserEvent(LINK(this, SvImpLBox, MyUserEvent),
+ reinterpret_cast<void*>(1));
+ return;
+ }
+ }
+
+ if (!m_pStartEntry)
+ {
+ m_pStartEntry = m_pView->First();
+ }
+
+ if (!m_pCursor && !mbNoAutoCurEntry)
+ {
+ // do not select if multiselection or explicit set
+ bool bNotSelect = (m_aSelEng.GetSelectionMode() == SelectionMode::Multiple ) || ((m_nStyle & WB_NOINITIALSELECTION) == WB_NOINITIALSELECTION);
+ SetCursor(m_pStartEntry, bNotSelect);
+ }
+
+ auto PaintEntry = [iconView = static_cast<IconView*>(m_pView.get()), &rRect,
+ &rRenderContext](const EntryAreaInfo& info)
+ {
+ if (!info.area.GetIntersection(rRect).IsEmpty())
+ {
+ iconView->PaintEntry(*info.entry, info.area.Left(), info.area.Top(), rRenderContext);
+ }
+ else if (info.area.Top() > rRect.Bottom())
+ {
+ return CallbackResult::Stop; // we are already below the last visible row
+ }
+ return CallbackResult::Continue;
+ };
+ IterateVisibleEntryAreas(PaintEntry, true);
+
+ m_nFlags &= ~LBoxFlags::DeselectAll;
+ rRenderContext.SetClipRegion();
+ m_nFlags &= ~LBoxFlags::InPaint;
+}
+
+void IconViewImpl::InvalidateEntry( tools::Long nId ) const
+{
+ if( m_nFlags & LBoxFlags::InPaint )
+ return;
+ if (nId < 0)
+ return;
+
+ // nId is a Y coordinate of the top of the element, coming from GetEntryLine
+ tools::Rectangle aRect( GetVisibleArea() );
+ if (nId > aRect.Bottom())
+ return;
+ aRect.SetTop(nId); // Invalidate everything below
+ m_pView->Invalidate( aRect );
+}
+
+bool IconViewImpl::KeyInput( const KeyEvent& rKEvt )
+{
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+
+ if( rKeyCode.IsMod2() )
+ return false; // don't evaluate Alt key
+
+ m_nFlags &= ~LBoxFlags::Filling;
+
+ if( !m_pCursor )
+ m_pCursor = m_pStartEntry;
+ if( !m_pCursor )
+ return false;
+
+ sal_uInt16 aCode = rKeyCode.GetCode();
+
+ bool bShift = rKeyCode.IsShift();
+ bool bMod1 = rKeyCode.IsMod1();
+
+ SvTreeListEntry* pNewCursor;
+
+ bool bHandled = true;
+
+ switch( aCode )
+ {
+ case KEY_LEFT:
+ if( !IsEntryInView( m_pCursor ) )
+ MakeVisible( m_pCursor );
+
+ pNewCursor = m_pCursor;
+ do
+ {
+ pNewCursor = m_pView->PrevVisible(pNewCursor);
+ } while( pNewCursor && !IsSelectable(pNewCursor) );
+
+ // if there is no next entry, take the current one
+ // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
+ // the cursor key
+ if (!pNewCursor)
+ pNewCursor = m_pCursor;
+
+ m_aSelEng.CursorPosChanging( bShift, bMod1 );
+ SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
+ if( !IsEntryInView( pNewCursor ) )
+ KeyUp( false );
+ break;
+
+ case KEY_RIGHT:
+ if( !IsEntryInView( m_pCursor ) )
+ MakeVisible( m_pCursor );
+
+ pNewCursor = m_pCursor;
+ do
+ {
+ pNewCursor = m_pView->NextVisible(pNewCursor);
+ } while( pNewCursor && !IsSelectable(pNewCursor) );
+
+ // if there is no next entry, take the current one
+ // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
+ // the cursor key
+ if ( !pNewCursor && m_pCursor )
+ pNewCursor = m_pCursor;
+
+ if( pNewCursor )
+ {
+ m_aSelEng.CursorPosChanging( bShift, bMod1 );
+ if( IsEntryInView( pNewCursor ) )
+ SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
+ else
+ {
+ if( m_pCursor )
+ m_pView->Select( m_pCursor, false );
+ KeyDown( false );
+ SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
+ }
+ }
+ else
+ KeyDown( false ); // because scrollbar range might still
+ // allow scrolling
+ break;
+
+ case KEY_UP:
+ {
+ pNewCursor = GoToPrevRow(m_pCursor, 1);
+
+ if( pNewCursor )
+ {
+ m_aSelEng.CursorPosChanging( bShift, bMod1 );
+ SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl is on
+ ScrollTo(pNewCursor);
+ }
+ break;
+ }
+
+ case KEY_DOWN:
+ {
+ pNewCursor = GoToNextRow(m_pCursor, 1);
+
+ if( pNewCursor )
+ {
+ m_aSelEng.CursorPosChanging( bShift, bMod1 );
+ ScrollTo(pNewCursor);
+ SetCursor(pNewCursor, bMod1); // no selection, when Ctrl is on
+ }
+ else
+ KeyDown( false ); // because scrollbar range might still
+ // allow scrolling
+ break;
+ }
+
+ case KEY_PAGEUP:
+ if (!bMod1)
+ {
+ const sal_uInt16 nDelta = m_aVerSBar->GetPageSize();
+ pNewCursor = GoToPrevRow(m_pCursor, nDelta);
+
+ if (pNewCursor)
+ {
+ m_aSelEng.CursorPosChanging(bShift, bMod1);
+ ScrollTo(pNewCursor);
+ SetCursor(pNewCursor);
+ }
+ }
+ else
+ bHandled = false;
+ break;
+
+ case KEY_PAGEDOWN:
+ if (!bMod1)
+ {
+ const sal_uInt16 nDelta = m_aVerSBar->GetPageSize();
+ pNewCursor = GoToNextRow(m_pCursor, nDelta);
+
+ if (pNewCursor)
+ {
+ m_aSelEng.CursorPosChanging(bShift, bMod1);
+ ScrollTo(pNewCursor);
+ SetCursor(pNewCursor);
+ }
+ else
+ KeyDown(false);
+ }
+ else
+ bHandled = false;
+ break;
+
+ case KEY_RETURN:
+ case KEY_SPACE:
+ {
+ bHandled = !m_pView->aDoubleClickHdl.Call(m_pView);
+ break;
+ }
+
+ case KEY_END:
+ {
+ pNewCursor = m_pView->GetModel()->Last();
+
+ while( pNewCursor && !IsSelectable(pNewCursor) )
+ {
+ pNewCursor = m_pView->PrevVisible(pNewCursor);
+ }
+
+ SetStartEntry(pNewCursor);
+
+ if( pNewCursor && pNewCursor != m_pCursor)
+ {
+// SelAllDestrAnch( false );
+ m_aSelEng.CursorPosChanging( bShift, bMod1 );
+ SetCursor( pNewCursor );
+ }
+
+ bHandled = true;
+
+ break;
+ }
+
+ default:
+ {
+ bHandled = false;
+ break;
+ }
+ }
+
+ if(!bHandled)
+ return SvImpLBox::KeyInput( rKEvt );
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */