/* -*- 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 <sal/log.hxx>
#include <o3tl/safeint.hxx>
#include <osl/diagnose.h>
#include <tools/debug.hxx>
#include <svtools/brwbox.hxx>
#include <svtools/brwhead.hxx>
#include <svtools/colorcfg.hxx>
#include <svtools/scrolladaptor.hxx>
#include "datwin.hxx"
#include <vcl/commandevent.hxx>
#include <vcl/help.hxx>
#include <vcl/ptrstyle.hxx>
#include <vcl/settings.hxx>
#include <tools/multisel.hxx>
#include <tools/fract.hxx>
#include <algorithm>
#include <memory>
using namespace ::com::sun::star::datatransfer;
void BrowseBox::StartDrag( sal_Int8 /* _nAction */, const Point& /* _rPosPixel */ )
{
// not interested in this event
}
sal_Int8 BrowseBox::AcceptDrop( const AcceptDropEvent& _rEvt )
{
AcceptDropEvent aTransformed( _rEvt );
aTransformed.maPosPixel = pDataWin->ScreenToOutputPixel( OutputToScreenPixel( _rEvt.maPosPixel ) );
return pDataWin->AcceptDrop( aTransformed );
}
sal_Int8 BrowseBox::ExecuteDrop( const ExecuteDropEvent& _rEvt )
{
ExecuteDropEvent aTransformed( _rEvt );
aTransformed.maPosPixel = pDataWin->ScreenToOutputPixel( OutputToScreenPixel( _rEvt.maPosPixel ) );
return pDataWin->ExecuteDrop( aTransformed );
}
sal_Int8 BrowseBox::AcceptDrop( const BrowserAcceptDropEvent& )
{
// not interested in this event
return DND_ACTION_NONE;
}
sal_Int8 BrowseBox::ExecuteDrop( const BrowserExecuteDropEvent& )
{
// not interested in this event
return DND_ACTION_NONE;
}
const DataFlavorExVector& BrowseBox::GetDataFlavors() const
{
if (pDataWin->bCallingDropCallback)
return pDataWin->GetDataFlavorExVector();
return GetDataFlavorExVector();
}
bool BrowseBox::IsDropFormatSupported( SotClipboardFormatId _nFormat ) const
{
if ( pDataWin->bCallingDropCallback )
return pDataWin->IsDropFormatSupported( _nFormat );
return DropTargetHelper::IsDropFormatSupported( _nFormat );
}
void BrowseBox::Command( const CommandEvent& rEvt )
{
if ( !pDataWin->bInCommand )
Control::Command( rEvt );
}
void BrowseBox::StateChanged( StateChangedType nStateChange )
{
Control::StateChanged( nStateChange );
if ( StateChangedType::Mirroring == nStateChange )
{
pDataWin->EnableRTL( IsRTLEnabled() );
HeaderBar* pHeaderBar = pDataWin->pHeaderBar;
if ( pHeaderBar )
pHeaderBar->EnableRTL( IsRTLEnabled() );
aHScroll->EnableRTL( IsRTLEnabled() );
if( pVScroll )
pVScroll->EnableRTL( IsRTLEnabled() );
Resize();
}
else if ( StateChangedType::InitShow == nStateChange )
{
bBootstrapped = true; // must be set first!
Resize();
if ( bMultiSelection )
uRow.pSel->SetTotalRange( Range( 0, nRowCount - 1 ) );
if ( nRowCount == 0 )
nCurRow = BROWSER_ENDOFSELECTION;
else if ( nCurRow == BROWSER_ENDOFSELECTION )
nCurRow = 0;
if ( HasFocus() )
{
bSelectionIsVisible = true;
bHasFocus = true;
}
UpdateScrollbars();
AutoSizeLastColumn();
CursorMoved();
}
else if (StateChangedType::Zoom == nStateChange)
{
pDataWin->SetZoom(GetZoom());
HeaderBar* pHeaderBar = pDataWin->pHeaderBar;
if (pHeaderBar)
pHeaderBar->SetZoom(GetZoom());
// let the columns calculate their new widths and adjust the header bar
for (auto & pCol : mvCols)
{
pCol->ZoomChanged(GetZoom());
if ( pHeaderBar )
pHeaderBar->SetItemSize( pCol->GetId(), pCol->Width() );
}
// all our controls have to be repositioned
Resize();
}
else if (StateChangedType::Enable == nStateChange)
{
// do we have a handle column?
bool bHandleCol = !mvCols.empty() && (0 == mvCols[ 0 ]->GetId());
// do we have a header bar?
bool bHeaderBar(pDataWin->pHeaderBar);
if ( nTitleLines
&& ( !bHeaderBar
|| bHandleCol
)
)
// we draw the text in our header bar in a color dependent on the enabled state. So if this state changed
// -> redraw
Invalidate(tools::Rectangle(Point(0, 0), Size(GetOutputSizePixel().Width(), GetTitleHeight() - 1)));
}
}
void BrowseBox::Select()
{
}
void BrowseBox::DoubleClick( const BrowserMouseEvent & )
{
}
tools::Long BrowseBox::QueryMinimumRowHeight()
{
return CalcZoom( 5 );
}
void BrowseBox::ImplStartTracking()
{
}
void BrowseBox::ImplEndTracking()
{
}
void BrowseBox::RowHeightChanged()
{
}
void BrowseBox::ColumnResized( sal_uInt16 )
{
}
void BrowseBox::ColumnMoved( sal_uInt16 )
{
}
void BrowseBox::StartScroll()
{
DoHideCursor();
}
void BrowseBox::EndScroll()
{
UpdateScrollbars();
AutoSizeLastColumn();
DoShowCursor();
}
void BrowseBox::ToggleSelection()
{
// selection highlight-toggling allowed?
if ( bHideSelect )
return;
if ( bNotToggleSel || !IsUpdateMode() || !bSelectionIsVisible )
return;
// only highlight painted areas!
bNotToggleSel = true;
// accumulate areas of rows to highlight
std::vector<tools::Rectangle> aHighlightList;
sal_Int32 nLastRowInRect = 0; // for the CFront
// don't highlight handle column
BrowserColumn *pFirstCol = mvCols.empty() ? nullptr : mvCols[ 0 ].get();
tools::Long nOfsX = (!pFirstCol || pFirstCol->GetId()) ? 0 : pFirstCol->Width();
// accumulate old row selection
sal_Int32 nBottomRow = nTopRow +
pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight();
if ( nBottomRow > GetRowCount() && GetRowCount() )
nBottomRow = GetRowCount();
for ( sal_Int32 nRow = bMultiSelection ? uRow.pSel->FirstSelected() : uRow.nSel;
nRow != BROWSER_ENDOFSELECTION && nRow <= nBottomRow;
nRow = bMultiSelection ? uRow.pSel->NextSelected() : BROWSER_ENDOFSELECTION )
{
if ( nRow < nTopRow )
continue;
tools::Rectangle aAddRect(
Point( nOfsX, (nRow-nTopRow)*GetDataRowHeight() ),
Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) );
if ( !aHighlightList.empty() && nLastRowInRect == ( nRow - 1 ) )
aHighlightList[ 0 ].Union( aAddRect );
else
aHighlightList.emplace( aHighlightList.begin(), aAddRect );
nLastRowInRect = nRow;
}
// unhighlight the old selection (if any)
while ( !aHighlightList.empty() )
{
pDataWin->Invalidate( aHighlightList.back() );
aHighlightList.pop_back();
}
// unhighlight old column selection (if any)
for ( tools::Long nColId = pColSel ? pColSel->FirstSelected() : BROWSER_ENDOFSELECTION;
nColId != BROWSER_ENDOFSELECTION;
nColId = pColSel->NextSelected() )
{
tools::Rectangle aRect( GetFieldRectPixel(nCurRow,
mvCols[ nColId ]->GetId(),
false ) );
aRect.AdjustLeft( -(MIN_COLUMNWIDTH) );
aRect.AdjustRight(MIN_COLUMNWIDTH );
aRect.SetTop( 0 );
aRect.SetBottom( pDataWin->GetOutputSizePixel().Height() );
pDataWin->Invalidate( aRect );
}
bNotToggleSel = false;
}
void BrowseBox::DrawCursor()
{
bool bReallyHide = false;
if ( bHideCursor == TRISTATE_INDET )
{
if ( !GetSelectRowCount() && !GetSelectColumnCount() )
bReallyHide = true;
}
else if ( bHideCursor == TRISTATE_TRUE )
{
bReallyHide = true;
}
bReallyHide |= !bSelectionIsVisible || !IsUpdateMode() || bScrolling || nCurRow < 0;
if (PaintCursorIfHiddenOnce())
bReallyHide |= ( GetCursorHideCount() > 1 );
else
bReallyHide |= ( GetCursorHideCount() > 0 );
// no cursor on handle column
if ( nCurColId == HandleColumnId )
nCurColId = GetColumnId(1);
// calculate cursor rectangle
tools::Rectangle aCursor;
if ( bColumnCursor )
{
aCursor = GetFieldRectPixel( nCurRow, nCurColId, false );
aCursor.AdjustLeft( -(MIN_COLUMNWIDTH) );
aCursor.AdjustRight(1 );
aCursor.AdjustBottom(1 );
}
else
aCursor = tools::Rectangle(
Point( ( !mvCols.empty() && mvCols[ 0 ]->GetId() == 0 ) ?
mvCols[ 0 ]->Width() : 0,
(nCurRow - nTopRow) * GetDataRowHeight() + 1 ),
Size( pDataWin->GetOutputSizePixel().Width() + 1,
GetDataRowHeight() - 2 ) );
if ( bHLines )
{
if ( !bMultiSelection )
aCursor.AdjustTop( -1 );
aCursor.AdjustBottom( -1 );
}
if (m_aCursorColor == COL_TRANSPARENT)
{
// on these platforms, the StarView focus works correctly
if ( bReallyHide )
static_cast<Control*>(pDataWin.get())->HideFocus();
else
static_cast<Control*>(pDataWin.get())->ShowFocus( aCursor );
}
else
{
Color rCol = bReallyHide ? pDataWin->GetOutDev()->GetFillColor() : m_aCursorColor;
Color aOldFillColor = pDataWin->GetOutDev()->GetFillColor();
Color aOldLineColor = pDataWin->GetOutDev()->GetLineColor();
pDataWin->GetOutDev()->SetFillColor();
pDataWin->GetOutDev()->SetLineColor( rCol );
pDataWin->GetOutDev()->DrawRect( aCursor );
pDataWin->GetOutDev()->SetLineColor( aOldLineColor );
pDataWin->GetOutDev()->SetFillColor( aOldFillColor );
}
}
tools::Long BrowseBox::GetColumnWidth( sal_uInt16 nId ) const
{
sal_uInt16 nItemPos = GetColumnPos( nId );
if ( nItemPos >= mvCols.size() )
return 0;
return mvCols[ nItemPos ]->Width();
}
sal_uInt16 BrowseBox::GetColumnId( sal_uInt16 nPos ) const
{
if ( nPos >= mvCols.size() )
return BROWSER_INVALIDID;
return mvCols[ nPos ]->GetId();
}
sal_uInt16 BrowseBox::GetColumnPos( sal_uInt16 nId ) const
{
for ( size_t nPos = 0; nPos < mvCols.size(); ++nPos )
if ( mvCols[ nPos ]->GetId() == nId )
return nPos;
return BROWSER_INVALIDID;
}
bool BrowseBox::IsFrozen( sal_uInt16 nColumnId ) const
{
for (auto const & pCol : mvCols)
if ( pCol->GetId() == nColumnId )
return pCol->IsFrozen();
return false;
}
void BrowseBox::ExpandRowSelection( const BrowserMouseEvent& rEvt )
{
DoHideCursor();
// expand the last selection
if ( bMultiSelection )
{
Range aJustifiedRange( aSelRange );
aJustifiedRange.Normalize();
bool bSelectThis = ( bSelect != aJustifiedRange.Contains( rEvt.GetRow() ) );
if ( aJustifiedRange.Contains( rEvt.GetRow() ) )
{
// down and up
while ( rEvt.GetRow() < aSelRange.Max() )
{ // ZTC/Mac bug - don't put these statements together!
SelectRow( aSelRange.Max(), bSelectThis );
--aSelRange.Max();
}
while ( rEvt.GetRow() > aSelRange.Max() )
{ // ZTC/Mac bug - don't put these statements together!
SelectRow( aSelRange.Max(), bSelectThis );
++aSelRange.Max();
}
}
else
{
// up and down
bool bOldSelecting = bSelecting;
bSelecting = true;
while ( rEvt.GetRow() < aSelRange.Max() )
{ // ZTC/Mac bug - don't put these statements together!
--aSelRange.Max();
if ( !IsRowSelected( aSelRange.Max() ) )
{
SelectRow( aSelRange.Max(), bSelectThis );
bSelect = true;
}
}
while ( rEvt.GetRow() > aSelRange.Max() )
{ // ZTC/Mac bug - don't put these statements together!
++aSelRange.Max();
if ( !IsRowSelected( aSelRange.Max() ) )
{
SelectRow( aSelRange.Max(), bSelectThis );
bSelect = true;
}
}
bSelecting = bOldSelecting;
if ( bSelect )
Select();
}
}
else
if (!IsRowSelected(rEvt.GetRow()))
SelectRow( rEvt.GetRow() );
GoToRow( rEvt.GetRow(), false );
DoShowCursor();
}
void BrowseBox::Resize()
{
if ( !bBootstrapped && IsReallyVisible() )
BrowseBox::StateChanged( StateChangedType::InitShow );
if ( mvCols.empty() )
{
pDataWin->bResizeOnPaint = true;
return;
}
pDataWin->bResizeOnPaint = false;
// calc the size of the scrollbars
tools::Long nSBHeight = GetBarHeight();
tools::Long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
if (IsZoom())
{
nSBHeight = static_cast<tools::Long>(nSBHeight * static_cast<double>(GetZoom()));
nSBWidth = static_cast<tools::Long>(nSBWidth * static_cast<double>(GetZoom()));
}
DoHideCursor();
sal_uInt16 nOldVisibleRows = 0;
//fdo#42694, post #i111125# GetDataRowHeight() can be 0
if (GetDataRowHeight())
nOldVisibleRows = static_cast<sal_uInt16>(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
// did we need a horizontal scroll bar or is there a Control Area?
if ( !pDataWin->bNoHScroll &&
( ( mvCols.size() - FrozenColCount() ) > 1 ) )
aHScroll->Show();
else
aHScroll->Hide();
// calculate the size of the data window
tools::Long nDataHeight = GetOutputSizePixel().Height() - GetTitleHeight();
if ( aHScroll->IsVisible() || ( nControlAreaWidth != USHRT_MAX ) )
nDataHeight -= nSBHeight;
tools::Long nDataWidth = GetOutputSizePixel().Width();
if ( pVScroll->IsVisible() )
nDataWidth -= nSBWidth;
// adjust position and size of data window
pDataWin->SetPosSizePixel(
Point( 0, GetTitleHeight() ),
Size( nDataWidth, nDataHeight ) );
sal_uInt16 nVisibleRows = 0;
if (GetDataRowHeight())
nVisibleRows = static_cast<sal_uInt16>(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
// TopRow is unchanged, but the number of visible lines has changed.
if ( nVisibleRows != nOldVisibleRows )
VisibleRowsChanged(nTopRow, nVisibleRows);
UpdateScrollbars();
// Control-Area
tools::Rectangle aInvalidArea( GetControlArea() );
aInvalidArea.SetRight( GetOutputSizePixel().Width() );
aInvalidArea.SetLeft( 0 );
Invalidate( aInvalidArea );
// external header-bar
HeaderBar* pHeaderBar = pDataWin->pHeaderBar;
if ( pHeaderBar )
{
// take the handle column into account
BrowserColumn *pFirstCol = mvCols[ 0 ].get();
tools::Long nOfsX = pFirstCol->GetId() ? 0 : pFirstCol->Width();
pHeaderBar->SetPosSizePixel( Point( nOfsX, 0 ), Size( GetOutputSizePixel().Width() - nOfsX, GetTitleHeight() ) );
}
AutoSizeLastColumn(); // adjust last column width
DoShowCursor();
}
void BrowseBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
{
// initializations
if (!bBootstrapped && IsReallyVisible())
BrowseBox::StateChanged(StateChangedType::InitShow);
if (mvCols.empty())
return;
BrowserColumn *pFirstCol = mvCols[ 0 ].get();
bool bHandleCol = pFirstCol && pFirstCol->GetId() == 0;
bool bHeaderBar(pDataWin->pHeaderBar);
// draw delimitational lines
if (!pDataWin->bNoHScroll)
rRenderContext.DrawLine(Point(0, aHScroll->GetPosPixel().Y()),
Point(GetOutputSizePixel().Width(),
aHScroll->GetPosPixel().Y()));
if (nTitleLines)
{
if (!bHeaderBar)
{
rRenderContext.DrawLine(Point(0, GetTitleHeight() - 1),
Point(GetOutputSizePixel().Width(), GetTitleHeight() - 1));
}
else if (bHandleCol)
{
rRenderContext.DrawLine(Point(0, GetTitleHeight() - 1),
Point(pFirstCol->Width(), GetTitleHeight() - 1));
}
}
// Title Bar
// If there is a handle column and if the header bar is available, only
// take the HandleColumn into account
if (!(nTitleLines && (!bHeaderBar || bHandleCol)))
return;
// iterate through columns to redraw
tools::Long nX = 0;
size_t nCol;
for (nCol = 0; nCol < mvCols.size() && nX < rRect.Right(); ++nCol)
{
// skip invisible columns between frozen and scrollable area
if (nCol < nFirstCol && !mvCols[nCol]->IsFrozen())
nCol = nFirstCol;
// only the handle column?
if (bHeaderBar && bHandleCol && nCol > 0)
break;
BrowserColumn* pCol = mvCols[nCol].get();
// draw the column and increment position
if ( pCol->Width() > 4 )
{
ButtonFrame aButtonFrame( Point( nX, 0 ),
Size( pCol->Width()-1, GetTitleHeight()-1 ),
pCol->Title(), !IsEnabled());
aButtonFrame.Draw(rRenderContext);
rRenderContext.DrawLine(Point(nX + pCol->Width() - 1, 0),
Point(nX + pCol->Width() - 1, GetTitleHeight() - 1));
}
else
{
rRenderContext.Push(vcl::PushFlags::FILLCOLOR);
rRenderContext.SetFillColor(COL_BLACK);
rRenderContext.DrawRect(tools::Rectangle(Point(nX, 0), Size(pCol->Width(), GetTitleHeight() - 1)));
rRenderContext.Pop();
}
// skip column
nX += pCol->Width();
}
// retouching
if ( !bHeaderBar && nCol == mvCols.size() )
{
const StyleSettings &rSettings = rRenderContext.GetSettings().GetStyleSettings();
Color aColFace(rSettings.GetFaceColor());
rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR);
rRenderContext.SetFillColor(aColFace);
rRenderContext.SetLineColor(aColFace);
rRenderContext.DrawRect(tools::Rectangle(Point(nX, 0),
Point(rRect.Right(), GetTitleHeight() - 2 )));
rRenderContext.Pop();
}
if (m_nActualCornerWidth)
{
const StyleSettings &rSettings = rRenderContext.GetSettings().GetStyleSettings();
Color aColFace(rSettings.GetFaceColor());
rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR);
rRenderContext.SetFillColor(aColFace);
rRenderContext.SetLineColor(aColFace);
rRenderContext.DrawRect(tools::Rectangle(Point(GetOutputSizePixel().Width() - m_nActualCornerWidth, aHScroll->GetPosPixel().Y()),
Size(m_nActualCornerWidth, m_nCornerHeight)));
rRenderContext.Pop();
}
}
void BrowseBox::Draw( OutputDevice* pDev, const Point& rPos, SystemTextColorFlags nFlags )
{
// we need pixel coordinates
Size aRealSize = GetSizePixel();
Point aRealPos = pDev->LogicToPixel(rPos);
if ((aRealSize.Width() < 3) || (aRealSize.Height() < 3))
// we want to have two pixels frame ...
return;
vcl::Font aFont = pDataWin->GetDrawPixelFont( pDev );
// the 'normal' painting uses always the data window as device to output to, so we have to calc the new font
// relative to the data wins current settings
pDev->Push();
pDev->SetMapMode();
pDev->SetFont( aFont );
if (nFlags & SystemTextColorFlags::Mono)
pDev->SetTextColor(COL_BLACK);
else
pDev->SetTextColor(pDataWin->GetTextColor());
// draw a frame
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
pDev->SetLineColor(rStyleSettings.GetDarkShadowColor());
pDev->DrawLine(Point(aRealPos.X(), aRealPos.Y()),
Point(aRealPos.X(), aRealPos.Y() + aRealSize.Height() - 1));
pDev->DrawLine(Point(aRealPos.X(), aRealPos.Y()),
Point(aRealPos.X() + aRealSize.Width() - 1, aRealPos.Y()));
pDev->SetLineColor(rStyleSettings.GetShadowColor());
pDev->DrawLine(Point(aRealPos.X() + aRealSize.Width() - 1, aRealPos.Y() + 1),
Point(aRealPos.X() + aRealSize.Width() - 1, aRealPos.Y() + aRealSize.Height() - 1));
pDev->DrawLine(Point(aRealPos.X() + aRealSize.Width() - 1, aRealPos.Y() + aRealSize.Height() - 1),
Point(aRealPos.X() + 1, aRealPos.Y() + aRealSize.Height() - 1));
HeaderBar* pBar = pDataWin->pHeaderBar;
// we're drawing onto a foreign device, so we have to fake the DataRowHeight for the subsequent ImplPaintData
// (as it is based on the settings of our data window, not the foreign device)
if (!m_nDataRowHeight)
ImpGetDataRowHeight();
tools::Long nHeightLogic = PixelToLogic(Size(0, m_nDataRowHeight), MapMode(MapUnit::Map10thMM)).Height();
tools::Long nForeignHeightPixel = pDev->LogicToPixel(Size(0, nHeightLogic), MapMode(MapUnit::Map10thMM)).Height();
tools::Long nOriginalHeight = m_nDataRowHeight;
m_nDataRowHeight = nForeignHeightPixel;
// this counts for the column widths, too
size_t nPos;
for ( nPos = 0; nPos < mvCols.size(); ++nPos )
{
BrowserColumn* pCurrent = mvCols[ nPos ].get();
tools::Long nWidthLogic = PixelToLogic(Size(pCurrent->Width(), 0), MapMode(MapUnit::Map10thMM)).Width();
tools::Long nForeignWidthPixel = pDev->LogicToPixel(Size(nWidthLogic, 0), MapMode(MapUnit::Map10thMM)).Width();
pCurrent->SetWidth(nForeignWidthPixel, GetZoom());
if ( pBar )
pBar->SetItemSize( pCurrent->GetId(), pCurrent->Width() );
}
// a smaller area for the content
aRealPos.AdjustX( 1 );
aRealPos.AdjustY( 1 );
aRealSize.AdjustWidth( -2 );
aRealSize.AdjustHeight( -2 );
// let the header bar draw itself
if ( pBar )
{
// the title height with respect to the font set for the given device
tools::Long nTitleHeight = PixelToLogic(Size(0, GetTitleHeight()), MapMode(MapUnit::Map10thMM)).Height();
nTitleHeight = pDev->LogicToPixel(Size(0, nTitleHeight), MapMode(MapUnit::Map10thMM)).Height();
BrowserColumn* pFirstCol = !mvCols.empty() ? mvCols[ 0 ].get() : nullptr;
Point aHeaderPos(pFirstCol && (pFirstCol->GetId() == 0) ? pFirstCol->Width() : 0, 0);
Size aHeaderSize(aRealSize.Width() - aHeaderPos.X(), nTitleHeight);
aHeaderPos += aRealPos;
// do this before converting to logics !
// the header's draw expects logic coordinates, again
aHeaderPos = pDev->PixelToLogic(aHeaderPos);
Size aOrigSize(pBar->GetSizePixel());
pBar->SetSizePixel(aHeaderSize);
pBar->Draw(pDev, aHeaderPos, nFlags);
pBar->SetSizePixel(aOrigSize);
// draw the "upper left cell" (the intersection between the header bar and the handle column)
if (pFirstCol && (pFirstCol->GetId() == 0) && (pFirstCol->Width() > 4))
{
ButtonFrame aButtonFrame( aRealPos,
Size( pFirstCol->Width()-1, nTitleHeight-1 ),
pFirstCol->Title(), !IsEnabled());
aButtonFrame.Draw( *pDev );
pDev->Push( vcl::PushFlags::LINECOLOR );
pDev->SetLineColor( COL_BLACK );
pDev->DrawLine( Point( aRealPos.X(), aRealPos.Y() + nTitleHeight-1 ),
Point( aRealPos.X() + pFirstCol->Width() - 1, aRealPos.Y() + nTitleHeight-1 ) );
pDev->DrawLine( Point( aRealPos.X() + pFirstCol->Width() - 1, aRealPos.Y() ),
Point( aRealPos.X() + pFirstCol->Width() - 1, aRealPos.Y() + nTitleHeight-1 ) );
pDev->Pop();
}
aRealPos.AdjustY(aHeaderSize.Height() );
aRealSize.AdjustHeight( -(aHeaderSize.Height()) );
}
// draw our own content (with clipping)
vcl::Region aRegion(tools::Rectangle(aRealPos, aRealSize));
pDev->SetClipRegion( pDev->PixelToLogic( aRegion ) );
// do we have to paint the background
bool bBackground = pDataWin->IsControlBackground();
if ( bBackground )
{
tools::Rectangle aRect( aRealPos, aRealSize );
pDev->SetFillColor( pDataWin->GetControlBackground() );
pDev->DrawRect( aRect );
}
ImplPaintData( *pDev, tools::Rectangle( aRealPos, aRealSize ), true );
// restore the column widths/data row height
m_nDataRowHeight = nOriginalHeight;
for ( nPos = 0; nPos < mvCols.size(); ++nPos )
{
BrowserColumn* pCurrent = mvCols[ nPos ].get();
tools::Long nForeignWidthLogic = pDev->PixelToLogic(Size(pCurrent->Width(), 0), MapMode(MapUnit::Map10thMM)).Width();
tools::Long nWidthPixel = LogicToPixel(Size(nForeignWidthLogic, 0), MapMode(MapUnit::Map10thMM)).Width();
pCurrent->SetWidth(nWidthPixel, GetZoom());
if ( pBar )
pBar->SetItemSize( pCurrent->GetId(), pCurrent->Width() );
}
pDev->Pop();
}
void BrowseBox::ImplPaintData(OutputDevice& _rOut, const tools::Rectangle& _rRect, bool _bForeignDevice)
{
Point aOverallAreaPos = _bForeignDevice ? _rRect.TopLeft() : Point(0,0);
Size aOverallAreaSize = _bForeignDevice ? _rRect.GetSize() : pDataWin->GetOutputSizePixel();
Point aOverallAreaBRPos = _bForeignDevice ? _rRect.BottomRight() : Point( aOverallAreaSize.Width(), aOverallAreaSize.Height() );
tools::Long nDataRowHeight = GetDataRowHeight();
// compute relative rows to redraw
sal_Int32 nRelTopRow = 0;
sal_Int32 nRelBottomRow = aOverallAreaSize.Height();
if (!_bForeignDevice && nDataRowHeight)
{
nRelTopRow = static_cast<sal_Int32>((_rRect.Top()) / nDataRowHeight);
nRelBottomRow = static_cast<sal_Int32>((_rRect.Bottom()) / nDataRowHeight);
}
// cache frequently used values
Point aPos( aOverallAreaPos.X(), nRelTopRow * nDataRowHeight + aOverallAreaPos.Y() );
_rOut.SetLineColor( COL_WHITE );
const AllSettings& rAllSets = _rOut.GetSettings();
const StyleSettings &rSettings = rAllSets.GetStyleSettings();
const Color &rHighlightTextColor = rSettings.GetHighlightTextColor();
const Color &rHighlightFillColor = rSettings.GetHighlightColor();
Color aOldTextColor = _rOut.GetTextColor();
Color aOldFillColor = _rOut.GetFillColor();
Color aOldLineColor = _rOut.GetLineColor();
tools::Long nHLineX = 0 == mvCols[ 0 ]->GetId() ? mvCols[ 0 ]->Width() : 0;
nHLineX += aOverallAreaPos.X();
Color aDelimiterLineColor( ::svtools::ColorConfig().GetColorValue( ::svtools::CALCGRID ).nColor );
// redraw the invalid fields
for ( sal_Int32 nRelRow = nRelTopRow;
nRelRow <= nRelBottomRow && nTopRow+nRelRow < nRowCount;
++nRelRow, aPos.AdjustY(nDataRowHeight ) )
{
// get row
// check valid area, to be on the safe side:
DBG_ASSERT( static_cast<sal_uInt16>(nTopRow+nRelRow) < nRowCount, "BrowseBox::ImplPaintData: invalid seek" );
if ( (nTopRow+tools::Long(nRelRow)) < 0 || static_cast<sal_uInt16>(nTopRow+nRelRow) >= nRowCount )
continue;
// prepare row
sal_Int32 nRow = nTopRow+nRelRow;
if ( !SeekRow( nRow) ) {
OSL_FAIL("BrowseBox::ImplPaintData: SeekRow failed");
}
_rOut.SetClipRegion();
aPos.setX( aOverallAreaPos.X() );
// #73325# don't paint the row outside the painting rectangle (DG)
// prepare auto-highlight
tools::Rectangle aRowRect( Point( _rRect.Left(), aPos.Y() ),
Size( _rRect.GetSize().Width(), nDataRowHeight ) );
bool bRowSelected = !bHideSelect
&& IsRowSelected( nRow );
if ( bRowSelected )
{
_rOut.SetTextColor( rHighlightTextColor );
_rOut.SetFillColor( rHighlightFillColor );
_rOut.SetLineColor();
_rOut.DrawRect( aRowRect );
}
// iterate through columns to redraw
size_t nCol;
for ( nCol = 0; nCol < mvCols.size(); ++nCol )
{
// get column
BrowserColumn *pCol = mvCols[ nCol ].get();
// at end of invalid area
if ( aPos.X() >= _rRect.Right() )
break;
// skip invisible columns between frozen and scrollable area
if ( nCol < nFirstCol && !pCol->IsFrozen() )
{
nCol = nFirstCol;
pCol = (nCol < mvCols.size() ) ? mvCols[ nCol ].get() : nullptr;
if (!pCol)
{ // FS - 21.05.99 - 66325
// actually this has been fixed elsewhere (in the right place),
// but let's make sure...
OSL_FAIL("BrowseBox::PaintData : nFirstCol is probably invalid !");
break;
}
}
// prepare Column-AutoHighlight
bool bColAutoHighlight = bColumnCursor
&& IsColumnSelected( pCol->GetId() );
if ( bColAutoHighlight )
{
_rOut.SetClipRegion();
_rOut.SetTextColor( rHighlightTextColor );
_rOut.SetFillColor( rHighlightFillColor );
_rOut.SetLineColor();
tools::Rectangle aFieldRect( aPos,
Size( pCol->Width(), nDataRowHeight ) );
_rOut.DrawRect( aFieldRect );
}
if (!m_bFocusOnlyCursor && (pCol->GetId() == GetCurColumnId()) && (nRow == GetCurRow()))
DrawCursor();
// draw a single field.
// else something is drawn to, e.g. handle column
if (pCol->Width())
{
// clip the column's output to the field area
if (_bForeignDevice)
{ // (not necessary if painting onto the data window)
Size aFieldSize(pCol->Width(), nDataRowHeight);
if (aPos.X() + aFieldSize.Width() > aOverallAreaBRPos.X())
aFieldSize.setWidth( aOverallAreaBRPos.X() - aPos.X() );
if (aPos.Y() + aFieldSize.Height() > aOverallAreaBRPos.Y() + 1)
{
// for non-handle cols we don't clip vertically : we just don't draw the cell if the line isn't completely visible
if (pCol->GetId() != 0)
continue;
aFieldSize.setHeight( aOverallAreaBRPos.Y() + 1 - aPos.Y() );
}
vcl::Region aClipToField(tools::Rectangle(aPos, aFieldSize));
_rOut.SetClipRegion(aClipToField);
}
pCol->Draw( *this, _rOut, aPos );
if (_bForeignDevice)
_rOut.SetClipRegion();
}
// reset Column-auto-highlight
if ( bColAutoHighlight )
{
_rOut.SetTextColor( aOldTextColor );
_rOut.SetFillColor( aOldFillColor );
_rOut.SetLineColor( aOldLineColor );
}
// skip column
aPos.AdjustX(pCol->Width() );
}
// reset auto-highlight
if ( bRowSelected )
{
_rOut.SetTextColor( aOldTextColor );
_rOut.SetFillColor( aOldFillColor );
_rOut.SetLineColor( aOldLineColor );
}
if ( bHLines )
{
// draw horizontal delimitation lines
_rOut.SetClipRegion();
_rOut.Push( vcl::PushFlags::LINECOLOR );
_rOut.SetLineColor( aDelimiterLineColor );
tools::Long nY = aPos.Y() + nDataRowHeight - 1;
if (nY <= aOverallAreaBRPos.Y())
_rOut.DrawLine( Point( nHLineX, nY ),
Point( bVLines
? std::min(tools::Long(aPos.X() - 1), aOverallAreaBRPos.X())
: aOverallAreaBRPos.X(),
nY ) );
_rOut.Pop();
}
}
if (aPos.Y() > aOverallAreaBRPos.Y() + 1)
aPos.setY( aOverallAreaBRPos.Y() + 1 );
// needed for some of the following drawing
// retouching
_rOut.SetClipRegion();
aOldLineColor = _rOut.GetLineColor();
aOldFillColor = _rOut.GetFillColor();
_rOut.SetFillColor( rSettings.GetFaceColor() );
if ( !mvCols.empty() && ( mvCols[ 0 ]->GetId() == 0 ) && ( aPos.Y() <= _rRect.Bottom() ) )
{
// fill rectangle gray below handle column
// DG: fill it only until the end of the drawing rect and not to the end, as this may overpaint handle columns
_rOut.SetLineColor( COL_BLACK );
_rOut.DrawRect( tools::Rectangle(
Point( aOverallAreaPos.X() - 1, aPos.Y() - 1 ),
Point( aOverallAreaPos.X() + mvCols[ 0 ]->Width() - 1,
_rRect.Bottom() + 1) ) );
}
_rOut.SetFillColor( aOldFillColor );
// draw vertical delimitational line between frozen and scrollable cols
_rOut.SetLineColor( COL_BLACK );
tools::Long nFrozenWidth = GetFrozenWidth()-1;
_rOut.DrawLine( Point( aOverallAreaPos.X() + nFrozenWidth, aPos.Y() ),
Point( aOverallAreaPos.X() + nFrozenWidth, bHLines
? aPos.Y() - 1
: aOverallAreaBRPos.Y() ) );
// draw vertical delimitational lines?
if ( bVLines )
{
_rOut.SetLineColor( aDelimiterLineColor );
Point aVertPos( aOverallAreaPos.X() - 1, aOverallAreaPos.Y() );
tools::Long nDeltaY = aOverallAreaBRPos.Y();
for ( size_t nCol = 0; nCol < mvCols.size(); ++nCol )
{
// get column
BrowserColumn *pCol = mvCols[ nCol ].get();
// skip invisible columns between frozen and scrollable area
if ( nCol < nFirstCol && !pCol->IsFrozen() )
{
nCol = nFirstCol;
pCol = mvCols[ nCol ].get();
}
// skip column
aVertPos.AdjustX(pCol->Width() );
// at end of invalid area
// invalid area is first reached when X > Right
// and not >=
if ( aVertPos.X() > _rRect.Right() )
break;
// draw a single line
if ( pCol->GetId() != 0 )
_rOut.DrawLine( aVertPos, Point( aVertPos.X(),
bHLines
? aPos.Y() - 1
: aPos.Y() + nDeltaY ) );
}
}
_rOut.SetLineColor( aOldLineColor );
}
void BrowseBox::PaintData( vcl::Window const & rWin, vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
{
if (!bBootstrapped && IsReallyVisible())
BrowseBox::StateChanged(StateChangedType::InitShow);
// initializations
if (mvCols.empty() || !rWin.IsUpdateMode())
return;
if (pDataWin->bResizeOnPaint)
Resize();
// MI: who was that? Window::Update();
ImplPaintData(rRenderContext, rRect, false);
}
void BrowseBox::UpdateScrollbars()
{
if ( !bBootstrapped || !IsUpdateMode() )
return;
// protect against recursion
if ( pDataWin->bInUpdateScrollbars )
{
pDataWin->bHadRecursion = true;
return;
}
pDataWin->bInUpdateScrollbars = true;
// the size of the corner window (and the width of the VSB/height of the HSB)
m_nCornerHeight = GetBarHeight();
m_nCornerWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
if (IsZoom())
{
m_nCornerHeight = static_cast<tools::Long>(m_nCornerHeight * static_cast<double>(GetZoom()));
m_nCornerWidth = static_cast<tools::Long>(m_nCornerWidth * static_cast<double>(GetZoom()));
}
bool bNeedsVScroll = false;
sal_Int32 nMaxRows = 0;
if (GetDataRowHeight())
{
// needs VScroll?
nMaxRows = (pDataWin->GetSizePixel().Height()) / GetDataRowHeight();
bNeedsVScroll = pDataWin->bAutoVScroll
? nTopRow || ( nRowCount > nMaxRows )
: !pDataWin->bNoVScroll;
}
Size aDataWinSize = pDataWin->GetSizePixel();
if ( !bNeedsVScroll )
{
if ( pVScroll->IsVisible() )
{
pVScroll->Hide();
Size aNewSize( aDataWinSize );
aNewSize.setWidth( GetOutputSizePixel().Width() );
aDataWinSize = aNewSize;
}
}
else if ( !pVScroll->IsVisible() )
{
Size aNewSize( aDataWinSize );
aNewSize.setWidth( GetOutputSizePixel().Width() - m_nCornerWidth );
aDataWinSize = aNewSize;
}
// needs HScroll?
sal_uInt16 nLastCol = GetColumnAtXPosPixel( aDataWinSize.Width() - 1 );
sal_uInt16 nFrozenCols = FrozenColCount();
bool bNeedsHScroll = pDataWin->bAutoHScroll
? ( nFirstCol > nFrozenCols ) || ( nLastCol <= mvCols.size() )
: !pDataWin->bNoHScroll;
if ( !bNeedsHScroll )
{
if ( aHScroll->IsVisible() )
{
aHScroll->Hide();
}
aDataWinSize.setHeight( GetOutputSizePixel().Height() - GetTitleHeight() );
if ( nControlAreaWidth != USHRT_MAX )
aDataWinSize.AdjustHeight( -sal_Int32(m_nCornerHeight) );
}
else if ( !aHScroll->IsVisible() )
{
Size aNewSize( aDataWinSize );
aNewSize.setHeight( GetOutputSizePixel().Height() - GetTitleHeight() - m_nCornerHeight );
aDataWinSize = aNewSize;
}
// adjust position and Width of horizontal scrollbar
tools::Long nHScrX = nControlAreaWidth == USHRT_MAX
? 0
: nControlAreaWidth;
aHScroll->SetPosSizePixel(
Point( nHScrX, GetOutputSizePixel().Height() - m_nCornerHeight ),
Size( aDataWinSize.Width() - nHScrX, m_nCornerHeight ) );
// total scrollable columns
short nScrollCols = short(mvCols.size()) - static_cast<short>(nFrozenCols);
// visible columns
short nVisibleHSize = nLastCol == BROWSER_INVALIDID
? static_cast<short>( mvCols.size() - nFirstCol )
: static_cast<short>( nLastCol - nFirstCol );
if (nVisibleHSize)
{
short nRange = std::max( nScrollCols, short(0) );
aHScroll->SetVisibleSize( nVisibleHSize );
aHScroll->SetRange( Range( 0, nRange ));
}
else
{
// ensure scrollbar is shown as fully filled
aHScroll->SetVisibleSize(1);
aHScroll->SetRange(Range(0, 1));
}
if ( bNeedsHScroll && !aHScroll->IsVisible() )
aHScroll->Show();
// adjust position and height of vertical scrollbar
pVScroll->SetPageSize( nMaxRows );
if ( nTopRow > nRowCount )
{
nTopRow = nRowCount - 1;
OSL_FAIL("BrowseBox: nTopRow > nRowCount");
}
if ( pVScroll->GetThumbPos() != nTopRow )
pVScroll->SetThumbPos( nTopRow );
tools::Long nVisibleSize = std::min( std::min( nRowCount, nMaxRows ), (nRowCount-nTopRow) );
pVScroll->SetVisibleSize( nVisibleSize ? nVisibleSize : 1 );
pVScroll->SetRange( Range( 0, nRowCount ) );
pVScroll->SetPosSizePixel(
Point( aDataWinSize.Width(), GetTitleHeight() ),
Size( m_nCornerWidth, aDataWinSize.Height()) );
tools::Long nLclDataRowHeight = GetDataRowHeight();
if ( nLclDataRowHeight > 0 && nRowCount < tools::Long( aDataWinSize.Height() / nLclDataRowHeight ) )
ScrollRows( -nTopRow );
if ( bNeedsVScroll && !pVScroll->IsVisible() )
pVScroll->Show();
pDataWin->SetPosSizePixel(
Point( 0, GetTitleHeight() ),
aDataWinSize );
// needs corner-window?
// (do that AFTER positioning BOTH scrollbars)
m_nActualCornerWidth = 0;
if (aHScroll->IsVisible() && pVScroll && pVScroll->IsVisible() )
{
// if we have both scrollbars, the corner window fills the point of intersection of these two
m_nActualCornerWidth = m_nCornerWidth;
}
else if ( !aHScroll->IsVisible() && ( nControlAreaWidth != USHRT_MAX ) )
{
// if we have no horizontal scrollbar, but a control area, we need the corner window to
// fill the space between the control are and the right border
m_nActualCornerWidth = GetOutputSizePixel().Width() - nControlAreaWidth;
}
// scroll headerbar, if necessary
if ( pDataWin->pHeaderBar )
{
tools::Long nWidth = 0;
for ( size_t nCol = 0;
nCol < mvCols.size() && nCol < nFirstCol;
++nCol )
{
// not the handle column
if ( mvCols[ nCol ]->GetId() )
nWidth += mvCols[ nCol ]->Width();
}
pDataWin->pHeaderBar->SetOffset( nWidth );
}
pDataWin->bInUpdateScrollbars = false;
if ( pDataWin->bHadRecursion )
{
pDataWin->bHadRecursion = false;
UpdateScrollbars();
}
}
void BrowseBox::SetUpdateMode( bool bUpdate )
{
bool bWasUpdate = IsUpdateMode();
if ( bWasUpdate == bUpdate )
return;
Control::SetUpdateMode( bUpdate );
// If WB_CLIPCHILDREN is st at the BrowseBox (to minimize flicker),
// the data window is not invalidated by SetUpdateMode.
if( bUpdate )
pDataWin->Invalidate();
pDataWin->SetUpdateMode( bUpdate );
if ( bUpdate )
{
if ( bBootstrapped )
{
UpdateScrollbars();
AutoSizeLastColumn();
}
DoShowCursor();
}
else
DoHideCursor();
}
bool BrowseBox::GetUpdateMode() const
{
return pDataWin->IsUpdateMode();
}
tools::Long BrowseBox::GetFrozenWidth() const
{
tools::Long nWidth = 0;
for ( size_t nCol = 0;
nCol < mvCols.size() && mvCols[ nCol ]->IsFrozen();
++nCol )
nWidth += mvCols[ nCol ]->Width();
return nWidth;
}
void BrowseBox::ColumnInserted( sal_uInt16 nPos )
{
if ( pColSel )
pColSel->Insert( nPos );
UpdateScrollbars();
}
sal_uInt16 BrowseBox::FrozenColCount() const
{
std::size_t nCol;
for ( nCol = 0;
nCol < mvCols.size() && mvCols[ nCol ]->IsFrozen();
++nCol )
/* empty loop */;
return nCol; //TODO: BrowserColumns::size_type -> sal_uInt16!
}
IMPL_LINK(BrowseBox, VertScrollHdl, weld::Scrollbar&, rScrollbar, void)
{
auto nCurScrollRow = nTopRow;
auto nPos = rScrollbar.adjustment_get_value();
ScrollRows(nPos - nCurScrollRow);
bool bShowTooltip = ((m_nCurrentMode & BrowserMode::TRACKING_TIPS) == BrowserMode::TRACKING_TIPS);
if (bShowTooltip &&
rScrollbar.get_scroll_type() == ScrollType::Drag &&
Help::IsQuickHelpEnabled())
{
OUString aTip = OUString::number(nPos) + "/";
if (!pDataWin->GetRealRowCount().isEmpty())
aTip += pDataWin->GetRealRowCount();
else
aTip += OUString::number(rScrollbar.adjustment_get_upper());
tools::Rectangle aRect(GetPointerPosPixel(), Size(GetTextWidth(aTip), GetTextHeight()));
Help::ShowQuickHelp(this, aRect, aTip);
}
}
IMPL_LINK(BrowseBox, HorzScrollHdl, weld::Scrollbar&, rScrollbar, void)
{
auto nCurScrollCol = nFirstCol - FrozenColCount();
ScrollColumns(rScrollbar.adjustment_get_value() - nCurScrollCol);
}
IMPL_LINK( BrowseBox, StartDragHdl, HeaderBar*, pBar, void )
{
pBar->SetDragSize( pDataWin->GetOutputSizePixel().Height() );
}
// usually only the first column was resized
void BrowseBox::MouseButtonDown( const MouseEvent& rEvt )
{
GrabFocus();
// only mouse events in the title-line are supported
const Point &rEvtPos = rEvt.GetPosPixel();
if ( rEvtPos.Y() >= GetTitleHeight() )
return;
tools::Long nX = 0;
tools::Long nWidth = GetOutputSizePixel().Width();
for ( size_t nCol = 0; nCol < mvCols.size() && nX < nWidth; ++nCol )
{
// is this column visible?
BrowserColumn *pCol = mvCols[ nCol ].get();
if ( pCol->IsFrozen() || nCol >= nFirstCol )
{
// compute right end of column
tools::Long nR = nX + pCol->Width() - 1;
// at the end of a column (and not handle column)?
if ( pCol->GetId() && std::abs( nR - rEvtPos.X() ) < 2 )
{
// start resizing the column
bResizing = true;
nResizeCol = nCol;
nDragX = nResizeX = rEvtPos.X();
SetPointer( PointerStyle::HSplit );
CaptureMouse();
pDataWin->GetOutDev()->DrawLine( Point( nDragX, 0 ),
Point( nDragX, pDataWin->GetSizePixel().Height() ) );
nMinResizeX = nX + MIN_COLUMNWIDTH;
return;
}
else if ( nX < rEvtPos.X() && nR > rEvtPos.X() )
{
MouseButtonDown( BrowserMouseEvent(
this, rEvt, -1, nCol, pCol->GetId(), tools::Rectangle() ) );
return;
}
nX = nR + 1;
}
}
// event occurred out of data area
if ( rEvt.IsRight() )
pDataWin->Command(
CommandEvent( Point( 1, LONG_MAX ), CommandEventId::ContextMenu, true ) );
else
SetNoSelection();
}
void BrowseBox::MouseMove( const MouseEvent& rEvt )
{
SAL_INFO("svtools", "BrowseBox::MouseMove( MouseEvent )" );
PointerStyle aNewPointer = PointerStyle::Arrow;
sal_uInt16 nX = 0;
for ( size_t nCol = 0;
nCol < mvCols.size() &&
( nX + mvCols[ nCol ]->Width() ) < GetOutputSizePixel().Width();
++nCol )
// is this column visible?
if ( mvCols[ nCol ]->IsFrozen() || nCol >= nFirstCol )
{
// compute right end of column
BrowserColumn *pCol = mvCols[ nCol ].get();
sal_uInt16 nR = static_cast<sal_uInt16>(nX + pCol->Width() - 1);
// show resize-pointer?
if ( bResizing || ( pCol->GetId() &&
std::abs( static_cast<tools::Long>(nR) - rEvt.GetPosPixel().X() ) < MIN_COLUMNWIDTH ) )
{
aNewPointer = PointerStyle::HSplit;
if ( bResizing )
{
// delete old auxiliary line
pDataWin->HideTracking() ;
// check allowed width and new delta
nDragX = std::max( rEvt.GetPosPixel().X(), nMinResizeX );
tools::Long nDeltaX = nDragX - nResizeX;
sal_uInt16 nId = GetColumnId(nResizeCol);
tools::Long nOldWidth = GetColumnWidth(nId);
nDragX = nOldWidth + nDeltaX + nResizeX - nOldWidth;
// draw new auxiliary line
pDataWin->ShowTracking( tools::Rectangle( Point( nDragX, 0 ),
Size( 1, pDataWin->GetSizePixel().Height() ) ),
ShowTrackFlags::Split|ShowTrackFlags::TrackWindow );
}
}
nX = nR + 1;
}
SetPointer( aNewPointer );
}
void BrowseBox::MouseButtonUp( const MouseEvent & rEvt )
{
if ( bResizing )
{
// delete auxiliary line
pDataWin->HideTracking();
// width changed?
nDragX = std::max( rEvt.GetPosPixel().X(), nMinResizeX );
if ( (nDragX - nResizeX) != mvCols[ nResizeCol ]->Width() )
{
// resize column
tools::Long nMaxX = pDataWin->GetSizePixel().Width();
nDragX = std::min( nDragX, nMaxX );
tools::Long nDeltaX = nDragX - nResizeX;
sal_uInt16 nId = GetColumnId(nResizeCol);
SetColumnWidth( GetColumnId(nResizeCol), GetColumnWidth(nId) + nDeltaX );
ColumnResized( nId );
}
// end action
SetPointer( PointerStyle::Arrow );
ReleaseMouse();
bResizing = false;
}
else
MouseButtonUp( BrowserMouseEvent( pDataWin,
MouseEvent( Point( rEvt.GetPosPixel().X(),
rEvt.GetPosPixel().Y() - pDataWin->GetPosPixel().Y() ),
rEvt.GetClicks(), rEvt.GetMode(), rEvt.GetButtons(),
rEvt.GetModifier() ) ) );
}
static bool bExtendedMode = false;
static bool bFieldMode = false;
void BrowseBox::MouseButtonDown( const BrowserMouseEvent& rEvt )
{
GrabFocus();
// adjust selection while and after double-click
if ( rEvt.GetClicks() == 2 )
{
SetNoSelection();
if ( rEvt.GetRow() >= 0 )
{
GoToRow( rEvt.GetRow() );
SelectRow( rEvt.GetRow(), true, false );
}
else
{
if ( bColumnCursor && rEvt.GetColumn() != 0 )
{
if ( rEvt.GetColumn() < mvCols.size() )
SelectColumnPos( rEvt.GetColumn(), true, false);
}
}
DoubleClick( rEvt );
}
// selections
else if ( ( rEvt.GetMode() & ( MouseEventModifiers::SELECT | MouseEventModifiers::SIMPLECLICK ) ) &&
( bColumnCursor || rEvt.GetRow() >= 0 ) )
{
if ( rEvt.GetClicks() == 1 )
{
// initialise flags
bHit = false;
// selection out of range?
if ( rEvt.GetRow() >= nRowCount ||
rEvt.GetColumnId() == BROWSER_INVALIDID )
{
SetNoSelection();
return;
}
// while selecting, no cursor
bSelecting = true;
DoHideCursor();
// DataRow?
if ( rEvt.GetRow() >= 0 )
{
// line selection?
if ( rEvt.GetColumnId() == HandleColumnId || !bColumnCursor )
{
if ( bMultiSelection )
{
// remove column-selection, if exists
if ( pColSel && pColSel->GetSelectCount() )
{
ToggleSelection();
if ( bMultiSelection )
uRow.pSel->SelectAll(false);
else
uRow.nSel = BROWSER_ENDOFSELECTION;
if ( pColSel )
pColSel->SelectAll(false);
bSelect = true;
}
// expanding mode?
if ( rEvt.GetMode() & MouseEventModifiers::RANGESELECT )
{
// select the further touched rows too
bSelect = true;
ExpandRowSelection( rEvt );
return;
}
// click in the selected area?
else if ( IsRowSelected( rEvt.GetRow() ) )
{
// wait for Drag&Drop
bHit = true;
bExtendedMode = bool( rEvt.GetMode() & MouseEventModifiers::MULTISELECT );
return;
}
// extension mode?
else if ( rEvt.GetMode() & MouseEventModifiers::MULTISELECT )
{
// determine the new selection range
// and selection/deselection
aSelRange = Range( rEvt.GetRow(), rEvt.GetRow() );
SelectRow( rEvt.GetRow(),
!uRow.pSel->IsSelected( rEvt.GetRow() ) );
bSelect = true;
return;
}
}
// select directly
SetNoSelection();
GoToRow( rEvt.GetRow() );
SelectRow( rEvt.GetRow() );
aSelRange = Range( rEvt.GetRow(), rEvt.GetRow() );
bSelect = true;
}
else // Column/Field-Selection
{
// click in selected column
if ( IsColumnSelected( rEvt.GetColumn() ) ||
IsRowSelected( rEvt.GetRow() ) )
{
bHit = true;
bFieldMode = true;
return;
}
SetNoSelection();
GoToRowColumnId( rEvt.GetRow(), rEvt.GetColumnId() );
bSelect = true;
}
}
else
{
if ( bMultiSelection && rEvt.GetColumnId() == HandleColumnId )
{
// toggle all-selection
if ( uRow.pSel->GetSelectCount() > ( GetRowCount() / 2 ) )
SetNoSelection();
else
SelectAll();
}
else
SelectColumnPos( GetColumnPos(rEvt.GetColumnId()), true, false);
}
// turn cursor on again, if necessary
bSelecting = false;
DoShowCursor();
if ( bSelect )
Select();
}
}
}
void BrowseBox::MouseButtonUp( const BrowserMouseEvent &rEvt )
{
// D&D was possible, but did not occur
if ( bHit )
{
aSelRange = Range( rEvt.GetRow(), rEvt.GetRow() );
if ( bExtendedMode )
SelectRow( rEvt.GetRow(), false );
else
{
SetNoSelection();
if ( bFieldMode )
GoToRowColumnId( rEvt.GetRow(), rEvt.GetColumnId() );
else
{
GoToRow( rEvt.GetRow() );
SelectRow( rEvt.GetRow() );
}
}
bSelect = true;
bExtendedMode = false;
bFieldMode = false;
bHit = false;
}
// activate cursor
if ( bSelecting )
{
bSelecting = false;
DoShowCursor();
if ( bSelect )
Select();
}
}
void BrowseBox::KeyInput( const KeyEvent& rEvt )
{
if ( !ProcessKey( rEvt ) )
Control::KeyInput( rEvt );
}
bool BrowseBox::ProcessKey( const KeyEvent& rEvt )
{
sal_uInt16 nCode = rEvt.GetKeyCode().GetCode();
bool bShift = rEvt.GetKeyCode().IsShift();
bool bCtrl = rEvt.GetKeyCode().IsMod1();
bool bAlt = rEvt.GetKeyCode().IsMod2();
sal_uInt16 nId = BROWSER_NONE;
if ( !bAlt && !bCtrl && !bShift )
{
switch ( nCode )
{
case KEY_DOWN: nId = BROWSER_CURSORDOWN; break;
case KEY_UP: nId = BROWSER_CURSORUP; break;
case KEY_HOME: nId = BROWSER_CURSORHOME; break;
case KEY_END: nId = BROWSER_CURSOREND; break;
case KEY_TAB:
if ( !bColumnCursor )
break;
[[fallthrough]];
case KEY_RIGHT: nId = BROWSER_CURSORRIGHT; break;
case KEY_LEFT: nId = BROWSER_CURSORLEFT; break;
case KEY_SPACE: nId = BROWSER_SELECT; break;
}
if ( BROWSER_NONE != nId )
SetNoSelection();
switch ( nCode )
{
case KEY_PAGEDOWN: nId = BROWSER_CURSORPAGEDOWN; break;
case KEY_PAGEUP: nId = BROWSER_CURSORPAGEUP; break;
}
}
if ( !bAlt && !bCtrl && bShift )
switch ( nCode )
{
case KEY_DOWN: nId = BROWSER_SELECTDOWN; break;
case KEY_UP: nId = BROWSER_SELECTUP; break;
case KEY_TAB:
if ( !bColumnCursor )
break;
nId = BROWSER_CURSORLEFT; break;
case KEY_HOME: nId = BROWSER_SELECTHOME; break;
case KEY_END: nId = BROWSER_SELECTEND; break;
}
if ( !bAlt && bCtrl && !bShift )
switch ( nCode )
{
case KEY_DOWN: nId = BROWSER_CURSORDOWN; break;
case KEY_UP: nId = BROWSER_CURSORUP; break;
case KEY_PAGEDOWN: nId = BROWSER_CURSORENDOFFILE; break;
case KEY_PAGEUP: nId = BROWSER_CURSORTOPOFFILE; break;
case KEY_HOME: nId = BROWSER_CURSORTOPOFSCREEN; break;
case KEY_END: nId = BROWSER_CURSORENDOFSCREEN; break;
case KEY_SPACE: nId = BROWSER_ENHANCESELECTION; break;
case KEY_LEFT: nId = BROWSER_MOVECOLUMNLEFT; break;
case KEY_RIGHT: nId = BROWSER_MOVECOLUMNRIGHT; break;
}
if ( nId != BROWSER_NONE )
Dispatch( nId );
return nId != BROWSER_NONE;
}
void BrowseBox::ChildFocusIn()
{
}
void BrowseBox::ChildFocusOut()
{
}
void BrowseBox::Dispatch( sal_uInt16 nId )
{
tools::Long nRowsOnPage = pDataWin->GetSizePixel().Height() / GetDataRowHeight();
switch ( nId )
{
case BROWSER_SELECTCOLUMN:
if ( ColCount() )
SelectColumnId( GetCurColumnId() );
break;
case BROWSER_CURSORDOWN:
if ( ( GetCurRow() + 1 ) < nRowCount )
GoToRow( GetCurRow() + 1, false );
break;
case BROWSER_CURSORUP:
if ( GetCurRow() > 0 )
GoToRow( GetCurRow() - 1, false );
break;
case BROWSER_SELECTHOME:
if ( GetRowCount() )
{
DoHideCursor();
for ( sal_Int32 nRow = GetCurRow(); nRow >= 0; --nRow )
SelectRow( nRow );
GoToRow( 0, true );
DoShowCursor();
}
break;
case BROWSER_SELECTEND:
if ( GetRowCount() )
{
DoHideCursor();
sal_Int32 nRows = GetRowCount();
for ( sal_Int32 nRow = GetCurRow(); nRow < nRows; ++nRow )
SelectRow( nRow );
GoToRow( GetRowCount() - 1, true );
DoShowCursor();
}
break;
case BROWSER_SELECTDOWN:
{
if ( GetRowCount() && ( GetCurRow() + 1 ) < nRowCount )
{
// deselect the current row, if it isn't the first
// and there is no other selected row above
sal_Int32 nRow = GetCurRow();
bool bLocalSelect = ( !IsRowSelected( nRow ) ||
GetSelectRowCount() == 1 || IsRowSelected( nRow - 1 ) );
SelectRow( nRow, bLocalSelect );
bool bDone = GoToRow( GetCurRow() + 1, false );
if ( bDone )
SelectRow( GetCurRow() );
}
else
ScrollRows( 1 );
break;
}
case BROWSER_SELECTUP:
if ( GetRowCount() )
{
// deselect the current row, if it isn't the first
// and there is no other selected row under
sal_Int32 nRow = GetCurRow();
bool bLocalSelect = ( !IsRowSelected( nRow ) ||
GetSelectRowCount() == 1 || IsRowSelected( nRow + 1 ) );
SelectRow( nCurRow, bLocalSelect );
bool bDone = GoToRow( nRow - 1, false );
if ( bDone )
SelectRow( GetCurRow() );
}
break;
case BROWSER_CURSORPAGEDOWN:
ScrollRows( nRowsOnPage );
break;
case BROWSER_CURSORPAGEUP:
ScrollRows( -nRowsOnPage );
break;
case BROWSER_CURSOREND:
if ( bColumnCursor )
{
sal_uInt16 nNewId = GetColumnId(ColCount() -1);
nNewId != HandleColumnId && GoToColumnId( nNewId );
break;
}
[[fallthrough]];
case BROWSER_CURSORENDOFFILE:
GoToRow( nRowCount - 1, false );
break;
case BROWSER_CURSORRIGHT:
if ( bColumnCursor )
{
sal_uInt16 nNewPos = GetColumnPos( GetCurColumnId() ) + 1;
sal_uInt16 nNewId = GetColumnId( nNewPos );
if (nNewId != BROWSER_INVALIDID) // At end of row ?
GoToColumnId( nNewId );
else
{
sal_uInt16 nColId = GetColumnId(0);
if ( nColId == BROWSER_INVALIDID || nColId == HandleColumnId )
nColId = GetColumnId(1);
if ( GetRowCount() )
{
if ( nCurRow < GetRowCount() - 1 )
{
GoToRowColumnId( nCurRow + 1, nColId );
}
}
else if ( ColCount() )
GoToColumnId( nColId );
}
}
else
ScrollColumns( 1 );
break;
case BROWSER_CURSORHOME:
if ( bColumnCursor )
{
sal_uInt16 nNewId = GetColumnId(1);
if (nNewId != HandleColumnId)
{
GoToColumnId( nNewId );
}
break;
}
[[fallthrough]];
case BROWSER_CURSORTOPOFFILE:
GoToRow( 0, false );
break;
case BROWSER_CURSORLEFT:
if ( bColumnCursor )
{
sal_uInt16 nNewPos = GetColumnPos( GetCurColumnId() ) - 1;
sal_uInt16 nNewId = GetColumnId( nNewPos );
if (nNewId != HandleColumnId)
GoToColumnId( nNewId );
else
{
if ( GetRowCount() )
{
if (nCurRow > 0)
{
GoToRowColumnId(nCurRow - 1, GetColumnId(ColCount() -1));
}
}
else if ( ColCount() )
GoToColumnId( GetColumnId(ColCount() -1) );
}
}
else
ScrollColumns( -1 );
break;
case BROWSER_ENHANCESELECTION:
if ( GetRowCount() )
SelectRow( GetCurRow(), !IsRowSelected( GetCurRow() ) );
break;
case BROWSER_SELECT:
if ( GetRowCount() )
SelectRow( GetCurRow(), !IsRowSelected( GetCurRow() ), false );
break;
case BROWSER_MOVECOLUMNLEFT:
case BROWSER_MOVECOLUMNRIGHT:
{ // check if column moving is allowed
BrowserHeader* pHeaderBar = pDataWin->pHeaderBar;
if ( pHeaderBar && pHeaderBar->IsDragable() )
{
sal_uInt16 nColId = GetCurColumnId();
bool bColumnSelected = IsColumnSelected(nColId);
sal_uInt16 nNewPos = GetColumnPos(nColId);
bool bMoveAllowed = false;
if ( BROWSER_MOVECOLUMNLEFT == nId && nNewPos > 1 )
{
--nNewPos;
bMoveAllowed = true;
}
else if ( BROWSER_MOVECOLUMNRIGHT == nId && nNewPos < (ColCount()-1) )
{
++nNewPos;
bMoveAllowed = true;
}
if ( bMoveAllowed )
{
SetColumnPos( nColId, nNewPos );
ColumnMoved( nColId );
MakeFieldVisible(GetCurRow(), nColId);
if ( bColumnSelected )
SelectColumnId(nColId);
}
}
}
break;
}
}
void BrowseBox::SetCursorColor(const Color& _rCol)
{
if (_rCol == m_aCursorColor)
return;
// ensure the cursor is hidden
DoHideCursor();
if (!m_bFocusOnlyCursor)
DoHideCursor();
m_aCursorColor = _rCol;
if (!m_bFocusOnlyCursor)
DoShowCursor();
DoShowCursor();
}
tools::Rectangle BrowseBox::calcHeaderRect(bool _bIsColumnBar, bool _bOnScreen)
{
vcl::Window* pParent = nullptr;
if ( !_bOnScreen )
pParent = GetAccessibleParentWindow();
Point aTopLeft;
tools::Long nWidth;
tools::Long nHeight;
if ( _bIsColumnBar )
{
nWidth = pDataWin->GetOutputSizePixel().Width();
nHeight = GetDataRowHeight();
}
else
{
aTopLeft.setY( GetDataRowHeight() );
nWidth = GetColumnWidth(0);
if (pParent)
nHeight = GetWindowExtentsRelative( *pParent ).GetHeight() - aTopLeft.Y() - GetControlArea().GetSize().Height();
else
nHeight = GetWindowExtentsAbsolute().GetHeight() - aTopLeft.Y() - GetControlArea().GetSize().Height();
}
if (pParent)
aTopLeft += GetWindowExtentsRelative( *pParent ).TopLeft();
else
aTopLeft += Point(GetWindowExtentsAbsolute().TopLeft());
return tools::Rectangle(aTopLeft,Size(nWidth,nHeight));
}
tools::Rectangle BrowseBox::calcTableRect(bool _bOnScreen)
{
vcl::Window* pParent = nullptr;
if ( !_bOnScreen )
pParent = GetAccessibleParentWindow();
tools::Rectangle aRect;
if (pParent)
aRect = GetWindowExtentsRelative( *pParent );
else
aRect = tools::Rectangle(GetWindowExtentsAbsolute());
tools::Rectangle aRowBar = calcHeaderRect(false, pParent == nullptr);
tools::Long nX = aRowBar.Right() - aRect.Left();
tools::Long nY = aRowBar.Top() - aRect.Top();
Size aSize(aRect.GetSize());
return tools::Rectangle(aRowBar.TopRight(), Size(aSize.Width() - nX, aSize.Height() - nY - GetBarHeight()) );
}
tools::Rectangle BrowseBox::GetFieldRectPixel( sal_Int32 _nRowId, sal_uInt16 _nColId, bool /*_bIsHeader*/, bool _bOnScreen )
{
vcl::Window* pParent = nullptr;
if ( !_bOnScreen )
pParent = GetAccessibleParentWindow();
tools::Rectangle aRect = GetFieldRectPixel(_nRowId,_nColId,_bOnScreen);
Point aTopLeft = aRect.TopLeft();
if (pParent)
aTopLeft += GetWindowExtentsRelative( *pParent ).TopLeft();
else
aTopLeft += Point(GetWindowExtentsAbsolute().TopLeft());
return tools::Rectangle(aTopLeft,aRect.GetSize());
}
// ------------------------------------------------------------------------- EOF
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'Union' is required to be utilized.
↑ V1048 The 'nDragX' variable was assigned the same value.