1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <svtools/brwbox.hxx>
21 #include <svtools/brwhead.hxx>
22 #include <svtools/scrolladaptor.hxx>
23 #include <o3tl/numeric.hxx>
24 #include <o3tl/safeint.hxx>
26 #include <tools/debug.hxx>
27 #include <tools/fract.hxx>
28 #include <sal/log.hxx>
29 #include <vcl/InterimItemWindow.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/weld.hxx>
34 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
35 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
36 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
37 #include <tools/multisel.hxx>
38 #include "brwimpl.hxx"
41 #define SCROLL_FLAGS (ScrollFlags::Clip | ScrollFlags::NoChildren)
43 using namespace com::sun::star::accessibility::AccessibleEventId
;
44 using namespace com::sun::star::accessibility::AccessibleTableModelChangeType
;
45 using com::sun::star::accessibility::AccessibleTableModelChange
;
46 using namespace ::com::sun::star::uno
;
51 void disposeAndClearHeaderCell(::svt::BrowseBoxImpl::THeaderCellMap
& _rHeaderCell
)
56 ::svt::BrowseBoxImpl::THeaderCellMapFunctorDispose()
62 void BrowseBox::ConstructImpl( BrowserMode nMode
)
64 SAL_INFO("svtools", "BrowseBox:ConstructImpl " << this );
65 bMultiSelection
= false;
68 pDataWin
= VclPtr
<BrowserDataWin
>::Create( this ).get();
69 m_pImpl
.reset( new ::svt::BrowseBoxImpl() );
71 InitSettings_Impl( this );
72 InitSettings_Impl( pDataWin
);
74 bBootstrapped
= false;
79 nCurRow
= BROWSER_ENDOFSELECTION
;
89 bSelectionIsVisible
= false;
90 bNotToggleSel
= false;
91 bRowDividerDrag
= false;
93 mbInteractiveRowHeight
= false;
95 bHideCursor
= TRISTATE_FALSE
;
97 m_bFocusOnlyCursor
= true;
98 m_aCursorColor
= COL_TRANSPARENT
;
99 m_nCurrentMode
= BrowserMode::NONE
;
100 nControlAreaWidth
= USHRT_MAX
;
101 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
103 aHScroll
->SetLineSize(1);
104 aHScroll
->SetScrollHdl( LINK( this, BrowseBox
, HorzScrollHdl
) );
108 bSelectionIsVisible
= bKeepHighlight
;
109 bHasFocus
= HasChildPathFocus();
110 pDataWin
->nCursorHidden
=
111 ( bHasFocus
? 0 : 1 ) + ( GetUpdateMode() ? 0 : 1 );
114 // we're just measuring the "real" NavigationBar
115 class MeasureStatusBar final
: public InterimItemWindow
118 std::unique_ptr
<weld::Label
> m_xRecordText
;
119 std::unique_ptr
<weld::Entry
> m_xAbsolute
;
120 std::unique_ptr
<weld::Label
> m_xRecordOf
;
121 std::unique_ptr
<weld::Label
> m_xRecordCount
;
123 MeasureStatusBar(vcl::Window
*pParent
)
124 : InterimItemWindow(pParent
, "svx/ui/navigationbar.ui", "NavigationBar")
125 , m_xRecordText(m_xBuilder
->weld_label("recordtext"))
126 , m_xAbsolute(m_xBuilder
->weld_entry("entry-noframe"))
127 , m_xRecordOf(m_xBuilder
->weld_label("recordof"))
128 , m_xRecordCount(m_xBuilder
->weld_label("recordcount"))
130 vcl::Font
aApplFont(Application::GetSettings().GetStyleSettings().GetToolFont());
131 m_xAbsolute
->set_font(aApplFont
);
132 m_xRecordText
->set_font(aApplFont
);
133 m_xRecordOf
->set_font(aApplFont
);
134 m_xRecordCount
->set_font(aApplFont
);
136 SetSizePixel(get_preferred_size());
139 virtual void dispose() override
141 m_xRecordCount
.reset();
144 m_xRecordText
.reset();
145 InterimItemWindow::dispose();
149 tools::Long
BrowseBox::GetBarHeight() const
151 tools::Long nScrollBarSize
= GetSettings().GetStyleSettings().GetScrollBarSize();
152 if (!m_bNavigationBar
)
153 return nScrollBarSize
;
155 // tdf#115941 because some platforms have things like overlay scrollbars, take a max
156 // of a statusbar height and a scrollbar height as the control area height
158 // (we can't ask the scrollbars for their size cause if we're zoomed they still have to be
159 // resized - which is done in UpdateScrollbars)
160 return std::max(aStatusBarHeight
->GetSizePixel().Height(), nScrollBarSize
);
163 BrowseBox::BrowseBox( vcl::Window
* pParent
, WinBits nBits
, BrowserMode nMode
)
164 :Control( pParent
, nBits
| WB_3DLOOK
)
165 ,DragSourceHelper( this )
166 ,DropTargetHelper( this )
167 ,aHScroll( VclPtr
<ScrollAdaptor
>::Create(this, true) )
168 // see NavigationBar ctor, here we just want to know its height
169 ,aStatusBarHeight(VclPtr
<MeasureStatusBar
>::Create(this))
172 ,m_nActualCornerWidth(0)
173 ,m_bNavigationBar(false)
175 ConstructImpl( nMode
);
178 BrowseBox::~BrowseBox()
183 void BrowseBox::DisposeAccessible()
185 if (m_pImpl
->m_pAccessible
)
187 disposeAndClearHeaderCell(m_pImpl
->m_aColHeaderCellMap
);
188 disposeAndClearHeaderCell(m_pImpl
->m_aRowHeaderCellMap
);
189 m_pImpl
->m_pAccessible
->dispose();
190 m_pImpl
->m_pAccessible
= nullptr;
194 void BrowseBox::dispose()
196 SAL_INFO("svtools", "BrowseBox:dispose " << this );
201 pDataWin
->pHeaderBar
.disposeAndClear();
202 pDataWin
.disposeAndClear();
203 pVScroll
.disposeAndClear();
204 aHScroll
.disposeAndClear();
205 aStatusBarHeight
.disposeAndClear();
207 // free columns-space
210 if ( bMultiSelection
)
212 DragSourceHelper::dispose();
213 DropTargetHelper::dispose();
218 short BrowseBox::GetCursorHideCount() const
220 return pDataWin
->nCursorHidden
;
224 void BrowseBox::DoShowCursor()
228 short nHiddenCount
= --pDataWin
->nCursorHidden
;
229 if (PaintCursorIfHiddenOnce())
231 if (1 == nHiddenCount
)
236 if (0 == nHiddenCount
)
242 void BrowseBox::DoHideCursor()
244 short nHiddenCount
= ++pDataWin
->nCursorHidden
;
245 if (PaintCursorIfHiddenOnce())
247 if (2 == nHiddenCount
)
252 if (1 == nHiddenCount
)
258 void BrowseBox::SetRealRowCount( const OUString
&rRealRowCount
)
260 pDataWin
->aRealRowCount
= rRealRowCount
;
264 void BrowseBox::SetFont( const vcl::Font
& rNewFont
)
266 pDataWin
->SetFont( rNewFont
);
267 ImpGetDataRowHeight();
270 const vcl::Font
& BrowseBox::GetFont() const
272 return pDataWin
->GetFont();
275 sal_uLong
BrowseBox::GetDefaultColumnWidth( const OUString
& _rText
) const
277 return pDataWin
->GetTextWidth( _rText
) + pDataWin
->GetTextWidth(OUString('0')) * 4;
281 void BrowseBox::InsertHandleColumn( sal_uLong nWidth
)
284 #if OSL_DEBUG_LEVEL > 0
285 OSL_ENSURE( ColCount() == 0 || mvCols
[0]->GetId() != HandleColumnId
, "BrowseBox::InsertHandleColumn: there is already a handle column" );
287 for (auto const & col
: mvCols
)
288 OSL_ENSURE( col
->GetId() != HandleColumnId
, "BrowseBox::InsertHandleColumn: there is a non-Handle column with handle ID" );
292 mvCols
.insert( mvCols
.begin(), std::unique_ptr
<BrowserColumn
>(new BrowserColumn( 0, OUString(), nWidth
, GetZoom() )) );
296 if ( pDataWin
->pHeaderBar
)
298 pDataWin
->pHeaderBar
->SetPosSizePixel(
300 Size( GetOutputSizePixel().Width() - nWidth
, GetTitleHeight() )
308 void BrowseBox::InsertDataColumn( sal_uInt16 nItemId
, const OUString
& rText
,
309 tools::Long nWidth
, HeaderBarItemBits nBits
, sal_uInt16 nPos
)
312 OSL_ENSURE( nItemId
!= HandleColumnId
, "BrowseBox::InsertDataColumn: nItemId is HandleColumnId" );
313 OSL_ENSURE( nItemId
!= BROWSER_INVALIDID
, "BrowseBox::InsertDataColumn: nItemId is reserved value BROWSER_INVALIDID" );
315 #if OSL_DEBUG_LEVEL > 0
317 for (auto const& col
: mvCols
)
318 OSL_ENSURE( col
->GetId() != nItemId
, "BrowseBox::InsertDataColumn: duplicate column Id" );
322 if ( nPos
< mvCols
.size() )
324 mvCols
.emplace( mvCols
.begin() + nPos
, new BrowserColumn( nItemId
, rText
, nWidth
, GetZoom() ) );
328 mvCols
.emplace_back( new BrowserColumn( nItemId
, rText
, nWidth
, GetZoom() ) );
330 if ( nCurColId
== 0 )
333 if ( pDataWin
->pHeaderBar
)
335 // Handle column not in the header bar
336 sal_uInt16 nHeaderPos
= nPos
;
337 if (nHeaderPos
!= HEADERBAR_APPEND
&& GetColumnId(0) == HandleColumnId
)
339 pDataWin
->pHeaderBar
->InsertItem(
340 nItemId
, rText
, nWidth
, nBits
, nHeaderPos
);
342 ColumnInserted( nPos
);
345 sal_uInt16
BrowseBox::ToggleSelectedColumn()
347 sal_uInt16 nSelectedColId
= BROWSER_INVALIDID
;
348 if ( pColSel
&& pColSel
->GetSelectCount() )
352 tools::Long nSelected
= pColSel
->FirstSelected();
353 if (nSelected
!= static_cast<tools::Long
>(SFX_ENDOFSELECTION
))
354 nSelectedColId
= mvCols
[nSelected
]->GetId();
355 pColSel
->SelectAll(false);
357 return nSelectedColId
;
360 void BrowseBox::SetToggledSelectedColumn(sal_uInt16 _nSelectedColumnId
)
362 if ( pColSel
&& _nSelectedColumnId
!= BROWSER_INVALIDID
)
364 pColSel
->Select( GetColumnPos( _nSelectedColumnId
) );
366 SAL_INFO("svtools", "BrowseBox::SetToggledSelectedColumn " << this );
371 void BrowseBox::FreezeColumn( sal_uInt16 nItemId
)
373 // get the position in the current array
374 size_t nItemPos
= GetColumnPos( nItemId
);
375 if ( nItemPos
>= mvCols
.size() )
379 // doesn't the state change?
380 if ( mvCols
[ nItemPos
]->IsFrozen() )
383 // remark the column selection
384 sal_uInt16 nSelectedColId
= ToggleSelectedColumn();
387 if ( nItemPos
!= 0 && !mvCols
[ nItemPos
-1 ]->IsFrozen() )
389 // move to the right of the last frozen column
390 sal_uInt16 nFirstScrollable
= FrozenColCount();
391 std::unique_ptr
<BrowserColumn
> pColumn
= std::move(mvCols
[ nItemPos
]);
392 mvCols
.erase( mvCols
.begin() + nItemPos
);
393 nItemPos
= nFirstScrollable
;
394 mvCols
.insert( mvCols
.begin() + nItemPos
, std::move(pColumn
) );
397 // adjust the number of the first scrollable and visible column
398 if ( nFirstCol
<= nItemPos
)
399 nFirstCol
= nItemPos
+ 1;
401 // toggle the freeze-state of the column
402 mvCols
[ nItemPos
]->Freeze();
404 // align the scrollbar-range
408 Control::Invalidate();
409 pDataWin
->Invalidate();
411 // remember the column selection
412 SetToggledSelectedColumn(nSelectedColId
);
416 void BrowseBox::SetColumnPos( sal_uInt16 nColumnId
, sal_uInt16 nPos
)
418 // never set pos of the handle column
419 if ( nColumnId
== HandleColumnId
)
422 // get the position in the current array
423 sal_uInt16 nOldPos
= GetColumnPos( nColumnId
);
424 if ( nOldPos
>= mvCols
.size() )
428 // does the state change?
432 // remark the column selection
433 sal_uInt16 nSelectedColId
= ToggleSelectedColumn();
435 // determine old column area
436 Size
aDataWinSize( pDataWin
->GetSizePixel() );
437 if ( pDataWin
->pHeaderBar
)
438 aDataWinSize
.AdjustHeight(pDataWin
->pHeaderBar
->GetSizePixel().Height() );
440 tools::Rectangle
aFromRect( GetFieldRect( nColumnId
) );
441 aFromRect
.AdjustRight(2*MIN_COLUMNWIDTH
);
443 sal_uInt16 nNextPos
= nOldPos
+ 1;
444 if ( nOldPos
> nPos
)
445 nNextPos
= nOldPos
- 1;
447 BrowserColumn
*pNextCol
= mvCols
[ nNextPos
].get();
448 tools::Rectangle
aNextRect(GetFieldRect( pNextCol
->GetId() ));
450 // move column internally
452 std::unique_ptr
<BrowserColumn
> pTemp
= std::move(mvCols
[nOldPos
]);
453 mvCols
.erase( mvCols
.begin() + nOldPos
);
454 mvCols
.insert( mvCols
.begin() + nPos
, std::move(pTemp
) );
457 // determine new column area
458 tools::Rectangle
aToRect( GetFieldRect( nColumnId
) );
459 aToRect
.AdjustRight(2*MIN_COLUMNWIDTH
);
461 // do scroll, let redraw
462 if( pDataWin
->GetBackground().IsScrollable() )
464 tools::Long nScroll
= -aFromRect
.GetWidth();
465 tools::Rectangle aScrollArea
;
466 if ( nOldPos
> nPos
)
468 tools::Long nFrozenWidth
= GetFrozenWidth();
469 if ( aToRect
.Left() < nFrozenWidth
)
470 aToRect
.SetLeft( nFrozenWidth
);
471 aScrollArea
= tools::Rectangle(Point(aToRect
.Left(),0),
472 Point(aNextRect
.Right(),aDataWinSize
.Height()));
473 nScroll
*= -1; // reverse direction
476 aScrollArea
= tools::Rectangle(Point(aNextRect
.Left(),0),
477 Point(aToRect
.Right(),aDataWinSize
.Height()));
479 pDataWin
->Scroll( nScroll
, 0, aScrollArea
);
481 aToRect
.SetBottom( aScrollArea
.Bottom() );
482 Invalidate( aToRect
);
485 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
487 // adjust header bar positions
488 if ( pDataWin
->pHeaderBar
)
490 sal_uInt16 nNewPos
= nPos
;
491 if ( GetColumnId(0) == HandleColumnId
)
493 pDataWin
->pHeaderBar
->MoveItem(nColumnId
,nNewPos
);
495 // remember the column selection
496 SetToggledSelectedColumn(nSelectedColId
);
498 if ( !isAccessibleAlive() )
503 Any( AccessibleTableModelChange(
516 Any( AccessibleTableModelChange(
530 void BrowseBox::SetColumnTitle( sal_uInt16 nItemId
, const OUString
& rTitle
)
533 // never set title of the handle-column
534 if ( nItemId
== HandleColumnId
)
537 // get the position in the current array
538 sal_uInt16 nItemPos
= GetColumnPos( nItemId
);
539 if ( nItemPos
>= mvCols
.size() )
543 // does the state change?
544 BrowserColumn
*pCol
= mvCols
[ nItemPos
].get();
545 if ( pCol
->Title() == rTitle
)
548 OUString
sOld(pCol
->Title());
550 pCol
->Title() = rTitle
;
552 // adjust headerbar column
553 if ( pDataWin
->pHeaderBar
)
554 pDataWin
->pHeaderBar
->SetItemText( nItemId
, rTitle
);
557 // redraw visible columns
558 if ( GetUpdateMode() && ( pCol
->IsFrozen() || nItemPos
> nFirstCol
) )
559 Invalidate( tools::Rectangle( Point(0,0),
560 Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
563 if ( isAccessibleAlive() )
565 commitTableEvent( TABLE_COLUMN_DESCRIPTION_CHANGED
,
573 void BrowseBox::SetColumnWidth( sal_uInt16 nItemId
, sal_uLong nWidth
)
576 // get the position in the current array
577 size_t nItemPos
= GetColumnPos( nItemId
);
578 if ( nItemPos
>= mvCols
.size() )
581 // does the state change?
582 if ( nWidth
< LONG_MAX
&& mvCols
[ nItemPos
]->Width() == nWidth
)
585 tools::Long nOldWidth
= mvCols
[ nItemPos
]->Width();
587 // adjust last column, if necessary
588 if ( IsVisible() && nItemPos
== mvCols
.size() - 1 )
590 tools::Long nMaxWidth
= pDataWin
->GetSizePixel().Width();
591 nMaxWidth
-= pDataWin
->bAutoSizeLastCol
592 ? GetFieldRect(nItemId
).Left()
594 if ( pDataWin
->bAutoSizeLastCol
|| nWidth
> o3tl::make_unsigned(nMaxWidth
) )
596 nWidth
= nMaxWidth
> 16 ? nMaxWidth
: nOldWidth
;
601 // In AutoSizeLastColumn(), we call SetColumnWidth with nWidth==0xffff.
602 // Thus, check here, if the width has actually changed.
603 if( static_cast<sal_uLong
>(nOldWidth
) == nWidth
)
606 // do we want to display the change immediately?
607 bool bUpdate
= GetUpdateMode() &&
608 ( mvCols
[ nItemPos
]->IsFrozen() || nItemPos
>= nFirstCol
);
615 //!pDataWin->Update();
616 //!Control::Update();
620 mvCols
[ nItemPos
]->SetWidth(nWidth
, GetZoom());
622 // scroll and invalidate
625 // get X-Pos of the column changed
627 for ( size_t nCol
= 0; nCol
< nItemPos
; ++nCol
)
629 BrowserColumn
*pCol
= mvCols
[ nCol
].get();
630 if ( pCol
->IsFrozen() || nCol
>= nFirstCol
)
634 // actually scroll+invalidate
635 pDataWin
->GetOutDev()->SetClipRegion();
636 bool bSelVis
= bSelectionIsVisible
;
637 bSelectionIsVisible
= false;
638 if( GetBackground().IsScrollable() )
641 tools::Rectangle
aScrRect( nX
+ std::min( static_cast<sal_uLong
>(nOldWidth
), nWidth
), 0,
642 GetSizePixel().Width() , // the header is longer than the datawin
643 pDataWin
->GetPosPixel().Y() - 1 );
644 Control::Scroll( nWidth
-nOldWidth
, 0, aScrRect
, SCROLL_FLAGS
);
645 aScrRect
.SetBottom( pDataWin
->GetSizePixel().Height() );
646 pDataWin
->Scroll( nWidth
-nOldWidth
, 0, aScrRect
, SCROLL_FLAGS
);
647 tools::Rectangle
aInvRect( nX
, 0, nX
+ std::max( nWidth
, static_cast<sal_uLong
>(nOldWidth
) ), USHRT_MAX
);
648 Control::Invalidate( aInvRect
, InvalidateFlags::NoChildren
);
649 pDataWin
->Invalidate( aInvRect
);
653 Control::Invalidate( InvalidateFlags::NoChildren
);
654 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
658 //!pDataWin->Update();
659 //!Control::Update();
660 bSelectionIsVisible
= bSelVis
;
666 // adjust headerbar column
667 if ( pDataWin
->pHeaderBar
)
668 pDataWin
->pHeaderBar
->SetItemSize(
669 nItemId
? nItemId
: USHRT_MAX
- 1, nWidth
);
671 // adjust last column
672 if ( nItemPos
!= mvCols
.size() - 1 )
673 AutoSizeLastColumn();
677 void BrowseBox::AutoSizeLastColumn()
679 if ( pDataWin
->bAutoSizeLastCol
&&
680 pDataWin
->GetUpdateMode() )
682 sal_uInt16 nId
= GetColumnId( static_cast<sal_uInt16
>(mvCols
.size()) - 1 );
683 SetColumnWidth( nId
, LONG_MAX
);
684 ColumnResized( nId
);
689 void BrowseBox::RemoveColumn( sal_uInt16 nItemId
)
692 // get column position
693 sal_uInt16 nPos
= GetColumnPos(nItemId
);
694 if ( nPos
>= ColCount() )
698 // correct column selection
700 pColSel
->Remove( nPos
);
702 // correct column cursor
703 if ( nCurColId
== nItemId
)
707 mvCols
.erase( mvCols
.begin() + nPos
);
708 if ( nFirstCol
>= nPos
&& nFirstCol
> FrozenColCount() )
710 OSL_ENSURE(nFirstCol
> 0,"FirstCol must be greater zero!");
714 // handlecolumn not in headerbar
717 if ( pDataWin
->pHeaderBar
)
718 pDataWin
->pHeaderBar
->RemoveItem( nItemId
);
723 if ( pDataWin
->pHeaderBar
)
725 pDataWin
->pHeaderBar
->SetPosSizePixel(
727 Size( GetOutputSizePixel().Width(), GetTitleHeight() )
732 // correct vertical scrollbar
735 // trigger repaint, if necessary
736 if ( GetUpdateMode() )
738 pDataWin
->Invalidate();
739 Control::Invalidate();
740 if ( pDataWin
->bAutoSizeLastCol
&& nPos
==ColCount() )
741 SetColumnWidth( GetColumnId( nPos
- 1 ), LONG_MAX
);
744 if ( !isAccessibleAlive() )
749 Any( AccessibleTableModelChange(COLUMNS_REMOVED
,
759 commitHeaderBarEvent(
762 Any( CreateAccessibleColumnHeader( nPos
) ),
768 void BrowseBox::RemoveColumns()
770 size_t nOldCount
= mvCols
.size();
772 // remove all columns
775 // correct column selection
778 pColSel
->SelectAll(false);
779 pColSel
->SetTotalRange( Range( 0, 0 ) );
782 // correct column cursor
786 if ( pDataWin
->pHeaderBar
)
787 pDataWin
->pHeaderBar
->Clear( );
789 // correct vertical scrollbar
792 // trigger repaint if necessary
793 if ( GetUpdateMode() )
795 pDataWin
->Invalidate();
796 Control::Invalidate();
799 if ( !isAccessibleAlive() )
802 if ( mvCols
.size() == nOldCount
)
805 // all columns should be removed, so we remove the column header bar and append it again
806 // to avoid to notify every column remove
807 commitBrowseBoxEvent(
810 Any(m_pImpl
->getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar
))
813 // and now append it again
814 commitBrowseBoxEvent(
816 Any(m_pImpl
->getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar
)),
820 // notify a table model change
823 Any ( AccessibleTableModelChange( COLUMNS_REMOVED
,
835 OUString
BrowseBox::GetColumnTitle( sal_uInt16 nId
) const
838 sal_uInt16 nItemPos
= GetColumnPos( nId
);
839 if ( nItemPos
>= mvCols
.size() )
841 return mvCols
[ nItemPos
]->Title();
844 sal_Int32
BrowseBox::GetRowCount() const
849 sal_uInt16
BrowseBox::ColCount() const
851 return static_cast<sal_uInt16
>(mvCols
.size());
854 tools::Long
BrowseBox::ImpGetDataRowHeight() const
856 BrowseBox
*pThis
= const_cast<BrowseBox
*>(this);
857 pThis
->m_nDataRowHeight
= pThis
->CalcReverseZoom(pDataWin
->GetTextHeight() + 4);
859 pDataWin
->Invalidate();
860 return m_nDataRowHeight
;
863 void BrowseBox::SetDataRowHeight( tools::Long nPixel
)
866 m_nDataRowHeight
= CalcReverseZoom(nPixel
);
868 pDataWin
->Invalidate();
871 void BrowseBox::SetTitleLines( sal_uInt16 nLines
)
874 nTitleLines
= nLines
;
877 sal_Int32
BrowseBox::ScrollColumns( sal_Int32 nCols
)
880 if ( nFirstCol
+ nCols
< 0 ||
881 o3tl::make_unsigned(nFirstCol
+ nCols
) >= mvCols
.size() )
884 // implicitly hides cursor while scrolling
887 bool bScrollable
= pDataWin
->GetBackground().IsScrollable();
888 bool bInvalidateView
= false;
890 // scrolling one column to the right?
893 // update internal value and scrollbar
895 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
899 bInvalidateView
= true;
903 tools::Long nDelta
= mvCols
[ nFirstCol
-1 ]->Width();
904 tools::Long nFrozenWidth
= GetFrozenWidth();
906 tools::Rectangle
aScrollRect( Point( nFrozenWidth
+ nDelta
, 0 ),
907 Size ( GetOutputSizePixel().Width() - nFrozenWidth
- nDelta
,
911 // scroll the header bar area (if there is no dedicated HeaderBar control)
912 if ( !pDataWin
->pHeaderBar
&& nTitleLines
)
915 Scroll( -nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
917 // invalidate the area of the column which was scrolled out to the left hand side
918 tools::Rectangle
aInvalidateRect( aScrollRect
);
919 aInvalidateRect
.SetLeft( nFrozenWidth
);
920 aInvalidateRect
.SetRight( nFrozenWidth
+ nDelta
- 1 );
921 Invalidate( aInvalidateRect
);
924 // scroll the data-area
925 aScrollRect
.SetBottom( pDataWin
->GetOutputSizePixel().Height() );
928 pDataWin
->Scroll( -nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
930 // invalidate the area of the column which was scrolled out to the left hand side
931 aScrollRect
.SetLeft( nFrozenWidth
);
932 aScrollRect
.SetRight( nFrozenWidth
+ nDelta
- 1 );
933 pDataWin
->Invalidate( aScrollRect
);
937 // scrolling one column to the left?
938 else if ( nCols
== -1 )
941 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
945 bInvalidateView
= true;
949 tools::Long nDelta
= mvCols
[ nFirstCol
]->Width();
950 tools::Long nFrozenWidth
= GetFrozenWidth();
952 tools::Rectangle
aScrollRect( Point( nFrozenWidth
, 0 ),
953 Size ( GetOutputSizePixel().Width() - nFrozenWidth
,
957 // scroll the header bar area (if there is no dedicated HeaderBar control)
958 if ( !pDataWin
->pHeaderBar
&& nTitleLines
)
960 Scroll( nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
963 // scroll the data-area
964 aScrollRect
.SetBottom( pDataWin
->GetOutputSizePixel().Height() );
965 pDataWin
->Scroll( nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
970 if ( GetUpdateMode() )
972 Invalidate( tools::Rectangle(
973 Point( GetFrozenWidth(), 0 ),
974 Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
975 pDataWin
->Invalidate( tools::Rectangle(
976 Point( GetFrozenWidth(), 0 ),
977 pDataWin
->GetSizePixel() ) );
980 nFirstCol
= nFirstCol
+ static_cast<sal_uInt16
>(nCols
);
981 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
984 // adjust external headerbar, if necessary
985 if ( pDataWin
->pHeaderBar
)
987 tools::Long nWidth
= 0;
988 for ( size_t nCol
= 0;
989 nCol
< mvCols
.size() && nCol
< nFirstCol
;
992 // not the handle column
993 if ( mvCols
[ nCol
]->GetId() )
994 nWidth
+= mvCols
[ nCol
]->Width();
997 pDataWin
->pHeaderBar
->SetOffset( nWidth
);
1000 if( bInvalidateView
)
1002 Control::Invalidate( InvalidateFlags::NoChildren
);
1003 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
1006 // implicitly show cursor after scrolling
1019 sal_Int32
BrowseBox::ScrollRows( sal_Int32 nRows
)
1021 // compute new top row
1022 sal_Int32 nTmpMin
= std::min( static_cast<sal_Int32
>(nTopRow
+ nRows
), static_cast<sal_Int32
>(nRowCount
- 1) );
1024 sal_Int32 nNewTopRow
= std::max
<sal_Int32
>( nTmpMin
, 0 );
1026 if ( nNewTopRow
== nTopRow
)
1029 sal_uInt16 nVisibleRows
=
1030 static_cast<sal_uInt16
>(pDataWin
->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1032 VisibleRowsChanged(nNewTopRow
, nVisibleRows
);
1034 // compute new top row again (nTopRow might have changed!)
1035 nTmpMin
= std::min( static_cast<tools::Long
>(nTopRow
+ nRows
), static_cast<tools::Long
>(nRowCount
- 1) );
1037 nNewTopRow
= std::max
<tools::Long
>( nTmpMin
, 0 );
1041 // scroll area on screen and/or repaint
1042 tools::Long nDeltaY
= GetDataRowHeight() * ( nNewTopRow
- nTopRow
);
1043 sal_Int32 nOldTopRow
= nTopRow
;
1044 nTopRow
= nNewTopRow
;
1046 if ( GetUpdateMode() )
1048 pVScroll
->SetRange( Range( 0L, nRowCount
) );
1049 pVScroll
->SetThumbPos( nTopRow
);
1051 if( pDataWin
->GetBackground().IsScrollable() &&
1052 std::abs( nDeltaY
) > 0 &&
1053 std::abs( nDeltaY
) < pDataWin
->GetSizePixel().Height() )
1055 pDataWin
->Scroll( 0, static_cast<short>(-nDeltaY
), SCROLL_FLAGS
);
1058 pDataWin
->Invalidate();
1060 if ( nTopRow
- nOldTopRow
)
1066 return nTopRow
- nOldTopRow
;
1070 void BrowseBox::RowModified( sal_Int32 nRow
, sal_uInt16 nColId
)
1073 if ( !GetUpdateMode() )
1076 tools::Rectangle aRect
;
1077 if ( nColId
== BROWSER_INVALIDID
)
1078 // invalidate the whole row
1079 aRect
= tools::Rectangle( Point( 0, (nRow
-nTopRow
) * GetDataRowHeight() ),
1080 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) );
1083 // invalidate the specific field
1084 aRect
= GetFieldRectPixel( nRow
, nColId
, false );
1086 pDataWin
->Invalidate( aRect
);
1090 void BrowseBox::Clear()
1092 // adjust the total number of rows
1094 sal_Int32 nOldRowCount
= nRowCount
;
1102 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1103 nCurRow
= BROWSER_ENDOFSELECTION
;
1107 // nFirstCol may not be reset, else the scrolling code will become confused.
1108 // nFirstCol may only be changed when adding or deleting columns
1109 // nFirstCol = 0; -> wrong!
1110 aHScroll
->SetThumbPos( 0 );
1111 pVScroll
->SetThumbPos( 0 );
1119 if ( !isAccessibleAlive() )
1122 // all rows should be removed, so we remove the row header bar and append it again
1123 // to avoid to notify every row remove
1124 if ( nOldRowCount
== nRowCount
)
1127 commitBrowseBoxEvent(
1130 Any( m_pImpl
->getAccessibleHeaderBar( AccessibleBrowseBoxObjType::RowHeaderBar
) )
1133 // and now append it again
1134 commitBrowseBoxEvent(
1136 Any( m_pImpl
->getAccessibleHeaderBar( AccessibleBrowseBoxObjType::RowHeaderBar
) ),
1140 // notify a table model change
1142 TABLE_MODEL_CHANGED
,
1143 Any( AccessibleTableModelChange(ROWS_REMOVED
,
1153 void BrowseBox::RowInserted( sal_Int32 nRow
, sal_Int32 nNumRows
, bool bDoPaint
, bool bKeepSelection
)
1158 else if (nRow
> nRowCount
) // maximal = nRowCount
1161 if ( nNumRows
<= 0 )
1164 // adjust total row count
1165 bool bLastRow
= nRow
>= nRowCount
;
1166 nRowCount
+= nNumRows
;
1170 // must we paint the new rows?
1171 sal_Int32 nOldCurRow
= nCurRow
;
1172 Size aSz
= pDataWin
->GetOutputSizePixel();
1173 if ( bDoPaint
&& nRow
>= nTopRow
&&
1174 nRow
<= nTopRow
+ aSz
.Height() / GetDataRowHeight() )
1176 tools::Long nY
= (nRow
-nTopRow
) * GetDataRowHeight();
1179 // scroll down the rows behind the new row
1180 pDataWin
->GetOutDev()->SetClipRegion();
1181 if( pDataWin
->GetBackground().IsScrollable() )
1183 pDataWin
->Scroll( 0, GetDataRowHeight() * nNumRows
,
1184 tools::Rectangle( Point( 0, nY
),
1185 Size( aSz
.Width(), aSz
.Height() - nY
) ),
1189 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
1192 // scroll would cause a repaint, so we must explicitly invalidate
1193 pDataWin
->Invalidate( tools::Rectangle( Point( 0, nY
),
1194 Size( aSz
.Width(), nNumRows
* GetDataRowHeight() ) ) );
1197 // correct top row if necessary
1198 if ( nRow
< nTopRow
)
1199 nTopRow
+= nNumRows
;
1201 // adjust the selection
1202 if ( bMultiSelection
)
1203 uRow
.pSel
->Insert( nRow
, nNumRows
);
1204 else if ( uRow
.nSel
!= BROWSER_ENDOFSELECTION
&& nRow
<= uRow
.nSel
)
1205 uRow
.nSel
+= nNumRows
;
1207 // adjust the cursor
1208 if ( nCurRow
== BROWSER_ENDOFSELECTION
)
1209 GoToRow( 0, false, bKeepSelection
);
1210 else if ( nRow
<= nCurRow
)
1212 nCurRow
+= nNumRows
;
1213 GoToRow( nCurRow
, false, bKeepSelection
);
1216 // adjust the vertical scrollbar
1220 AutoSizeLastColumn();
1224 // notify accessible that rows were inserted
1225 if ( isAccessibleAlive() )
1228 TABLE_MODEL_CHANGED
,
1229 Any( AccessibleTableModelChange(
1240 for (tools::Long i
= nRow
+1 ; i
<= nRowCount
; ++i
)
1242 commitHeaderBarEvent(
1244 Any( CreateAccessibleRowHeader( i
) ),
1251 if ( nCurRow
!= nOldCurRow
)
1254 DBG_ASSERT(nRowCount
> 0,"BrowseBox: nRowCount <= 0");
1255 DBG_ASSERT(nCurRow
>= 0,"BrowseBox: nCurRow < 0");
1256 DBG_ASSERT(nCurRow
< nRowCount
,"nCurRow >= nRowCount");
1260 void BrowseBox::RowRemoved( sal_Int32 nRow
, sal_Int32 nNumRows
, bool bDoPaint
)
1265 else if ( nRow
>= nRowCount
)
1266 nRow
= nRowCount
- 1;
1268 if ( nNumRows
<= 0 )
1271 if ( nRowCount
<= 0 )
1276 // hide cursor and selection
1277 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1282 // adjust total row count
1283 nRowCount
-= nNumRows
;
1284 if (nRowCount
< 0) nRowCount
= 0;
1285 sal_Int32 nOldCurRow
= nCurRow
;
1287 // adjust the selection
1288 if ( bMultiSelection
)
1289 // uRow.pSel->Remove( nRow, nNumRows );
1290 for ( tools::Long i
= 0; i
< nNumRows
; i
++ )
1291 uRow
.pSel
->Remove( nRow
);
1292 else if ( nRow
< uRow
.nSel
&& uRow
.nSel
>= nNumRows
)
1293 uRow
.nSel
-= nNumRows
;
1294 else if ( nRow
<= uRow
.nSel
)
1295 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1297 // adjust the cursor
1298 if ( nRowCount
== 0 ) // don't compare nRowCount with nNumRows as nNumRows already was subtracted from nRowCount
1299 nCurRow
= BROWSER_ENDOFSELECTION
;
1300 else if ( nRow
< nCurRow
)
1302 nCurRow
-= std::min( nCurRow
- nRow
, nNumRows
);
1303 // with the above nCurRow points a) to the first row after the removed block or b) to the same line
1304 // as before, but moved up nNumRows
1305 // case a) needs an additional correction if the last n lines were deleted, as 'the first row after the
1306 // removed block' is an invalid position then
1307 // FS - 09/28/99 - 68429
1308 if (nCurRow
== nRowCount
)
1311 else if( nRow
== nCurRow
&& nCurRow
== nRowCount
)
1312 nCurRow
= nRowCount
-1;
1314 // is the deleted row visible?
1315 Size aSz
= pDataWin
->GetOutputSizePixel();
1316 if ( nRow
>= nTopRow
&&
1317 nRow
<= nTopRow
+ aSz
.Height() / GetDataRowHeight() )
1321 // scroll up the rows behind the deleted row
1322 // if there are Rows behind
1323 if (nRow
< nRowCount
)
1325 tools::Long nY
= (nRow
-nTopRow
) * GetDataRowHeight();
1326 pDataWin
->GetOutDev()->SetClipRegion();
1327 if( pDataWin
->GetBackground().IsScrollable() )
1329 pDataWin
->Scroll( 0, - static_cast<short>(GetDataRowHeight()) * nNumRows
,
1330 tools::Rectangle( Point( 0, nY
), Size( aSz
.Width(),
1331 aSz
.Height() - nY
+ nNumRows
*GetDataRowHeight() ) ),
1335 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
1339 // Repaint the Rect of the deleted row
1340 tools::Rectangle
aRect(
1341 Point( 0, (nRow
-nTopRow
)*GetDataRowHeight() ),
1342 Size( pDataWin
->GetSizePixel().Width(),
1343 nNumRows
* GetDataRowHeight() ) );
1344 pDataWin
->Invalidate( aRect
);
1348 // is the deleted row above of the visible area?
1349 else if ( nRow
< nTopRow
)
1350 nTopRow
= nTopRow
>= nNumRows
? nTopRow
-nNumRows
: 0;
1354 // reshow cursor and selection
1356 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1359 // adjust the vertical scrollbar
1361 AutoSizeLastColumn();
1364 if ( isAccessibleAlive() )
1366 if ( nRowCount
== 0 )
1368 // all columns should be removed, so we remove the column header bar and append it again
1369 // to avoid to notify every column remove
1370 commitBrowseBoxEvent(
1373 Any( m_pImpl
->getAccessibleHeaderBar( AccessibleBrowseBoxObjType::RowHeaderBar
) )
1376 // and now append it again
1377 commitBrowseBoxEvent(
1379 Any(m_pImpl
->getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar
)),
1382 commitBrowseBoxEvent(
1385 Any( m_pImpl
->getAccessibleTable() )
1388 // and now append it again
1389 commitBrowseBoxEvent(
1391 Any( m_pImpl
->getAccessibleTable() ),
1398 TABLE_MODEL_CHANGED
,
1399 Any( AccessibleTableModelChange(
1410 for (tools::Long i
= nRow
+1 ; i
<= (nRow
+nNumRows
) ; ++i
)
1412 commitHeaderBarEvent(
1415 Any( CreateAccessibleRowHeader( i
) ),
1422 if ( nOldCurRow
!= nCurRow
)
1425 DBG_ASSERT(nRowCount
>= 0,"BrowseBox: nRowCount < 0");
1426 DBG_ASSERT(nCurRow
>= 0 || nRowCount
== 0,"BrowseBox: nCurRow < 0 && nRowCount != 0");
1427 DBG_ASSERT(nCurRow
< nRowCount
,"nCurRow >= nRowCount");
1431 bool BrowseBox::GoToRow( sal_Int32 nRow
)
1433 return GoToRow(nRow
, false);
1437 bool BrowseBox::GoToRow( sal_Int32 nRow
, bool bRowColMove
, bool bKeepSelection
)
1439 sal_Int32 nOldCurRow
= nCurRow
;
1442 if ( nRow
== nCurRow
&& ( bMultiSelection
|| uRow
.nSel
== nRow
) )
1446 if ( nRow
< 0 || nRow
>= nRowCount
)
1450 if ( !bRowColMove
&& !IsCursorMoveAllowed( nRow
, nCurColId
) )
1453 // compute the last visible row
1454 Size
aSz( pDataWin
->GetSizePixel() );
1455 sal_uInt16 nVisibleRows
= sal_uInt16( aSz
.Height() / GetDataRowHeight() - 1 );
1456 sal_Int32 nLastRow
= nTopRow
+ nVisibleRows
;
1459 pDataWin
->EnterUpdateLock();
1461 // remove old highlight, if necessary
1462 if ( !bMultiSelection
&& !bKeepSelection
)
1467 bool bWasVisible
= bSelectionIsVisible
;
1468 if (! bMultiSelection
)
1470 if( !bKeepSelection
)
1471 bSelectionIsVisible
= false;
1473 if ( nRow
< nTopRow
)
1474 ScrollRows( nRow
- nTopRow
);
1475 else if ( nRow
> nLastRow
)
1476 ScrollRows( nRow
- nLastRow
);
1477 bSelectionIsVisible
= bWasVisible
;
1479 // adjust cursor (selection) and thumb
1480 if ( GetUpdateMode() )
1481 pVScroll
->SetThumbPos( nTopRow
);
1483 // relative positioning (because nCurRow might have changed in the meantime)!
1484 if (nCurRow
!= BROWSER_ENDOFSELECTION
)
1485 nCurRow
= nCurRow
+ (nRow
- nOldCurRow
);
1487 // make sure that the current position is valid
1488 if (nCurRow
== BROWSER_ENDOFSELECTION
&& nRowCount
> 0)
1490 else if ( nCurRow
>= nRowCount
)
1491 nCurRow
= nRowCount
- 1;
1492 aSelRange
= Range( nCurRow
, nCurRow
);
1494 // display new highlight if necessary
1495 if ( !bMultiSelection
&& !bKeepSelection
)
1499 pDataWin
->LeaveUpdateLock();
1502 if ( !bMultiSelection
&& !bKeepSelection
)
1505 if ( !bRowColMove
&& nOldCurRow
!= nCurRow
)
1508 if ( !bMultiSelection
&& !bKeepSelection
)
1519 bool BrowseBox::GoToColumnId( sal_uInt16 nColId
)
1521 return GoToColumnId(nColId
, true);
1525 bool BrowseBox::GoToColumnId( sal_uInt16 nColId
, bool bMakeVisible
, bool bRowColMove
)
1531 if (!bRowColMove
&& !IsCursorMoveAllowed( nCurRow
, nColId
) )
1534 if ( nColId
!= nCurColId
|| (bMakeVisible
&& !IsFieldVisible(nCurRow
, nColId
, true)))
1536 sal_uInt16 nNewPos
= GetColumnPos(nColId
);
1537 BrowserColumn
* pColumn
= (nNewPos
< mvCols
.size()) ? mvCols
[ nNewPos
].get() : nullptr;
1538 DBG_ASSERT( pColumn
, "no column object - invalid id?" );
1545 bool bScrolled
= false;
1547 sal_uInt16 nFirstPos
= nFirstCol
;
1548 sal_uInt16 nWidth
= static_cast<sal_uInt16
>(pColumn
->Width());
1549 sal_uInt16 nLastPos
= GetColumnAtXPosPixel(
1550 pDataWin
->GetSizePixel().Width()-nWidth
);
1551 sal_uInt16 nFrozen
= FrozenColCount();
1552 if ( bMakeVisible
&& nLastPos
&&
1553 nNewPos
>= nFrozen
&& ( nNewPos
< nFirstPos
|| nNewPos
> nLastPos
) )
1555 if ( nNewPos
< nFirstPos
)
1556 ScrollColumns( nNewPos
-nFirstPos
);
1557 else if ( nNewPos
> nLastPos
)
1558 ScrollColumns( nNewPos
-nLastPos
);
1565 //try to move to nCurRow, nColId
1566 CursorMoveAttempt
aAttempt(nCurRow
, nColId
, bScrolled
);
1567 //Detect if we are already in a call to BrowseBox::GoToColumnId
1568 //but the attempt is impossible and we are simply recursing
1569 //into BrowseBox::GoToColumnId with the same impossible to
1570 //fulfill conditions
1571 if (m_aGotoStack
.empty() || aAttempt
!= m_aGotoStack
.top())
1573 m_aGotoStack
.push(aAttempt
);
1584 bool BrowseBox::GoToRowColumnId( sal_Int32 nRow
, sal_uInt16 nColId
)
1588 if ( nRow
< 0 || nRow
>= nRowCount
)
1595 if ( nRow
== nCurRow
&& ( bMultiSelection
|| uRow
.nSel
== nRow
) &&
1596 nColId
== nCurColId
&& IsFieldVisible(nCurRow
, nColId
, true))
1600 if (!IsCursorMoveAllowed(nRow
, nColId
))
1604 bool bMoved
= GoToRow(nRow
, true) && GoToColumnId(nColId
, true, true);
1614 void BrowseBox::SetNoSelection()
1617 // is there no selection
1618 if ( ( !pColSel
|| !pColSel
->GetSelectCount() ) &&
1619 ( ( !bMultiSelection
&& uRow
.nSel
== BROWSER_ENDOFSELECTION
) ||
1620 ( bMultiSelection
&& !uRow
.pSel
->GetSelectCount() ) ) )
1624 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1628 if ( bMultiSelection
)
1629 uRow
.pSel
->SelectAll(false);
1631 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1633 pColSel
->SelectAll(false);
1640 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1642 if ( isAccessibleAlive() )
1653 void BrowseBox::SelectAll()
1656 if ( !bMultiSelection
)
1659 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1664 pColSel
->SelectAll(false);
1665 uRow
.pSel
->SelectAll();
1667 // don't highlight handle column
1668 BrowserColumn
*pFirstCol
= mvCols
[ 0 ].get();
1669 tools::Long nOfsX
= pFirstCol
->GetId() ? 0 : pFirstCol
->Width();
1671 // highlight the row selection
1674 tools::Rectangle aHighlightRect
;
1675 sal_uInt16 nVisibleRows
=
1676 static_cast<sal_uInt16
>(pDataWin
->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1677 for ( sal_Int32 nRow
= std::max
<sal_Int32
>( nTopRow
, uRow
.pSel
->FirstSelected() );
1678 nRow
!= BROWSER_ENDOFSELECTION
&& nRow
< nTopRow
+ nVisibleRows
;
1679 nRow
= uRow
.pSel
->NextSelected() )
1680 aHighlightRect
.Union( tools::Rectangle(
1681 Point( nOfsX
, (nRow
-nTopRow
)*GetDataRowHeight() ),
1682 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) ) );
1683 pDataWin
->Invalidate( aHighlightRect
);
1692 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1694 if ( !isAccessibleAlive() )
1702 commitHeaderBarEvent(
1707 ); // column header event
1709 commitHeaderBarEvent(
1714 ); // row header event
1718 void BrowseBox::SelectRow( sal_Int32 nRow
, bool _bSelect
, bool bExpand
)
1721 if ( !bMultiSelection
)
1723 // deselecting is impossible, selecting via cursor
1725 GoToRow(nRow
, false);
1729 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1731 // remove old selection?
1732 if ( !bExpand
|| !bMultiSelection
)
1735 if ( bMultiSelection
)
1736 uRow
.pSel
->SelectAll(false);
1738 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1740 pColSel
->SelectAll(false);
1743 // set new selection
1745 && ( ( bMultiSelection
1746 && uRow
.pSel
->GetTotalRange().Max() >= nRow
1747 && uRow
.pSel
->Select( nRow
, _bSelect
)
1749 || ( !bMultiSelection
1750 && ( uRow
.nSel
= nRow
) != BROWSER_ENDOFSELECTION
)
1754 // don't highlight handle column
1755 BrowserColumn
*pFirstCol
= mvCols
[ 0 ].get();
1756 tools::Long nOfsX
= pFirstCol
->GetId() ? 0 : pFirstCol
->Width();
1758 // highlight only newly selected part
1759 tools::Rectangle
aRect(
1760 Point( nOfsX
, (nRow
-nTopRow
)*GetDataRowHeight() ),
1761 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) );
1762 pDataWin
->Invalidate( aRect
);
1771 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1773 if ( !isAccessibleAlive() )
1781 commitHeaderBarEvent(
1786 ); // row header event
1790 sal_Int32
BrowseBox::GetSelectRowCount() const
1793 return bMultiSelection
? uRow
.pSel
->GetSelectCount() :
1794 uRow
.nSel
== BROWSER_ENDOFSELECTION
? 0 : 1;
1798 void BrowseBox::SelectColumnPos( sal_uInt16 nNewColPos
, bool _bSelect
, bool bMakeVisible
)
1801 if ( !bColumnCursor
|| nNewColPos
== BROWSER_INVALIDID
)
1804 if ( !bMultiSelection
)
1807 GoToColumnId( mvCols
[ nNewColPos
]->GetId(), bMakeVisible
);
1812 if ( !GoToColumnId( mvCols
[ nNewColPos
]->GetId(), bMakeVisible
) )
1816 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1818 if ( bMultiSelection
)
1819 uRow
.pSel
->SelectAll(false);
1821 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1822 pColSel
->SelectAll(false);
1824 if ( pColSel
->Select( nNewColPos
, _bSelect
) )
1826 // GoToColumnId( mvCols->GetObject(nNewColPos)->GetId(), bMakeVisible );
1828 // only highlight painted areas
1830 tools::Rectangle
aFieldRectPix( GetFieldRectPixel( nCurRow
, nCurColId
, false ) );
1831 tools::Rectangle
aRect(
1832 Point( aFieldRectPix
.Left() - MIN_COLUMNWIDTH
, 0 ),
1833 Size( mvCols
[ nNewColPos
]->Width(),
1834 pDataWin
->GetOutputSizePixel().Height() ) );
1835 pDataWin
->Invalidate( aRect
);
1841 if ( isAccessibleAlive() )
1848 commitHeaderBarEvent(
1853 ); // column header event
1858 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1862 sal_uInt16
BrowseBox::GetSelectColumnCount() const
1865 // while bAutoSelect (==!pColSel), 1 if any rows (yes rows!) else none
1866 return pColSel
? static_cast<sal_uInt16
>(pColSel
->GetSelectCount()) :
1867 nCurRow
>= 0 ? 1 : 0;
1871 sal_Int32
BrowseBox::FirstSelectedColumn( ) const
1873 return pColSel
? pColSel
->FirstSelected() : BROWSER_ENDOFSELECTION
;
1877 sal_Int32
BrowseBox::FirstSelectedRow()
1880 return bMultiSelection
? uRow
.pSel
->FirstSelected() : uRow
.nSel
;
1884 sal_Int32
BrowseBox::NextSelectedRow()
1887 return bMultiSelection
? uRow
.pSel
->NextSelected() : BROWSER_ENDOFSELECTION
;
1891 sal_Int32
BrowseBox::LastSelectedRow()
1894 return bMultiSelection
? uRow
.pSel
->LastSelected() : uRow
.nSel
;
1898 bool BrowseBox::IsRowSelected( sal_Int32 nRow
) const
1901 return bMultiSelection
? uRow
.pSel
->IsSelected(nRow
) : nRow
== uRow
.nSel
;
1905 bool BrowseBox::IsColumnSelected( sal_uInt16 nColumnId
) const
1908 return pColSel
? pColSel
->IsSelected( GetColumnPos(nColumnId
) ) :
1909 nCurColId
== nColumnId
;
1913 void BrowseBox::MakeFieldVisible
1915 sal_Int32 nRow
, // line number of the field (starting with 0)
1916 sal_uInt16 nColId
// column ID of the field
1921 Makes visible the field described in 'nRow' and 'nColId' by scrolling
1930 Size aTestSize
= pDataWin
->GetSizePixel();
1932 if ( !bBootstrapped
|| aTestSize
.IsEmpty() )
1935 // is it visible already?
1936 bool bVisible
= IsFieldVisible( nRow
, nColId
, true/*bComplete*/ );
1940 // calculate column position, field rectangle and painting area
1941 sal_uInt16 nColPos
= GetColumnPos( nColId
);
1942 tools::Rectangle aFieldRect
= GetFieldRectPixel( nRow
, nColId
, false );
1943 tools::Rectangle
aDataRect( Point(0, 0), pDataWin
->GetSizePixel() );
1945 // positioned outside on the left?
1946 if ( nColPos
>= FrozenColCount() && nColPos
< nFirstCol
)
1947 // => scroll to the right
1948 ScrollColumns( nColPos
- nFirstCol
);
1950 // while outside on the right
1951 while ( aDataRect
.Right() < aFieldRect
.Right() )
1953 // => scroll to the left
1954 if ( ScrollColumns( 1 ) != 1 )
1955 // no more need to scroll
1957 aFieldRect
= GetFieldRectPixel( nRow
, nColId
, false );
1960 // positioned outside above?
1961 if ( nRow
< nTopRow
)
1962 // scroll further to the bottom
1963 ScrollRows( nRow
- nTopRow
);
1965 // positioned outside below?
1966 sal_Int32 nBottomRow
= nTopRow
+ GetVisibleRows();
1967 // decrement nBottomRow to make it the number of the last visible line
1968 // (count starts with 0!).
1969 // Example: BrowseBox contains exactly one entry. nBottomRow := 0 + 1 - 1
1973 if ( nRow
> nBottomRow
)
1974 // scroll further to the top
1975 ScrollRows( nRow
- nBottomRow
);
1979 bool BrowseBox::IsFieldVisible( sal_Int32 nRow
, sal_uInt16 nColumnId
,
1980 bool bCompletely
) const
1983 // hidden by frozen column?
1984 sal_uInt16 nColPos
= GetColumnPos( nColumnId
);
1985 if ( nColPos
>= FrozenColCount() && nColPos
< nFirstCol
)
1988 tools::Rectangle
aRect( ImplFieldRectPixel( nRow
, nColumnId
) );
1989 if ( aRect
.IsEmpty() )
1992 // get the visible area
1993 tools::Rectangle
aOutRect( Point(0, 0), pDataWin
->GetOutputSizePixel() );
1996 // test if the field is completely visible
1997 return aOutRect
.Contains( aRect
);
1999 // test if the field is partly of completely visible
2000 return !aOutRect
.Intersection( aRect
).IsEmpty();
2004 tools::Rectangle
BrowseBox::GetFieldRectPixel( sal_Int32 nRow
, sal_uInt16 nColumnId
,
2005 bool bRelToBrowser
) const
2008 // get the rectangle relative to DataWin
2009 tools::Rectangle
aRect( ImplFieldRectPixel( nRow
, nColumnId
) );
2010 if ( aRect
.IsEmpty() )
2013 // adjust relative to BrowseBox's output area
2014 Point
aTopLeft( aRect
.TopLeft() );
2015 if ( bRelToBrowser
)
2017 aTopLeft
= pDataWin
->OutputToScreenPixel( aTopLeft
);
2018 aTopLeft
= ScreenToOutputPixel( aTopLeft
);
2021 return tools::Rectangle( aTopLeft
, aRect
.GetSize() );
2025 tools::Rectangle
BrowseBox::GetRowRectPixel( sal_Int32 nRow
) const
2028 // get the rectangle relative to DataWin
2029 tools::Rectangle aRect
;
2030 if ( nTopRow
> nRow
)
2031 // row is above visible area
2033 aRect
= tools::Rectangle(
2034 Point( 0, GetDataRowHeight() * (nRow
-nTopRow
) ),
2035 Size( pDataWin
->GetOutputSizePixel().Width(), GetDataRowHeight() ) );
2036 if ( aRect
.Top() > pDataWin
->GetOutputSizePixel().Height() )
2037 // row is below visible area
2040 // adjust relative to BrowseBox's output area
2041 Point
aTopLeft( aRect
.TopLeft() );
2042 aTopLeft
= pDataWin
->OutputToScreenPixel( aTopLeft
);
2043 aTopLeft
= ScreenToOutputPixel( aTopLeft
);
2045 return tools::Rectangle( aTopLeft
, aRect
.GetSize() );
2049 tools::Rectangle
BrowseBox::ImplFieldRectPixel( sal_Int32 nRow
, sal_uInt16 nColumnId
) const
2052 // compute the X-coordinate relative to DataWin by accumulation
2053 tools::Long nColX
= 0;
2054 sal_uInt16 nFrozenCols
= FrozenColCount();
2057 nCol
< mvCols
.size() && mvCols
[ nCol
]->GetId() != nColumnId
;
2059 if ( mvCols
[ nCol
]->IsFrozen() || nCol
>= nFirstCol
)
2060 nColX
+= mvCols
[ nCol
]->Width();
2062 if ( nCol
>= mvCols
.size() || ( nCol
>= nFrozenCols
&& nCol
< nFirstCol
) )
2063 return tools::Rectangle();
2065 // compute the Y-coordinate relative to DataWin
2066 tools::Long nRowY
= GetDataRowHeight();
2067 if ( nRow
!= BROWSER_ENDOFSELECTION
) // #105497# OJ
2068 nRowY
= ( nRow
- nTopRow
) * GetDataRowHeight();
2070 // assemble the Rectangle relative to DataWin
2071 return tools::Rectangle(
2072 Point( nColX
+ MIN_COLUMNWIDTH
, nRowY
),
2073 Size( (mvCols
[nCol
]->Width() == LONG_MAX
2074 ? LONG_MAX
- (nColX
+ MIN_COLUMNWIDTH
) : mvCols
[ nCol
]->Width() - 2*MIN_COLUMNWIDTH
),
2075 GetDataRowHeight() - 1 ) );
2079 sal_Int32
BrowseBox::GetRowAtYPosPixel( tools::Long nY
, bool bRelToBrowser
) const
2082 // compute the Y-coordinate
2083 if ( bRelToBrowser
)
2085 Point aDataTopLeft
= pDataWin
->OutputToScreenPixel( Point(0, 0) );
2086 Point aTopLeft
= OutputToScreenPixel( Point(0, 0) );
2087 nY
-= aDataTopLeft
.Y() - aTopLeft
.Y();
2090 // no row there (e.g. in the header)
2091 if ( nY
< 0 || nY
>= pDataWin
->GetOutputSizePixel().Height() )
2094 return nY
/ GetDataRowHeight() + nTopRow
;
2098 tools::Rectangle
BrowseBox::GetFieldRect( sal_uInt16 nColumnId
) const
2101 return GetFieldRectPixel( nCurRow
, nColumnId
);
2105 sal_uInt16
BrowseBox::GetColumnAtXPosPixel( tools::Long nX
) const
2108 // accumulate the widths of the visible columns
2109 tools::Long nColX
= 0;
2110 for ( size_t nCol
= 0; nCol
< mvCols
.size(); ++nCol
)
2112 BrowserColumn
*pCol
= mvCols
[ nCol
].get();
2113 if ( pCol
->IsFrozen() || nCol
>= nFirstCol
)
2114 nColX
+= pCol
->Width();
2120 return BROWSER_INVALIDID
;
2123 bool BrowseBox::ReserveControlArea(sal_uInt16 nWidth
)
2125 if (nWidth
!= nControlAreaWidth
)
2127 OSL_ENSURE(nWidth
,"Control area of 0 is not allowed, Use USHRT_MAX instead!");
2128 nControlAreaWidth
= nWidth
;
2135 tools::Rectangle
BrowseBox::GetControlArea() const
2137 auto nHeight
= aHScroll
->GetSizePixel().Height();
2138 auto nEndRight
= aHScroll
->GetPosPixel().X();
2140 return tools::Rectangle(
2141 Point( 0, GetOutputSizePixel().Height() - nHeight
),
2142 Size( nEndRight
, nHeight
) );
2145 void BrowseBox::SetMode( BrowserMode nMode
)
2148 pDataWin
->bAutoHScroll
= BrowserMode::AUTO_HSCROLL
== ( nMode
& BrowserMode::AUTO_HSCROLL
);
2149 pDataWin
->bAutoVScroll
= BrowserMode::AUTO_VSCROLL
== ( nMode
& BrowserMode::AUTO_VSCROLL
);
2150 pDataWin
->bNoHScroll
= BrowserMode::NO_HSCROLL
== ( nMode
& BrowserMode::NO_HSCROLL
);
2151 pDataWin
->bNoVScroll
= BrowserMode::NO_VSCROLL
== ( nMode
& BrowserMode::NO_VSCROLL
);
2153 DBG_ASSERT( !( pDataWin
->bAutoHScroll
&& pDataWin
->bNoHScroll
),
2154 "BrowseBox::SetMode: AutoHScroll *and* NoHScroll?" );
2155 DBG_ASSERT( !( pDataWin
->bAutoVScroll
&& pDataWin
->bNoVScroll
),
2156 "BrowseBox::SetMode: AutoVScroll *and* NoVScroll?" );
2157 if ( pDataWin
->bAutoHScroll
)
2158 pDataWin
->bNoHScroll
= false;
2159 if ( pDataWin
->bAutoVScroll
)
2160 pDataWin
->bNoVScroll
= false;
2162 if ( pDataWin
->bNoHScroll
)
2165 nControlAreaWidth
= USHRT_MAX
;
2167 tools::Long nOldRowSel
= bMultiSelection
? uRow
.pSel
->FirstSelected() : uRow
.nSel
;
2168 MultiSelection
*pOldRowSel
= bMultiSelection
? uRow
.pSel
: nullptr;
2170 pVScroll
.disposeAndClear();
2172 bMultiSelection
= bool( nMode
& BrowserMode::MULTISELECTION
);
2173 bColumnCursor
= bool( nMode
& BrowserMode::COLUMNSELECTION
);
2174 bKeepHighlight
= bool( nMode
& BrowserMode::KEEPHIGHLIGHT
);
2176 bHideSelect
= ((nMode
& BrowserMode::HIDESELECT
) == BrowserMode::HIDESELECT
);
2177 // default: do not hide the cursor at all (untaken scrolling and such)
2178 bHideCursor
= TRISTATE_FALSE
;
2180 if ( BrowserMode::HIDECURSOR
== ( nMode
& BrowserMode::HIDECURSOR
) )
2182 bHideCursor
= TRISTATE_TRUE
;
2185 m_bFocusOnlyCursor
= ((nMode
& BrowserMode::CURSOR_WO_FOCUS
) == BrowserMode::NONE
);
2187 bHLines
= ( nMode
& BrowserMode::HLINES
) == BrowserMode::HLINES
;
2188 bVLines
= ( nMode
& BrowserMode::VLINES
) == BrowserMode::VLINES
;
2190 pVScroll
= VclPtr
<ScrollAdaptor
>::Create(this, false);
2191 pVScroll
->SetLineSize( 1 );
2192 pVScroll
->SetPageSize(1);
2193 pVScroll
->SetScrollHdl( LINK( this, BrowseBox
, VertScrollHdl
) );
2195 pDataWin
->bAutoSizeLastCol
=
2196 BrowserMode::AUTOSIZE_LASTCOL
== ( nMode
& BrowserMode::AUTOSIZE_LASTCOL
);
2198 // create a headerbar. what happens, if a headerbar has to be created and
2199 // there already are columns?
2200 if ( BrowserMode::HEADERBAR_NEW
== ( nMode
& BrowserMode::HEADERBAR_NEW
) )
2202 if (!pDataWin
->pHeaderBar
)
2203 pDataWin
->pHeaderBar
= CreateHeaderBar( this );
2207 pDataWin
->pHeaderBar
.disposeAndClear();
2210 if ( bColumnCursor
)
2213 pColSel
.reset(new MultiSelection
);
2214 pColSel
->SetTotalRange( Range( 0, mvCols
.size()-1 ) );
2221 if ( bMultiSelection
)
2224 uRow
.pSel
= pOldRowSel
;
2226 uRow
.pSel
= new MultiSelection
;
2230 uRow
.nSel
= nOldRowSel
;
2234 if ( bBootstrapped
)
2236 StateChanged( StateChangedType::InitShow
);
2237 if ( bMultiSelection
&& !pOldRowSel
&&
2238 nOldRowSel
!= BROWSER_ENDOFSELECTION
)
2239 uRow
.pSel
->Select( nOldRowSel
);
2243 pDataWin
->Invalidate();
2245 // no cursor on handle column
2246 if ( nCurColId
== HandleColumnId
)
2247 nCurColId
= GetColumnId( 1 );
2249 m_nCurrentMode
= nMode
;
2253 void BrowseBox::VisibleRowsChanged( sal_Int32
, sal_uInt16
)
2256 // old behavior: automatically correct NumRows:
2257 if ( nRowCount
< GetRowCount() )
2259 RowInserted(nRowCount
,GetRowCount() - nRowCount
, false);
2261 else if ( nRowCount
> GetRowCount() )
2263 RowRemoved(nRowCount
-(nRowCount
- GetRowCount()),nRowCount
- GetRowCount(), false);
2268 bool BrowseBox::IsCursorMoveAllowed( sal_Int32
, sal_uInt16
) const
2272 This virtual method is always called before the cursor is moved directly.
2273 By means of 'return false', we avoid doing this if e.g. a record
2274 contradicts any rules.
2276 This method is not called, if the cursor movement results from removing or
2277 deleting a row/column (thus, in cases where only a "cursor correction" happens).
2279 The base implementation currently always returns true.
2287 tools::Long
BrowseBox::GetDataRowHeight() const
2289 return CalcZoom(m_nDataRowHeight
? m_nDataRowHeight
: ImpGetDataRowHeight());
2293 VclPtr
<BrowserHeader
> BrowseBox::CreateHeaderBar( BrowseBox
* pParent
)
2295 VclPtr
<BrowserHeader
> pNewBar
= VclPtr
<BrowserHeader
>::Create( pParent
);
2296 pNewBar
->SetStartDragHdl( LINK( this, BrowseBox
, StartDragHdl
) );
2300 void BrowseBox::SetHeaderBar( BrowserHeader
* pHeaderBar
)
2302 pDataWin
->pHeaderBar
.disposeAndClear();
2303 pDataWin
->pHeaderBar
= pHeaderBar
;
2304 pDataWin
->pHeaderBar
->SetStartDragHdl( LINK( this, BrowseBox
, StartDragHdl
) );
2307 tools::Long
BrowseBox::GetTitleHeight() const
2309 tools::Long nHeight
;
2310 // ask the header bar for the text height (if possible), as the header bar's font is adjusted with
2311 // our (and the header's) zoom factor
2312 HeaderBar
* pHeaderBar
= pDataWin
->pHeaderBar
;
2314 nHeight
= pHeaderBar
->GetTextHeight();
2316 nHeight
= GetTextHeight();
2318 return nTitleLines
? nTitleLines
* nHeight
+ 4 : 0;
2321 tools::Long
BrowseBox::CalcReverseZoom(tools::Long nVal
) const
2325 const Fraction
& rZoom
= GetZoom();
2326 double n
= static_cast<double>(nVal
);
2327 n
*= static_cast<double>(rZoom
.GetDenominator());
2328 if (!rZoom
.GetNumerator())
2329 throw o3tl::divide_by_zero();
2330 n
/= static_cast<double>(rZoom
.GetNumerator());
2331 nVal
= n
>0 ? static_cast<tools::Long
>(n
+ 0.5) : -static_cast<tools::Long
>(-n
+ 0.5);
2337 void BrowseBox::CursorMoved()
2339 // before implementing more here, please adjust the EditBrowseBox
2341 if ( isAccessibleAlive() && HasFocus() )
2343 ACTIVE_DESCENDANT_CHANGED
,
2344 Any( CreateAccessibleCell( GetCurRow(),GetColumnPos( GetCurColumnId() ) ) ),
2349 void BrowseBox::LoseFocus()
2351 SAL_INFO("svtools", "BrowseBox::LoseFocus " << this );
2355 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
2358 if ( !bKeepHighlight
)
2361 bSelectionIsVisible
= false;
2366 Control::LoseFocus();
2370 void BrowseBox::GetFocus()
2372 SAL_INFO("svtools", "BrowseBox::GetFocus " << this );
2376 if ( !bSelectionIsVisible
)
2378 bSelectionIsVisible
= true;
2379 if ( bBootstrapped
)
2386 Control::GetFocus();
2390 sal_uInt16
BrowseBox::GetVisibleRows() const
2392 return static_cast<sal_uInt16
>((pDataWin
->GetOutputSizePixel().Height() - 1 )/ GetDataRowHeight() + 1);
2395 BrowserDataWin
& BrowseBox::GetDataWindow() const
2400 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */