/* -*- 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 .
*/
// tdf#115941 because some platforms have things like overlay scrollbars, take a max // of a statusbar height and a scrollbar height as the control area height
// (we can't ask the scrollbars for their size cause if we're zoomed they still have to be // resized - which is done in UpdateScrollbars) return std::max(aStatusBarHeight->GetSizePixel().Height(), nScrollBarSize);
}
BrowseBox::BrowseBox( vcl::Window* pParent, WinBits nBits, BrowserMode nMode )
:Control( pParent, nBits | WB_3DLOOK )
,DragSourceHelper( this )
,DropTargetHelper( this )
,aHScroll( VclPtr<ScrollAdaptor>::Create(this, true) ) // see NavigationBar ctor, here we just want to know its height
,aStatusBarHeight(VclPtr<MeasureStatusBar>::Create(this))
,m_nCornerHeight(0)
,m_nCornerWidth(0)
,m_nActualCornerWidth(0)
,m_bNavigationBar(false)
{
bMultiSelection = false;
pColSel = nullptr;
pVScroll = nullptr;
pDataWin = VclPtr<BrowserDataWin>::Create( this ).get();
InitSettings_Impl( this );
InitSettings_Impl( pDataWin );
#if OSL_DEBUG_LEVEL > 0
OSL_ENSURE( ColCount() == 0 || mvCols[0]->GetId() != HandleColumnId , "BrowseBox::InsertHandleColumn: there is already a handle column" );
{ for (autoconst & col : mvCols)
OSL_ENSURE( col->GetId() != HandleColumnId, "BrowseBox::InsertHandleColumn: there is a non-Handle column with handle ID" );
} #endif
void BrowseBox::FreezeColumn( sal_uInt16 nItemId )
{ // get the position in the current array
size_t nItemPos = GetColumnPos( nItemId ); if ( nItemPos >= mvCols.size() ) // not available! return;
// doesn't the state change? if ( mvCols[ nItemPos ]->IsFrozen() ) return;
// remark the column selection
sal_uInt16 nSelectedColId = ToggleSelectedColumn();
// to be moved? if ( nItemPos != 0 && !mvCols[ nItemPos-1 ]->IsFrozen() )
{ // move to the right of the last frozen column
sal_uInt16 nFirstScrollable = FrozenColCount();
std::unique_ptr<BrowserColumn> pColumn = std::move(mvCols[ nItemPos ]);
mvCols.erase( mvCols.begin() + nItemPos );
nItemPos = nFirstScrollable;
mvCols.insert( mvCols.begin() + nItemPos, std::move(pColumn) );
}
// adjust the number of the first scrollable and visible column if ( nFirstCol <= nItemPos )
nFirstCol = nItemPos + 1;
// toggle the freeze-state of the column
mvCols[ nItemPos ]->Freeze();
// remember the column selection
SetToggledSelectedColumn(nSelectedColId);
}
void BrowseBox::SetColumnPos( sal_uInt16 nColumnId, sal_uInt16 nPos )
{ // never set pos of the handle column if ( nColumnId == HandleColumnId ) return;
// get the position in the current array
sal_uInt16 nOldPos = GetColumnPos( nColumnId ); if ( nOldPos >= mvCols.size() ) // not available! return;
// does the state change? if (nOldPos == nPos) return;
// remark the column selection
sal_uInt16 nSelectedColId = ToggleSelectedColumn();
// determine old column area
Size aDataWinSize( pDataWin->GetSizePixel() ); if ( pDataWin->pHeaderBar )
aDataWinSize.AdjustHeight(pDataWin->pHeaderBar->GetSizePixel().Height() );
// OV // In AutoSizeLastColumn(), we call SetColumnWidth with nWidth==0xffff. // Thus, check here, if the width has actually changed. if( nOldWidth == nWidth ) return;
// do we want to display the change immediately? bool bUpdate = GetUpdateMode() &&
( mvCols[ nItemPos ]->IsFrozen() || nItemPos >= nFirstCol );
if ( pDataWin->pHeaderBar )
pDataWin->pHeaderBar->Clear( );
// correct vertical scrollbar
UpdateScrollbars();
// trigger repaint if necessary if ( GetUpdateMode() )
{
pDataWin->Invalidate();
Control::Invalidate();
}
if ( !isAccessibleAlive() ) return;
if ( mvCols.size() == nOldCount ) return;
// all columns should be removed, so we remove the column header bar and append it again // to avoid to notify every column remove
commitBrowseBoxEvent(
AccessibleEventId::CHILD,
Any(),
Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar))
);
// and now append it again
commitBrowseBoxEvent(
AccessibleEventId::CHILD,
Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar)),
Any()
);
// notify a table model change
commitTableEvent(
AccessibleEventId::TABLE_MODEL_CHANGED,
Any ( AccessibleTableModelChange( COLUMNS_REMOVED,
-1,
-1,
0,
nOldCount
)
),
Any()
);
}
const OUString & BrowseBox::GetColumnTitle( sal_uInt16 nId ) const
{
sal_uInt16 nItemPos = GetColumnPos( nId ); if ( nItemPos >= mvCols.size() ) return EMPTY_OUSTRING; return mvCols[ nItemPos ]->Title();
}
// scrolling one column to the right? if ( nCols == 1 )
{ // update internal value and scrollbar
++nFirstCol;
aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
// scroll the header bar area (if there is no dedicated HeaderBar control) if ( !pDataWin->pHeaderBar && nTitleLines )
{ // actually scroll
Scroll( -nDelta, 0, aScrollRect, SCROLL_FLAGS );
// invalidate the area of the column which was scrolled out to the left hand side
tools::Rectangle aInvalidateRect( aScrollRect );
aInvalidateRect.SetLeft( nFrozenWidth );
aInvalidateRect.SetRight( nFrozenWidth + nDelta - 1 );
Invalidate( aInvalidateRect );
}
// scroll the data-area
aScrollRect.SetBottom( pDataWin->GetOutputSizePixel().Height() );
// invalidate the area of the column which was scrolled out to the left hand side
aScrollRect.SetLeft( nFrozenWidth );
aScrollRect.SetRight( nFrozenWidth + nDelta - 1 );
pDataWin->Invalidate( aScrollRect );
}
}
// scrolling one column to the left? elseif ( nCols == -1 )
{
--nFirstCol;
aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
// scroll the header bar area (if there is no dedicated HeaderBar control) if ( !pDataWin->pHeaderBar && nTitleLines )
{
Scroll( nDelta, 0, aScrollRect, SCROLL_FLAGS );
}
// compute new top row again (nTopRow might have changed!)
nTmpMin = std::min( static_cast<tools::Long>(nTopRow + nRows), static_cast<tools::Long>(nRowCount - 1) );
tools::Rectangle aRect; if ( nColId == BROWSER_INVALIDID ) // invalidate the whole row
aRect = tools::Rectangle( Point( 0, (nRow-nTopRow) * GetDataRowHeight() ),
Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) ); else
{ // invalidate the specific field
aRect = GetFieldRectPixel( nRow, nColId, false );
}
pDataWin->Invalidate( aRect );
}
void BrowseBox::Clear()
{ // adjust the total number of rows
DoHideCursor();
sal_Int32 nOldRowCount = nRowCount;
nRowCount = 0; if(bMultiSelection)
{
assert(uRow.pSel);
uRow.pSel->Reset();
} else
uRow.nSel = BROWSER_ENDOFSELECTION;
nCurRow = BROWSER_ENDOFSELECTION;
nTopRow = 0;
nCurColId = 0;
// nFirstCol may not be reset, else the scrolling code will become confused. // nFirstCol may only be changed when adding or deleting columns // nFirstCol = 0; -> wrong!
aHScroll->SetThumbPos( 0 );
pVScroll->SetThumbPos( 0 );
// all rows should be removed, so we remove the row header bar and append it again // to avoid to notify every row remove if ( nOldRowCount == nRowCount ) return;
// and now append it again
commitBrowseBoxEvent(
AccessibleEventId::CHILD,
Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)),
Any()
);
// notify a table model change
commitTableEvent(
AccessibleEventId::TABLE_MODEL_CHANGED,
Any( AccessibleTableModelChange(ROWS_REMOVED,
0,
nOldRowCount,
-1,
-1)
),
Any()
);
}
if ( bDoPaint )
{ // hide cursor and selection
SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
ToggleSelection();
DoHideCursor();
}
// adjust total row count
nRowCount -= nNumRows;
if (nRowCount < 0) nRowCount = 0;
sal_Int32 nOldCurRow = nCurRow;
// adjust the selection
if ( bMultiSelection )
// uRow.pSel->Remove( nRow, nNumRows );
for ( tools::Long i = 0; i < nNumRows; i++ )
uRow.pSel->Remove( nRow );
else if ( nRow < uRow.nSel && uRow.nSel >= nNumRows )
uRow.nSel -= nNumRows;
else if ( nRow <= uRow.nSel )
uRow.nSel = BROWSER_ENDOFSELECTION;
// adjust the cursor
if ( nRowCount == 0 ) // don't compare nRowCount with nNumRows as nNumRows already was subtracted from nRowCount
nCurRow = BROWSER_ENDOFSELECTION;
else if ( nRow < nCurRow )
{
nCurRow -= std::min( nCurRow - nRow, nNumRows );
// with the above nCurRow points a) to the first row after the removed block or b) to the same line
// as before, but moved up nNumRows
// case a) needs an additional correction if the last n lines were deleted, as 'the first row after the
// removed block' is an invalid position then
// FS - 09/28/99 - 68429
if (nCurRow == nRowCount)
--nCurRow;
}
else if( nRow == nCurRow && nCurRow == nRowCount )
nCurRow = nRowCount-1;
// is the deleted row visible?
Size aSz = pDataWin->GetOutputSizePixel();
if ( nRow >= nTopRow &&
nRow <= nTopRow + aSz.Height() / GetDataRowHeight() )
{
if ( bDoPaint )
{
// scroll up the rows behind the deleted row
// if there are Rows behind
if (nRow < nRowCount)
{
tools::Long nY = (nRow-nTopRow) * GetDataRowHeight();
pDataWin->GetOutDev()->SetClipRegion();
if( pDataWin->GetBackground().IsScrollable() )
{
pDataWin->Scroll( 0, - static_cast<short>(GetDataRowHeight()) * nNumRows,
tools::Rectangle( Point( 0, nY ), Size( aSz.Width(),
aSz.Height() - nY + nNumRows*GetDataRowHeight() ) ),
SCROLL_FLAGS );
}
else
pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
}
else
{
// Repaint the Rect of the deleted row
tools::Rectangle aRect(
Point( 0, (nRow-nTopRow)*GetDataRowHeight() ),
Size( pDataWin->GetSizePixel().Width(),
nNumRows * GetDataRowHeight() ) );
pDataWin->Invalidate( aRect );
}
}
}
// is the deleted row above of the visible area?
else if ( nRow < nTopRow )
nTopRow = nTopRow >= nNumRows ? nTopRow-nNumRows : 0;
if ( bDoPaint )
{
// reshow cursor and selection
ToggleSelection();
SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
DoShowCursor();
// adjust the vertical scrollbar
UpdateScrollbars();
AutoSizeLastColumn();
}
if ( isAccessibleAlive() )
{
if ( nRowCount == 0 )
{
// all columns should be removed, so we remove the column header bar and append it again
// to avoid to notify every column remove
commitBrowseBoxEvent(
AccessibleEventId::CHILD,
Any(),
Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar))
);
// and now append it again
commitBrowseBoxEvent(
AccessibleEventId::CHILD,
Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)),
Any()
);
commitBrowseBoxEvent(
AccessibleEventId::CHILD,
Any(),
Any(getAccessibleTable())
);
// and now append it again
commitBrowseBoxEvent(
AccessibleEventId::CHILD,
Any(getAccessibleTable()),
Any()
);
}
else
{
commitTableEvent(
AccessibleEventId::TABLE_MODEL_CHANGED,
Any( AccessibleTableModelChange(
ROWS_REMOVED,
nRow,
nRow + nNumRows,
-1,
-1
)
),
Any()
);
for (tools::Long i = nRow+1 ; i <= (nRow+nNumRows) ; ++i)
{
commitHeaderBarEvent(
AccessibleEventId::CHILD,
Any(),
Any( CreateAccessibleRowHeader( i ) ),
false
);
}
}
}
// remove old highlight, if necessary
if ( !bMultiSelection && !bKeepSelection )
ToggleSelection();
DoHideCursor();
// must we scroll?
bool bWasVisible = bSelectionIsVisible;
if (! bMultiSelection)
{
if( !bKeepSelection )
bSelectionIsVisible = false;
}
if ( nRow < nTopRow )
ScrollRows( nRow - nTopRow );
else if ( nRow > nLastRow )
ScrollRows( nRow - nLastRow );
bSelectionIsVisible = bWasVisible;
// adjust cursor (selection) and thumb
if ( GetUpdateMode() )
pVScroll->SetThumbPos( nTopRow );
// relative positioning (because nCurRow might have changed in the meantime)!
if (nCurRow != BROWSER_ENDOFSELECTION )
nCurRow = nCurRow + (nRow - nOldCurRow);
// make sure that the current position is valid
if (nCurRow == BROWSER_ENDOFSELECTION && nRowCount > 0)
nCurRow = 0;
else if ( nCurRow >= nRowCount )
nCurRow = nRowCount - 1;
aSelRange = Range( nCurRow, nCurRow );
// display new highlight if necessary
if ( !bMultiSelection && !bKeepSelection )
uRow.nSel = nRow;
// resume Updates
pDataWin->LeaveUpdateLock();
// Cursor+Highlight
if ( !bMultiSelection && !bKeepSelection)
ToggleSelection();
DoShowCursor();
if ( !bRowColMove && nOldCurRow != nCurRow )
CursorMoved();
if ( !bMultiSelection && !bKeepSelection )
{
if ( !bSelecting )
Select();
else
bSelect = true;
}
return true;
}
DoShowCursor();
if (!bRowColMove)
{
//try to move to nCurRow, nColId
CursorMoveAttempt aAttempt(nCurRow, nColId, bScrolled);
//Detect if we are already in a call to BrowseBox::GoToColumnId
//but the attempt is impossible and we are simply recursing
//into BrowseBox::GoToColumnId with the same impossible to
//fulfill conditions
if (m_aGotoStack.empty() || aAttempt != m_aGotoStack.top())
{
m_aGotoStack.push(aAttempt);
CursorMoved();
m_aGotoStack.pop();
}
}
return true;
}
return true;
}
void BrowseBox::MakeFieldVisible
(
sal_Int32 nRow, // line number of the field (starting with 0)
sal_uInt16 nColId // column ID of the field
)
/* [Description]
Makes visible the field described in 'nRow' and 'nColId' by scrolling
accordingly.
*/
{
if (!pDataWin)
return;
Size aTestSize = pDataWin->GetSizePixel();
if ( !bBootstrapped || aTestSize.IsEmpty() )
return;
// is it visible already?
bool bVisible = IsFieldVisible( nRow, nColId, true/*bComplete*/ );
if ( bVisible )
return;
// calculate column position, field rectangle and painting area
sal_uInt16 nColPos = GetColumnPos( nColId );
tools::Rectangle aFieldRect = GetFieldRectPixel( nRow, nColId, false );
tools::Rectangle aDataRect( Point(0, 0), pDataWin->GetSizePixel() );
// positioned outside on the left?
if ( nColPos >= FrozenColCount() && nColPos < nFirstCol )
// => scroll to the right
ScrollColumns( nColPos - nFirstCol );
// while outside on the right
while ( aDataRect.Right() < aFieldRect.Right() )
{
// => scroll to the left
if ( ScrollColumns( 1 ) != 1 )
// no more need to scroll
break;
aFieldRect = GetFieldRectPixel( nRow, nColId, false );
}
// positioned outside above?
if ( nRow < nTopRow )
// scroll further to the bottom
ScrollRows( nRow - nTopRow );
// positioned outside below?
sal_Int32 nBottomRow = nTopRow + GetVisibleRows();
// decrement nBottomRow to make it the number of the last visible line
// (count starts with 0!).
// Example: BrowseBox contains exactly one entry. nBottomRow := 0 + 1 - 1
if( nBottomRow )
nBottomRow--;
if ( nRow > nBottomRow )
// scroll further to the top
ScrollRows( nRow - nBottomRow );
}
// get the visible area
tools::Rectangle aOutRect( Point(0, 0), pDataWin->GetOutputSizePixel() );
if ( bCompletely )
// test if the field is completely visible
return aOutRect.Contains( aRect );
else
// test if the field is partly of completely visible
return !aOutRect.Intersection( aRect ).IsEmpty();
}
// accumulate the widths of the visible columns
tools::Long nColX = 0;
for ( size_t nCol = 0; nCol < mvCols.size(); ++nCol )
{
BrowserColumn *pCol = mvCols[ nCol ].get();
if ( pCol->IsFrozen() || nCol >= nFirstCol )
nColX += pCol->Width();
if ( nColX > nX )
return nCol;
}
return BROWSER_INVALIDID;
}
bool BrowseBox::ReserveControlArea(sal_uInt16 nWidth)
{
if (nWidth != nControlAreaWidth)
{
OSL_ENSURE(nWidth,"Control area of 0 is not allowed, Use USHRT_MAX instead!");
nControlAreaWidth = nWidth;
UpdateScrollbars();
return true;
}
return false;
}
tools::Rectangle BrowseBox::GetControlArea() const
{
auto nHeight = aHScroll->GetSizePixel().Height();
auto nEndRight = aHScroll->GetPosPixel().X();
bHideSelect = ((nMode & BrowserMode::HIDESELECT) == BrowserMode::HIDESELECT);
// default: do not hide the cursor at all (untaken scrolling and such)
bHideCursor = TRISTATE_FALSE;
// create a headerbar. what happens, if a headerbar has to be created and
// there already are columns?
if ( BrowserMode::HEADERBAR_NEW == ( nMode & BrowserMode::HEADERBAR_NEW ) )
{
if (!pDataWin->pHeaderBar)
pDataWin->pHeaderBar = CreateHeaderBar( this );
}
else
{
pDataWin->pHeaderBar.disposeAndClear();
}
if ( bColumnCursor )
{
if (!pColSel)
pColSel.reset(new MultiSelection);
pColSel->SetTotalRange( Range( 0, mvCols.size()-1 ) );
}
else
{
pColSel.reset();
}
if ( bMultiSelection )
{
if ( pOldRowSel )
uRow.pSel = pOldRowSel;
else
uRow.pSel = new MultiSelection;
}
else
{
uRow.nSel = nOldRowSel;
delete pOldRowSel;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.