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 <comphelper/diagnose_ex.hxx>
21 #include <svtools/brwbox.hxx>
22 #include <svtools/brwhead.hxx>
23 #include <svtools/scrolladaptor.hxx>
24 #include <o3tl/numeric.hxx>
25 #include <o3tl/safeint.hxx>
27 #include <osl/diagnose.h>
28 #include <tools/debug.hxx>
29 #include <tools/fract.hxx>
30 #include <sal/log.hxx>
31 #include <vcl/InterimItemWindow.hxx>
32 #include <vcl/svapp.hxx>
33 #include <vcl/weld.hxx>
36 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
37 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
38 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
39 #include <com/sun/star/lang/XComponent.hpp>
40 #include <tools/multisel.hxx>
43 #define SCROLL_FLAGS (ScrollFlags::Clip | ScrollFlags::NoChildren)
45 using namespace com::sun::star::accessibility::AccessibleTableModelChangeType
;
46 using com::sun::star::accessibility::AccessibleTableModelChange
;
47 using namespace com::sun::star::accessibility
;
48 using namespace ::com::sun::star::uno
;
53 struct THeaderCellMapFunctorDispose
55 void operator()(const BrowseBox::THeaderCellMap::value_type
& _aType
)
57 css::uno::Reference
<css::lang::XComponent
> xComp(_aType
.second
, css::uno::UNO_QUERY
);
58 OSL_ENSURE(xComp
.is() || !_aType
.second
.is(), "THeaderCellMapFunctorDispose: invalid accessible cell (no XComponent)!");
64 catch(const css::uno::Exception
&)
66 TOOLS_WARN_EXCEPTION("svtools", "THeaderCellMapFunctorDispose");
71 void disposeAndClearHeaderCell(BrowseBox::THeaderCellMap
& _rHeaderCell
)
76 THeaderCellMapFunctorDispose()
82 // we're just measuring the "real" NavigationBar
83 class MeasureStatusBar final
: public InterimItemWindow
86 std::unique_ptr
<weld::Label
> m_xRecordText
;
87 std::unique_ptr
<weld::Entry
> m_xAbsolute
;
88 std::unique_ptr
<weld::Label
> m_xRecordOf
;
89 std::unique_ptr
<weld::Label
> m_xRecordCount
;
91 MeasureStatusBar(vcl::Window
*pParent
)
92 : InterimItemWindow(pParent
, u
"svx/ui/navigationbar.ui"_ustr
, u
"NavigationBar"_ustr
)
93 , m_xRecordText(m_xBuilder
->weld_label(u
"recordtext"_ustr
))
94 , m_xAbsolute(m_xBuilder
->weld_entry(u
"entry-noframe"_ustr
))
95 , m_xRecordOf(m_xBuilder
->weld_label(u
"recordof"_ustr
))
96 , m_xRecordCount(m_xBuilder
->weld_label(u
"recordcount"_ustr
))
98 vcl::Font
aApplFont(Application::GetSettings().GetStyleSettings().GetToolFont());
99 m_xAbsolute
->set_font(aApplFont
);
100 m_xRecordText
->set_font(aApplFont
);
101 m_xRecordOf
->set_font(aApplFont
);
102 m_xRecordCount
->set_font(aApplFont
);
104 SetSizePixel(get_preferred_size());
107 virtual void dispose() override
109 m_xRecordCount
.reset();
112 m_xRecordText
.reset();
113 InterimItemWindow::dispose();
117 tools::Long
BrowseBox::GetBarHeight() const
119 tools::Long nScrollBarSize
= GetSettings().GetStyleSettings().GetScrollBarSize();
120 if (!m_bNavigationBar
)
121 return nScrollBarSize
;
123 // tdf#115941 because some platforms have things like overlay scrollbars, take a max
124 // of a statusbar height and a scrollbar height as the control area height
126 // (we can't ask the scrollbars for their size cause if we're zoomed they still have to be
127 // resized - which is done in UpdateScrollbars)
128 return std::max(aStatusBarHeight
->GetSizePixel().Height(), nScrollBarSize
);
131 BrowseBox::BrowseBox( vcl::Window
* pParent
, WinBits nBits
, BrowserMode nMode
)
132 :Control( pParent
, nBits
| WB_3DLOOK
)
133 ,DragSourceHelper( this )
134 ,DropTargetHelper( this )
135 ,aHScroll( VclPtr
<ScrollAdaptor
>::Create(this, true) )
136 // see NavigationBar ctor, here we just want to know its height
137 ,aStatusBarHeight(VclPtr
<MeasureStatusBar
>::Create(this))
140 ,m_nActualCornerWidth(0)
141 ,m_bNavigationBar(false)
143 bMultiSelection
= false;
146 pDataWin
= VclPtr
<BrowserDataWin
>::Create( this ).get();
148 InitSettings_Impl( this );
149 InitSettings_Impl( pDataWin
);
151 bBootstrapped
= false;
152 m_nDataRowHeight
= 0;
156 nCurRow
= BROWSER_ENDOFSELECTION
;
166 bSelectionIsVisible
= false;
167 bNotToggleSel
= false;
168 bRowDividerDrag
= false;
170 mbInteractiveRowHeight
= false;
172 bHideCursor
= TRISTATE_FALSE
;
174 m_bFocusOnlyCursor
= true;
175 m_aCursorColor
= COL_TRANSPARENT
;
176 m_nCurrentMode
= BrowserMode::NONE
;
177 nControlAreaWidth
= USHRT_MAX
;
178 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
180 aHScroll
->SetLineSize(1);
181 aHScroll
->SetScrollHdl( LINK( this, BrowseBox
, HorzScrollHdl
) );
185 bSelectionIsVisible
= bKeepHighlight
;
186 bHasFocus
= HasChildPathFocus();
187 pDataWin
->nCursorHidden
=
188 ( bHasFocus
? 0 : 1 ) + ( GetUpdateMode() ? 0 : 1 );
191 BrowseBox::~BrowseBox()
196 void BrowseBox::DisposeAccessible()
200 disposeAndClearHeaderCell(m_aColHeaderCellMap
);
201 disposeAndClearHeaderCell(m_aRowHeaderCellMap
);
202 m_pAccessible
->dispose();
203 m_pAccessible
= nullptr;
207 void BrowseBox::dispose()
209 SAL_INFO("svtools", "BrowseBox:dispose " << this );
214 pDataWin
->pHeaderBar
.disposeAndClear();
215 pDataWin
.disposeAndClear();
216 pVScroll
.disposeAndClear();
217 aHScroll
.disposeAndClear();
218 aStatusBarHeight
.disposeAndClear();
220 // free columns-space
223 if ( bMultiSelection
)
225 DragSourceHelper::dispose();
226 DropTargetHelper::dispose();
231 short BrowseBox::GetCursorHideCount() const
233 return pDataWin
->nCursorHidden
;
237 void BrowseBox::DoShowCursor()
241 short nHiddenCount
= --pDataWin
->nCursorHidden
;
242 if (PaintCursorIfHiddenOnce())
244 if (1 == nHiddenCount
)
249 if (0 == nHiddenCount
)
255 void BrowseBox::DoHideCursor()
257 short nHiddenCount
= ++pDataWin
->nCursorHidden
;
258 if (PaintCursorIfHiddenOnce())
260 if (2 == nHiddenCount
)
265 if (1 == nHiddenCount
)
271 void BrowseBox::SetRealRowCount( const OUString
&rRealRowCount
)
273 pDataWin
->aRealRowCount
= rRealRowCount
;
277 void BrowseBox::SetFont( const vcl::Font
& rNewFont
)
279 pDataWin
->SetFont( rNewFont
);
280 ImpGetDataRowHeight();
283 const vcl::Font
& BrowseBox::GetFont() const
285 return pDataWin
->GetFont();
288 tools::Long
BrowseBox::GetDefaultColumnWidth( const OUString
& _rText
) const
290 return pDataWin
->GetTextWidth( _rText
) + pDataWin
->GetTextWidth(OUString('0')) * 4;
294 void BrowseBox::InsertHandleColumn( tools::Long nWidth
)
297 #if OSL_DEBUG_LEVEL > 0
298 OSL_ENSURE( ColCount() == 0 || mvCols
[0]->GetId() != HandleColumnId
, "BrowseBox::InsertHandleColumn: there is already a handle column" );
300 for (auto const & col
: mvCols
)
301 OSL_ENSURE( col
->GetId() != HandleColumnId
, "BrowseBox::InsertHandleColumn: there is a non-Handle column with handle ID" );
305 mvCols
.insert( mvCols
.begin(), std::unique_ptr
<BrowserColumn
>(new BrowserColumn( 0, OUString(), nWidth
, GetZoom() )) );
309 if ( pDataWin
->pHeaderBar
)
311 pDataWin
->pHeaderBar
->SetPosSizePixel(
313 Size( GetOutputSizePixel().Width() - nWidth
, GetTitleHeight() )
321 void BrowseBox::InsertDataColumn( sal_uInt16 nItemId
, const OUString
& rText
,
322 tools::Long nWidth
, HeaderBarItemBits nBits
, sal_uInt16 nPos
)
325 OSL_ENSURE( nItemId
!= HandleColumnId
, "BrowseBox::InsertDataColumn: nItemId is HandleColumnId" );
326 OSL_ENSURE( nItemId
!= BROWSER_INVALIDID
, "BrowseBox::InsertDataColumn: nItemId is reserved value BROWSER_INVALIDID" );
328 #if OSL_DEBUG_LEVEL > 0
330 for (auto const& col
: mvCols
)
331 OSL_ENSURE( col
->GetId() != nItemId
, "BrowseBox::InsertDataColumn: duplicate column Id" );
335 if ( nPos
< mvCols
.size() )
337 mvCols
.emplace( mvCols
.begin() + nPos
, new BrowserColumn( nItemId
, rText
, nWidth
, GetZoom() ) );
341 mvCols
.emplace_back( new BrowserColumn( nItemId
, rText
, nWidth
, GetZoom() ) );
343 if ( nCurColId
== 0 )
346 if ( pDataWin
->pHeaderBar
)
348 // Handle column not in the header bar
349 sal_uInt16 nHeaderPos
= nPos
;
350 if (nHeaderPos
!= HEADERBAR_APPEND
&& GetColumnId(0) == HandleColumnId
)
352 pDataWin
->pHeaderBar
->InsertItem(
353 nItemId
, rText
, nWidth
, nBits
, nHeaderPos
);
355 ColumnInserted( nPos
);
358 sal_uInt16
BrowseBox::ToggleSelectedColumn()
360 sal_uInt16 nSelectedColId
= BROWSER_INVALIDID
;
361 if ( pColSel
&& pColSel
->GetSelectCount() )
365 tools::Long nSelected
= pColSel
->FirstSelected();
366 if (nSelected
!= static_cast<tools::Long
>(SFX_ENDOFSELECTION
))
367 nSelectedColId
= mvCols
[nSelected
]->GetId();
368 pColSel
->SelectAll(false);
370 return nSelectedColId
;
373 void BrowseBox::SetToggledSelectedColumn(sal_uInt16 _nSelectedColumnId
)
375 if ( pColSel
&& _nSelectedColumnId
!= BROWSER_INVALIDID
)
377 pColSel
->Select( GetColumnPos( _nSelectedColumnId
) );
379 SAL_INFO("svtools", "BrowseBox::SetToggledSelectedColumn " << this );
384 void BrowseBox::FreezeColumn( sal_uInt16 nItemId
)
386 // get the position in the current array
387 size_t nItemPos
= GetColumnPos( nItemId
);
388 if ( nItemPos
>= mvCols
.size() )
392 // doesn't the state change?
393 if ( mvCols
[ nItemPos
]->IsFrozen() )
396 // remark the column selection
397 sal_uInt16 nSelectedColId
= ToggleSelectedColumn();
400 if ( nItemPos
!= 0 && !mvCols
[ nItemPos
-1 ]->IsFrozen() )
402 // move to the right of the last frozen column
403 sal_uInt16 nFirstScrollable
= FrozenColCount();
404 std::unique_ptr
<BrowserColumn
> pColumn
= std::move(mvCols
[ nItemPos
]);
405 mvCols
.erase( mvCols
.begin() + nItemPos
);
406 nItemPos
= nFirstScrollable
;
407 mvCols
.insert( mvCols
.begin() + nItemPos
, std::move(pColumn
) );
410 // adjust the number of the first scrollable and visible column
411 if ( nFirstCol
<= nItemPos
)
412 nFirstCol
= nItemPos
+ 1;
414 // toggle the freeze-state of the column
415 mvCols
[ nItemPos
]->Freeze();
417 // align the scrollbar-range
421 Control::Invalidate();
422 pDataWin
->Invalidate();
424 // remember the column selection
425 SetToggledSelectedColumn(nSelectedColId
);
429 void BrowseBox::SetColumnPos( sal_uInt16 nColumnId
, sal_uInt16 nPos
)
431 // never set pos of the handle column
432 if ( nColumnId
== HandleColumnId
)
435 // get the position in the current array
436 sal_uInt16 nOldPos
= GetColumnPos( nColumnId
);
437 if ( nOldPos
>= mvCols
.size() )
441 // does the state change?
445 // remark the column selection
446 sal_uInt16 nSelectedColId
= ToggleSelectedColumn();
448 // determine old column area
449 Size
aDataWinSize( pDataWin
->GetSizePixel() );
450 if ( pDataWin
->pHeaderBar
)
451 aDataWinSize
.AdjustHeight(pDataWin
->pHeaderBar
->GetSizePixel().Height() );
453 tools::Rectangle
aFromRect( GetFieldRect( nColumnId
) );
454 aFromRect
.AdjustRight(2*MIN_COLUMNWIDTH
);
456 sal_uInt16 nNextPos
= nOldPos
+ 1;
457 if ( nOldPos
> nPos
)
458 nNextPos
= nOldPos
- 1;
460 BrowserColumn
*pNextCol
= mvCols
[ nNextPos
].get();
461 tools::Rectangle
aNextRect(GetFieldRect( pNextCol
->GetId() ));
463 // move column internally
465 std::unique_ptr
<BrowserColumn
> pTemp
= std::move(mvCols
[nOldPos
]);
466 mvCols
.erase( mvCols
.begin() + nOldPos
);
467 mvCols
.insert( mvCols
.begin() + nPos
, std::move(pTemp
) );
470 // determine new column area
471 tools::Rectangle
aToRect( GetFieldRect( nColumnId
) );
472 aToRect
.AdjustRight(2*MIN_COLUMNWIDTH
);
474 // do scroll, let redraw
475 if( pDataWin
->GetBackground().IsScrollable() )
477 tools::Long nScroll
= -aFromRect
.GetWidth();
478 tools::Rectangle aScrollArea
;
479 if ( nOldPos
> nPos
)
481 tools::Long nFrozenWidth
= GetFrozenWidth();
482 if ( aToRect
.Left() < nFrozenWidth
)
483 aToRect
.SetLeft( nFrozenWidth
);
484 aScrollArea
= tools::Rectangle(Point(aToRect
.Left(),0),
485 Point(aNextRect
.Right(),aDataWinSize
.Height()));
486 nScroll
*= -1; // reverse direction
489 aScrollArea
= tools::Rectangle(Point(aNextRect
.Left(),0),
490 Point(aToRect
.Right(),aDataWinSize
.Height()));
492 pDataWin
->Scroll( nScroll
, 0, aScrollArea
);
494 aToRect
.SetBottom( aScrollArea
.Bottom() );
495 Invalidate( aToRect
);
498 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
500 // adjust header bar positions
501 if ( pDataWin
->pHeaderBar
)
503 sal_uInt16 nNewPos
= nPos
;
504 if ( GetColumnId(0) == HandleColumnId
)
506 pDataWin
->pHeaderBar
->MoveItem(nColumnId
,nNewPos
);
508 // remember the column selection
509 SetToggledSelectedColumn(nSelectedColId
);
511 if ( !isAccessibleAlive() )
515 AccessibleEventId::TABLE_MODEL_CHANGED
,
516 Any( AccessibleTableModelChange(
528 AccessibleEventId::TABLE_MODEL_CHANGED
,
529 Any( AccessibleTableModelChange(
543 void BrowseBox::SetColumnTitle( sal_uInt16 nItemId
, const OUString
& rTitle
)
546 // never set title of the handle-column
547 if ( nItemId
== HandleColumnId
)
550 // get the position in the current array
551 sal_uInt16 nItemPos
= GetColumnPos( nItemId
);
552 if ( nItemPos
>= mvCols
.size() )
556 // does the state change?
557 BrowserColumn
*pCol
= mvCols
[ nItemPos
].get();
558 if ( pCol
->Title() == rTitle
)
561 OUString
sOld(pCol
->Title());
563 pCol
->Title() = rTitle
;
565 // adjust headerbar column
566 if ( pDataWin
->pHeaderBar
)
567 pDataWin
->pHeaderBar
->SetItemText( nItemId
, rTitle
);
570 // redraw visible columns
571 if ( GetUpdateMode() && ( pCol
->IsFrozen() || nItemPos
> nFirstCol
) )
572 Invalidate( tools::Rectangle( Point(0,0),
573 Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
576 if ( isAccessibleAlive() )
578 commitTableEvent(AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED
,
586 void BrowseBox::SetColumnWidth( sal_uInt16 nItemId
, tools::Long nWidth
)
589 // get the position in the current array
590 size_t nItemPos
= GetColumnPos( nItemId
);
591 if ( nItemPos
>= mvCols
.size() )
594 // does the state change?
595 if ( nWidth
< LONG_MAX
&& mvCols
[ nItemPos
]->Width() == nWidth
)
598 tools::Long nOldWidth
= mvCols
[ nItemPos
]->Width();
600 // adjust last column, if necessary
601 if ( IsVisible() && nItemPos
== mvCols
.size() - 1 )
603 tools::Long nMaxWidth
= pDataWin
->GetSizePixel().Width();
604 nMaxWidth
-= pDataWin
->bAutoSizeLastCol
605 ? GetFieldRect(nItemId
).Left()
607 if ( pDataWin
->bAutoSizeLastCol
|| nWidth
> nMaxWidth
)
609 nWidth
= nMaxWidth
> 16 ? nMaxWidth
: nOldWidth
;
614 // In AutoSizeLastColumn(), we call SetColumnWidth with nWidth==0xffff.
615 // Thus, check here, if the width has actually changed.
616 if( nOldWidth
== nWidth
)
619 // do we want to display the change immediately?
620 bool bUpdate
= GetUpdateMode() &&
621 ( mvCols
[ nItemPos
]->IsFrozen() || nItemPos
>= nFirstCol
);
628 //!pDataWin->Update();
629 //!Control::Update();
633 mvCols
[ nItemPos
]->SetWidth(nWidth
, GetZoom());
635 // scroll and invalidate
638 // get X-Pos of the column changed
640 for ( size_t nCol
= 0; nCol
< nItemPos
; ++nCol
)
642 BrowserColumn
*pCol
= mvCols
[ nCol
].get();
643 if ( pCol
->IsFrozen() || nCol
>= nFirstCol
)
647 // actually scroll+invalidate
648 pDataWin
->GetOutDev()->SetClipRegion();
649 bool bSelVis
= bSelectionIsVisible
;
650 bSelectionIsVisible
= false;
651 if( GetBackground().IsScrollable() )
654 tools::Rectangle
aScrRect( nX
+ std::min( nOldWidth
, nWidth
), 0,
655 GetSizePixel().Width() , // the header is longer than the datawin
656 pDataWin
->GetPosPixel().Y() - 1 );
657 Control::Scroll( nWidth
-nOldWidth
, 0, aScrRect
, SCROLL_FLAGS
);
658 aScrRect
.SetBottom( pDataWin
->GetSizePixel().Height() );
659 pDataWin
->Scroll( nWidth
-nOldWidth
, 0, aScrRect
, SCROLL_FLAGS
);
660 tools::Rectangle
aInvRect( nX
, 0, nX
+ std::max( nWidth
, nOldWidth
), USHRT_MAX
);
661 Control::Invalidate( aInvRect
, InvalidateFlags::NoChildren
);
662 pDataWin
->Invalidate( aInvRect
);
666 Control::Invalidate( InvalidateFlags::NoChildren
);
667 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
671 //!pDataWin->Update();
672 //!Control::Update();
673 bSelectionIsVisible
= bSelVis
;
679 // adjust headerbar column
680 if ( pDataWin
->pHeaderBar
)
681 pDataWin
->pHeaderBar
->SetItemSize(
682 nItemId
? nItemId
: USHRT_MAX
- 1, nWidth
);
684 // adjust last column
685 if ( nItemPos
!= mvCols
.size() - 1 )
686 AutoSizeLastColumn();
690 void BrowseBox::AutoSizeLastColumn()
692 if ( pDataWin
->bAutoSizeLastCol
&&
693 pDataWin
->GetUpdateMode() )
695 sal_uInt16 nId
= GetColumnId( static_cast<sal_uInt16
>(mvCols
.size()) - 1 );
696 SetColumnWidth( nId
, LONG_MAX
);
697 ColumnResized( nId
);
702 void BrowseBox::RemoveColumn( sal_uInt16 nItemId
)
705 // get column position
706 sal_uInt16 nPos
= GetColumnPos(nItemId
);
707 if ( nPos
>= ColCount() )
711 // correct column selection
713 pColSel
->Remove( nPos
);
715 // correct column cursor
716 if ( nCurColId
== nItemId
)
720 mvCols
.erase( mvCols
.begin() + nPos
);
721 if ( nFirstCol
>= nPos
&& nFirstCol
> FrozenColCount() )
723 OSL_ENSURE(nFirstCol
> 0,"FirstCol must be greater zero!");
727 // handlecolumn not in headerbar
730 if ( pDataWin
->pHeaderBar
)
731 pDataWin
->pHeaderBar
->RemoveItem( nItemId
);
736 if ( pDataWin
->pHeaderBar
)
738 pDataWin
->pHeaderBar
->SetPosSizePixel(
740 Size( GetOutputSizePixel().Width(), GetTitleHeight() )
745 // correct vertical scrollbar
748 // trigger repaint, if necessary
749 if ( GetUpdateMode() )
751 pDataWin
->Invalidate();
752 Control::Invalidate();
753 if ( pDataWin
->bAutoSizeLastCol
&& nPos
==ColCount() )
754 SetColumnWidth( GetColumnId( nPos
- 1 ), LONG_MAX
);
757 if ( !isAccessibleAlive() )
761 AccessibleEventId::TABLE_MODEL_CHANGED
,
762 Any( AccessibleTableModelChange(COLUMNS_REMOVED
,
772 commitHeaderBarEvent(
773 AccessibleEventId::CHILD
,
775 Any( CreateAccessibleColumnHeader( nPos
) ),
781 void BrowseBox::RemoveColumns()
783 size_t nOldCount
= mvCols
.size();
785 // remove all columns
788 // correct column selection
791 pColSel
->SelectAll(false);
792 pColSel
->SetTotalRange( Range( 0, 0 ) );
795 // correct column cursor
799 if ( pDataWin
->pHeaderBar
)
800 pDataWin
->pHeaderBar
->Clear( );
802 // correct vertical scrollbar
805 // trigger repaint if necessary
806 if ( GetUpdateMode() )
808 pDataWin
->Invalidate();
809 Control::Invalidate();
812 if ( !isAccessibleAlive() )
815 if ( mvCols
.size() == nOldCount
)
818 // all columns should be removed, so we remove the column header bar and append it again
819 // to avoid to notify every column remove
820 commitBrowseBoxEvent(
821 AccessibleEventId::CHILD
,
823 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar
))
826 // and now append it again
827 commitBrowseBoxEvent(
828 AccessibleEventId::CHILD
,
829 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar
)),
833 // notify a table model change
835 AccessibleEventId::TABLE_MODEL_CHANGED
,
836 Any ( AccessibleTableModelChange( COLUMNS_REMOVED
,
848 const OUString
& BrowseBox::GetColumnTitle( sal_uInt16 nId
) const
851 sal_uInt16 nItemPos
= GetColumnPos( nId
);
852 if ( nItemPos
>= mvCols
.size() )
853 return EMPTY_OUSTRING
;
854 return mvCols
[ nItemPos
]->Title();
857 sal_Int32
BrowseBox::GetRowCount() const
862 sal_uInt16
BrowseBox::ColCount() const
864 return static_cast<sal_uInt16
>(mvCols
.size());
867 tools::Long
BrowseBox::ImpGetDataRowHeight() const
869 BrowseBox
*pThis
= const_cast<BrowseBox
*>(this);
870 pThis
->m_nDataRowHeight
= pThis
->CalcReverseZoom(pDataWin
->GetTextHeight() + 4);
872 pDataWin
->Invalidate();
873 return m_nDataRowHeight
;
876 void BrowseBox::SetDataRowHeight( tools::Long nPixel
)
879 m_nDataRowHeight
= CalcReverseZoom(nPixel
);
881 pDataWin
->Invalidate();
884 void BrowseBox::SetTitleLines( sal_uInt16 nLines
)
887 nTitleLines
= nLines
;
890 sal_Int32
BrowseBox::ScrollColumns( sal_Int32 nCols
)
893 if ( nFirstCol
+ nCols
< 0 ||
894 o3tl::make_unsigned(nFirstCol
+ nCols
) >= mvCols
.size() )
897 // implicitly hides cursor while scrolling
900 bool bScrollable
= pDataWin
->GetBackground().IsScrollable();
901 bool bInvalidateView
= false;
903 // scrolling one column to the right?
906 // update internal value and scrollbar
908 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
912 bInvalidateView
= true;
916 tools::Long nDelta
= mvCols
[ nFirstCol
-1 ]->Width();
917 tools::Long nFrozenWidth
= GetFrozenWidth();
919 tools::Rectangle
aScrollRect( Point( nFrozenWidth
+ nDelta
, 0 ),
920 Size ( GetOutputSizePixel().Width() - nFrozenWidth
- nDelta
,
924 // scroll the header bar area (if there is no dedicated HeaderBar control)
925 if ( !pDataWin
->pHeaderBar
&& nTitleLines
)
928 Scroll( -nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
930 // invalidate the area of the column which was scrolled out to the left hand side
931 tools::Rectangle
aInvalidateRect( aScrollRect
);
932 aInvalidateRect
.SetLeft( nFrozenWidth
);
933 aInvalidateRect
.SetRight( nFrozenWidth
+ nDelta
- 1 );
934 Invalidate( aInvalidateRect
);
937 // scroll the data-area
938 aScrollRect
.SetBottom( pDataWin
->GetOutputSizePixel().Height() );
941 pDataWin
->Scroll( -nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
943 // invalidate the area of the column which was scrolled out to the left hand side
944 aScrollRect
.SetLeft( nFrozenWidth
);
945 aScrollRect
.SetRight( nFrozenWidth
+ nDelta
- 1 );
946 pDataWin
->Invalidate( aScrollRect
);
950 // scrolling one column to the left?
951 else if ( nCols
== -1 )
954 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
958 bInvalidateView
= true;
962 tools::Long nDelta
= mvCols
[ nFirstCol
]->Width();
963 tools::Long nFrozenWidth
= GetFrozenWidth();
965 tools::Rectangle
aScrollRect( Point( nFrozenWidth
, 0 ),
966 Size ( GetOutputSizePixel().Width() - nFrozenWidth
,
970 // scroll the header bar area (if there is no dedicated HeaderBar control)
971 if ( !pDataWin
->pHeaderBar
&& nTitleLines
)
973 Scroll( nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
976 // scroll the data-area
977 aScrollRect
.SetBottom( pDataWin
->GetOutputSizePixel().Height() );
978 pDataWin
->Scroll( nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
983 if ( GetUpdateMode() )
985 Invalidate( tools::Rectangle(
986 Point( GetFrozenWidth(), 0 ),
987 Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
988 pDataWin
->Invalidate( tools::Rectangle(
989 Point( GetFrozenWidth(), 0 ),
990 pDataWin
->GetSizePixel() ) );
993 nFirstCol
= nFirstCol
+ static_cast<sal_uInt16
>(nCols
);
994 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
997 // adjust external headerbar, if necessary
998 if ( pDataWin
->pHeaderBar
)
1000 tools::Long nWidth
= 0;
1001 for ( size_t nCol
= 0;
1002 nCol
< mvCols
.size() && nCol
< nFirstCol
;
1005 // not the handle column
1006 if ( mvCols
[ nCol
]->GetId() )
1007 nWidth
+= mvCols
[ nCol
]->Width();
1010 pDataWin
->pHeaderBar
->SetOffset( nWidth
);
1013 if( bInvalidateView
)
1015 Control::Invalidate( InvalidateFlags::NoChildren
);
1016 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
1019 // implicitly show cursor after scrolling
1032 sal_Int32
BrowseBox::ScrollRows( sal_Int32 nRows
)
1034 // compute new top row
1035 sal_Int32 nTmpMin
= std::min( static_cast<sal_Int32
>(nTopRow
+ nRows
), static_cast<sal_Int32
>(nRowCount
- 1) );
1037 sal_Int32 nNewTopRow
= std::max
<sal_Int32
>( nTmpMin
, 0 );
1039 if ( nNewTopRow
== nTopRow
)
1042 sal_uInt16 nVisibleRows
=
1043 static_cast<sal_uInt16
>(pDataWin
->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1045 VisibleRowsChanged(nNewTopRow
, nVisibleRows
);
1047 // compute new top row again (nTopRow might have changed!)
1048 nTmpMin
= std::min( static_cast<tools::Long
>(nTopRow
+ nRows
), static_cast<tools::Long
>(nRowCount
- 1) );
1050 nNewTopRow
= std::max
<tools::Long
>( nTmpMin
, 0 );
1054 // scroll area on screen and/or repaint
1055 tools::Long nDeltaY
= GetDataRowHeight() * ( nNewTopRow
- nTopRow
);
1056 sal_Int32 nOldTopRow
= nTopRow
;
1057 nTopRow
= nNewTopRow
;
1059 if ( GetUpdateMode() )
1061 pVScroll
->SetRange( Range( 0L, nRowCount
) );
1062 pVScroll
->SetThumbPos( nTopRow
);
1064 if( pDataWin
->GetBackground().IsScrollable() &&
1065 std::abs( nDeltaY
) > 0 &&
1066 std::abs( nDeltaY
) < pDataWin
->GetSizePixel().Height() )
1068 pDataWin
->Scroll( 0, static_cast<short>(-nDeltaY
), SCROLL_FLAGS
);
1071 pDataWin
->Invalidate();
1073 if ( nTopRow
- nOldTopRow
)
1079 return nTopRow
- nOldTopRow
;
1083 void BrowseBox::RowModified( sal_Int32 nRow
, sal_uInt16 nColId
)
1086 if ( !GetUpdateMode() )
1089 tools::Rectangle aRect
;
1090 if ( nColId
== BROWSER_INVALIDID
)
1091 // invalidate the whole row
1092 aRect
= tools::Rectangle( Point( 0, (nRow
-nTopRow
) * GetDataRowHeight() ),
1093 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) );
1096 // invalidate the specific field
1097 aRect
= GetFieldRectPixel( nRow
, nColId
, false );
1099 pDataWin
->Invalidate( aRect
);
1103 void BrowseBox::Clear()
1105 // adjust the total number of rows
1107 sal_Int32 nOldRowCount
= nRowCount
;
1115 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1116 nCurRow
= BROWSER_ENDOFSELECTION
;
1120 // nFirstCol may not be reset, else the scrolling code will become confused.
1121 // nFirstCol may only be changed when adding or deleting columns
1122 // nFirstCol = 0; -> wrong!
1123 aHScroll
->SetThumbPos( 0 );
1124 pVScroll
->SetThumbPos( 0 );
1132 if ( !isAccessibleAlive() )
1135 // all rows should be removed, so we remove the row header bar and append it again
1136 // to avoid to notify every row remove
1137 if ( nOldRowCount
== nRowCount
)
1140 commitBrowseBoxEvent(
1141 AccessibleEventId::CHILD
,
1143 Any(getAccessibleHeaderBar( AccessibleBrowseBoxObjType::RowHeaderBar
))
1146 // and now append it again
1147 commitBrowseBoxEvent(
1148 AccessibleEventId::CHILD
,
1149 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar
)),
1153 // notify a table model change
1155 AccessibleEventId::TABLE_MODEL_CHANGED
,
1156 Any( AccessibleTableModelChange(ROWS_REMOVED
,
1166 void BrowseBox::RowInserted( sal_Int32 nRow
, sal_Int32 nNumRows
, bool bDoPaint
, bool bKeepSelection
)
1171 else if (nRow
> nRowCount
) // maximal = nRowCount
1174 if ( nNumRows
<= 0 )
1177 // adjust total row count
1178 bool bLastRow
= nRow
>= nRowCount
;
1179 nRowCount
+= nNumRows
;
1183 // must we paint the new rows?
1184 sal_Int32 nOldCurRow
= nCurRow
;
1185 Size aSz
= pDataWin
->GetOutputSizePixel();
1186 if ( bDoPaint
&& nRow
>= nTopRow
&&
1187 nRow
<= nTopRow
+ aSz
.Height() / GetDataRowHeight() )
1189 tools::Long nY
= (nRow
-nTopRow
) * GetDataRowHeight();
1192 // scroll down the rows behind the new row
1193 pDataWin
->GetOutDev()->SetClipRegion();
1194 if( pDataWin
->GetBackground().IsScrollable() )
1196 pDataWin
->Scroll( 0, GetDataRowHeight() * nNumRows
,
1197 tools::Rectangle( Point( 0, nY
),
1198 Size( aSz
.Width(), aSz
.Height() - nY
) ),
1202 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
1205 // scroll would cause a repaint, so we must explicitly invalidate
1206 pDataWin
->Invalidate( tools::Rectangle( Point( 0, nY
),
1207 Size( aSz
.Width(), nNumRows
* GetDataRowHeight() ) ) );
1210 // correct top row if necessary
1211 if ( nRow
< nTopRow
)
1212 nTopRow
+= nNumRows
;
1214 // adjust the selection
1215 if ( bMultiSelection
)
1216 uRow
.pSel
->Insert( nRow
, nNumRows
);
1217 else if ( uRow
.nSel
!= BROWSER_ENDOFSELECTION
&& nRow
<= uRow
.nSel
)
1218 uRow
.nSel
+= nNumRows
;
1220 // adjust the cursor
1221 if ( nCurRow
== BROWSER_ENDOFSELECTION
)
1222 GoToRow( 0, false, bKeepSelection
);
1223 else if ( nRow
<= nCurRow
)
1225 nCurRow
+= nNumRows
;
1226 GoToRow( nCurRow
, false, bKeepSelection
);
1229 // adjust the vertical scrollbar
1233 AutoSizeLastColumn();
1237 // notify accessible that rows were inserted
1238 if ( isAccessibleAlive() )
1241 AccessibleEventId::TABLE_MODEL_CHANGED
,
1242 Any( AccessibleTableModelChange(
1253 for (tools::Long i
= nRow
+1 ; i
<= nRowCount
; ++i
)
1255 commitHeaderBarEvent(
1256 AccessibleEventId::CHILD
,
1257 Any( CreateAccessibleRowHeader( i
) ),
1264 if ( nCurRow
!= nOldCurRow
)
1267 DBG_ASSERT(nRowCount
> 0,"BrowseBox: nRowCount <= 0");
1268 DBG_ASSERT(nCurRow
>= 0,"BrowseBox: nCurRow < 0");
1269 DBG_ASSERT(nCurRow
< nRowCount
,"nCurRow >= nRowCount");
1273 void BrowseBox::RowRemoved( sal_Int32 nRow
, sal_Int32 nNumRows
, bool bDoPaint
)
1278 else if ( nRow
>= nRowCount
)
1279 nRow
= nRowCount
- 1;
1281 if ( nNumRows
<= 0 )
1284 if ( nRowCount
<= 0 )
1289 // hide cursor and selection
1290 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1295 // adjust total row count
1296 nRowCount
-= nNumRows
;
1297 if (nRowCount
< 0) nRowCount
= 0;
1298 sal_Int32 nOldCurRow
= nCurRow
;
1300 // adjust the selection
1301 if ( bMultiSelection
)
1302 // uRow.pSel->Remove( nRow, nNumRows );
1303 for ( tools::Long i
= 0; i
< nNumRows
; i
++ )
1304 uRow
.pSel
->Remove( nRow
);
1305 else if ( nRow
< uRow
.nSel
&& uRow
.nSel
>= nNumRows
)
1306 uRow
.nSel
-= nNumRows
;
1307 else if ( nRow
<= uRow
.nSel
)
1308 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1310 // adjust the cursor
1311 if ( nRowCount
== 0 ) // don't compare nRowCount with nNumRows as nNumRows already was subtracted from nRowCount
1312 nCurRow
= BROWSER_ENDOFSELECTION
;
1313 else if ( nRow
< nCurRow
)
1315 nCurRow
-= std::min( nCurRow
- nRow
, nNumRows
);
1316 // with the above nCurRow points a) to the first row after the removed block or b) to the same line
1317 // as before, but moved up nNumRows
1318 // case a) needs an additional correction if the last n lines were deleted, as 'the first row after the
1319 // removed block' is an invalid position then
1320 // FS - 09/28/99 - 68429
1321 if (nCurRow
== nRowCount
)
1324 else if( nRow
== nCurRow
&& nCurRow
== nRowCount
)
1325 nCurRow
= nRowCount
-1;
1327 // is the deleted row visible?
1328 Size aSz
= pDataWin
->GetOutputSizePixel();
1329 if ( nRow
>= nTopRow
&&
1330 nRow
<= nTopRow
+ aSz
.Height() / GetDataRowHeight() )
1334 // scroll up the rows behind the deleted row
1335 // if there are Rows behind
1336 if (nRow
< nRowCount
)
1338 tools::Long nY
= (nRow
-nTopRow
) * GetDataRowHeight();
1339 pDataWin
->GetOutDev()->SetClipRegion();
1340 if( pDataWin
->GetBackground().IsScrollable() )
1342 pDataWin
->Scroll( 0, - static_cast<short>(GetDataRowHeight()) * nNumRows
,
1343 tools::Rectangle( Point( 0, nY
), Size( aSz
.Width(),
1344 aSz
.Height() - nY
+ nNumRows
*GetDataRowHeight() ) ),
1348 pDataWin
->Window::Invalidate( InvalidateFlags::NoChildren
);
1352 // Repaint the Rect of the deleted row
1353 tools::Rectangle
aRect(
1354 Point( 0, (nRow
-nTopRow
)*GetDataRowHeight() ),
1355 Size( pDataWin
->GetSizePixel().Width(),
1356 nNumRows
* GetDataRowHeight() ) );
1357 pDataWin
->Invalidate( aRect
);
1361 // is the deleted row above of the visible area?
1362 else if ( nRow
< nTopRow
)
1363 nTopRow
= nTopRow
>= nNumRows
? nTopRow
-nNumRows
: 0;
1367 // reshow cursor and selection
1369 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1372 // adjust the vertical scrollbar
1374 AutoSizeLastColumn();
1377 if ( isAccessibleAlive() )
1379 if ( nRowCount
== 0 )
1381 // all columns should be removed, so we remove the column header bar and append it again
1382 // to avoid to notify every column remove
1383 commitBrowseBoxEvent(
1384 AccessibleEventId::CHILD
,
1386 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar
))
1389 // and now append it again
1390 commitBrowseBoxEvent(
1391 AccessibleEventId::CHILD
,
1392 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar
)),
1395 commitBrowseBoxEvent(
1396 AccessibleEventId::CHILD
,
1398 Any(getAccessibleTable())
1401 // and now append it again
1402 commitBrowseBoxEvent(
1403 AccessibleEventId::CHILD
,
1404 Any(getAccessibleTable()),
1411 AccessibleEventId::TABLE_MODEL_CHANGED
,
1412 Any( AccessibleTableModelChange(
1423 for (tools::Long i
= nRow
+1 ; i
<= (nRow
+nNumRows
) ; ++i
)
1425 commitHeaderBarEvent(
1426 AccessibleEventId::CHILD
,
1428 Any( CreateAccessibleRowHeader( i
) ),
1435 if ( nOldCurRow
!= nCurRow
)
1438 DBG_ASSERT(nRowCount
>= 0,"BrowseBox: nRowCount < 0");
1439 DBG_ASSERT(nCurRow
>= 0 || nRowCount
== 0,"BrowseBox: nCurRow < 0 && nRowCount != 0");
1440 DBG_ASSERT(nCurRow
< nRowCount
,"nCurRow >= nRowCount");
1444 bool BrowseBox::GoToRow( sal_Int32 nRow
)
1446 return GoToRow(nRow
, false);
1450 bool BrowseBox::GoToRow( sal_Int32 nRow
, bool bRowColMove
, bool bKeepSelection
)
1452 sal_Int32 nOldCurRow
= nCurRow
;
1455 if ( nRow
== nCurRow
&& ( bMultiSelection
|| uRow
.nSel
== nRow
) )
1459 if ( nRow
< 0 || nRow
>= nRowCount
)
1463 if ( !bRowColMove
&& !IsCursorMoveAllowed( nRow
, nCurColId
) )
1466 // compute the last visible row
1467 Size
aSz( pDataWin
->GetSizePixel() );
1468 sal_uInt16 nVisibleRows
= sal_uInt16( aSz
.Height() / GetDataRowHeight() - 1 );
1469 sal_Int32 nLastRow
= nTopRow
+ nVisibleRows
;
1472 pDataWin
->EnterUpdateLock();
1474 // remove old highlight, if necessary
1475 if ( !bMultiSelection
&& !bKeepSelection
)
1480 bool bWasVisible
= bSelectionIsVisible
;
1481 if (! bMultiSelection
)
1483 if( !bKeepSelection
)
1484 bSelectionIsVisible
= false;
1486 if ( nRow
< nTopRow
)
1487 ScrollRows( nRow
- nTopRow
);
1488 else if ( nRow
> nLastRow
)
1489 ScrollRows( nRow
- nLastRow
);
1490 bSelectionIsVisible
= bWasVisible
;
1492 // adjust cursor (selection) and thumb
1493 if ( GetUpdateMode() )
1494 pVScroll
->SetThumbPos( nTopRow
);
1496 // relative positioning (because nCurRow might have changed in the meantime)!
1497 if (nCurRow
!= BROWSER_ENDOFSELECTION
)
1498 nCurRow
= nCurRow
+ (nRow
- nOldCurRow
);
1500 // make sure that the current position is valid
1501 if (nCurRow
== BROWSER_ENDOFSELECTION
&& nRowCount
> 0)
1503 else if ( nCurRow
>= nRowCount
)
1504 nCurRow
= nRowCount
- 1;
1505 aSelRange
= Range( nCurRow
, nCurRow
);
1507 // display new highlight if necessary
1508 if ( !bMultiSelection
&& !bKeepSelection
)
1512 pDataWin
->LeaveUpdateLock();
1515 if ( !bMultiSelection
&& !bKeepSelection
)
1518 if ( !bRowColMove
&& nOldCurRow
!= nCurRow
)
1521 if ( !bMultiSelection
&& !bKeepSelection
)
1532 bool BrowseBox::GoToColumnId( sal_uInt16 nColId
)
1534 return GoToColumnId(nColId
, true);
1538 bool BrowseBox::GoToColumnId( sal_uInt16 nColId
, bool bMakeVisible
, bool bRowColMove
)
1544 if (!bRowColMove
&& !IsCursorMoveAllowed( nCurRow
, nColId
) )
1547 if ( nColId
!= nCurColId
|| (bMakeVisible
&& !IsFieldVisible(nCurRow
, nColId
, true)))
1549 sal_uInt16 nNewPos
= GetColumnPos(nColId
);
1550 BrowserColumn
* pColumn
= (nNewPos
< mvCols
.size()) ? mvCols
[ nNewPos
].get() : nullptr;
1551 DBG_ASSERT( pColumn
, "no column object - invalid id?" );
1558 bool bScrolled
= false;
1560 sal_uInt16 nFirstPos
= nFirstCol
;
1561 sal_uInt16 nWidth
= static_cast<sal_uInt16
>(pColumn
->Width());
1562 sal_uInt16 nLastPos
= GetColumnAtXPosPixel(
1563 pDataWin
->GetSizePixel().Width()-nWidth
);
1564 sal_uInt16 nFrozen
= FrozenColCount();
1565 if ( bMakeVisible
&& nLastPos
&&
1566 nNewPos
>= nFrozen
&& ( nNewPos
< nFirstPos
|| nNewPos
> nLastPos
) )
1568 if ( nNewPos
< nFirstPos
)
1569 ScrollColumns( nNewPos
-nFirstPos
);
1570 else if ( nNewPos
> nLastPos
)
1571 ScrollColumns( nNewPos
-nLastPos
);
1578 //try to move to nCurRow, nColId
1579 CursorMoveAttempt
aAttempt(nCurRow
, nColId
, bScrolled
);
1580 //Detect if we are already in a call to BrowseBox::GoToColumnId
1581 //but the attempt is impossible and we are simply recursing
1582 //into BrowseBox::GoToColumnId with the same impossible to
1583 //fulfill conditions
1584 if (m_aGotoStack
.empty() || aAttempt
!= m_aGotoStack
.top())
1586 m_aGotoStack
.push(aAttempt
);
1597 bool BrowseBox::GoToRowColumnId( sal_Int32 nRow
, sal_uInt16 nColId
)
1601 if ( nRow
< 0 || nRow
>= nRowCount
)
1608 if ( nRow
== nCurRow
&& ( bMultiSelection
|| uRow
.nSel
== nRow
) &&
1609 nColId
== nCurColId
&& IsFieldVisible(nCurRow
, nColId
, true))
1613 if (!IsCursorMoveAllowed(nRow
, nColId
))
1617 bool bMoved
= GoToRow(nRow
, true) && GoToColumnId(nColId
, true, true);
1627 void BrowseBox::SetNoSelection()
1630 // is there no selection
1631 if ( ( !pColSel
|| !pColSel
->GetSelectCount() ) &&
1632 ( ( !bMultiSelection
&& uRow
.nSel
== BROWSER_ENDOFSELECTION
) ||
1633 ( bMultiSelection
&& !uRow
.pSel
->GetSelectCount() ) ) )
1637 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1641 if ( bMultiSelection
)
1642 uRow
.pSel
->SelectAll(false);
1644 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1646 pColSel
->SelectAll(false);
1653 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1655 if ( isAccessibleAlive() )
1658 AccessibleEventId::SELECTION_CHANGED
,
1666 void BrowseBox::SelectAll()
1669 if ( !bMultiSelection
)
1672 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1677 pColSel
->SelectAll(false);
1678 uRow
.pSel
->SelectAll();
1680 // don't highlight handle column
1681 BrowserColumn
*pFirstCol
= mvCols
[ 0 ].get();
1682 tools::Long nOfsX
= pFirstCol
->GetId() ? 0 : pFirstCol
->Width();
1684 // highlight the row selection
1687 tools::Rectangle aHighlightRect
;
1688 sal_uInt16 nVisibleRows
=
1689 static_cast<sal_uInt16
>(pDataWin
->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1690 for ( sal_Int32 nRow
= std::max
<sal_Int32
>( nTopRow
, uRow
.pSel
->FirstSelected() );
1691 nRow
!= BROWSER_ENDOFSELECTION
&& nRow
< nTopRow
+ nVisibleRows
;
1692 nRow
= uRow
.pSel
->NextSelected() )
1693 aHighlightRect
.Union( tools::Rectangle(
1694 Point( nOfsX
, (nRow
-nTopRow
)*GetDataRowHeight() ),
1695 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) ) );
1696 pDataWin
->Invalidate( aHighlightRect
);
1705 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1707 if ( !isAccessibleAlive() )
1711 AccessibleEventId::SELECTION_CHANGED
,
1715 commitHeaderBarEvent(
1716 AccessibleEventId::SELECTION_CHANGED
,
1720 ); // column header event
1722 commitHeaderBarEvent(
1723 AccessibleEventId::SELECTION_CHANGED
,
1727 ); // row header event
1731 void BrowseBox::SelectRow( sal_Int32 nRow
, bool _bSelect
, bool bExpand
)
1734 if ( !bMultiSelection
)
1736 // deselecting is impossible, selecting via cursor
1738 GoToRow(nRow
, false);
1742 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1744 // remove old selection?
1745 if ( !bExpand
|| !bMultiSelection
)
1748 if ( bMultiSelection
)
1749 uRow
.pSel
->SelectAll(false);
1751 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1753 pColSel
->SelectAll(false);
1756 // set new selection
1758 && ( ( bMultiSelection
1759 && uRow
.pSel
->GetTotalRange().Max() >= nRow
1760 && uRow
.pSel
->Select( nRow
, _bSelect
)
1762 || ( !bMultiSelection
1763 && ( uRow
.nSel
= nRow
) != BROWSER_ENDOFSELECTION
)
1767 // don't highlight handle column
1768 BrowserColumn
*pFirstCol
= mvCols
[ 0 ].get();
1769 tools::Long nOfsX
= pFirstCol
->GetId() ? 0 : pFirstCol
->Width();
1771 // highlight only newly selected part
1772 tools::Rectangle
aRect(
1773 Point( nOfsX
, (nRow
-nTopRow
)*GetDataRowHeight() ),
1774 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) );
1775 pDataWin
->Invalidate( aRect
);
1784 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1786 if ( !isAccessibleAlive() )
1790 AccessibleEventId::SELECTION_CHANGED
,
1794 commitHeaderBarEvent(
1795 AccessibleEventId::SELECTION_CHANGED
,
1799 ); // row header event
1803 sal_Int32
BrowseBox::GetSelectRowCount() const
1806 return bMultiSelection
? uRow
.pSel
->GetSelectCount() :
1807 uRow
.nSel
== BROWSER_ENDOFSELECTION
? 0 : 1;
1811 void BrowseBox::SelectColumnPos( sal_uInt16 nNewColPos
, bool _bSelect
, bool bMakeVisible
)
1814 if ( !bColumnCursor
|| nNewColPos
== BROWSER_INVALIDID
)
1817 if ( !bMultiSelection
)
1820 GoToColumnId( mvCols
[ nNewColPos
]->GetId(), bMakeVisible
);
1825 if ( !GoToColumnId( mvCols
[ nNewColPos
]->GetId(), bMakeVisible
) )
1829 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1831 if ( bMultiSelection
)
1832 uRow
.pSel
->SelectAll(false);
1834 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1835 pColSel
->SelectAll(false);
1837 if ( pColSel
->Select( nNewColPos
, _bSelect
) )
1839 // GoToColumnId( mvCols->GetObject(nNewColPos)->GetId(), bMakeVisible );
1841 // only highlight painted areas
1843 tools::Rectangle
aFieldRectPix( GetFieldRectPixel( nCurRow
, nCurColId
, false ) );
1844 tools::Rectangle
aRect(
1845 Point( aFieldRectPix
.Left() - MIN_COLUMNWIDTH
, 0 ),
1846 Size( mvCols
[ nNewColPos
]->Width(),
1847 pDataWin
->GetOutputSizePixel().Height() ) );
1848 pDataWin
->Invalidate( aRect
);
1854 if ( isAccessibleAlive() )
1857 AccessibleEventId::SELECTION_CHANGED
,
1861 commitHeaderBarEvent(
1862 AccessibleEventId::SELECTION_CHANGED
,
1866 ); // column header event
1871 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1875 sal_uInt16
BrowseBox::GetSelectColumnCount() const
1878 // while bAutoSelect (==!pColSel), 1 if any rows (yes rows!) else none
1879 return pColSel
? static_cast<sal_uInt16
>(pColSel
->GetSelectCount()) :
1880 nCurRow
>= 0 ? 1 : 0;
1884 sal_Int32
BrowseBox::FirstSelectedColumn( ) const
1886 return pColSel
? pColSel
->FirstSelected() : BROWSER_ENDOFSELECTION
;
1890 sal_Int32
BrowseBox::FirstSelectedRow()
1893 return bMultiSelection
? uRow
.pSel
->FirstSelected() : uRow
.nSel
;
1897 sal_Int32
BrowseBox::NextSelectedRow()
1900 return bMultiSelection
? uRow
.pSel
->NextSelected() : BROWSER_ENDOFSELECTION
;
1904 sal_Int32
BrowseBox::LastSelectedRow()
1907 return bMultiSelection
? uRow
.pSel
->LastSelected() : uRow
.nSel
;
1911 bool BrowseBox::IsRowSelected( sal_Int32 nRow
) const
1914 return bMultiSelection
? uRow
.pSel
->IsSelected(nRow
) : nRow
== uRow
.nSel
;
1918 bool BrowseBox::IsColumnSelected( sal_uInt16 nColumnId
) const
1921 return pColSel
? pColSel
->IsSelected( GetColumnPos(nColumnId
) ) :
1922 nCurColId
== nColumnId
;
1926 void BrowseBox::MakeFieldVisible
1928 sal_Int32 nRow
, // line number of the field (starting with 0)
1929 sal_uInt16 nColId
// column ID of the field
1934 Makes visible the field described in 'nRow' and 'nColId' by scrolling
1943 Size aTestSize
= pDataWin
->GetSizePixel();
1945 if ( !bBootstrapped
|| aTestSize
.IsEmpty() )
1948 // is it visible already?
1949 bool bVisible
= IsFieldVisible( nRow
, nColId
, true/*bComplete*/ );
1953 // calculate column position, field rectangle and painting area
1954 sal_uInt16 nColPos
= GetColumnPos( nColId
);
1955 tools::Rectangle aFieldRect
= GetFieldRectPixel( nRow
, nColId
, false );
1956 tools::Rectangle
aDataRect( Point(0, 0), pDataWin
->GetSizePixel() );
1958 // positioned outside on the left?
1959 if ( nColPos
>= FrozenColCount() && nColPos
< nFirstCol
)
1960 // => scroll to the right
1961 ScrollColumns( nColPos
- nFirstCol
);
1963 // while outside on the right
1964 while ( aDataRect
.Right() < aFieldRect
.Right() )
1966 // => scroll to the left
1967 if ( ScrollColumns( 1 ) != 1 )
1968 // no more need to scroll
1970 aFieldRect
= GetFieldRectPixel( nRow
, nColId
, false );
1973 // positioned outside above?
1974 if ( nRow
< nTopRow
)
1975 // scroll further to the bottom
1976 ScrollRows( nRow
- nTopRow
);
1978 // positioned outside below?
1979 sal_Int32 nBottomRow
= nTopRow
+ GetVisibleRows();
1980 // decrement nBottomRow to make it the number of the last visible line
1981 // (count starts with 0!).
1982 // Example: BrowseBox contains exactly one entry. nBottomRow := 0 + 1 - 1
1986 if ( nRow
> nBottomRow
)
1987 // scroll further to the top
1988 ScrollRows( nRow
- nBottomRow
);
1992 bool BrowseBox::IsFieldVisible( sal_Int32 nRow
, sal_uInt16 nColumnId
,
1993 bool bCompletely
) const
1996 // hidden by frozen column?
1997 sal_uInt16 nColPos
= GetColumnPos( nColumnId
);
1998 if ( nColPos
>= FrozenColCount() && nColPos
< nFirstCol
)
2001 tools::Rectangle
aRect( ImplFieldRectPixel( nRow
, nColumnId
) );
2002 if ( aRect
.IsEmpty() )
2005 // get the visible area
2006 tools::Rectangle
aOutRect( Point(0, 0), pDataWin
->GetOutputSizePixel() );
2009 // test if the field is completely visible
2010 return aOutRect
.Contains( aRect
);
2012 // test if the field is partly of completely visible
2013 return !aOutRect
.Intersection( aRect
).IsEmpty();
2017 tools::Rectangle
BrowseBox::GetFieldRectPixel( sal_Int32 nRow
, sal_uInt16 nColumnId
,
2018 bool bRelToBrowser
) const
2021 // get the rectangle relative to DataWin
2022 tools::Rectangle
aRect( ImplFieldRectPixel( nRow
, nColumnId
) );
2023 if ( aRect
.IsEmpty() )
2026 // adjust relative to BrowseBox's output area
2027 Point
aTopLeft( aRect
.TopLeft() );
2028 if ( bRelToBrowser
)
2030 aTopLeft
= pDataWin
->OutputToScreenPixel( aTopLeft
);
2031 aTopLeft
= ScreenToOutputPixel( aTopLeft
);
2034 return tools::Rectangle( aTopLeft
, aRect
.GetSize() );
2038 tools::Rectangle
BrowseBox::GetRowRectPixel( sal_Int32 nRow
) const
2041 // get the rectangle relative to DataWin
2042 tools::Rectangle aRect
;
2043 if ( nTopRow
> nRow
)
2044 // row is above visible area
2046 aRect
= tools::Rectangle(
2047 Point( 0, GetDataRowHeight() * (nRow
-nTopRow
) ),
2048 Size( pDataWin
->GetOutputSizePixel().Width(), GetDataRowHeight() ) );
2049 if ( aRect
.Top() > pDataWin
->GetOutputSizePixel().Height() )
2050 // row is below visible area
2053 // adjust relative to BrowseBox's output area
2054 Point
aTopLeft( aRect
.TopLeft() );
2055 aTopLeft
= pDataWin
->OutputToScreenPixel( aTopLeft
);
2056 aTopLeft
= ScreenToOutputPixel( aTopLeft
);
2058 return tools::Rectangle( aTopLeft
, aRect
.GetSize() );
2062 tools::Rectangle
BrowseBox::ImplFieldRectPixel( sal_Int32 nRow
, sal_uInt16 nColumnId
) const
2065 // compute the X-coordinate relative to DataWin by accumulation
2066 tools::Long nColX
= 0;
2067 sal_uInt16 nFrozenCols
= FrozenColCount();
2070 nCol
< mvCols
.size() && mvCols
[ nCol
]->GetId() != nColumnId
;
2072 if ( mvCols
[ nCol
]->IsFrozen() || nCol
>= nFirstCol
)
2073 nColX
+= mvCols
[ nCol
]->Width();
2075 if ( nCol
>= mvCols
.size() || ( nCol
>= nFrozenCols
&& nCol
< nFirstCol
) )
2076 return tools::Rectangle();
2078 // compute the Y-coordinate relative to DataWin
2079 tools::Long nRowY
= GetDataRowHeight();
2080 if ( nRow
!= BROWSER_ENDOFSELECTION
) // #105497# OJ
2081 nRowY
= ( nRow
- nTopRow
) * GetDataRowHeight();
2083 // assemble the Rectangle relative to DataWin
2084 return tools::Rectangle(
2085 Point( nColX
+ MIN_COLUMNWIDTH
, nRowY
),
2086 Size( (mvCols
[nCol
]->Width() == LONG_MAX
2087 ? LONG_MAX
- (nColX
+ MIN_COLUMNWIDTH
) : mvCols
[ nCol
]->Width() - 2*MIN_COLUMNWIDTH
),
2088 GetDataRowHeight() - 1 ) );
2092 sal_Int32
BrowseBox::GetRowAtYPosPixel( tools::Long nY
, bool bRelToBrowser
) const
2095 // compute the Y-coordinate
2096 if ( bRelToBrowser
)
2098 Point aDataTopLeft
= pDataWin
->OutputToScreenPixel( Point(0, 0) );
2099 Point aTopLeft
= OutputToScreenPixel( Point(0, 0) );
2100 nY
-= aDataTopLeft
.Y() - aTopLeft
.Y();
2103 // no row there (e.g. in the header)
2104 if ( nY
< 0 || nY
>= pDataWin
->GetOutputSizePixel().Height() )
2107 return nY
/ GetDataRowHeight() + nTopRow
;
2111 tools::Rectangle
BrowseBox::GetFieldRect( sal_uInt16 nColumnId
) const
2114 return GetFieldRectPixel( nCurRow
, nColumnId
);
2118 sal_uInt16
BrowseBox::GetColumnAtXPosPixel( tools::Long nX
) const
2121 // accumulate the widths of the visible columns
2122 tools::Long nColX
= 0;
2123 for ( size_t nCol
= 0; nCol
< mvCols
.size(); ++nCol
)
2125 BrowserColumn
*pCol
= mvCols
[ nCol
].get();
2126 if ( pCol
->IsFrozen() || nCol
>= nFirstCol
)
2127 nColX
+= pCol
->Width();
2133 return BROWSER_INVALIDID
;
2136 bool BrowseBox::ReserveControlArea(sal_uInt16 nWidth
)
2138 if (nWidth
!= nControlAreaWidth
)
2140 OSL_ENSURE(nWidth
,"Control area of 0 is not allowed, Use USHRT_MAX instead!");
2141 nControlAreaWidth
= nWidth
;
2148 tools::Rectangle
BrowseBox::GetControlArea() const
2150 auto nHeight
= aHScroll
->GetSizePixel().Height();
2151 auto nEndRight
= aHScroll
->GetPosPixel().X();
2153 return tools::Rectangle(
2154 Point( 0, GetOutputSizePixel().Height() - nHeight
),
2155 Size( nEndRight
, nHeight
) );
2158 void BrowseBox::SetMode( BrowserMode nMode
)
2161 pDataWin
->bAutoHScroll
= BrowserMode::AUTO_HSCROLL
== ( nMode
& BrowserMode::AUTO_HSCROLL
);
2162 pDataWin
->bAutoVScroll
= BrowserMode::AUTO_VSCROLL
== ( nMode
& BrowserMode::AUTO_VSCROLL
);
2163 pDataWin
->bNoHScroll
= BrowserMode::NO_HSCROLL
== ( nMode
& BrowserMode::NO_HSCROLL
);
2164 pDataWin
->bNoVScroll
= BrowserMode::NO_VSCROLL
== ( nMode
& BrowserMode::NO_VSCROLL
);
2166 DBG_ASSERT( !( pDataWin
->bAutoHScroll
&& pDataWin
->bNoHScroll
),
2167 "BrowseBox::SetMode: AutoHScroll *and* NoHScroll?" );
2168 DBG_ASSERT( !( pDataWin
->bAutoVScroll
&& pDataWin
->bNoVScroll
),
2169 "BrowseBox::SetMode: AutoVScroll *and* NoVScroll?" );
2170 if ( pDataWin
->bAutoHScroll
)
2171 pDataWin
->bNoHScroll
= false;
2172 if ( pDataWin
->bAutoVScroll
)
2173 pDataWin
->bNoVScroll
= false;
2175 if ( pDataWin
->bNoHScroll
)
2178 nControlAreaWidth
= USHRT_MAX
;
2180 tools::Long nOldRowSel
= bMultiSelection
? uRow
.pSel
->FirstSelected() : uRow
.nSel
;
2181 MultiSelection
*pOldRowSel
= bMultiSelection
? uRow
.pSel
: nullptr;
2183 pVScroll
.disposeAndClear();
2185 bMultiSelection
= bool( nMode
& BrowserMode::MULTISELECTION
);
2186 bColumnCursor
= bool( nMode
& BrowserMode::COLUMNSELECTION
);
2187 bKeepHighlight
= bool( nMode
& BrowserMode::KEEPHIGHLIGHT
);
2189 bHideSelect
= ((nMode
& BrowserMode::HIDESELECT
) == BrowserMode::HIDESELECT
);
2190 // default: do not hide the cursor at all (untaken scrolling and such)
2191 bHideCursor
= TRISTATE_FALSE
;
2193 if ( BrowserMode::HIDECURSOR
== ( nMode
& BrowserMode::HIDECURSOR
) )
2195 bHideCursor
= TRISTATE_TRUE
;
2198 m_bFocusOnlyCursor
= ((nMode
& BrowserMode::CURSOR_WO_FOCUS
) == BrowserMode::NONE
);
2200 bHLines
= ( nMode
& BrowserMode::HLINES
) == BrowserMode::HLINES
;
2201 bVLines
= ( nMode
& BrowserMode::VLINES
) == BrowserMode::VLINES
;
2203 pVScroll
= VclPtr
<ScrollAdaptor
>::Create(this, false);
2204 pVScroll
->SetLineSize( 1 );
2205 pVScroll
->SetPageSize(1);
2206 pVScroll
->SetScrollHdl( LINK( this, BrowseBox
, VertScrollHdl
) );
2208 pDataWin
->bAutoSizeLastCol
=
2209 BrowserMode::AUTOSIZE_LASTCOL
== ( nMode
& BrowserMode::AUTOSIZE_LASTCOL
);
2211 // create a headerbar. what happens, if a headerbar has to be created and
2212 // there already are columns?
2213 if ( BrowserMode::HEADERBAR_NEW
== ( nMode
& BrowserMode::HEADERBAR_NEW
) )
2215 if (!pDataWin
->pHeaderBar
)
2216 pDataWin
->pHeaderBar
= CreateHeaderBar( this );
2220 pDataWin
->pHeaderBar
.disposeAndClear();
2223 if ( bColumnCursor
)
2226 pColSel
.reset(new MultiSelection
);
2227 pColSel
->SetTotalRange( Range( 0, mvCols
.size()-1 ) );
2234 if ( bMultiSelection
)
2237 uRow
.pSel
= pOldRowSel
;
2239 uRow
.pSel
= new MultiSelection
;
2243 uRow
.nSel
= nOldRowSel
;
2247 if ( bBootstrapped
)
2249 StateChanged( StateChangedType::InitShow
);
2250 if ( bMultiSelection
&& !pOldRowSel
&&
2251 nOldRowSel
!= BROWSER_ENDOFSELECTION
)
2252 uRow
.pSel
->Select( nOldRowSel
);
2256 pDataWin
->Invalidate();
2258 // no cursor on handle column
2259 if ( nCurColId
== HandleColumnId
)
2260 nCurColId
= GetColumnId( 1 );
2262 m_nCurrentMode
= nMode
;
2266 void BrowseBox::VisibleRowsChanged( sal_Int32
, sal_uInt16
)
2269 // old behavior: automatically correct NumRows:
2270 if ( nRowCount
< GetRowCount() )
2272 RowInserted(nRowCount
,GetRowCount() - nRowCount
, false);
2274 else if ( nRowCount
> GetRowCount() )
2276 RowRemoved(GetRowCount(), nRowCount
- GetRowCount(), false);
2281 bool BrowseBox::IsCursorMoveAllowed( sal_Int32
, sal_uInt16
) const
2285 This virtual method is always called before the cursor is moved directly.
2286 By means of 'return false', we avoid doing this if e.g. a record
2287 contradicts any rules.
2289 This method is not called, if the cursor movement results from removing or
2290 deleting a row/column (thus, in cases where only a "cursor correction" happens).
2292 The base implementation currently always returns true.
2300 tools::Long
BrowseBox::GetDataRowHeight() const
2302 return CalcZoom(m_nDataRowHeight
? m_nDataRowHeight
: ImpGetDataRowHeight());
2306 VclPtr
<BrowserHeader
> BrowseBox::CreateHeaderBar( BrowseBox
* pParent
)
2308 VclPtr
<BrowserHeader
> pNewBar
= VclPtr
<BrowserHeader
>::Create( pParent
);
2309 pNewBar
->SetStartDragHdl( LINK( this, BrowseBox
, StartDragHdl
) );
2313 void BrowseBox::SetHeaderBar( BrowserHeader
* pHeaderBar
)
2315 pDataWin
->pHeaderBar
.disposeAndClear();
2316 pDataWin
->pHeaderBar
= pHeaderBar
;
2317 pDataWin
->pHeaderBar
->SetStartDragHdl( LINK( this, BrowseBox
, StartDragHdl
) );
2320 tools::Long
BrowseBox::GetTitleHeight() const
2322 tools::Long nHeight
;
2323 // ask the header bar for the text height (if possible), as the header bar's font is adjusted with
2324 // our (and the header's) zoom factor
2325 HeaderBar
* pHeaderBar
= pDataWin
->pHeaderBar
;
2327 nHeight
= pHeaderBar
->GetTextHeight();
2329 nHeight
= GetTextHeight();
2331 return nTitleLines
? nTitleLines
* nHeight
+ 4 : 0;
2334 tools::Long
BrowseBox::CalcReverseZoom(tools::Long nVal
) const
2338 const Fraction
& rZoom
= GetZoom();
2339 double n
= static_cast<double>(nVal
);
2340 n
*= static_cast<double>(rZoom
.GetDenominator());
2341 if (!rZoom
.GetNumerator())
2342 throw o3tl::divide_by_zero();
2343 n
/= static_cast<double>(rZoom
.GetNumerator());
2344 nVal
= n
>0 ? static_cast<tools::Long
>(n
+ 0.5) : -static_cast<tools::Long
>(-n
+ 0.5);
2350 void BrowseBox::CursorMoved()
2352 // before implementing more here, please adjust the EditBrowseBox
2354 if ( isAccessibleAlive() && HasFocus() )
2356 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
,
2357 Any( CreateAccessibleCell( GetCurRow(),GetColumnPos( GetCurColumnId() ) ) ),
2362 void BrowseBox::LoseFocus()
2364 SAL_INFO("svtools", "BrowseBox::LoseFocus " << this );
2368 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
2371 if ( !bKeepHighlight
)
2374 bSelectionIsVisible
= false;
2379 Control::LoseFocus();
2383 void BrowseBox::GetFocus()
2385 SAL_INFO("svtools", "BrowseBox::GetFocus " << this );
2389 if ( !bSelectionIsVisible
)
2391 bSelectionIsVisible
= true;
2392 if ( bBootstrapped
)
2399 Control::GetFocus();
2403 sal_uInt16
BrowseBox::GetVisibleRows() const
2405 return static_cast<sal_uInt16
>((pDataWin
->GetOutputSizePixel().Height() - 1 )/ GetDataRowHeight() + 1);
2408 BrowserDataWin
& BrowseBox::GetDataWindow() const
2413 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */