cid#1606940 Check of thread-shared field evades lock acquisition
[LibreOffice.git] / svtools / source / brwbox / brwbox1.cxx
blob11f750b96b5c08de4bcdd93b20d9317f8eddf41f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
26 #include "datwin.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>
35 #include <algorithm>
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;
49 using namespace svt;
51 namespace
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)!");
59 if (xComp.is())
60 try
62 xComp->dispose();
64 catch(const css::uno::Exception&)
66 TOOLS_WARN_EXCEPTION("svtools", "THeaderCellMapFunctorDispose");
71 void disposeAndClearHeaderCell(BrowseBox::THeaderCellMap& _rHeaderCell)
73 ::std::for_each(
74 _rHeaderCell.begin(),
75 _rHeaderCell.end(),
76 THeaderCellMapFunctorDispose()
78 _rHeaderCell.clear();
82 // we're just measuring the "real" NavigationBar
83 class MeasureStatusBar final : public InterimItemWindow
85 private:
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;
90 public:
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();
110 m_xRecordOf.reset();
111 m_xAbsolute.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))
138 ,m_nCornerHeight(0)
139 ,m_nCornerWidth(0)
140 ,m_nActualCornerWidth(0)
141 ,m_bNavigationBar(false)
143 bMultiSelection = false;
144 pColSel = nullptr;
145 pVScroll = nullptr;
146 pDataWin = VclPtr<BrowserDataWin>::Create( this ).get();
148 InitSettings_Impl( this );
149 InitSettings_Impl( pDataWin );
151 bBootstrapped = false;
152 m_nDataRowHeight = 0;
153 nTitleLines = 1;
154 nFirstCol = 0;
155 nTopRow = 0;
156 nCurRow = BROWSER_ENDOFSELECTION;
157 nCurColId = 0;
158 nResizeX = 0;
159 nMinResizeX = 0;
160 nDragX = 0;
161 nResizeCol = 0;
162 bResizing = false;
163 bSelect = false;
164 bSelecting = false;
165 bScrolling = false;
166 bSelectionIsVisible = false;
167 bNotToggleSel = false;
168 bRowDividerDrag = false;
169 bHit = false;
170 mbInteractiveRowHeight = false;
171 bHideSelect = false;
172 bHideCursor = TRISTATE_FALSE;
173 nRowCount = 0;
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 ) );
182 pDataWin->Show();
184 SetMode( nMode );
185 bSelectionIsVisible = bKeepHighlight;
186 bHasFocus = HasChildPathFocus();
187 pDataWin->nCursorHidden =
188 ( bHasFocus ? 0 : 1 ) + ( GetUpdateMode() ? 0 : 1 );
191 BrowseBox::~BrowseBox()
193 disposeOnce();
196 void BrowseBox::DisposeAccessible()
198 if (m_pAccessible )
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 );
211 DisposeAccessible();
213 Hide();
214 pDataWin->pHeaderBar.disposeAndClear();
215 pDataWin.disposeAndClear();
216 pVScroll.disposeAndClear();
217 aHScroll.disposeAndClear();
218 aStatusBarHeight.disposeAndClear();
220 // free columns-space
221 mvCols.clear();
222 pColSel.reset();
223 if ( bMultiSelection )
224 delete uRow.pSel;
225 DragSourceHelper::dispose();
226 DropTargetHelper::dispose();
227 Control::dispose();
231 short BrowseBox::GetCursorHideCount() const
233 return pDataWin->nCursorHidden;
237 void BrowseBox::DoShowCursor()
239 if (!pDataWin)
240 return;
241 short nHiddenCount = --pDataWin->nCursorHidden;
242 if (PaintCursorIfHiddenOnce())
244 if (1 == nHiddenCount)
245 DrawCursor();
247 else
249 if (0 == nHiddenCount)
250 DrawCursor();
255 void BrowseBox::DoHideCursor()
257 short nHiddenCount = ++pDataWin->nCursorHidden;
258 if (PaintCursorIfHiddenOnce())
260 if (2 == nHiddenCount)
261 DrawCursor();
263 else
265 if (1 == nHiddenCount)
266 DrawCursor();
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" );
303 #endif
305 mvCols.insert( mvCols.begin(), std::unique_ptr<BrowserColumn>(new BrowserColumn( 0, OUString(), nWidth, GetZoom() )) );
306 FreezeColumn( 0 );
308 // adjust headerbar
309 if ( pDataWin->pHeaderBar )
311 pDataWin->pHeaderBar->SetPosSizePixel(
312 Point(nWidth, 0),
313 Size( GetOutputSizePixel().Width() - nWidth, GetTitleHeight() )
317 ColumnInserted( 0 );
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" );
333 #endif
335 if ( nPos < mvCols.size() )
337 mvCols.emplace( mvCols.begin() + nPos, new BrowserColumn( nItemId, rText, nWidth, GetZoom() ) );
339 else
341 mvCols.emplace_back( new BrowserColumn( nItemId, rText, nWidth, GetZoom() ) );
343 if ( nCurColId == 0 )
344 nCurColId = nItemId;
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 )
351 nHeaderPos--;
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() )
363 DoHideCursor();
364 ToggleSelection();
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 ) );
378 ToggleSelection();
379 SAL_INFO("svtools", "BrowseBox::SetToggledSelectedColumn " << this );
380 DoShowCursor();
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() )
389 // not available!
390 return;
392 // doesn't the state change?
393 if ( mvCols[ nItemPos ]->IsFrozen() )
394 return;
396 // remark the column selection
397 sal_uInt16 nSelectedColId = ToggleSelectedColumn();
399 // to be moved?
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
418 UpdateScrollbars();
420 // repaint
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 )
433 return;
435 // get the position in the current array
436 sal_uInt16 nOldPos = GetColumnPos( nColumnId );
437 if ( nOldPos >= mvCols.size() )
438 // not available!
439 return;
441 // does the state change?
442 if (nOldPos == nPos)
443 return;
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
488 else
489 aScrollArea = tools::Rectangle(Point(aNextRect.Left(),0),
490 Point(aToRect.Right(),aDataWinSize.Height()));
492 pDataWin->Scroll( nScroll, 0, aScrollArea );
493 aToRect.SetTop( 0 );
494 aToRect.SetBottom( aScrollArea.Bottom() );
495 Invalidate( aToRect );
497 else
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 )
505 --nNewPos;
506 pDataWin->pHeaderBar->MoveItem(nColumnId,nNewPos);
508 // remember the column selection
509 SetToggledSelectedColumn(nSelectedColId);
511 if ( !isAccessibleAlive() )
512 return;
514 commitTableEvent(
515 AccessibleEventId::TABLE_MODEL_CHANGED,
516 Any( AccessibleTableModelChange(
517 COLUMNS_REMOVED,
520 nOldPos,
521 nOldPos
524 Any()
527 commitTableEvent(
528 AccessibleEventId::TABLE_MODEL_CHANGED,
529 Any( AccessibleTableModelChange(
530 COLUMNS_INSERTED,
533 nPos,
534 nPos
537 Any()
543 void BrowseBox::SetColumnTitle( sal_uInt16 nItemId, const OUString& rTitle )
546 // never set title of the handle-column
547 if ( nItemId == HandleColumnId )
548 return;
550 // get the position in the current array
551 sal_uInt16 nItemPos = GetColumnPos( nItemId );
552 if ( nItemPos >= mvCols.size() )
553 // not available!
554 return;
556 // does the state change?
557 BrowserColumn *pCol = mvCols[ nItemPos ].get();
558 if ( pCol->Title() == rTitle )
559 return;
561 OUString sOld(pCol->Title());
563 pCol->Title() = rTitle;
565 // adjust headerbar column
566 if ( pDataWin->pHeaderBar )
567 pDataWin->pHeaderBar->SetItemText( nItemId, rTitle );
568 else
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,
579 Any( rTitle ),
580 Any( sOld )
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() )
592 return;
594 // does the state change?
595 if ( nWidth < LONG_MAX && mvCols[ nItemPos ]->Width() == nWidth )
596 return;
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()
606 : GetFrozenWidth();
607 if ( pDataWin->bAutoSizeLastCol || nWidth > nMaxWidth )
609 nWidth = nMaxWidth > 16 ? nMaxWidth : nOldWidth;
613 // OV
614 // In AutoSizeLastColumn(), we call SetColumnWidth with nWidth==0xffff.
615 // Thus, check here, if the width has actually changed.
616 if( nOldWidth == nWidth )
617 return;
619 // do we want to display the change immediately?
620 bool bUpdate = GetUpdateMode() &&
621 ( mvCols[ nItemPos ]->IsFrozen() || nItemPos >= nFirstCol );
623 if ( bUpdate )
625 // Selection hidden
626 DoHideCursor();
627 ToggleSelection();
628 //!pDataWin->Update();
629 //!Control::Update();
632 // set width
633 mvCols[ nItemPos ]->SetWidth(nWidth, GetZoom());
635 // scroll and invalidate
636 if ( bUpdate )
638 // get X-Pos of the column changed
639 tools::Long nX = 0;
640 for ( size_t nCol = 0; nCol < nItemPos; ++nCol )
642 BrowserColumn *pCol = mvCols[ nCol ].get();
643 if ( pCol->IsFrozen() || nCol >= nFirstCol )
644 nX += pCol->Width();
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 );
664 else
666 Control::Invalidate( InvalidateFlags::NoChildren );
667 pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
671 //!pDataWin->Update();
672 //!Control::Update();
673 bSelectionIsVisible = bSelVis;
674 ToggleSelection();
675 DoShowCursor();
677 UpdateScrollbars();
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() )
708 // not available
709 return;
711 // correct column selection
712 if ( pColSel )
713 pColSel->Remove( nPos );
715 // correct column cursor
716 if ( nCurColId == nItemId )
717 nCurColId = 0;
719 // delete column
720 mvCols.erase( mvCols.begin() + nPos );
721 if ( nFirstCol >= nPos && nFirstCol > FrozenColCount() )
723 OSL_ENSURE(nFirstCol > 0,"FirstCol must be greater zero!");
724 --nFirstCol;
727 // handlecolumn not in headerbar
728 if (nItemId)
730 if ( pDataWin->pHeaderBar )
731 pDataWin->pHeaderBar->RemoveItem( nItemId );
733 else
735 // adjust headerbar
736 if ( pDataWin->pHeaderBar )
738 pDataWin->pHeaderBar->SetPosSizePixel(
739 Point(0, 0),
740 Size( GetOutputSizePixel().Width(), GetTitleHeight() )
745 // correct vertical scrollbar
746 UpdateScrollbars();
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() )
758 return;
760 commitTableEvent(
761 AccessibleEventId::TABLE_MODEL_CHANGED,
762 Any( AccessibleTableModelChange(COLUMNS_REMOVED,
765 nPos,
766 nPos
769 Any()
772 commitHeaderBarEvent(
773 AccessibleEventId::CHILD,
774 Any(),
775 Any( CreateAccessibleColumnHeader( nPos ) ),
776 true
781 void BrowseBox::RemoveColumns()
783 size_t nOldCount = mvCols.size();
785 // remove all columns
786 mvCols.clear();
788 // correct column selection
789 if ( pColSel )
791 pColSel->SelectAll(false);
792 pColSel->SetTotalRange( Range( 0, 0 ) );
795 // correct column cursor
796 nCurColId = 0;
797 nFirstCol = 0;
799 if ( pDataWin->pHeaderBar )
800 pDataWin->pHeaderBar->Clear( );
802 // correct vertical scrollbar
803 UpdateScrollbars();
805 // trigger repaint if necessary
806 if ( GetUpdateMode() )
808 pDataWin->Invalidate();
809 Control::Invalidate();
812 if ( !isAccessibleAlive() )
813 return;
815 if ( mvCols.size() == nOldCount )
816 return;
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,
822 Any(),
823 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar))
826 // and now append it again
827 commitBrowseBoxEvent(
828 AccessibleEventId::CHILD,
829 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::ColumnHeaderBar)),
830 Any()
833 // notify a table model change
834 commitTableEvent(
835 AccessibleEventId::TABLE_MODEL_CHANGED,
836 Any ( AccessibleTableModelChange( COLUMNS_REMOVED,
840 nOldCount
843 Any()
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
859 return nRowCount;
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);
871 pThis->Resize();
872 pDataWin->Invalidate();
873 return m_nDataRowHeight;
876 void BrowseBox::SetDataRowHeight( tools::Long nPixel )
879 m_nDataRowHeight = CalcReverseZoom(nPixel);
880 Resize();
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() )
895 return 0;
897 // implicitly hides cursor while scrolling
898 StartScroll();
899 bScrolling = true;
900 bool bScrollable = pDataWin->GetBackground().IsScrollable();
901 bool bInvalidateView = false;
903 // scrolling one column to the right?
904 if ( nCols == 1 )
906 // update internal value and scrollbar
907 ++nFirstCol;
908 aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
910 if ( !bScrollable )
912 bInvalidateView = true;
914 else
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,
921 GetTitleHeight() - 1
922 ) );
924 // scroll the header bar area (if there is no dedicated HeaderBar control)
925 if ( !pDataWin->pHeaderBar && nTitleLines )
927 // actually scroll
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() );
940 // actually scroll
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 )
953 --nFirstCol;
954 aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
956 if ( !bScrollable )
958 bInvalidateView = true;
960 else
962 tools::Long nDelta = mvCols[ nFirstCol ]->Width();
963 tools::Long nFrozenWidth = GetFrozenWidth();
965 tools::Rectangle aScrollRect( Point( nFrozenWidth, 0 ),
966 Size ( GetOutputSizePixel().Width() - nFrozenWidth,
967 GetTitleHeight() - 1
968 ) );
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 );
981 else
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;
1003 ++nCol )
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
1020 if ( nCols )
1022 pDataWin->Update();
1023 PaintImmediately();
1025 bScrolling = false;
1026 EndScroll();
1028 return nCols;
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 )
1040 return 0;
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 );
1052 StartScroll();
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 );
1070 else
1071 pDataWin->Invalidate();
1073 if ( nTopRow - nOldTopRow )
1074 pDataWin->Update();
1077 EndScroll();
1079 return nTopRow - nOldTopRow;
1083 void BrowseBox::RowModified( sal_Int32 nRow, sal_uInt16 nColId )
1086 if ( !GetUpdateMode() )
1087 return;
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() ) );
1094 else
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
1106 DoHideCursor();
1107 sal_Int32 nOldRowCount = nRowCount;
1108 nRowCount = 0;
1109 if(bMultiSelection)
1111 assert(uRow.pSel);
1112 uRow.pSel->Reset();
1114 else
1115 uRow.nSel = BROWSER_ENDOFSELECTION;
1116 nCurRow = BROWSER_ENDOFSELECTION;
1117 nTopRow = 0;
1118 nCurColId = 0;
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 );
1126 Invalidate();
1127 UpdateScrollbars();
1128 SetNoSelection();
1129 DoShowCursor();
1130 CursorMoved();
1132 if ( !isAccessibleAlive() )
1133 return;
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 )
1138 return;
1140 commitBrowseBoxEvent(
1141 AccessibleEventId::CHILD,
1142 Any(),
1143 Any(getAccessibleHeaderBar( AccessibleBrowseBoxObjType::RowHeaderBar))
1146 // and now append it again
1147 commitBrowseBoxEvent(
1148 AccessibleEventId::CHILD,
1149 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)),
1150 Any()
1153 // notify a table model change
1154 commitTableEvent(
1155 AccessibleEventId::TABLE_MODEL_CHANGED,
1156 Any( AccessibleTableModelChange(ROWS_REMOVED,
1158 nOldRowCount,
1162 Any()
1166 void BrowseBox::RowInserted( sal_Int32 nRow, sal_Int32 nNumRows, bool bDoPaint, bool bKeepSelection )
1169 if (nRow < 0)
1170 nRow = 0;
1171 else if (nRow > nRowCount) // maximal = nRowCount
1172 nRow = nRowCount;
1174 if ( nNumRows <= 0 )
1175 return;
1177 // adjust total row count
1178 bool bLastRow = nRow >= nRowCount;
1179 nRowCount += nNumRows;
1181 DoHideCursor();
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();
1190 if ( !bLastRow )
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 ) ),
1199 SCROLL_FLAGS );
1201 else
1202 pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
1204 else
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
1230 if ( bDoPaint )
1232 UpdateScrollbars();
1233 AutoSizeLastColumn();
1236 DoShowCursor();
1237 // notify accessible that rows were inserted
1238 if ( isAccessibleAlive() )
1240 commitTableEvent(
1241 AccessibleEventId::TABLE_MODEL_CHANGED,
1242 Any( AccessibleTableModelChange(
1243 ROWS_INSERTED,
1244 nRow,
1245 nRow + nNumRows,
1250 Any()
1253 for (tools::Long i = nRow+1 ; i <= nRowCount ; ++i)
1255 commitHeaderBarEvent(
1256 AccessibleEventId::CHILD,
1257 Any( CreateAccessibleRowHeader( i ) ),
1258 Any(),
1259 false
1264 if ( nCurRow != nOldCurRow )
1265 CursorMoved();
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 )
1276 if ( nRow < 0 )
1277 nRow = 0;
1278 else if ( nRow >= nRowCount )
1279 nRow = nRowCount - 1;
1281 if ( nNumRows <= 0 )
1282 return;
1284 if ( nRowCount <= 0 )
1285 return;
1287 if ( bDoPaint )
1289 // hide cursor and selection
1290 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1291 ToggleSelection();
1292 DoHideCursor();
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)
1322 --nCurRow;
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() )
1332 if ( bDoPaint )
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() ) ),
1345 SCROLL_FLAGS );
1347 else
1348 pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
1350 else
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;
1365 if ( bDoPaint )
1367 // reshow cursor and selection
1368 ToggleSelection();
1369 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1370 DoShowCursor();
1372 // adjust the vertical scrollbar
1373 UpdateScrollbars();
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,
1385 Any(),
1386 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar))
1389 // and now append it again
1390 commitBrowseBoxEvent(
1391 AccessibleEventId::CHILD,
1392 Any(getAccessibleHeaderBar(AccessibleBrowseBoxObjType::RowHeaderBar)),
1393 Any()
1395 commitBrowseBoxEvent(
1396 AccessibleEventId::CHILD,
1397 Any(),
1398 Any(getAccessibleTable())
1401 // and now append it again
1402 commitBrowseBoxEvent(
1403 AccessibleEventId::CHILD,
1404 Any(getAccessibleTable()),
1405 Any()
1408 else
1410 commitTableEvent(
1411 AccessibleEventId::TABLE_MODEL_CHANGED,
1412 Any( AccessibleTableModelChange(
1413 ROWS_REMOVED,
1414 nRow,
1415 nRow + nNumRows,
1420 Any()
1423 for (tools::Long i = nRow+1 ; i <= (nRow+nNumRows) ; ++i)
1425 commitHeaderBarEvent(
1426 AccessibleEventId::CHILD,
1427 Any(),
1428 Any( CreateAccessibleRowHeader( i ) ),
1429 false
1435 if ( nOldCurRow != nCurRow )
1436 CursorMoved();
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;
1454 // nothing to do?
1455 if ( nRow == nCurRow && ( bMultiSelection || uRow.nSel == nRow ) )
1456 return true;
1458 // out of range?
1459 if ( nRow < 0 || nRow >= nRowCount )
1460 return false;
1462 // not allowed?
1463 if ( !bRowColMove && !IsCursorMoveAllowed( nRow, nCurColId ) )
1464 return false;
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;
1471 // suspend Updates
1472 pDataWin->EnterUpdateLock();
1474 // remove old highlight, if necessary
1475 if ( !bMultiSelection && !bKeepSelection )
1476 ToggleSelection();
1477 DoHideCursor();
1479 // must we scroll?
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)
1502 nCurRow = 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 )
1509 uRow.nSel = nRow;
1511 // resume Updates
1512 pDataWin->LeaveUpdateLock();
1514 // Cursor+Highlight
1515 if ( !bMultiSelection && !bKeepSelection)
1516 ToggleSelection();
1517 DoShowCursor();
1518 if ( !bRowColMove && nOldCurRow != nCurRow )
1519 CursorMoved();
1521 if ( !bMultiSelection && !bKeepSelection )
1523 if ( !bSelecting )
1524 Select();
1525 else
1526 bSelect = true;
1528 return true;
1532 bool BrowseBox::GoToColumnId( sal_uInt16 nColId)
1534 return GoToColumnId(nColId, true);
1538 bool BrowseBox::GoToColumnId( sal_uInt16 nColId, bool bMakeVisible, bool bRowColMove)
1540 if (!bColumnCursor)
1541 return false;
1543 // allowed?
1544 if (!bRowColMove && !IsCursorMoveAllowed( nCurRow, nColId ) )
1545 return false;
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?" );
1552 if ( !pColumn )
1553 return false;
1555 DoHideCursor();
1556 nCurColId = nColId;
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 );
1572 bScrolled = true;
1575 DoShowCursor();
1576 if (!bRowColMove)
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);
1587 CursorMoved();
1588 m_aGotoStack.pop();
1591 return true;
1593 return true;
1597 bool BrowseBox::GoToRowColumnId( sal_Int32 nRow, sal_uInt16 nColId )
1600 // out of range?
1601 if ( nRow < 0 || nRow >= nRowCount )
1602 return false;
1604 if (!bColumnCursor)
1605 return false;
1607 // nothing to do ?
1608 if ( nRow == nCurRow && ( bMultiSelection || uRow.nSel == nRow ) &&
1609 nColId == nCurColId && IsFieldVisible(nCurRow, nColId, true))
1610 return true;
1612 // allowed?
1613 if (!IsCursorMoveAllowed(nRow, nColId))
1614 return false;
1616 DoHideCursor();
1617 bool bMoved = GoToRow(nRow, true) && GoToColumnId(nColId, true, true);
1618 DoShowCursor();
1620 if (bMoved)
1621 CursorMoved();
1623 return bMoved;
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() ) ) )
1634 // nothing to do
1635 return;
1637 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1638 ToggleSelection();
1640 // unselect all
1641 if ( bMultiSelection )
1642 uRow.pSel->SelectAll(false);
1643 else
1644 uRow.nSel = BROWSER_ENDOFSELECTION;
1645 if ( pColSel )
1646 pColSel->SelectAll(false);
1647 if ( !bSelecting )
1648 Select();
1649 else
1650 bSelect = true;
1652 // restore screen
1653 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1655 if ( isAccessibleAlive() )
1657 commitTableEvent(
1658 AccessibleEventId::SELECTION_CHANGED,
1659 Any(),
1660 Any()
1666 void BrowseBox::SelectAll()
1669 if ( !bMultiSelection )
1670 return;
1672 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1673 ToggleSelection();
1675 // select all rows
1676 if ( pColSel )
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
1685 if ( !bHideSelect )
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 );
1699 if ( !bSelecting )
1700 Select();
1701 else
1702 bSelect = true;
1704 // restore screen
1705 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1707 if ( !isAccessibleAlive() )
1708 return;
1710 commitTableEvent(
1711 AccessibleEventId::SELECTION_CHANGED,
1712 Any(),
1713 Any()
1715 commitHeaderBarEvent(
1716 AccessibleEventId::SELECTION_CHANGED,
1717 Any(),
1718 Any(),
1719 true
1720 ); // column header event
1722 commitHeaderBarEvent(
1723 AccessibleEventId::SELECTION_CHANGED,
1724 Any(),
1725 Any(),
1726 false
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
1737 if ( _bSelect )
1738 GoToRow(nRow, false);
1739 return;
1742 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1744 // remove old selection?
1745 if ( !bExpand || !bMultiSelection )
1747 ToggleSelection();
1748 if ( bMultiSelection )
1749 uRow.pSel->SelectAll(false);
1750 else
1751 uRow.nSel = BROWSER_ENDOFSELECTION;
1752 if ( pColSel )
1753 pColSel->SelectAll(false);
1756 // set new selection
1757 if ( !bHideSelect
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 );
1778 if ( !bSelecting )
1779 Select();
1780 else
1781 bSelect = true;
1783 // restore screen
1784 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1786 if ( !isAccessibleAlive() )
1787 return;
1789 commitTableEvent(
1790 AccessibleEventId::SELECTION_CHANGED,
1791 Any(),
1792 Any()
1794 commitHeaderBarEvent(
1795 AccessibleEventId::SELECTION_CHANGED,
1796 Any(),
1797 Any(),
1798 false
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 )
1815 return;
1817 if ( !bMultiSelection )
1819 if ( _bSelect )
1820 GoToColumnId( mvCols[ nNewColPos ]->GetId(), bMakeVisible );
1821 return;
1823 else
1825 if ( !GoToColumnId( mvCols[ nNewColPos ]->GetId(), bMakeVisible ) )
1826 return;
1829 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1830 ToggleSelection();
1831 if ( bMultiSelection )
1832 uRow.pSel->SelectAll(false);
1833 else
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
1842 pDataWin->Update();
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 );
1849 if ( !bSelecting )
1850 Select();
1851 else
1852 bSelect = true;
1854 if ( isAccessibleAlive() )
1856 commitTableEvent(
1857 AccessibleEventId::SELECTION_CHANGED,
1858 Any(),
1859 Any()
1861 commitHeaderBarEvent(
1862 AccessibleEventId::SELECTION_CHANGED,
1863 Any(),
1864 Any(),
1865 true
1866 ); // column header event
1870 // restore screen
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
1932 /* [Description]
1934 Makes visible the field described in 'nRow' and 'nColId' by scrolling
1935 accordingly.
1940 if (!pDataWin)
1941 return;
1943 Size aTestSize = pDataWin->GetSizePixel();
1945 if ( !bBootstrapped || aTestSize.IsEmpty() )
1946 return;
1948 // is it visible already?
1949 bool bVisible = IsFieldVisible( nRow, nColId, true/*bComplete*/ );
1950 if ( bVisible )
1951 return;
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
1969 break;
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
1983 if( nBottomRow )
1984 nBottomRow--;
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 )
1999 return false;
2001 tools::Rectangle aRect( ImplFieldRectPixel( nRow, nColumnId ) );
2002 if ( aRect.IsEmpty() )
2003 return false;
2005 // get the visible area
2006 tools::Rectangle aOutRect( Point(0, 0), pDataWin->GetOutputSizePixel() );
2008 if ( bCompletely )
2009 // test if the field is completely visible
2010 return aOutRect.Contains( aRect );
2011 else
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() )
2024 return aRect;
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
2045 return aRect;
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
2051 return aRect;
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();
2068 size_t nCol;
2069 for ( nCol = 0;
2070 nCol < mvCols.size() && mvCols[ nCol ]->GetId() != nColumnId;
2071 ++nCol )
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() )
2105 return -1;
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();
2129 if ( nColX > nX )
2130 return nCol;
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;
2142 UpdateScrollbars();
2143 return true;
2145 return false;
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 )
2176 aHScroll->Hide();
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 );
2218 else
2220 pDataWin->pHeaderBar.disposeAndClear();
2223 if ( bColumnCursor )
2225 if (!pColSel)
2226 pColSel.reset(new MultiSelection);
2227 pColSel->SetTotalRange( Range( 0, mvCols.size()-1 ) );
2229 else
2231 pColSel.reset();
2234 if ( bMultiSelection )
2236 if ( pOldRowSel )
2237 uRow.pSel = pOldRowSel;
2238 else
2239 uRow.pSel = new MultiSelection;
2241 else
2243 uRow.nSel = nOldRowSel;
2244 delete pOldRowSel;
2247 if ( bBootstrapped )
2249 StateChanged( StateChangedType::InitShow );
2250 if ( bMultiSelection && !pOldRowSel &&
2251 nOldRowSel != BROWSER_ENDOFSELECTION )
2252 uRow.pSel->Select( nOldRowSel );
2255 if ( pDataWin )
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
2283 /* [Description]
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.
2296 return 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 ) );
2310 return pNewBar;
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;
2326 if ( pHeaderBar )
2327 nHeight = pHeaderBar->GetTextHeight();
2328 else
2329 nHeight = GetTextHeight();
2331 return nTitleLines ? nTitleLines * nHeight + 4 : 0;
2334 tools::Long BrowseBox::CalcReverseZoom(tools::Long nVal) const
2336 if (IsZoom())
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);
2347 return nVal;
2350 void BrowseBox::CursorMoved()
2352 // before implementing more here, please adjust the EditBrowseBox
2354 if ( isAccessibleAlive() && HasFocus() )
2355 commitTableEvent(
2356 AccessibleEventId::ACTIVE_DESCENDANT_CHANGED,
2357 Any( CreateAccessibleCell( GetCurRow(),GetColumnPos( GetCurColumnId() ) ) ),
2358 Any()
2362 void BrowseBox::LoseFocus()
2364 SAL_INFO("svtools", "BrowseBox::LoseFocus " << this );
2366 if ( bHasFocus )
2368 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
2369 DoHideCursor();
2371 if ( !bKeepHighlight )
2373 ToggleSelection();
2374 bSelectionIsVisible = false;
2377 bHasFocus = false;
2379 Control::LoseFocus();
2383 void BrowseBox::GetFocus()
2385 SAL_INFO("svtools", "BrowseBox::GetFocus " << this );
2387 if ( !bHasFocus )
2389 if ( !bSelectionIsVisible )
2391 bSelectionIsVisible = true;
2392 if ( bBootstrapped )
2393 ToggleSelection();
2396 bHasFocus = true;
2397 DoShowCursor();
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
2410 return *pDataWin;
2413 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */