1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svtools/brwbox.hxx>
21 #include <svtools/brwhead.hxx>
22 #include <o3tl/numeric.hxx>
24 #include <tools/debug.hxx>
25 #include <tools/stream.hxx>
26 #include <tools/fract.hxx>
30 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
31 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
32 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
33 #include <com/sun/star/accessibility/XAccessible.hpp>
34 #include <tools/multisel.hxx>
35 #include "brwimpl.hxx"
38 #define SCROLL_FLAGS (SCROLL_CLIP | SCROLL_NOCHILDREN)
39 #define getDataWindow() (static_cast<BrowserDataWin*>(pDataWin.get()))
41 using namespace com::sun::star::accessibility::AccessibleEventId
;
42 using namespace com::sun::star::accessibility::AccessibleTableModelChangeType
;
43 using com::sun::star::accessibility::AccessibleTableModelChange
;
44 using com::sun::star::lang::XComponent
;
45 using namespace ::com::sun::star::uno
;
50 void disposeAndClearHeaderCell(::svt::BrowseBoxImpl::THeaderCellMap
& _rHeaderCell
)
55 ::svt::BrowseBoxImpl::THeaderCellMapFunctorDispose()
61 void BrowseBox::ConstructImpl( BrowserMode nMode
)
63 OSL_TRACE( "BrowseBox: %p->ConstructImpl", this );
64 bMultiSelection
= false;
69 pDataWin
= VclPtr
<BrowserDataWin
>::Create( this ).get();
70 pCols
= new BrowserColumns
;
71 m_pImpl
.reset( new ::svt::BrowseBoxImpl() );
73 aGridLineColor
= Color( COL_LIGHTGRAY
);
74 InitSettings_Impl( this );
75 InitSettings_Impl( pDataWin
);
77 bBootstrapped
= false;
82 nCurRow
= BROWSER_ENDOFSELECTION
;
88 bSelectionIsVisible
= false;
89 bNotToggleSel
= false;
90 bRowDividerDrag
= false;
92 mbInteractiveRowHeight
= false;
94 bHideCursor
= TRISTATE_FALSE
;
96 m_bFocusOnlyCursor
= true;
97 m_aCursorColor
= COL_TRANSPARENT
;
98 m_nCurrentMode
= BrowserMode::NONE
;
99 nControlAreaWidth
= USHRT_MAX
;
100 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
102 aHScroll
->SetLineSize(1);
103 aHScroll
->SetScrollHdl( LINK( this, BrowseBox
, ScrollHdl
) );
104 aHScroll
->SetEndScrollHdl( LINK( this, BrowseBox
, EndScrollHdl
) );
108 bSelectionIsVisible
= bKeepHighlight
;
109 bHasFocus
= HasChildPathFocus();
110 getDataWindow()->nCursorHidden
=
111 ( bHasFocus
? 0 : 1 ) + ( GetUpdateMode() ? 0 : 1 );
116 BrowseBox::BrowseBox( vcl::Window
* pParent
, WinBits nBits
, BrowserMode nMode
)
117 :Control( pParent
, nBits
| WB_3DLOOK
)
118 ,DragSourceHelper( this )
119 ,DropTargetHelper( this )
120 ,aHScroll( VclPtr
<ScrollBar
>::Create(this, WinBits( WB_HSCROLL
)) )
122 ConstructImpl( nMode
);
127 BrowseBox::BrowseBox( vcl::Window
* pParent
, const ResId
& rId
, BrowserMode nMode
)
128 :Control( pParent
, rId
)
129 ,DragSourceHelper( this )
130 ,DropTargetHelper( this )
131 ,aHScroll( VclPtr
<ScrollBar
>::Create(this, WinBits(WB_HSCROLL
)) )
133 ConstructImpl(nMode
);
137 BrowseBox::~BrowseBox()
142 void BrowseBox::dispose()
144 OSL_TRACE( "BrowseBox: %p~", this );
146 if ( m_pImpl
->m_pAccessible
)
148 disposeAndClearHeaderCell(m_pImpl
->m_aColHeaderCellMap
);
149 disposeAndClearHeaderCell(m_pImpl
->m_aRowHeaderCellMap
);
150 m_pImpl
->m_pAccessible
->dispose();
154 getDataWindow()->pHeaderBar
.disposeAndClear();
155 getDataWindow()->pCornerWin
.disposeAndClear();
156 pDataWin
.disposeAndClear();
157 pVScroll
.disposeAndClear();
158 aHScroll
.disposeAndClear();
160 // free columns-space
161 for ( size_t i
= 0, n
= pCols
->size(); i
< n
; ++i
)
162 delete (*pCols
)[ i
];
166 if ( bMultiSelection
)
173 short BrowseBox::GetCursorHideCount() const
175 return getDataWindow()->nCursorHidden
;
180 void BrowseBox::DoShowCursor( const char * )
182 if (!getDataWindow())
184 short nHiddenCount
= --getDataWindow()->nCursorHidden
;
185 if (PaintCursorIfHiddenOnce())
187 if (1 == nHiddenCount
)
192 if (0 == nHiddenCount
)
199 void BrowseBox::DoHideCursor( const char * )
201 short nHiddenCount
= ++getDataWindow()->nCursorHidden
;
202 if (PaintCursorIfHiddenOnce())
204 if (2 == nHiddenCount
)
209 if (1 == nHiddenCount
)
216 void BrowseBox::SetRealRowCount( const OUString
&rRealRowCount
)
218 getDataWindow()->aRealRowCount
= rRealRowCount
;
223 void BrowseBox::SetFont( const vcl::Font
& rNewFont
)
225 pDataWin
->SetFont( rNewFont
);
226 ImpGetDataRowHeight();
231 sal_uLong
BrowseBox::GetDefaultColumnWidth( const OUString
& _rText
) const
233 return GetDataWindow().GetTextWidth( _rText
) + GetDataWindow().GetTextWidth(OUString('0')) * 4;
238 void BrowseBox::InsertHandleColumn( sal_uLong nWidth
)
241 #if OSL_DEBUG_LEVEL > 0
242 OSL_ENSURE( ColCount() == 0 || (*pCols
)[0]->GetId() != HandleColumnId
, "BrowseBox::InsertHandleColumn: there is already a handle column" );
244 BrowserColumns::iterator iCol
= pCols
->begin();
245 const BrowserColumns::iterator colsEnd
= pCols
->end();
246 if ( iCol
!= colsEnd
)
247 for (++iCol
; iCol
!= colsEnd
; ++iCol
)
248 OSL_ENSURE( (*iCol
)->GetId() != HandleColumnId
, "BrowseBox::InsertHandleColumn: there is a non-Handle column with handle ID" );
252 pCols
->insert( pCols
->begin(), new BrowserColumn( 0, Image(), OUString(), nWidth
, GetZoom() ) );
256 if ( getDataWindow()->pHeaderBar
)
258 getDataWindow()->pHeaderBar
->SetPosSizePixel(
260 Size( GetOutputSizePixel().Width() - nWidth
, GetTitleHeight() )
269 void BrowseBox::InsertDataColumn( sal_uInt16 nItemId
, const OUString
& rText
,
270 long nWidth
, HeaderBarItemBits nBits
, sal_uInt16 nPos
)
273 OSL_ENSURE( nItemId
!= HandleColumnId
, "BrowseBox::InsertDataColumn: nItemId is HandleColumnId" );
274 OSL_ENSURE( nItemId
!= BROWSER_INVALIDID
, "BrowseBox::InsertDataColumn: nItemId is reserved value BROWSER_INVALIDID" );
276 #if OSL_DEBUG_LEVEL > 0
278 const BrowserColumns::iterator colsEnd
= pCols
->end();
279 for (BrowserColumns::iterator iCol
= pCols
->begin(); iCol
!= colsEnd
; ++iCol
)
280 OSL_ENSURE( (*iCol
)->GetId() != nItemId
, "BrowseBox::InsertDataColumn: duplicate column Id" );
284 if ( nPos
< pCols
->size() )
286 BrowserColumns::iterator it
= pCols
->begin();
287 ::std::advance( it
, nPos
);
288 pCols
->insert( it
, new BrowserColumn( nItemId
, Image(), rText
, nWidth
, GetZoom() ) );
292 pCols
->push_back( new BrowserColumn( nItemId
, Image(), rText
, nWidth
, GetZoom() ) );
294 if ( nCurColId
== 0 )
297 if ( getDataWindow()->pHeaderBar
)
299 // Handle column not in the header bar
300 sal_uInt16 nHeaderPos
= nPos
;
301 if (nHeaderPos
!= HEADERBAR_APPEND
&& GetColumnId(0) == HandleColumnId
)
303 getDataWindow()->pHeaderBar
->InsertItem(
304 nItemId
, rText
, nWidth
, nBits
, nHeaderPos
);
306 ColumnInserted( nPos
);
309 sal_uInt16
BrowseBox::ToggleSelectedColumn()
311 sal_uInt16 nSelectedColId
= BROWSER_INVALIDID
;
312 if ( pColSel
&& pColSel
->GetSelectCount() )
314 DoHideCursor( "ToggleSelectedColumn" );
316 long nSelected
= pColSel
->FirstSelected();
317 if (nSelected
!= static_cast<long>(SFX_ENDOFSELECTION
))
318 nSelectedColId
= (*pCols
)[nSelected
]->GetId();
319 pColSel
->SelectAll(false);
321 return nSelectedColId
;
324 void BrowseBox::SetToggledSelectedColumn(sal_uInt16 _nSelectedColumnId
)
326 if ( pColSel
&& _nSelectedColumnId
!= BROWSER_INVALIDID
)
328 pColSel
->Select( GetColumnPos( _nSelectedColumnId
) );
330 OSL_TRACE( "BrowseBox: %p->SetToggledSelectedColumn", this );
331 DoShowCursor( "SetToggledSelectedColumn" );
335 void BrowseBox::FreezeColumn( sal_uInt16 nItemId
, bool bFreeze
)
338 // never unfreeze the handle-column
339 if ( nItemId
== HandleColumnId
&& !bFreeze
)
342 // get the position in the current array
343 size_t nItemPos
= GetColumnPos( nItemId
);
344 if ( nItemPos
>= pCols
->size() )
348 // doesn't the state change?
349 if ( (*pCols
)[ nItemPos
]->IsFrozen() == bFreeze
)
352 // remark the column selection
353 sal_uInt16 nSelectedColId
= ToggleSelectedColumn();
355 // freeze or unfreeze?
359 if ( nItemPos
!= 0 && !(*pCols
)[ nItemPos
-1 ]->IsFrozen() )
361 // move to the right of the last frozen column
362 sal_uInt16 nFirstScrollable
= FrozenColCount();
363 BrowserColumn
*pColumn
= (*pCols
)[ nItemPos
];
364 BrowserColumns::iterator it
= pCols
->begin();
365 ::std::advance( it
, nItemPos
);
367 nItemPos
= nFirstScrollable
;
369 ::std::advance( it
, nItemPos
);
370 pCols
->insert( it
, pColumn
);
373 // adjust the number of the first scrollable and visible column
374 if ( nFirstCol
<= nItemPos
)
375 nFirstCol
= nItemPos
+ 1;
380 if ( (sal_Int32
)nItemPos
!= FrozenColCount()-1 )
382 // move to the leftmost scrollable column
383 sal_uInt16 nFirstScrollable
= FrozenColCount();
384 BrowserColumn
*pColumn
= (*pCols
)[ nItemPos
];
385 BrowserColumns::iterator it
= pCols
->begin();
386 ::std::advance( it
, nItemPos
);
388 nItemPos
= nFirstScrollable
;
390 ::std::advance( it
, nItemPos
);
391 pCols
->insert( it
, pColumn
);
394 // adjust the number of the first scrollable and visible column
395 nFirstCol
= nItemPos
;
398 // toggle the freeze-state of the column
399 (*pCols
)[ nItemPos
]->Freeze( bFreeze
);
401 // align the scrollbar-range
405 Control::Invalidate();
406 getDataWindow()->Invalidate();
408 // remember the column selection
409 SetToggledSelectedColumn(nSelectedColId
);
414 void BrowseBox::SetColumnPos( sal_uInt16 nColumnId
, sal_uInt16 nPos
)
416 // never set pos of the handle column
417 if ( nColumnId
== HandleColumnId
)
420 // get the position in the current array
421 sal_uInt16 nOldPos
= GetColumnPos( nColumnId
);
422 if ( nOldPos
>= pCols
->size() )
426 // does the state change?
429 // remark the column selection
430 sal_uInt16 nSelectedColId
= ToggleSelectedColumn();
432 // determine old column area
433 Size
aDataWinSize( pDataWin
->GetSizePixel() );
434 if ( getDataWindow()->pHeaderBar
)
435 aDataWinSize
.Height() += getDataWindow()->pHeaderBar
->GetSizePixel().Height();
437 Rectangle
aFromRect( GetFieldRect( nColumnId
) );
438 aFromRect
.Right() += 2*MIN_COLUMNWIDTH
;
440 sal_uInt16 nNextPos
= nOldPos
+ 1;
441 if ( nOldPos
> nPos
)
442 nNextPos
= nOldPos
- 1;
444 BrowserColumn
*pNextCol
= (*pCols
)[ nNextPos
];
445 Rectangle
aNextRect(GetFieldRect( pNextCol
->GetId() ));
447 // move column internally
449 BrowserColumns::iterator it
= pCols
->begin();
450 ::std::advance( it
, nOldPos
);
451 BrowserColumn
* pTemp
= *it
;
454 ::std::advance( it
, nPos
);
455 pCols
->insert( it
, pTemp
);
458 // determine new column area
459 Rectangle
aToRect( GetFieldRect( nColumnId
) );
460 aToRect
.Right() += 2*MIN_COLUMNWIDTH
;
462 // do scroll, let redraw
463 if( pDataWin
->GetBackground().IsScrollable() )
465 long nScroll
= -aFromRect
.GetWidth();
466 Rectangle aScrollArea
;
467 if ( nOldPos
> nPos
)
469 long nFrozenWidth
= GetFrozenWidth();
470 if ( aToRect
.Left() < nFrozenWidth
)
471 aToRect
.Left() = nFrozenWidth
;
472 aScrollArea
= Rectangle(Point(aToRect
.Left(),0),
473 Point(aNextRect
.Right(),aDataWinSize
.Height()));
474 nScroll
*= -1; // reverse direction
477 aScrollArea
= Rectangle(Point(aNextRect
.Left(),0),
478 Point(aToRect
.Right(),aDataWinSize
.Height()));
480 pDataWin
->Scroll( nScroll
, 0, aScrollArea
);
482 aToRect
.Bottom() = aScrollArea
.Bottom();
483 Invalidate( aToRect
);
486 pDataWin
->Window::Invalidate( INVALIDATE_NOCHILDREN
);
488 // adjust header bar positions
489 if ( getDataWindow()->pHeaderBar
)
491 sal_uInt16 nNewPos
= nPos
;
492 if ( GetColumnId(0) == HandleColumnId
)
494 getDataWindow()->pHeaderBar
->MoveItem(nColumnId
,nNewPos
);
496 // remember the column selection
497 SetToggledSelectedColumn(nSelectedColId
);
499 if ( isAccessibleAlive() )
503 makeAny( AccessibleTableModelChange(
516 makeAny( AccessibleTableModelChange(
533 void BrowseBox::SetColumnTitle( sal_uInt16 nItemId
, const OUString
& rTitle
)
536 // never set title of the handle-column
537 if ( nItemId
== HandleColumnId
)
540 // get the position in the current array
541 sal_uInt16 nItemPos
= GetColumnPos( nItemId
);
542 if ( nItemPos
>= pCols
->size() )
546 // does the state change?
547 BrowserColumn
*pCol
= (*pCols
)[ nItemPos
];
548 if ( pCol
->Title() != rTitle
)
550 OUString
sNew(rTitle
);
551 OUString
sOld(pCol
->Title());
553 pCol
->Title() = rTitle
;
555 // adjust headerbar column
556 if ( getDataWindow()->pHeaderBar
)
557 getDataWindow()->pHeaderBar
->SetItemText( nItemId
, rTitle
);
560 // redraw visible columns
561 if ( GetUpdateMode() && ( pCol
->IsFrozen() || nItemPos
> nFirstCol
) )
562 Invalidate( Rectangle( Point(0,0),
563 Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
566 if ( isAccessibleAlive() )
568 commitTableEvent( TABLE_COLUMN_DESCRIPTION_CHANGED
,
578 void BrowseBox::SetColumnWidth( sal_uInt16 nItemId
, sal_uLong nWidth
)
581 // get the position in the current array
582 size_t nItemPos
= GetColumnPos( nItemId
);
583 if ( nItemPos
>= pCols
->size() )
586 // does the state change?
587 nWidth
= QueryColumnResize( nItemId
, nWidth
);
588 if ( nWidth
>= LONG_MAX
|| (*pCols
)[ nItemPos
]->Width() != nWidth
)
590 long nOldWidth
= (*pCols
)[ nItemPos
]->Width();
592 // adjust last column, if necessary
593 if ( IsVisible() && nItemPos
== pCols
->size() - 1 )
595 long nMaxWidth
= pDataWin
->GetSizePixel().Width();
596 nMaxWidth
-= getDataWindow()->bAutoSizeLastCol
597 ? GetFieldRect(nItemId
).Left()
599 if ( static_cast<BrowserDataWin
*>( pDataWin
.get() )->bAutoSizeLastCol
|| nWidth
> (sal_uLong
)nMaxWidth
)
601 nWidth
= nMaxWidth
> 16 ? nMaxWidth
: nOldWidth
;
602 nWidth
= QueryColumnResize( nItemId
, nWidth
);
607 // In AutoSizeLastColumn(), we call SetColumnWidth with nWidth==0xffff.
608 // Thus, check here, if the width has actually changed.
609 if( (sal_uLong
)nOldWidth
== nWidth
)
612 // do we want to display the change immediately?
613 bool bUpdate
= GetUpdateMode() &&
614 ( (*pCols
)[ nItemPos
]->IsFrozen() || nItemPos
>= nFirstCol
);
619 DoHideCursor( "SetColumnWidth" );
621 //!getDataWindow()->Update();
622 //!Control::Update();
626 (*pCols
)[ nItemPos
]->SetWidth(nWidth
, GetZoom());
628 // scroll and invalidate
631 // get X-Pos of the column changed
633 for ( sal_uInt16 nCol
= 0; nCol
< nItemPos
; ++nCol
)
635 BrowserColumn
*pCol
= (*pCols
)[ nCol
];
636 if ( pCol
->IsFrozen() || nCol
>= nFirstCol
)
640 // actually scroll+invalidate
641 pDataWin
->SetClipRegion();
642 bool bSelVis
= bSelectionIsVisible
;
643 bSelectionIsVisible
= false;
644 if( GetBackground().IsScrollable() )
647 Rectangle
aScrRect( nX
+ std::min( (sal_uLong
)nOldWidth
, nWidth
), 0,
648 GetSizePixel().Width() , // the header is longer than the datawin
649 pDataWin
->GetPosPixel().Y() - 1 );
650 Control::Scroll( nWidth
-nOldWidth
, 0, aScrRect
, SCROLL_FLAGS
);
651 aScrRect
.Bottom() = pDataWin
->GetSizePixel().Height();
652 getDataWindow()->Scroll( nWidth
-nOldWidth
, 0, aScrRect
, SCROLL_FLAGS
);
653 Rectangle
aInvRect( nX
, 0, nX
+ std::max( nWidth
, (sal_uLong
)nOldWidth
), USHRT_MAX
);
654 Control::Invalidate( aInvRect
, INVALIDATE_NOCHILDREN
);
655 static_cast<BrowserDataWin
*>( pDataWin
.get() )->Invalidate( aInvRect
);
659 Control::Invalidate( INVALIDATE_NOCHILDREN
);
660 getDataWindow()->Window::Invalidate( INVALIDATE_NOCHILDREN
);
664 //!getDataWindow()->Update();
665 //!Control::Update();
666 bSelectionIsVisible
= bSelVis
;
668 DoShowCursor( "SetColumnWidth" );
672 // adjust headerbar column
673 if ( getDataWindow()->pHeaderBar
)
674 getDataWindow()->pHeaderBar
->SetItemSize(
675 nItemId
? nItemId
: USHRT_MAX
- 1, nWidth
);
677 // adjust last column
678 if ( nItemPos
!= pCols
->size() - 1 )
679 AutoSizeLastColumn();
686 void BrowseBox::AutoSizeLastColumn()
688 if ( getDataWindow()->bAutoSizeLastCol
&&
689 getDataWindow()->GetUpdateMode() )
691 sal_uInt16 nId
= GetColumnId( (sal_uInt16
)pCols
->size() - 1 );
692 SetColumnWidth( nId
, LONG_MAX
);
693 ColumnResized( nId
);
699 void BrowseBox::RemoveColumn( sal_uInt16 nItemId
)
702 // get column position
703 sal_uInt16 nPos
= GetColumnPos(nItemId
);
704 if ( nPos
>= ColCount() )
708 // correct column selection
710 pColSel
->Remove( nPos
);
712 // correct column cursor
713 if ( nCurColId
== nItemId
)
717 BrowserColumns::iterator it
= pCols
->begin();
718 ::std::advance( it
, nPos
);
721 if ( nFirstCol
>= nPos
&& nFirstCol
> FrozenColCount() )
723 OSL_ENSURE(nFirstCol
> 0,"FirstCol must be greater zero!");
727 // handlecolumn not in headerbar
730 if ( getDataWindow()->pHeaderBar
)
731 getDataWindow()->pHeaderBar
->RemoveItem( nItemId
);
736 if ( getDataWindow()->pHeaderBar
)
738 getDataWindow()->pHeaderBar
->SetPosSizePixel(
740 Size( GetOutputSizePixel().Width(), GetTitleHeight() )
745 // correct vertical scrollbar
748 // trigger repaint, if necessary
749 if ( GetUpdateMode() )
751 getDataWindow()->Invalidate();
752 Control::Invalidate();
753 if ( getDataWindow()->bAutoSizeLastCol
&& nPos
==ColCount() )
754 SetColumnWidth( GetColumnId( nPos
- 1 ), LONG_MAX
);
757 if ( isAccessibleAlive() )
761 makeAny( AccessibleTableModelChange( DELETE
,
771 commitHeaderBarEvent(
774 makeAny( CreateAccessibleColumnHeader( nPos
) ),
782 void BrowseBox::RemoveColumns()
784 size_t nOldCount
= pCols
->size();
786 // remove all columns
787 for ( size_t i
= 0; i
< nOldCount
; ++i
)
788 delete (*pCols
)[ i
];
791 // correct column selection
794 pColSel
->SelectAll(false);
795 pColSel
->SetTotalRange( Range( 0, 0 ) );
798 // correct column cursor
802 if ( getDataWindow()->pHeaderBar
)
803 getDataWindow()->pHeaderBar
->Clear( );
805 // correct vertical scrollbar
808 // trigger repaint if necessary
809 if ( GetUpdateMode() )
811 getDataWindow()->Invalidate();
812 Control::Invalidate();
815 if ( isAccessibleAlive() )
817 if ( pCols
->size() != nOldCount
)
819 // all columns should be removed, so we remove the column header bar and append it again
820 // to avoid to notify every column remove
821 commitBrowseBoxEvent(
824 makeAny(m_pImpl
->getAccessibleHeaderBar(BBTYPE_COLUMNHEADERBAR
))
827 // and now append it again
828 commitBrowseBoxEvent(
830 makeAny(m_pImpl
->getAccessibleHeaderBar(BBTYPE_COLUMNHEADERBAR
)),
834 // notify a table model change
837 makeAny ( AccessibleTableModelChange( DELETE
,
852 OUString
BrowseBox::GetColumnTitle( sal_uInt16 nId
) const
855 sal_uInt16 nItemPos
= GetColumnPos( nId
);
856 if ( nItemPos
>= pCols
->size() )
858 return (*pCols
)[ nItemPos
]->Title();
863 long BrowseBox::GetRowCount() const
870 sal_uInt16
BrowseBox::ColCount() const
873 return (sal_uInt16
) pCols
->size();
878 long BrowseBox::ImpGetDataRowHeight() const
881 BrowseBox
*pThis
= const_cast<BrowseBox
*>(this);
882 pThis
->nDataRowHeight
= pThis
->CalcReverseZoom(pDataWin
->GetTextHeight() + 2);
884 getDataWindow()->Invalidate();
885 return nDataRowHeight
;
890 void BrowseBox::SetDataRowHeight( long nPixel
)
893 nDataRowHeight
= CalcReverseZoom(nPixel
);
895 getDataWindow()->Invalidate();
900 void BrowseBox::SetTitleLines( sal_uInt16 nLines
)
903 nTitleLines
= nLines
;
908 long BrowseBox::ScrollColumns( long nCols
)
911 if ( nFirstCol
+ nCols
< 0 ||
912 nFirstCol
+ nCols
>= (long)pCols
->size() )
915 // implicitly hides cursor while scrolling
918 bool bScrollable
= pDataWin
->GetBackground().IsScrollable();
919 bool bInvalidateView
= false;
921 // scrolling one column to the right?
924 // update internal value and scrollbar
926 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
930 bInvalidateView
= true;
934 long nDelta
= (*pCols
)[ nFirstCol
-1 ]->Width();
935 long nFrozenWidth
= GetFrozenWidth();
937 Rectangle
aScrollRect( Point( nFrozenWidth
+ nDelta
, 0 ),
938 Size ( GetOutputSizePixel().Width() - nFrozenWidth
- nDelta
,
942 // scroll the header bar area (if there is no dedicated HeaderBar control)
943 if ( !getDataWindow()->pHeaderBar
&& nTitleLines
)
946 Scroll( -nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
948 // invalidate the area of the column which was scrolled out to the left hand side
949 Rectangle
aInvalidateRect( aScrollRect
);
950 aInvalidateRect
.Left() = nFrozenWidth
;
951 aInvalidateRect
.Right() = nFrozenWidth
+ nDelta
- 1;
952 Invalidate( aInvalidateRect
);
955 // scroll the data-area
956 aScrollRect
.Bottom() = pDataWin
->GetOutputSizePixel().Height();
959 pDataWin
->Scroll( -nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
961 // invalidate the area of the column which was scrolled out to the left hand side
962 aScrollRect
.Left() = nFrozenWidth
;
963 aScrollRect
.Right() = nFrozenWidth
+ nDelta
- 1;
964 getDataWindow()->Invalidate( aScrollRect
);
968 // scrolling one column to the left?
969 else if ( nCols
== -1 )
972 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
976 bInvalidateView
= true;
980 long nDelta
= (*pCols
)[ nFirstCol
]->Width();
981 long nFrozenWidth
= GetFrozenWidth();
983 Rectangle
aScrollRect( Point( nFrozenWidth
, 0 ),
984 Size ( GetOutputSizePixel().Width() - nFrozenWidth
,
988 // scroll the header bar area (if there is no dedicated HeaderBar control)
989 if ( !getDataWindow()->pHeaderBar
&& nTitleLines
)
991 Scroll( nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
994 // scroll the data-area
995 aScrollRect
.Bottom() = pDataWin
->GetOutputSizePixel().Height();
996 pDataWin
->Scroll( nDelta
, 0, aScrollRect
, SCROLL_FLAGS
);
1001 if ( GetUpdateMode() )
1003 Invalidate( Rectangle(
1004 Point( GetFrozenWidth(), 0 ),
1005 Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
1006 getDataWindow()->Invalidate( Rectangle(
1007 Point( GetFrozenWidth(), 0 ),
1008 pDataWin
->GetSizePixel() ) );
1011 nFirstCol
= nFirstCol
+ (sal_uInt16
)nCols
;
1012 aHScroll
->SetThumbPos( nFirstCol
- FrozenColCount() );
1015 // adjust external headerbar, if necessary
1016 if ( getDataWindow()->pHeaderBar
)
1019 for ( size_t nCol
= 0;
1020 nCol
< pCols
->size() && nCol
< nFirstCol
;
1023 // not the handle column
1024 if ( (*pCols
)[ nCol
]->GetId() )
1025 nWidth
+= (*pCols
)[ nCol
]->Width();
1028 getDataWindow()->pHeaderBar
->SetOffset( nWidth
);
1031 if( bInvalidateView
)
1033 Control::Invalidate( INVALIDATE_NOCHILDREN
);
1034 pDataWin
->Window::Invalidate( INVALIDATE_NOCHILDREN
);
1037 // implicitly show cursor after scrolling
1040 getDataWindow()->Update();
1051 long BrowseBox::ScrollRows( long nRows
)
1055 if ( getDataWindow()->bNoScrollBack
&& nRows
< 0 )
1058 // compute new top row
1059 long nTmpMin
= std::min( (long)(nTopRow
+ nRows
), (long)(nRowCount
- 1) );
1061 long nNewTopRow
= std::max( (long)nTmpMin
, (long)0 );
1063 if ( nNewTopRow
== nTopRow
)
1066 sal_uInt16 nVisibleRows
=
1067 (sal_uInt16
)(pDataWin
->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1069 VisibleRowsChanged(nNewTopRow
, nVisibleRows
);
1071 // compute new top row again (nTopRow might have changed!)
1072 nTmpMin
= std::min( (long)(nTopRow
+ nRows
), (long)(nRowCount
- 1) );
1074 nNewTopRow
= std::max( (long)nTmpMin
, (long)0 );
1078 // scroll area on screen and/or repaint
1079 long nDeltaY
= GetDataRowHeight() * ( nNewTopRow
- nTopRow
);
1080 long nOldTopRow
= nTopRow
;
1081 nTopRow
= nNewTopRow
;
1083 if ( GetUpdateMode() )
1085 pVScroll
->SetRange( Range( 0L, nRowCount
) );
1086 pVScroll
->SetThumbPos( nTopRow
);
1088 if( pDataWin
->GetBackground().IsScrollable() &&
1089 std::abs( nDeltaY
) > 0 &&
1090 std::abs( nDeltaY
) < pDataWin
->GetSizePixel().Height() )
1092 pDataWin
->Scroll( 0, (short)-nDeltaY
, SCROLL_FLAGS
);
1095 getDataWindow()->Invalidate();
1097 if ( nTopRow
- nOldTopRow
)
1098 getDataWindow()->Update();
1103 return nTopRow
- nOldTopRow
;
1108 void BrowseBox::RowModified( long nRow
, sal_uInt16 nColId
)
1111 if ( !GetUpdateMode() )
1115 if ( nColId
== BROWSER_INVALIDID
)
1116 // invalidate the whole row
1117 aRect
= Rectangle( Point( 0, (nRow
-nTopRow
) * GetDataRowHeight() ),
1118 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) );
1121 // invalidate the specific field
1122 aRect
= GetFieldRectPixel( nRow
, nColId
, false );
1124 getDataWindow()->Invalidate( aRect
);
1129 void BrowseBox::Clear()
1132 // adjust the total number of rows
1133 DoHideCursor( "Clear" );
1134 long nOldRowCount
= nRowCount
;
1139 *uRow
.pSel
= MultiSelection();
1142 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1143 nCurRow
= BROWSER_ENDOFSELECTION
;
1147 // nFirstCol may not be reset, else the scrolling code will become confused.
1148 // nFirstCol may only be changed when adding or deleting columns
1149 // nFirstCol = 0; -> wrong!
1150 aHScroll
->SetThumbPos( 0 );
1151 pVScroll
->SetThumbPos( 0 );
1156 DoShowCursor( "Clear" );
1159 if ( isAccessibleAlive() )
1161 // all rows should be removed, so we remove the row header bar and append it again
1162 // to avoid to notify every row remove
1163 if ( nOldRowCount
!= nRowCount
)
1165 commitBrowseBoxEvent(
1168 makeAny( m_pImpl
->getAccessibleHeaderBar( BBTYPE_ROWHEADERBAR
) )
1171 // and now append it again
1172 commitBrowseBoxEvent(
1174 makeAny( m_pImpl
->getAccessibleHeaderBar( BBTYPE_ROWHEADERBAR
) ),
1178 // notify a table model change
1180 TABLE_MODEL_CHANGED
,
1181 makeAny( AccessibleTableModelChange( DELETE
,
1193 void BrowseBox::RowInserted( long nRow
, long nNumRows
, bool bDoPaint
, bool bKeepSelection
)
1198 else if (nRow
> nRowCount
) // maximal = nRowCount
1201 if ( nNumRows
<= 0 )
1204 // adjust total row count
1205 bool bLastRow
= nRow
>= nRowCount
;
1206 nRowCount
+= nNumRows
;
1208 DoHideCursor( "RowInserted" );
1210 // must we paint the new rows?
1211 long nOldCurRow
= nCurRow
;
1212 Size aSz
= pDataWin
->GetOutputSizePixel();
1213 if ( bDoPaint
&& nRow
>= nTopRow
&&
1214 nRow
<= nTopRow
+ aSz
.Height() / GetDataRowHeight() )
1216 long nY
= (nRow
-nTopRow
) * GetDataRowHeight();
1219 // scroll down the rows behind the new row
1220 pDataWin
->SetClipRegion();
1221 if( pDataWin
->GetBackground().IsScrollable() )
1223 pDataWin
->Scroll( 0, GetDataRowHeight() * nNumRows
,
1224 Rectangle( Point( 0, nY
),
1225 Size( aSz
.Width(), aSz
.Height() - nY
) ),
1229 pDataWin
->Window::Invalidate( INVALIDATE_NOCHILDREN
);
1232 // scroll would cause a repaint, so we must explicitly invalidate
1233 pDataWin
->Invalidate( Rectangle( Point( 0, nY
),
1234 Size( aSz
.Width(), nNumRows
* GetDataRowHeight() ) ) );
1237 // correct top row if necessary
1238 if ( nRow
< nTopRow
)
1239 nTopRow
+= nNumRows
;
1241 // adjust the selection
1242 if ( bMultiSelection
)
1243 uRow
.pSel
->Insert( nRow
, nNumRows
);
1244 else if ( uRow
.nSel
!= BROWSER_ENDOFSELECTION
&& nRow
<= uRow
.nSel
)
1245 uRow
.nSel
+= nNumRows
;
1247 // adjust the cursor
1248 if ( nCurRow
== BROWSER_ENDOFSELECTION
)
1249 GoToRow( 0, false, bKeepSelection
);
1250 else if ( nRow
<= nCurRow
)
1251 GoToRow( nCurRow
+= nNumRows
, false, bKeepSelection
);
1253 // adjust the vertical scrollbar
1257 AutoSizeLastColumn();
1260 DoShowCursor( "RowInserted" );
1261 // notify accessible that rows were inserted
1262 if ( isAccessibleAlive() )
1265 TABLE_MODEL_CHANGED
,
1266 makeAny( AccessibleTableModelChange(
1277 for (sal_Int32 i
= nRow
+1 ; i
<= nRowCount
; ++i
)
1279 commitHeaderBarEvent(
1281 makeAny( CreateAccessibleRowHeader( i
) ),
1288 if ( nCurRow
!= nOldCurRow
)
1291 DBG_ASSERT(nRowCount
> 0,"BrowseBox: nRowCount <= 0");
1292 DBG_ASSERT(nCurRow
>= 0,"BrowseBox: nCurRow < 0");
1293 DBG_ASSERT(nCurRow
< nRowCount
,"nCurRow >= nRowCount");
1298 void BrowseBox::RowRemoved( long nRow
, long nNumRows
, bool bDoPaint
)
1303 else if ( nRow
>= nRowCount
)
1304 nRow
= nRowCount
- 1;
1306 if ( nNumRows
<= 0 )
1309 if ( nRowCount
<= 0 )
1314 // hide cursor and selection
1315 OSL_TRACE( "BrowseBox: %p->HideCursor", this );
1317 DoHideCursor( "RowRemoved" );
1320 // adjust total row count
1321 nRowCount
-= nNumRows
;
1322 if (nRowCount
< 0) nRowCount
= 0;
1323 long nOldCurRow
= nCurRow
;
1325 // adjust the selection
1326 if ( bMultiSelection
)
1327 // uRow.pSel->Remove( nRow, nNumRows );
1328 for ( long i
= 0; i
< nNumRows
; i
++ )
1329 uRow
.pSel
->Remove( nRow
);
1330 else if ( nRow
< uRow
.nSel
&& uRow
.nSel
>= nNumRows
)
1331 uRow
.nSel
-= nNumRows
;
1332 else if ( nRow
<= uRow
.nSel
)
1333 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1335 // adjust the cursor
1336 if ( nRowCount
== 0 ) // don't compare nRowCount with nNumRows as nNumRows already was subtracted from nRowCount
1337 nCurRow
= BROWSER_ENDOFSELECTION
;
1338 else if ( nRow
< nCurRow
)
1340 nCurRow
-= std::min( nCurRow
- nRow
, nNumRows
);
1341 // with the above nCurRow points a) to the first row after the removed block or b) to the same line
1342 // as before, but moved up nNumRows
1343 // case a) needs an additional correction if the last n lines were deleted, as 'the first row after the
1344 // removed block' is an invalid position then
1345 // FS - 09/28/99 - 68429
1346 if (nCurRow
== nRowCount
)
1349 else if( nRow
== nCurRow
&& nCurRow
== nRowCount
)
1350 nCurRow
= nRowCount
-1;
1352 // is the deleted row visible?
1353 Size aSz
= pDataWin
->GetOutputSizePixel();
1354 if ( nRow
>= nTopRow
&&
1355 nRow
<= nTopRow
+ aSz
.Height() / GetDataRowHeight() )
1359 // scroll up the rows behind the deleted row
1360 // if there are Rows behind
1361 if (nRow
< nRowCount
)
1363 long nY
= (nRow
-nTopRow
) * GetDataRowHeight();
1364 pDataWin
->SetClipRegion();
1365 if( pDataWin
->GetBackground().IsScrollable() )
1367 pDataWin
->Scroll( 0, - (short) GetDataRowHeight() * nNumRows
,
1368 Rectangle( Point( 0, nY
), Size( aSz
.Width(),
1369 aSz
.Height() - nY
+ nNumRows
*GetDataRowHeight() ) ),
1373 pDataWin
->Window::Invalidate( INVALIDATE_NOCHILDREN
);
1377 // Repaint the Rect of the deleted row
1379 Point( 0, (nRow
-nTopRow
)*GetDataRowHeight() ),
1380 Size( pDataWin
->GetSizePixel().Width(),
1381 nNumRows
* GetDataRowHeight() ) );
1382 pDataWin
->Invalidate( aRect
);
1386 // is the deleted row above of the visible area?
1387 else if ( nRow
< nTopRow
)
1388 nTopRow
= nTopRow
>= nNumRows
? nTopRow
-nNumRows
: 0;
1392 // reshow cursor and selection
1394 OSL_TRACE( "BrowseBox: %p->ShowCursor", this );
1395 DoShowCursor( "RowRemoved" );
1397 // adjust the vertical scrollbar
1399 AutoSizeLastColumn();
1402 if ( isAccessibleAlive() )
1404 if ( nRowCount
== 0 )
1406 // all columns should be removed, so we remove the column header bar and append it again
1407 // to avoid to notify every column remove
1408 commitBrowseBoxEvent(
1411 makeAny( m_pImpl
->getAccessibleHeaderBar( BBTYPE_ROWHEADERBAR
) )
1414 // and now append it again
1415 commitBrowseBoxEvent(
1417 makeAny(m_pImpl
->getAccessibleHeaderBar(BBTYPE_ROWHEADERBAR
)),
1420 commitBrowseBoxEvent(
1423 makeAny( m_pImpl
->getAccessibleTable() )
1426 // and now append it again
1427 commitBrowseBoxEvent(
1429 makeAny( m_pImpl
->getAccessibleTable() ),
1436 TABLE_MODEL_CHANGED
,
1437 makeAny( AccessibleTableModelChange(
1448 for (sal_Int32 i
= nRow
+1 ; i
<= (nRow
+nNumRows
) ; ++i
)
1450 commitHeaderBarEvent(
1453 makeAny( CreateAccessibleRowHeader( i
) ),
1460 if ( nOldCurRow
!= nCurRow
)
1463 DBG_ASSERT(nRowCount
>= 0,"BrowseBox: nRowCount < 0");
1464 DBG_ASSERT(nCurRow
>= 0 || nRowCount
== 0,"BrowseBox: nCurRow < 0 && nRowCount != 0");
1465 DBG_ASSERT(nCurRow
< nRowCount
,"nCurRow >= nRowCount");
1470 bool BrowseBox::GoToRow( long nRow
)
1472 return GoToRow(nRow
, false, false);
1477 bool BrowseBox::GoToRow( long nRow
, bool bRowColMove
, bool bKeepSelection
)
1480 long nOldCurRow
= nCurRow
;
1483 if ( nRow
== nCurRow
&& ( bMultiSelection
|| uRow
.nSel
== nRow
) )
1487 if ( nRow
< 0 || nRow
>= nRowCount
)
1491 if ( ( !bRowColMove
&& !IsCursorMoveAllowed( nRow
, nCurColId
) ) )
1494 if ( getDataWindow()->bNoScrollBack
&& nRow
< nTopRow
)
1497 // compute the last visible row
1498 Size
aSz( pDataWin
->GetSizePixel() );
1499 sal_uInt16 nVisibleRows
= sal_uInt16( aSz
.Height() / GetDataRowHeight() - 1 );
1500 long nLastRow
= nTopRow
+ nVisibleRows
;
1503 getDataWindow()->EnterUpdateLock();
1505 // remove old highlight, if necessary
1506 if ( !bMultiSelection
&& !bKeepSelection
)
1508 DoHideCursor( "GoToRow" );
1511 bool bWasVisible
= bSelectionIsVisible
;
1512 if (! bMultiSelection
)
1514 if( !bKeepSelection
)
1515 bSelectionIsVisible
= false;
1517 if ( nRow
< nTopRow
)
1518 ScrollRows( nRow
- nTopRow
);
1519 else if ( nRow
> nLastRow
)
1520 ScrollRows( nRow
- nLastRow
);
1521 bSelectionIsVisible
= bWasVisible
;
1523 // adjust cursor (selection) and thumb
1524 if ( GetUpdateMode() )
1525 pVScroll
->SetThumbPos( nTopRow
);
1527 // relative positioning (because nCurRow might have changed in the meantime)!
1528 if (nCurRow
!= BROWSER_ENDOFSELECTION
)
1529 nCurRow
= nCurRow
+ (nRow
- nOldCurRow
);
1531 // make sure that the current position is valid
1532 if (nCurRow
== BROWSER_ENDOFSELECTION
&& nRowCount
> 0)
1534 else if ( nCurRow
>= nRowCount
)
1535 nCurRow
= nRowCount
- 1;
1536 aSelRange
= Range( nCurRow
, nCurRow
);
1538 // display new highlight if necessary
1539 if ( !bMultiSelection
&& !bKeepSelection
)
1543 getDataWindow()->LeaveUpdateLock();
1546 if ( !bMultiSelection
&& !bKeepSelection
)
1548 DoShowCursor( "GoToRow" );
1549 if ( !bRowColMove
&& nOldCurRow
!= nCurRow
)
1552 if ( !bMultiSelection
&& !bKeepSelection
)
1564 bool BrowseBox::GoToColumnId( sal_uInt16 nColId
)
1566 return GoToColumnId(nColId
, true, false);
1570 bool BrowseBox::GoToColumnId( sal_uInt16 nColId
, bool bMakeVisible
, bool bRowColMove
)
1576 if (!bRowColMove
&& !IsCursorMoveAllowed( nCurRow
, nColId
) )
1579 if ( nColId
!= nCurColId
|| (bMakeVisible
&& !IsFieldVisible(nCurRow
, nColId
, true)))
1581 sal_uInt16 nNewPos
= GetColumnPos(nColId
);
1582 BrowserColumn
* pColumn
= (nNewPos
< pCols
->size()) ? (*pCols
)[ nNewPos
] : NULL
;
1583 DBG_ASSERT( pColumn
, "no column object - invalid id?" );
1587 DoHideCursor( "GoToColumnId" );
1590 bool bScrolled
= false;
1592 sal_uInt16 nFirstPos
= nFirstCol
;
1593 sal_uInt16 nWidth
= (sal_uInt16
)pColumn
->Width();
1594 sal_uInt16 nLastPos
= GetColumnAtXPosPixel(
1595 pDataWin
->GetSizePixel().Width()-nWidth
, false );
1596 sal_uInt16 nFrozen
= FrozenColCount();
1597 if ( bMakeVisible
&& nLastPos
&&
1598 nNewPos
>= nFrozen
&& ( nNewPos
< nFirstPos
|| nNewPos
> nLastPos
) )
1600 if ( nNewPos
< nFirstPos
)
1601 ScrollColumns( nNewPos
-nFirstPos
);
1602 else if ( nNewPos
> nLastPos
)
1603 ScrollColumns( nNewPos
-nLastPos
);
1607 DoShowCursor( "GoToColumnId" );
1610 //try to move to nCurRow, nColId
1611 CursorMoveAttempt
aAttempt(nCurRow
, nColId
, bScrolled
);
1612 //Detect if we are already in a call to BrowseBox::GoToColumnId
1613 //but the attempt is impossible and we are simply recursing
1614 //into BrowseBox::GoToColumnId with the same impossible to
1615 //fulfill conditions
1616 if (m_aGotoStack
.empty() || aAttempt
!= m_aGotoStack
.top())
1618 m_aGotoStack
.push(aAttempt
);
1630 bool BrowseBox::GoToRowColumnId( long nRow
, sal_uInt16 nColId
)
1634 if ( nRow
< 0 || nRow
>= nRowCount
)
1641 if ( nRow
== nCurRow
&& ( bMultiSelection
|| uRow
.nSel
== nRow
) &&
1642 nColId
== nCurColId
&& IsFieldVisible(nCurRow
, nColId
, true))
1646 if (!IsCursorMoveAllowed(nRow
, nColId
))
1649 DoHideCursor( "GoToRowColumnId" );
1650 bool bMoved
= GoToRow(nRow
, true) && GoToColumnId(nColId
, true, true);
1651 DoShowCursor( "GoToRowColumnId" );
1661 void BrowseBox::SetNoSelection()
1664 // is there no selection
1665 if ( ( !pColSel
|| !pColSel
->GetSelectCount() ) &&
1666 ( ( !bMultiSelection
&& uRow
.nSel
== BROWSER_ENDOFSELECTION
) ||
1667 ( bMultiSelection
&& !uRow
.pSel
->GetSelectCount() ) ) )
1671 OSL_TRACE( "BrowseBox: %p->HideCursor", this );
1675 if ( bMultiSelection
)
1676 uRow
.pSel
->SelectAll(false);
1678 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1680 pColSel
->SelectAll(false);
1687 OSL_TRACE( "BrowseBox: %p->ShowCursor", this );
1689 if ( isAccessibleAlive() )
1701 void BrowseBox::SelectAll()
1704 if ( !bMultiSelection
)
1707 OSL_TRACE( "BrowseBox: %p->HideCursor", this );
1712 pColSel
->SelectAll(false);
1713 uRow
.pSel
->SelectAll(true);
1715 // don't highlight handle column
1716 BrowserColumn
*pFirstCol
= (*pCols
)[ 0 ];
1717 long nOfsX
= pFirstCol
->GetId() ? 0 : pFirstCol
->Width();
1719 // highlight the row selection
1722 Rectangle aHighlightRect
;
1723 sal_uInt16 nVisibleRows
=
1724 (sal_uInt16
)(pDataWin
->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1725 for ( long nRow
= std::max( nTopRow
, uRow
.pSel
->FirstSelected() );
1726 nRow
!= BROWSER_ENDOFSELECTION
&& nRow
< nTopRow
+ nVisibleRows
;
1727 nRow
= uRow
.pSel
->NextSelected() )
1728 aHighlightRect
.Union( Rectangle(
1729 Point( nOfsX
, (nRow
-nTopRow
)*GetDataRowHeight() ),
1730 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) ) );
1731 pDataWin
->Invalidate( aHighlightRect
);
1740 OSL_TRACE( "BrowseBox: %p->ShowCursor", this );
1742 if ( isAccessibleAlive() )
1749 commitHeaderBarEvent(
1754 ); // column header event
1756 commitHeaderBarEvent(
1761 ); // row header event
1767 void BrowseBox::SelectRow( long nRow
, bool _bSelect
, bool bExpand
)
1770 if ( !bMultiSelection
)
1772 // deselecting is impossible, selecting via cursor
1774 GoToRow(nRow
, false);
1778 OSL_TRACE( "BrowseBox: %p->HideCursor", this );
1780 // remove old selection?
1781 if ( !bExpand
|| !bMultiSelection
)
1784 if ( bMultiSelection
)
1785 uRow
.pSel
->SelectAll(false);
1787 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1789 pColSel
->SelectAll(false);
1792 // set new selection
1794 && ( ( bMultiSelection
1795 && uRow
.pSel
->GetTotalRange().Max() >= nRow
1796 && uRow
.pSel
->Select( nRow
, _bSelect
)
1798 || ( !bMultiSelection
1799 && ( uRow
.nSel
= nRow
) != BROWSER_ENDOFSELECTION
)
1803 // don't highlight handle column
1804 BrowserColumn
*pFirstCol
= (*pCols
)[ 0 ];
1805 long nOfsX
= pFirstCol
->GetId() ? 0 : pFirstCol
->Width();
1807 // highlight only newly selected part
1809 Point( nOfsX
, (nRow
-nTopRow
)*GetDataRowHeight() ),
1810 Size( pDataWin
->GetSizePixel().Width(), GetDataRowHeight() ) );
1811 pDataWin
->Invalidate( aRect
);
1820 OSL_TRACE( "BrowseBox: %p->ShowCursor", this );
1822 if ( isAccessibleAlive() )
1829 commitHeaderBarEvent(
1834 ); // row header event
1840 long BrowseBox::GetSelectRowCount() const
1843 return bMultiSelection
? uRow
.pSel
->GetSelectCount() :
1844 uRow
.nSel
== BROWSER_ENDOFSELECTION
? 0 : 1;
1849 void BrowseBox::SelectColumnPos( sal_uInt16 nNewColPos
, bool _bSelect
, bool bMakeVisible
)
1852 if ( !bColumnCursor
|| nNewColPos
== BROWSER_INVALIDID
)
1855 if ( !bMultiSelection
)
1858 GoToColumnId( (*pCols
)[ nNewColPos
]->GetId(), bMakeVisible
);
1863 if ( !GoToColumnId( (*pCols
)[ nNewColPos
]->GetId(), bMakeVisible
) )
1867 OSL_TRACE( "BrowseBox: %p->HideCursor", this );
1869 if ( bMultiSelection
)
1870 uRow
.pSel
->SelectAll(false);
1872 uRow
.nSel
= BROWSER_ENDOFSELECTION
;
1873 pColSel
->SelectAll(false);
1875 if ( pColSel
->Select( nNewColPos
, _bSelect
) )
1877 // GoToColumnId( pCols->GetObject(nNewColPos)->GetId(), bMakeVisible );
1879 // only highlight painted areas
1881 Rectangle
aFieldRectPix( GetFieldRectPixel( nCurRow
, nCurColId
, false ) );
1883 Point( aFieldRectPix
.Left() - MIN_COLUMNWIDTH
, 0 ),
1884 Size( (*pCols
)[ nNewColPos
]->Width(),
1885 pDataWin
->GetOutputSizePixel().Height() ) );
1886 pDataWin
->Invalidate( aRect
);
1892 if ( isAccessibleAlive() )
1899 commitHeaderBarEvent(
1904 ); // column header event
1909 OSL_TRACE( "BrowseBox: %p->ShowCursor", this );
1914 sal_uInt16
BrowseBox::GetSelectColumnCount() const
1917 // while bAutoSelect (==!pColSel), 1 if any rows (yes rows!) else none
1918 return pColSel
? (sal_uInt16
) pColSel
->GetSelectCount() :
1919 nCurRow
>= 0 ? 1 : 0;
1923 long BrowseBox::FirstSelectedColumn( ) const
1925 return pColSel
? pColSel
->FirstSelected() : BROWSER_ENDOFSELECTION
;
1930 long BrowseBox::FirstSelectedRow( bool bInverse
)
1933 return bMultiSelection
? uRow
.pSel
->FirstSelected(bInverse
) : uRow
.nSel
;
1938 long BrowseBox::NextSelectedRow()
1941 return bMultiSelection
? uRow
.pSel
->NextSelected() : BROWSER_ENDOFSELECTION
;
1946 long BrowseBox::LastSelectedRow()
1949 return bMultiSelection
? uRow
.pSel
->LastSelected() : uRow
.nSel
;
1954 bool BrowseBox::IsRowSelected( long nRow
) const
1957 return bMultiSelection
? uRow
.pSel
->IsSelected(nRow
) : nRow
== uRow
.nSel
;
1962 bool BrowseBox::IsColumnSelected( sal_uInt16 nColumnId
) const
1965 return pColSel
? pColSel
->IsSelected( GetColumnPos(nColumnId
) ) :
1966 nCurColId
== nColumnId
;
1971 bool BrowseBox::MakeFieldVisible
1973 long nRow
, // line number of the field (starting with 0)
1974 sal_uInt16 nColId
, // column ID of the field
1975 bool bComplete
// (== false), true => make visible in its entirety
1980 Makes visible the field described in 'nRow' and 'nColId' by scrolling
1981 accordingly. If 'bComplete' is set, the field should become visible in its
1987 The given field is already visible or was already visible.
1990 The given field could not be made visible or in the case of
1991 'bComplete' could not be made visible in its entirety.
1995 Size aTestSize
= pDataWin
->GetSizePixel();
1997 if ( !bBootstrapped
||
1998 ( aTestSize
.Width() == 0 && aTestSize
.Height() == 0 ) )
2001 // is it visible already?
2002 bool bVisible
= IsFieldVisible( nRow
, nColId
, bComplete
);
2006 // calculate column position, field rectangle and painting area
2007 sal_uInt16 nColPos
= GetColumnPos( nColId
);
2008 Rectangle aFieldRect
= GetFieldRectPixel( nRow
, nColId
, false );
2009 Rectangle aDataRect
= Rectangle( Point(0, 0), pDataWin
->GetSizePixel() );
2011 // positioned outside on the left?
2012 if ( nColPos
>= FrozenColCount() && nColPos
< nFirstCol
)
2013 // => scroll to the right
2014 ScrollColumns( nColPos
- nFirstCol
);
2016 // while outside on the right
2017 while ( aDataRect
.Right() < ( bComplete
2018 ? aFieldRect
.Right()
2019 : aFieldRect
.Left()+aFieldRect
.GetWidth()/2 ) )
2021 // => scroll to the left
2022 if ( ScrollColumns( 1 ) != 1 )
2023 // no more need to scroll
2025 aFieldRect
= GetFieldRectPixel( nRow
, nColId
, false );
2028 // positioned outside above?
2029 if ( nRow
< nTopRow
)
2030 // scroll further to the bottom
2031 ScrollRows( nRow
- nTopRow
);
2033 // positioned outside below?
2034 long nBottomRow
= nTopRow
+ GetVisibleRows();
2035 // decrement nBottomRow to make it the number of the last visible line
2036 // (count starts with 0!).
2037 // Example: BrowseBox contains exactly one entry. nBottomRow := 0 + 1 - 1
2041 if ( nRow
> nBottomRow
)
2042 // scroll further to the top
2043 ScrollRows( nRow
- nBottomRow
);
2045 // it might still not actually fit, e.g. if the window is too small
2046 return IsFieldVisible( nRow
, nColId
, bComplete
);
2051 bool BrowseBox::IsFieldVisible( long nRow
, sal_uInt16 nColumnId
,
2052 bool bCompletely
) const
2055 // hidden by frozen column?
2056 sal_uInt16 nColPos
= GetColumnPos( nColumnId
);
2057 if ( nColPos
>= FrozenColCount() && nColPos
< nFirstCol
)
2060 Rectangle
aRect( ImplFieldRectPixel( nRow
, nColumnId
) );
2061 if ( aRect
.IsEmpty() )
2064 // get the visible area
2065 Rectangle
aOutRect( Point(0, 0), pDataWin
->GetOutputSizePixel() );
2068 // test if the field is completely visible
2069 return aOutRect
.IsInside( aRect
);
2071 // test if the field is partly of completely visible
2072 return !aOutRect
.Intersection( aRect
).IsEmpty();
2077 Rectangle
BrowseBox::GetFieldRectPixel( long nRow
, sal_uInt16 nColumnId
,
2078 bool bRelToBrowser
) const
2081 // get the rectangle relative to DataWin
2082 Rectangle
aRect( ImplFieldRectPixel( nRow
, nColumnId
) );
2083 if ( aRect
.IsEmpty() )
2086 // adjust relative to BrowseBox's output area
2087 Point
aTopLeft( aRect
.TopLeft() );
2088 if ( bRelToBrowser
)
2090 aTopLeft
= pDataWin
->OutputToScreenPixel( aTopLeft
);
2091 aTopLeft
= ScreenToOutputPixel( aTopLeft
);
2094 return Rectangle( aTopLeft
, aRect
.GetSize() );
2099 Rectangle
BrowseBox::GetRowRectPixel( long nRow
, bool bRelToBrowser
) const
2102 // get the rectangle relative to DataWin
2104 if ( nTopRow
> nRow
)
2105 // row is above visible area
2108 Point( 0, GetDataRowHeight() * (nRow
-nTopRow
) ),
2109 Size( pDataWin
->GetOutputSizePixel().Width(), GetDataRowHeight() ) );
2110 if ( aRect
.TopLeft().Y() > pDataWin
->GetOutputSizePixel().Height() )
2111 // row is below visible area
2114 // adjust relative to BrowseBox's output area
2115 Point
aTopLeft( aRect
.TopLeft() );
2116 if ( bRelToBrowser
)
2118 aTopLeft
= pDataWin
->OutputToScreenPixel( aTopLeft
);
2119 aTopLeft
= ScreenToOutputPixel( aTopLeft
);
2122 return Rectangle( aTopLeft
, aRect
.GetSize() );
2127 Rectangle
BrowseBox::ImplFieldRectPixel( long nRow
, sal_uInt16 nColumnId
) const
2130 // compute the X-coordinate relative to DataWin by accumulation
2132 sal_uInt16 nFrozenCols
= FrozenColCount();
2135 nCol
< pCols
->size() && (*pCols
)[ nCol
]->GetId() != nColumnId
;
2137 if ( (*pCols
)[ nCol
]->IsFrozen() || nCol
>= nFirstCol
)
2138 nColX
+= (*pCols
)[ nCol
]->Width();
2140 if ( nCol
>= pCols
->size() || ( nCol
>= nFrozenCols
&& nCol
< nFirstCol
) )
2143 // compute the Y-coordinate relative to DataWin
2144 long nRowY
= GetDataRowHeight();
2145 if ( nRow
!= BROWSER_ENDOFSELECTION
) // #105497# OJ
2146 nRowY
= ( nRow
- nTopRow
) * GetDataRowHeight();
2148 // assemble the Rectangle relative to DataWin
2150 Point( nColX
+ MIN_COLUMNWIDTH
, nRowY
),
2151 Size( (*pCols
)[ nCol
]->Width() - 2*MIN_COLUMNWIDTH
,
2152 GetDataRowHeight() - 1 ) );
2157 long BrowseBox::GetRowAtYPosPixel( long nY
, bool bRelToBrowser
) const
2160 // compute the Y-coordinate
2161 if ( bRelToBrowser
)
2163 Point aDataTopLeft
= pDataWin
->OutputToScreenPixel( Point(0, 0) );
2164 Point aTopLeft
= OutputToScreenPixel( Point(0, 0) );
2165 nY
-= aDataTopLeft
.Y() - aTopLeft
.Y();
2168 // no row there (e.g. in the header)
2169 if ( nY
< 0 || nY
>= pDataWin
->GetOutputSizePixel().Height() )
2172 return nY
/ GetDataRowHeight() + nTopRow
;
2177 Rectangle
BrowseBox::GetFieldRect( sal_uInt16 nColumnId
) const
2180 return GetFieldRectPixel( nCurRow
, nColumnId
);
2185 sal_uInt16
BrowseBox::GetColumnAtXPosPixel( long nX
, bool ) const
2188 // accumulate the widths of the visible columns
2190 for ( size_t nCol
= 0; nCol
< pCols
->size(); ++nCol
)
2192 BrowserColumn
*pCol
= (*pCols
)[ nCol
];
2193 if ( pCol
->IsFrozen() || nCol
>= nFirstCol
)
2194 nColX
+= pCol
->Width();
2200 return BROWSER_INVALIDID
;
2205 void BrowseBox::ReserveControlArea( sal_uInt16 nWidth
)
2208 if ( nWidth
!= nControlAreaWidth
)
2210 OSL_ENSURE(nWidth
,"Control area of 0 is not allowed, Use USHRT_MAX instead!");
2211 nControlAreaWidth
= nWidth
;
2218 Rectangle
BrowseBox::GetControlArea() const
2222 Point( 0, GetOutputSizePixel().Height() - aHScroll
->GetSizePixel().Height() ),
2223 Size( GetOutputSizePixel().Width() - aHScroll
->GetSizePixel().Width(),
2224 aHScroll
->GetSizePixel().Height() ) );
2229 void BrowseBox::SetMode( BrowserMode nMode
)
2232 getDataWindow()->bAutoHScroll
= BrowserMode::AUTO_HSCROLL
== ( nMode
& BrowserMode::AUTO_HSCROLL
);
2233 getDataWindow()->bAutoVScroll
= BrowserMode::AUTO_VSCROLL
== ( nMode
& BrowserMode::AUTO_VSCROLL
);
2234 getDataWindow()->bNoHScroll
= BrowserMode::NO_HSCROLL
== ( nMode
& BrowserMode::NO_HSCROLL
);
2235 getDataWindow()->bNoVScroll
= BrowserMode::NO_VSCROLL
== ( nMode
& BrowserMode::NO_VSCROLL
);
2237 DBG_ASSERT( !( getDataWindow()->bAutoHScroll
&& getDataWindow()->bNoHScroll
),
2238 "BrowseBox::SetMode: AutoHScroll *and* NoHScroll?" );
2239 DBG_ASSERT( !( getDataWindow()->bAutoVScroll
&& getDataWindow()->bNoVScroll
),
2240 "BrowseBox::SetMode: AutoVScroll *and* NoVScroll?" );
2241 if ( getDataWindow()->bAutoHScroll
)
2242 getDataWindow()->bNoHScroll
= false;
2243 if ( getDataWindow()->bAutoVScroll
)
2244 getDataWindow()->bNoVScroll
= false;
2246 if ( getDataWindow()->bNoHScroll
)
2249 nControlAreaWidth
= USHRT_MAX
;
2251 getDataWindow()->bNoScrollBack
=
2252 BrowserMode::NO_SCROLLBACK
== ( nMode
& BrowserMode::NO_SCROLLBACK
);
2254 long nOldRowSel
= bMultiSelection
? uRow
.pSel
->FirstSelected() : uRow
.nSel
;
2255 MultiSelection
*pOldRowSel
= bMultiSelection
? uRow
.pSel
: 0;
2256 MultiSelection
*pOldColSel
= pColSel
;
2258 pVScroll
.disposeAndClear();
2260 bThumbDragging
= ( nMode
& BrowserMode::THUMBDRAGGING
) == BrowserMode::THUMBDRAGGING
;
2261 bMultiSelection
= ( nMode
& BrowserMode::MULTISELECTION
) == BrowserMode::MULTISELECTION
;
2262 bColumnCursor
= ( nMode
& BrowserMode::COLUMNSELECTION
) == BrowserMode::COLUMNSELECTION
;
2263 bKeepHighlight
= ( nMode
& BrowserMode::KEEPHIGHLIGHT
) == BrowserMode::KEEPHIGHLIGHT
;
2265 bHideSelect
= ((nMode
& BrowserMode::HIDESELECT
) == BrowserMode::HIDESELECT
);
2266 // default: do not hide the cursor at all (untaken scrolling and such)
2267 bHideCursor
= TRISTATE_FALSE
;
2269 if ( BrowserMode::SMART_HIDECURSOR
== ( nMode
& BrowserMode::SMART_HIDECURSOR
) )
2270 { // smart cursor hide overrules hard cursor hide
2271 bHideCursor
= TRISTATE_INDET
;
2273 else if ( BrowserMode::HIDECURSOR
== ( nMode
& BrowserMode::HIDECURSOR
) )
2275 bHideCursor
= TRISTATE_TRUE
;
2278 m_bFocusOnlyCursor
= ((nMode
& BrowserMode::CURSOR_WO_FOCUS
) == BrowserMode::NONE
);
2280 bHLines
= ( nMode
& BrowserMode::HLINES
) == BrowserMode::HLINES
;
2281 bVLines
= ( nMode
& BrowserMode::VLINES
) == BrowserMode::VLINES
;
2283 WinBits nVScrollWinBits
=
2284 WB_VSCROLL
| ( ( nMode
& BrowserMode::THUMBDRAGGING
) ? WB_DRAG
: 0 );
2285 pVScroll
= VclPtr
<ScrollBar
>(
2286 ( nMode
& BrowserMode::TRACKING_TIPS
) == BrowserMode::TRACKING_TIPS
2287 ? VclPtr
<BrowserScrollBar
>::Create( this, nVScrollWinBits
,
2288 static_cast<BrowserDataWin
*>( pDataWin
.get() ) )
2289 : VclPtr
<ScrollBar
>::Create( this, nVScrollWinBits
));
2290 pVScroll
->SetLineSize( 1 );
2291 pVScroll
->SetPageSize(1);
2292 pVScroll
->SetScrollHdl( LINK( this, BrowseBox
, ScrollHdl
) );
2293 pVScroll
->SetEndScrollHdl( LINK( this, BrowseBox
, EndScrollHdl
) );
2295 getDataWindow()->bAutoSizeLastCol
=
2296 BrowserMode::AUTOSIZE_LASTCOL
== ( nMode
& BrowserMode::AUTOSIZE_LASTCOL
);
2297 getDataWindow()->bOwnDataChangedHdl
=
2298 BrowserMode::OWN_DATACHANGED
== ( nMode
& BrowserMode::OWN_DATACHANGED
);
2300 // create a headerbar. what happens, if a headerbar has to be created and
2301 // there already are columns?
2302 if ( BrowserMode::HEADERBAR_NEW
== ( nMode
& BrowserMode::HEADERBAR_NEW
) )
2304 if (!getDataWindow()->pHeaderBar
)
2305 getDataWindow()->pHeaderBar
= CreateHeaderBar( this );
2309 getDataWindow()->pHeaderBar
.disposeAndClear();
2312 if ( bColumnCursor
)
2314 pColSel
= pOldColSel
? pOldColSel
: new MultiSelection
;
2315 pColSel
->SetTotalRange( Range( 0, pCols
->size()-1 ) );
2323 if ( bMultiSelection
)
2326 uRow
.pSel
= pOldRowSel
;
2328 uRow
.pSel
= new MultiSelection
;
2332 uRow
.nSel
= nOldRowSel
;
2336 if ( bBootstrapped
)
2338 StateChanged( StateChangedType::InitShow
);
2339 if ( bMultiSelection
&& !pOldRowSel
&&
2340 nOldRowSel
!= BROWSER_ENDOFSELECTION
)
2341 uRow
.pSel
->Select( nOldRowSel
);
2345 pDataWin
->Invalidate();
2347 // no cursor on handle column
2348 if ( nCurColId
== HandleColumnId
)
2349 nCurColId
= GetColumnId( 1 );
2351 m_nCurrentMode
= nMode
;
2356 void BrowseBox::VisibleRowsChanged( long, sal_uInt16
)
2359 // old behavior: automatically correct NumRows:
2360 if ( nRowCount
< GetRowCount() )
2362 RowInserted(nRowCount
,GetRowCount() - nRowCount
, false);
2364 else if ( nRowCount
> GetRowCount() )
2366 RowRemoved(nRowCount
-(nRowCount
- GetRowCount()),nRowCount
- GetRowCount(), false);
2372 bool BrowseBox::IsCursorMoveAllowed( long, sal_uInt16
) const
2376 This virtual method is always called before the cursor is moved directly.
2377 By means of 'return sal_False', we avoid doing this if e.g. a record
2378 contradicts any rules.
2380 This method is not called, if the cursor movement results from removing or
2381 deleting a row/column (thus, in cases where only a "cursor correction" happens).
2383 The base implementation currently always returns true.
2392 long BrowseBox::GetDataRowHeight() const
2394 return CalcZoom(nDataRowHeight
? nDataRowHeight
: ImpGetDataRowHeight());
2399 VclPtr
<BrowserHeader
> BrowseBox::CreateHeaderBar( BrowseBox
* pParent
)
2401 VclPtr
<BrowserHeader
> pNewBar
= VclPtr
<BrowserHeader
>::Create( pParent
);
2402 pNewBar
->SetStartDragHdl( LINK( this, BrowseBox
, StartDragHdl
) );
2406 void BrowseBox::SetHeaderBar( BrowserHeader
* pHeaderBar
)
2408 static_cast<BrowserDataWin
*>( pDataWin
.get() )->pHeaderBar
.disposeAndClear();
2409 static_cast<BrowserDataWin
*>( pDataWin
.get() )->pHeaderBar
= pHeaderBar
;
2410 static_cast<BrowserDataWin
*>( pDataWin
.get() )->pHeaderBar
->SetStartDragHdl( LINK( this, BrowseBox
, StartDragHdl
) );
2413 long BrowseBox::GetTitleHeight() const
2416 // ask the header bar for the text height (if possible), as the header bar's font is adjusted with
2417 // our (and the header's) zoom factor
2418 HeaderBar
* pHeaderBar
= static_cast<BrowserDataWin
*>( pDataWin
.get() )->pHeaderBar
;
2420 nHeight
= pHeaderBar
->GetTextHeight();
2422 nHeight
= GetTextHeight();
2424 return nTitleLines
? nTitleLines
* nHeight
+ 4 : 0;
2427 long BrowseBox::CalcReverseZoom(long nVal
)
2431 const Fraction
& rZoom
= GetZoom();
2432 double n
= (double)nVal
;
2433 n
*= (double)rZoom
.GetDenominator();
2434 if (!rZoom
.GetNumerator())
2435 throw o3tl::divide_by_zero();
2436 n
/= (double)rZoom
.GetNumerator();
2437 nVal
= n
>0 ? (long)(n
+ 0.5) : -(long)(-n
+ 0.5);
2443 void BrowseBox::CursorMoved()
2445 // before implementing more here, please adjust the EditBrowseBox
2447 if ( isAccessibleAlive() && HasFocus() )
2449 ACTIVE_DESCENDANT_CHANGED
,
2450 makeAny( CreateAccessibleCell( GetCurRow(),GetColumnPos( GetCurColumnId() ) ) ),
2455 void BrowseBox::LoseFocus()
2457 OSL_TRACE( "BrowseBox: %p->LoseFocus", this );
2461 OSL_TRACE( "BrowseBox: %p->HideCursor", this );
2462 DoHideCursor( "LoseFocus" );
2464 if ( !bKeepHighlight
)
2467 bSelectionIsVisible
= false;
2472 Control::LoseFocus();
2477 void BrowseBox::GetFocus()
2479 OSL_TRACE( "BrowseBox: %p->GetFocus", this );
2483 if ( !bSelectionIsVisible
)
2485 bSelectionIsVisible
= true;
2486 if ( bBootstrapped
)
2491 DoShowCursor( "GetFocus" );
2493 Control::GetFocus();
2497 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */