1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <svtools/brwbox.hxx>
21 #include <svtools/brwhead.hxx>
22 #include <o3tl/numeric.hxx>
23 #include "datwin.hxx"
24 #include <tools/debug.hxx>
25 #include <tools/fract.hxx>
26 #include <sal/log.hxx>
27
28 #include <algorithm>
29 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
30 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
31 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
32 #include <tools/multisel.hxx>
33 #include "brwimpl.hxx"
34
35
36 #define SCROLL_FLAGS (ScrollFlags::Clip | ScrollFlags::NoChildren)
37
38 using namespace com::sun::star::accessibility::AccessibleEventId;
39 using namespace com::sun::star::accessibility::AccessibleTableModelChangeType;
40 using com::sun::star::accessibility::AccessibleTableModelChange;
41 using namespace ::com::sun::star::uno;
42 using namespace svt;
43
44 namespace
45 {
disposeAndClearHeaderCell(::svt::BrowseBoxImpl::THeaderCellMap & _rHeaderCell)46 void disposeAndClearHeaderCell(::svt::BrowseBoxImpl::THeaderCellMap& _rHeaderCell)
47 {
48 ::std::for_each(
49 _rHeaderCell.begin(),
50 _rHeaderCell.end(),
51 ::svt::BrowseBoxImpl::THeaderCellMapFunctorDispose()
52 );
53 _rHeaderCell.clear();
54 }
55 }
56
ConstructImpl(BrowserMode nMode)57 void BrowseBox::ConstructImpl( BrowserMode nMode )
58 {
59 SAL_INFO("svtools", "BrowseBox:ConstructImpl " << this );
60 bMultiSelection = false;
61 pColSel = nullptr;
62 pVScroll = nullptr;
63 pDataWin = VclPtr<BrowserDataWin>::Create( this ).get();
64 m_pImpl.reset( new ::svt::BrowseBoxImpl() );
65
66 InitSettings_Impl( this );
67 InitSettings_Impl( pDataWin );
68
69 bBootstrapped = false;
70 nDataRowHeight = 0;
71 nTitleLines = 1;
72 nFirstCol = 0;
73 nTopRow = 0;
74 nCurRow = BROWSER_ENDOFSELECTION;
75 nCurColId = 0;
76 bResizing = false;
77 bSelect = false;
78 bSelecting = false;
79 bScrolling = false;
80 bSelectionIsVisible = false;
81 bNotToggleSel = false;
82 bRowDividerDrag = false;
83 bHit = false;
84 mbInteractiveRowHeight = false;
85 bHideSelect = false;
86 bHideCursor = TRISTATE_FALSE;
87 nRowCount = 0;
88 m_bFocusOnlyCursor = true;
89 m_aCursorColor = COL_TRANSPARENT;
90 m_nCurrentMode = BrowserMode::NONE;
91 nControlAreaWidth = USHRT_MAX;
92 uRow.nSel = BROWSER_ENDOFSELECTION;
93
94 aHScroll->SetLineSize(1);
95 aHScroll->SetScrollHdl( LINK( this, BrowseBox, ScrollHdl ) );
96 pDataWin->Show();
97
98 SetMode( nMode );
99 bSelectionIsVisible = bKeepHighlight;
100 bHasFocus = HasChildPathFocus();
101 pDataWin->nCursorHidden =
102 ( bHasFocus ? 0 : 1 ) + ( GetUpdateMode() ? 0 : 1 );
103 }
104
BrowseBox(vcl::Window * pParent,WinBits nBits,BrowserMode nMode)105 BrowseBox::BrowseBox( vcl::Window* pParent, WinBits nBits, BrowserMode nMode )
106 :Control( pParent, nBits | WB_3DLOOK )
107 ,DragSourceHelper( this )
108 ,DropTargetHelper( this )
109 ,aHScroll( VclPtr<ScrollBar>::Create(this, WB_HSCROLL) )
110 ,aStatusBar( VclPtr<StatusBar>::Create(this) )
111 {
112 ConstructImpl( nMode );
113 }
114
~BrowseBox()115 BrowseBox::~BrowseBox()
116 {
117 disposeOnce();
118 }
119
dispose()120 void BrowseBox::dispose()
121 {
122 SAL_INFO("svtools", "BrowseBox:dispose " << this );
123
124 if ( m_pImpl->m_pAccessible )
125 {
126 disposeAndClearHeaderCell(m_pImpl->m_aColHeaderCellMap);
127 disposeAndClearHeaderCell(m_pImpl->m_aRowHeaderCellMap);
128 m_pImpl->m_pAccessible->dispose();
129 }
130
131 Hide();
132 pDataWin->pHeaderBar.disposeAndClear();
133 pDataWin->pCornerWin.disposeAndClear();
134 pDataWin.disposeAndClear();
135 pVScroll.disposeAndClear();
136 aHScroll.disposeAndClear();
137 aStatusBar.disposeAndClear();
138
139 // free columns-space
140 mvCols.clear();
141 pColSel.reset();
142 if ( bMultiSelection )
143 delete uRow.pSel;
144 DragSourceHelper::dispose();
145 DropTargetHelper::dispose();
146 Control::dispose();
147 }
148
149
GetCursorHideCount() const150 short BrowseBox::GetCursorHideCount() const
151 {
152 return pDataWin->nCursorHidden;
153 }
154
155
DoShowCursor(const char *)156 void BrowseBox::DoShowCursor( const char * )
157 {
158 if (!pDataWin)
159 return;
160 short nHiddenCount = --pDataWin->nCursorHidden;
161 if (PaintCursorIfHiddenOnce())
162 {
163 if (1 == nHiddenCount)
164 DrawCursor();
165 }
166 else
167 {
168 if (0 == nHiddenCount)
169 DrawCursor();
170 }
171 }
172
173
DoHideCursor(const char *)174 void BrowseBox::DoHideCursor( const char * )
175 {
176 short nHiddenCount = ++pDataWin->nCursorHidden;
177 if (PaintCursorIfHiddenOnce())
178 {
179 if (2 == nHiddenCount)
180 DrawCursor();
181 }
182 else
183 {
184 if (1 == nHiddenCount)
185 DrawCursor();
186 }
187 }
188
189
SetRealRowCount(const OUString & rRealRowCount)190 void BrowseBox::SetRealRowCount( const OUString &rRealRowCount )
191 {
192 pDataWin->aRealRowCount = rRealRowCount;
193 }
194
195
SetFont(const vcl::Font & rNewFont)196 void BrowseBox::SetFont( const vcl::Font& rNewFont )
197 {
198 pDataWin->SetFont( rNewFont );
199 ImpGetDataRowHeight();
200 }
201
GetFont() const202 const vcl::Font& BrowseBox::GetFont() const
203 {
204 return pDataWin->GetFont();
205 }
206
GetDefaultColumnWidth(const OUString & _rText) const207 sal_uLong BrowseBox::GetDefaultColumnWidth( const OUString& _rText ) const
208 {
209 return pDataWin->GetTextWidth( _rText ) + pDataWin->GetTextWidth(OUString('0')) * 4;
210 }
211
212
InsertHandleColumn(sal_uLong nWidth)213 void BrowseBox::InsertHandleColumn( sal_uLong nWidth )
214 {
215
216 #if OSL_DEBUG_LEVEL > 0
217 OSL_ENSURE( ColCount() == 0 || mvCols[0]->GetId() != HandleColumnId , "BrowseBox::InsertHandleColumn: there is already a handle column" );
218 {
219 for (auto const & col : mvCols)
220 OSL_ENSURE( col->GetId() != HandleColumnId, "BrowseBox::InsertHandleColumn: there is a non-Handle column with handle ID" );
221 }
222 #endif
223
224 mvCols.insert( mvCols.begin(), std::unique_ptr<BrowserColumn>(new BrowserColumn( 0, OUString(), nWidth, GetZoom() )) );
225 FreezeColumn( 0 );
226
227 // adjust headerbar
228 if ( pDataWin->pHeaderBar )
229 {
230 pDataWin->pHeaderBar->SetPosSizePixel(
231 Point(nWidth, 0),
232 Size( GetOutputSizePixel().Width() - nWidth, GetTitleHeight() )
233 );
234 }
235
236 ColumnInserted( 0 );
237 }
238
239
InsertDataColumn(sal_uInt16 nItemId,const OUString & rText,long nWidth,HeaderBarItemBits nBits,sal_uInt16 nPos)240 void BrowseBox::InsertDataColumn( sal_uInt16 nItemId, const OUString& rText,
241 long nWidth, HeaderBarItemBits nBits, sal_uInt16 nPos )
242 {
243
244 OSL_ENSURE( nItemId != HandleColumnId, "BrowseBox::InsertDataColumn: nItemId is HandleColumnId" );
245 OSL_ENSURE( nItemId != BROWSER_INVALIDID, "BrowseBox::InsertDataColumn: nItemId is reserved value BROWSER_INVALIDID" );
246
247 #if OSL_DEBUG_LEVEL > 0
248 {
249 for (auto const& col : mvCols)
250 OSL_ENSURE( col->GetId() != nItemId, "BrowseBox::InsertDataColumn: duplicate column Id" );
251 }
252 #endif
253
254 if ( nPos < mvCols.size() )
255 {
256 mvCols.emplace( mvCols.begin() + nPos, new BrowserColumn( nItemId, rText, nWidth, GetZoom() ) );
257 }
258 else
259 {
260 mvCols.emplace_back( new BrowserColumn( nItemId, rText, nWidth, GetZoom() ) );
261 }
262 if ( nCurColId == 0 )
263 nCurColId = nItemId;
264
265 if ( pDataWin->pHeaderBar )
266 {
267 // Handle column not in the header bar
268 sal_uInt16 nHeaderPos = nPos;
269 if (nHeaderPos != HEADERBAR_APPEND && GetColumnId(0) == HandleColumnId )
270 nHeaderPos--;
271 pDataWin->pHeaderBar->InsertItem(
272 nItemId, rText, nWidth, nBits, nHeaderPos );
273 }
274 ColumnInserted( nPos );
275 }
276
ToggleSelectedColumn()277 sal_uInt16 BrowseBox::ToggleSelectedColumn()
278 {
279 sal_uInt16 nSelectedColId = BROWSER_INVALIDID;
280 if ( pColSel && pColSel->GetSelectCount() )
281 {
282 DoHideCursor( "ToggleSelectedColumn" );
283 ToggleSelection();
284 long nSelected = pColSel->FirstSelected();
285 if (nSelected != static_cast<long>(SFX_ENDOFSELECTION))
286 nSelectedColId = mvCols[nSelected]->GetId();
287 pColSel->SelectAll(false);
288 }
289 return nSelectedColId;
290 }
291
SetToggledSelectedColumn(sal_uInt16 _nSelectedColumnId)292 void BrowseBox::SetToggledSelectedColumn(sal_uInt16 _nSelectedColumnId)
293 {
294 if ( pColSel && _nSelectedColumnId != BROWSER_INVALIDID )
295 {
296 pColSel->Select( GetColumnPos( _nSelectedColumnId ) );
297 ToggleSelection();
298 SAL_INFO("svtools", "BrowseBox::SetToggledSelectedColumn " << this );
299 DoShowCursor( "SetToggledSelectedColumn" );
300 }
301 }
302
FreezeColumn(sal_uInt16 nItemId)303 void BrowseBox::FreezeColumn( sal_uInt16 nItemId )
304 {
305 // get the position in the current array
306 size_t nItemPos = GetColumnPos( nItemId );
307 if ( nItemPos >= mvCols.size() )
308 // not available!
309 return;
310
311 // doesn't the state change?
312 if ( mvCols[ nItemPos ]->IsFrozen() )
313 return;
314
315 // remark the column selection
316 sal_uInt16 nSelectedColId = ToggleSelectedColumn();
317
318 // to be moved?
319 if ( nItemPos != 0 && !mvCols[ nItemPos-1 ]->IsFrozen() )
320 {
321 // move to the right of the last frozen column
322 sal_uInt16 nFirstScrollable = FrozenColCount();
323 std::unique_ptr<BrowserColumn> pColumn = std::move(mvCols[ nItemPos ]);
324 mvCols.erase( mvCols.begin() + nItemPos );
325 nItemPos = nFirstScrollable;
326 mvCols.insert( mvCols.begin() + nItemPos, std::move(pColumn) );
327 }
328
329 // adjust the number of the first scrollable and visible column
330 if ( nFirstCol <= nItemPos )
331 nFirstCol = nItemPos + 1;
332
333 // toggle the freeze-state of the column
334 mvCols[ nItemPos ]->Freeze();
335
336 // align the scrollbar-range
337 UpdateScrollbars();
338
339 // repaint
340 Control::Invalidate();
341 pDataWin->Invalidate();
342
343 // remember the column selection
344 SetToggledSelectedColumn(nSelectedColId);
345 }
346
347
SetColumnPos(sal_uInt16 nColumnId,sal_uInt16 nPos)348 void BrowseBox::SetColumnPos( sal_uInt16 nColumnId, sal_uInt16 nPos )
349 {
350 // never set pos of the handle column
351 if ( nColumnId == HandleColumnId )
352 return;
353
354 // get the position in the current array
355 sal_uInt16 nOldPos = GetColumnPos( nColumnId );
356 if ( nOldPos >= mvCols.size() )
357 // not available!
358 return;
359
360 // does the state change?
361 if (nOldPos == nPos)
362 return;
363
364 // remark the column selection
365 sal_uInt16 nSelectedColId = ToggleSelectedColumn();
366
367 // determine old column area
368 Size aDataWinSize( pDataWin->GetSizePixel() );
369 if ( pDataWin->pHeaderBar )
370 aDataWinSize.AdjustHeight(pDataWin->pHeaderBar->GetSizePixel().Height() );
371
372 tools::Rectangle aFromRect( GetFieldRect( nColumnId) );
373 aFromRect.AdjustRight(2*MIN_COLUMNWIDTH );
374
375 sal_uInt16 nNextPos = nOldPos + 1;
376 if ( nOldPos > nPos )
377 nNextPos = nOldPos - 1;
378
379 BrowserColumn *pNextCol = mvCols[ nNextPos ].get();
380 tools::Rectangle aNextRect(GetFieldRect( pNextCol->GetId() ));
381
382 // move column internally
383 {
384 std::unique_ptr<BrowserColumn> pTemp = std::move(mvCols[nOldPos]);
385 mvCols.erase( mvCols.begin() + nOldPos );
386 mvCols.insert( mvCols.begin() + nPos, std::move(pTemp) );
387 }
388
389 // determine new column area
390 tools::Rectangle aToRect( GetFieldRect( nColumnId ) );
391 aToRect.AdjustRight(2*MIN_COLUMNWIDTH );
392
393 // do scroll, let redraw
394 if( pDataWin->GetBackground().IsScrollable() )
395 {
396 long nScroll = -aFromRect.GetWidth();
397 tools::Rectangle aScrollArea;
398 if ( nOldPos > nPos )
399 {
400 long nFrozenWidth = GetFrozenWidth();
401 if ( aToRect.Left() < nFrozenWidth )
402 aToRect.SetLeft( nFrozenWidth );
403 aScrollArea = tools::Rectangle(Point(aToRect.Left(),0),
404 Point(aNextRect.Right(),aDataWinSize.Height()));
405 nScroll *= -1; // reverse direction
406 }
407 else
408 aScrollArea = tools::Rectangle(Point(aNextRect.Left(),0),
409 Point(aToRect.Right(),aDataWinSize.Height()));
410
411 pDataWin->Scroll( nScroll, 0, aScrollArea );
412 aToRect.SetTop( 0 );
413 aToRect.SetBottom( aScrollArea.Bottom() );
414 Invalidate( aToRect );
415 }
416 else
417 pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
418
419 // adjust header bar positions
420 if ( pDataWin->pHeaderBar )
421 {
422 sal_uInt16 nNewPos = nPos;
423 if ( GetColumnId(0) == HandleColumnId )
424 --nNewPos;
425 pDataWin->pHeaderBar->MoveItem(nColumnId,nNewPos);
426 }
427 // remember the column selection
428 SetToggledSelectedColumn(nSelectedColId);
429
430 if ( !isAccessibleAlive() )
431 return;
432
433 commitTableEvent(
434 TABLE_MODEL_CHANGED,
435 makeAny( AccessibleTableModelChange(
436 DELETE,
437 0,
438 GetRowCount(),
439 nOldPos,
440 nOldPos
441 )
442 ),
443 Any()
444 );
445
446 commitTableEvent(
447 TABLE_MODEL_CHANGED,
448 makeAny( AccessibleTableModelChange(
449 INSERT,
450 0,
451 GetRowCount(),
452 nPos,
453 nPos
454 )
455 ),
456 Any()
457 );
458
459 }
460
461
SetColumnTitle(sal_uInt16 nItemId,const OUString & rTitle)462 void BrowseBox::SetColumnTitle( sal_uInt16 nItemId, const OUString& rTitle )
463 {
464
465 // never set title of the handle-column
466 if ( nItemId == HandleColumnId )
467 return;
468
469 // get the position in the current array
470 sal_uInt16 nItemPos = GetColumnPos( nItemId );
471 if ( nItemPos >= mvCols.size() )
472 // not available!
473 return;
474
475 // does the state change?
476 BrowserColumn *pCol = mvCols[ nItemPos ].get();
477 if ( pCol->Title() == rTitle )
478 return;
479
480 OUString sOld(pCol->Title());
481
482 pCol->Title() = rTitle;
483
484 // adjust headerbar column
485 if ( pDataWin->pHeaderBar )
486 pDataWin->pHeaderBar->SetItemText( nItemId, rTitle );
487 else
488 {
489 // redraw visible columns
490 if ( GetUpdateMode() && ( pCol->IsFrozen() || nItemPos > nFirstCol ) )
491 Invalidate( tools::Rectangle( Point(0,0),
492 Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
493 }
494
495 if ( isAccessibleAlive() )
496 {
497 commitTableEvent( TABLE_COLUMN_DESCRIPTION_CHANGED,
498 makeAny( rTitle ),
499 makeAny( sOld )
500 );
501 }
502 }
503
504
SetColumnWidth(sal_uInt16 nItemId,sal_uLong nWidth)505 void BrowseBox::SetColumnWidth( sal_uInt16 nItemId, sal_uLong nWidth )
506 {
507
508 // get the position in the current array
509 size_t nItemPos = GetColumnPos( nItemId );
510 if ( nItemPos >= mvCols.size() )
511 return;
512
513 // does the state change?
514 if ( !(nWidth >= LONG_MAX || mvCols[ nItemPos ]->Width() != nWidth) )
515 return;
516
517 long nOldWidth = mvCols[ nItemPos ]->Width();
518
519 // adjust last column, if necessary
520 if ( IsVisible() && nItemPos == mvCols.size() - 1 )
521 {
522 long nMaxWidth = pDataWin->GetSizePixel().Width();
523 nMaxWidth -= pDataWin->bAutoSizeLastCol
524 ? GetFieldRect(nItemId).Left()
525 : GetFrozenWidth();
526 if ( pDataWin->bAutoSizeLastCol || nWidth > static_cast<sal_uLong>(nMaxWidth) )
527 {
528 nWidth = nMaxWidth > 16 ? nMaxWidth : nOldWidth;
529 }
530 }
531
532 // OV
533 // In AutoSizeLastColumn(), we call SetColumnWidth with nWidth==0xffff.
534 // Thus, check here, if the width has actually changed.
535 if( static_cast<sal_uLong>(nOldWidth) == nWidth )
536 return;
537
538 // do we want to display the change immediately?
539 bool bUpdate = GetUpdateMode() &&
540 ( mvCols[ nItemPos ]->IsFrozen() || nItemPos >= nFirstCol );
541
542 if ( bUpdate )
543 {
544 // Selection hidden
545 DoHideCursor( "SetColumnWidth" );
546 ToggleSelection();
547 //!pDataWin->Update();
548 //!Control::Update();
549 }
550
551 // set width
552 mvCols[ nItemPos ]->SetWidth(nWidth, GetZoom());
553
554 // scroll and invalidate
555 if ( bUpdate )
556 {
557 // get X-Pos of the column changed
558 long nX = 0;
559 for ( size_t nCol = 0; nCol < nItemPos; ++nCol )
560 {
561 BrowserColumn *pCol = mvCols[ nCol ].get();
562 if ( pCol->IsFrozen() || nCol >= nFirstCol )
563 nX += pCol->Width();
564 }
565
566 // actually scroll+invalidate
567 pDataWin->SetClipRegion();
568 bool bSelVis = bSelectionIsVisible;
569 bSelectionIsVisible = false;
570 if( GetBackground().IsScrollable() )
571 {
572
573 tools::Rectangle aScrRect( nX + std::min( static_cast<sal_uLong>(nOldWidth), nWidth ), 0,
574 GetSizePixel().Width() , // the header is longer than the datawin
575 pDataWin->GetPosPixel().Y() - 1 );
576 Control::Scroll( nWidth-nOldWidth, 0, aScrRect, SCROLL_FLAGS );
577 aScrRect.SetBottom( pDataWin->GetSizePixel().Height() );
578 pDataWin->Scroll( nWidth-nOldWidth, 0, aScrRect, SCROLL_FLAGS );
579 tools::Rectangle aInvRect( nX, 0, nX + std::max( nWidth, static_cast<sal_uLong>(nOldWidth) ), USHRT_MAX );
580 Control::Invalidate( aInvRect, InvalidateFlags::NoChildren );
581 pDataWin->Invalidate( aInvRect );
582 }
583 else
584 {
585 Control::Invalidate( InvalidateFlags::NoChildren );
586 pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
587 }
588
589
590 //!pDataWin->Update();
591 //!Control::Update();
592 bSelectionIsVisible = bSelVis;
593 ToggleSelection();
594 DoShowCursor( "SetColumnWidth" );
595 }
596 UpdateScrollbars();
597
598 // adjust headerbar column
599 if ( pDataWin->pHeaderBar )
600 pDataWin->pHeaderBar->SetItemSize(
601 nItemId ? nItemId : USHRT_MAX - 1, nWidth );
602
603 // adjust last column
604 if ( nItemPos != mvCols.size() - 1 )
605 AutoSizeLastColumn();
606 }
607
608
AutoSizeLastColumn()609 void BrowseBox::AutoSizeLastColumn()
610 {
611 if ( pDataWin->bAutoSizeLastCol &&
612 pDataWin->GetUpdateMode() )
613 {
614 sal_uInt16 nId = GetColumnId( static_cast<sal_uInt16>(mvCols.size()) - 1 );
615 SetColumnWidth( nId, LONG_MAX );
616 ColumnResized( nId );
617 }
618 }
619
620
RemoveColumn(sal_uInt16 nItemId)621 void BrowseBox::RemoveColumn( sal_uInt16 nItemId )
622 {
623
624 // get column position
625 sal_uInt16 nPos = GetColumnPos(nItemId);
626 if ( nPos >= ColCount() )
627 // not available
628 return;
629
630 // correct column selection
631 if ( pColSel )
632 pColSel->Remove( nPos );
633
634 // correct column cursor
635 if ( nCurColId == nItemId )
636 nCurColId = 0;
637
638 // delete column
639 mvCols.erase( mvCols.begin() + nPos );
640 if ( nFirstCol >= nPos && nFirstCol > FrozenColCount() )
641 {
642 OSL_ENSURE(nFirstCol > 0,"FirstCol must be greater zero!");
643 --nFirstCol;
644 }
645
646 // handlecolumn not in headerbar
647 if (nItemId)
648 {
649 if ( pDataWin->pHeaderBar )
650 pDataWin->pHeaderBar->RemoveItem( nItemId );
651 }
652 else
653 {
654 // adjust headerbar
655 if ( pDataWin->pHeaderBar )
656 {
657 pDataWin->pHeaderBar->SetPosSizePixel(
658 Point(0, 0),
659 Size( GetOutputSizePixel().Width(), GetTitleHeight() )
660 );
661 }
662 }
663
664 // correct vertical scrollbar
665 UpdateScrollbars();
666
667 // trigger repaint, if necessary
668 if ( GetUpdateMode() )
669 {
670 pDataWin->Invalidate();
671 Control::Invalidate();
672 if ( pDataWin->bAutoSizeLastCol && nPos ==ColCount() )
673 SetColumnWidth( GetColumnId( nPos - 1 ), LONG_MAX );
674 }
675
676 if ( !isAccessibleAlive() )
677 return;
678
679 commitTableEvent(
680 TABLE_MODEL_CHANGED,
681 makeAny( AccessibleTableModelChange( DELETE,
682 0,
683 GetRowCount(),
684 nPos,
685 nPos
686 )
687 ),
688 Any()
689 );
690
691 commitHeaderBarEvent(
692 CHILD,
693 Any(),
694 makeAny( CreateAccessibleColumnHeader( nPos ) ),
695 true
696 );
697 }
698
699
RemoveColumns()700 void BrowseBox::RemoveColumns()
701 {
702 size_t nOldCount = mvCols.size();
703
704 // remove all columns
705 mvCols.clear();
706
707 // correct column selection
708 if ( pColSel )
709 {
710 pColSel->SelectAll(false);
711 pColSel->SetTotalRange( Range( 0, 0 ) );
712 }
713
714 // correct column cursor
715 nCurColId = 0;
716 nFirstCol = 0;
717
718 if ( pDataWin->pHeaderBar )
719 pDataWin->pHeaderBar->Clear( );
720
721 // correct vertical scrollbar
722 UpdateScrollbars();
723
724 // trigger repaint if necessary
725 if ( GetUpdateMode() )
726 {
727 pDataWin->Invalidate();
728 Control::Invalidate();
729 }
730
731 if ( !isAccessibleAlive() )
732 return;
733
734 if ( mvCols.size() == nOldCount )
735 return;
736
737 // all columns should be removed, so we remove the column header bar and append it again
738 // to avoid to notify every column remove
739 commitBrowseBoxEvent(
740 CHILD,
741 Any(),
742 makeAny(m_pImpl->getAccessibleHeaderBar(vcl::BBTYPE_COLUMNHEADERBAR))
743 );
744
745 // and now append it again
746 commitBrowseBoxEvent(
747 CHILD,
748 makeAny(m_pImpl->getAccessibleHeaderBar(vcl::BBTYPE_COLUMNHEADERBAR)),
749 Any()
750 );
751
752 // notify a table model change
753 commitTableEvent(
754 TABLE_MODEL_CHANGED,
755 makeAny ( AccessibleTableModelChange( DELETE,
756 0,
757 GetRowCount(),
758 0,
759 nOldCount
760 )
761 ),
762 Any()
763 );
764 }
765
766
GetColumnTitle(sal_uInt16 nId) const767 OUString BrowseBox::GetColumnTitle( sal_uInt16 nId ) const
768 {
769
770 sal_uInt16 nItemPos = GetColumnPos( nId );
771 if ( nItemPos >= mvCols.size() )
772 return OUString();
773 return mvCols[ nItemPos ]->Title();
774 }
775
776
GetRowCount() const777 long BrowseBox::GetRowCount() const
778 {
779 return nRowCount;
780 }
781
782
ColCount() const783 sal_uInt16 BrowseBox::ColCount() const
784 {
785
786 return static_cast<sal_uInt16>(mvCols.size());
787 }
788
789
ImpGetDataRowHeight() const790 long BrowseBox::ImpGetDataRowHeight() const
791 {
792
793 BrowseBox *pThis = const_cast<BrowseBox*>(this);
794 pThis->nDataRowHeight = pThis->CalcReverseZoom(pDataWin->GetTextHeight() + 2);
795 pThis->Resize();
796 pDataWin->Invalidate();
797 return nDataRowHeight;
798 }
799
800
SetDataRowHeight(long nPixel)801 void BrowseBox::SetDataRowHeight( long nPixel )
802 {
803
804 nDataRowHeight = CalcReverseZoom(nPixel);
805 Resize();
806 pDataWin->Invalidate();
807 }
808
809
SetTitleLines(sal_uInt16 nLines)810 void BrowseBox::SetTitleLines( sal_uInt16 nLines )
811 {
812
813 nTitleLines = nLines;
814 }
815
816
ScrollColumns(long nCols)817 long BrowseBox::ScrollColumns( long nCols )
818 {
819
820 if ( nFirstCol + nCols < 0 ||
821 nFirstCol + nCols >= static_cast<long>(mvCols.size()) )
822 return 0;
823
824 // implicitly hides cursor while scrolling
825 StartScroll();
826 bScrolling = true;
827 bool bScrollable = pDataWin->GetBackground().IsScrollable();
828 bool bInvalidateView = false;
829
830 // scrolling one column to the right?
831 if ( nCols == 1 )
832 {
833 // update internal value and scrollbar
834 ++nFirstCol;
835 aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
836
837 if ( !bScrollable )
838 {
839 bInvalidateView = true;
840 }
841 else
842 {
843 long nDelta = mvCols[ nFirstCol-1 ]->Width();
844 long nFrozenWidth = GetFrozenWidth();
845
846 tools::Rectangle aScrollRect( Point( nFrozenWidth + nDelta, 0 ),
847 Size ( GetOutputSizePixel().Width() - nFrozenWidth - nDelta,
848 GetTitleHeight() - 1
849 ) );
850
851 // scroll the header bar area (if there is no dedicated HeaderBar control)
852 if ( !pDataWin->pHeaderBar && nTitleLines )
853 {
854 // actually scroll
855 Scroll( -nDelta, 0, aScrollRect, SCROLL_FLAGS );
856
857 // invalidate the area of the column which was scrolled out to the left hand side
858 tools::Rectangle aInvalidateRect( aScrollRect );
859 aInvalidateRect.SetLeft( nFrozenWidth );
860 aInvalidateRect.SetRight( nFrozenWidth + nDelta - 1 );
861 Invalidate( aInvalidateRect );
862 }
863
864 // scroll the data-area
865 aScrollRect.SetBottom( pDataWin->GetOutputSizePixel().Height() );
866
867 // actually scroll
868 pDataWin->Scroll( -nDelta, 0, aScrollRect, SCROLL_FLAGS );
869
870 // invalidate the area of the column which was scrolled out to the left hand side
871 aScrollRect.SetLeft( nFrozenWidth );
872 aScrollRect.SetRight( nFrozenWidth + nDelta - 1 );
873 pDataWin->Invalidate( aScrollRect );
874 }
875 }
876
877 // scrolling one column to the left?
878 else if ( nCols == -1 )
879 {
880 --nFirstCol;
881 aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
882
883 if ( !bScrollable )
884 {
885 bInvalidateView = true;
886 }
887 else
888 {
889 long nDelta = mvCols[ nFirstCol ]->Width();
890 long nFrozenWidth = GetFrozenWidth();
891
892 tools::Rectangle aScrollRect( Point( nFrozenWidth, 0 ),
893 Size ( GetOutputSizePixel().Width() - nFrozenWidth,
894 GetTitleHeight() - 1
895 ) );
896
897 // scroll the header bar area (if there is no dedicated HeaderBar control)
898 if ( !pDataWin->pHeaderBar && nTitleLines )
899 {
900 Scroll( nDelta, 0, aScrollRect, SCROLL_FLAGS );
901 }
902
903 // scroll the data-area
904 aScrollRect.SetBottom( pDataWin->GetOutputSizePixel().Height() );
905 pDataWin->Scroll( nDelta, 0, aScrollRect, SCROLL_FLAGS );
906 }
907 }
908 else
909 {
910 if ( GetUpdateMode() )
911 {
912 Invalidate( tools::Rectangle(
913 Point( GetFrozenWidth(), 0 ),
914 Size( GetOutputSizePixel().Width(), GetTitleHeight() ) ) );
915 pDataWin->Invalidate( tools::Rectangle(
916 Point( GetFrozenWidth(), 0 ),
917 pDataWin->GetSizePixel() ) );
918 }
919
920 nFirstCol = nFirstCol + static_cast<sal_uInt16>(nCols);
921 aHScroll->SetThumbPos( nFirstCol - FrozenColCount() );
922 }
923
924 // adjust external headerbar, if necessary
925 if ( pDataWin->pHeaderBar )
926 {
927 long nWidth = 0;
928 for ( size_t nCol = 0;
929 nCol < mvCols.size() && nCol < nFirstCol;
930 ++nCol )
931 {
932 // not the handle column
933 if ( mvCols[ nCol ]->GetId() )
934 nWidth += mvCols[ nCol ]->Width();
935 }
936
937 pDataWin->pHeaderBar->SetOffset( nWidth );
938 }
939
940 if( bInvalidateView )
941 {
942 Control::Invalidate( InvalidateFlags::NoChildren );
943 pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
944 }
945
946 // implicitly show cursor after scrolling
947 if ( nCols )
948 {
949 pDataWin->Update();
950 Update();
951 }
952 bScrolling = false;
953 EndScroll();
954
955 return nCols;
956 }
957
958
ScrollRows(long nRows)959 long BrowseBox::ScrollRows( long nRows )
960 {
961 // compute new top row
962 long nTmpMin = std::min( static_cast<long>(nTopRow + nRows), static_cast<long>(nRowCount - 1) );
963
964 long nNewTopRow = std::max<long>( nTmpMin, 0 );
965
966 if ( nNewTopRow == nTopRow )
967 return 0;
968
969 sal_uInt16 nVisibleRows =
970 static_cast<sal_uInt16>(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
971
972 VisibleRowsChanged(nNewTopRow, nVisibleRows);
973
974 // compute new top row again (nTopRow might have changed!)
975 nTmpMin = std::min( static_cast<long>(nTopRow + nRows), static_cast<long>(nRowCount - 1) );
976
977 nNewTopRow = std::max<long>( nTmpMin, 0 );
978
979 StartScroll();
980
981 // scroll area on screen and/or repaint
982 long nDeltaY = GetDataRowHeight() * ( nNewTopRow - nTopRow );
983 long nOldTopRow = nTopRow;
984 nTopRow = nNewTopRow;
985
986 if ( GetUpdateMode() )
987 {
988 pVScroll->SetRange( Range( 0L, nRowCount ) );
989 pVScroll->SetThumbPos( nTopRow );
990
991 if( pDataWin->GetBackground().IsScrollable() &&
992 std::abs( nDeltaY ) > 0 &&
993 std::abs( nDeltaY ) < pDataWin->GetSizePixel().Height() )
994 {
995 pDataWin->Scroll( 0, static_cast<short>(-nDeltaY), SCROLL_FLAGS );
996 }
997 else
998 pDataWin->Invalidate();
999
1000 if ( nTopRow - nOldTopRow )
1001 pDataWin->Update();
1002 }
1003
1004 EndScroll();
1005
1006 return nTopRow - nOldTopRow;
1007 }
1008
1009
RowModified(long nRow,sal_uInt16 nColId)1010 void BrowseBox::RowModified( long nRow, sal_uInt16 nColId )
1011 {
1012
1013 if ( !GetUpdateMode() )
1014 return;
1015
1016 tools::Rectangle aRect;
1017 if ( nColId == BROWSER_INVALIDID )
1018 // invalidate the whole row
1019 aRect = tools::Rectangle( Point( 0, (nRow-nTopRow) * GetDataRowHeight() ),
1020 Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) );
1021 else
1022 {
1023 // invalidate the specific field
1024 aRect = GetFieldRectPixel( nRow, nColId, false );
1025 }
1026 pDataWin->Invalidate( aRect );
1027 }
1028
1029
Clear()1030 void BrowseBox::Clear()
1031 {
1032
1033 // adjust the total number of rows
1034 DoHideCursor( "Clear" );
1035 long nOldRowCount = nRowCount;
1036 nRowCount = 0;
1037 if(bMultiSelection)
1038 {
1039 assert(uRow.pSel);
1040 uRow.pSel->Reset();
1041 }
1042 else
1043 uRow.nSel = BROWSER_ENDOFSELECTION;
1044 nCurRow = BROWSER_ENDOFSELECTION;
1045 nTopRow = 0;
1046 nCurColId = 0;
1047
1048 // nFirstCol may not be reset, else the scrolling code will become confused.
1049 // nFirstCol may only be changed when adding or deleting columns
1050 // nFirstCol = 0; -> wrong!
1051 aHScroll->SetThumbPos( 0 );
1052 pVScroll->SetThumbPos( 0 );
1053
1054 Invalidate();
1055 UpdateScrollbars();
1056 SetNoSelection();
1057 DoShowCursor( "Clear" );
1058 CursorMoved();
1059
1060 if ( !isAccessibleAlive() )
1061 return;
1062
1063 // all rows should be removed, so we remove the row header bar and append it again
1064 // to avoid to notify every row remove
1065 if ( nOldRowCount == nRowCount )
1066 return;
1067
1068 commitBrowseBoxEvent(
1069 CHILD,
1070 Any(),
1071 makeAny( m_pImpl->getAccessibleHeaderBar( vcl::BBTYPE_ROWHEADERBAR ) )
1072 );
1073
1074 // and now append it again
1075 commitBrowseBoxEvent(
1076 CHILD,
1077 makeAny( m_pImpl->getAccessibleHeaderBar( vcl::BBTYPE_ROWHEADERBAR ) ),
1078 Any()
1079 );
1080
1081 // notify a table model change
1082 commitTableEvent(
1083 TABLE_MODEL_CHANGED,
1084 makeAny( AccessibleTableModelChange( DELETE,
1085 0,
1086 nOldRowCount,
1087 0,
1088 GetColumnCount())
1089 ),
1090 Any()
1091 );
1092 }
1093
RowInserted(long nRow,long nNumRows,bool bDoPaint,bool bKeepSelection)1094 void BrowseBox::RowInserted( long nRow, long nNumRows, bool bDoPaint, bool bKeepSelection )
1095 {
1096
1097 if (nRow < 0)
1098 nRow = 0;
1099 else if (nRow > nRowCount) // maximal = nRowCount
1100 nRow = nRowCount;
1101
1102 if ( nNumRows <= 0 )
1103 return;
1104
1105 // adjust total row count
1106 bool bLastRow = nRow >= nRowCount;
1107 nRowCount += nNumRows;
1108
1109 DoHideCursor( "RowInserted" );
1110
1111 // must we paint the new rows?
1112 long nOldCurRow = nCurRow;
1113 Size aSz = pDataWin->GetOutputSizePixel();
1114 if ( bDoPaint && nRow >= nTopRow &&
1115 nRow <= nTopRow + aSz.Height() / GetDataRowHeight() )
1116 {
1117 long nY = (nRow-nTopRow) * GetDataRowHeight();
1118 if ( !bLastRow )
1119 {
1120 // scroll down the rows behind the new row
1121 pDataWin->SetClipRegion();
1122 if( pDataWin->GetBackground().IsScrollable() )
1123 {
1124 pDataWin->Scroll( 0, GetDataRowHeight() * nNumRows,
1125 tools::Rectangle( Point( 0, nY ),
1126 Size( aSz.Width(), aSz.Height() - nY ) ),
1127 SCROLL_FLAGS );
1128 }
1129 else
1130 pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
1131 }
1132 else
1133 // scroll would cause a repaint, so we must explicitly invalidate
1134 pDataWin->Invalidate( tools::Rectangle( Point( 0, nY ),
1135 Size( aSz.Width(), nNumRows * GetDataRowHeight() ) ) );
1136 }
1137
1138 // correct top row if necessary
1139 if ( nRow < nTopRow )
1140 nTopRow += nNumRows;
1141
1142 // adjust the selection
1143 if ( bMultiSelection )
1144 uRow.pSel->Insert( nRow, nNumRows );
1145 else if ( uRow.nSel != BROWSER_ENDOFSELECTION && nRow <= uRow.nSel )
1146 uRow.nSel += nNumRows;
1147
1148 // adjust the cursor
1149 if ( nCurRow == BROWSER_ENDOFSELECTION )
1150 GoToRow( 0, false, bKeepSelection );
1151 else if ( nRow <= nCurRow )
1152 {
1153 nCurRow += nNumRows;
1154 GoToRow( nCurRow, false, bKeepSelection );
1155 }
1156
1157 // adjust the vertical scrollbar
1158 if ( bDoPaint )
1159 {
1160 UpdateScrollbars();
1161 AutoSizeLastColumn();
1162 }
1163
1164 DoShowCursor( "RowInserted" );
1165 // notify accessible that rows were inserted
1166 if ( isAccessibleAlive() )
1167 {
1168 commitTableEvent(
1169 TABLE_MODEL_CHANGED,
1170 makeAny( AccessibleTableModelChange(
1171 INSERT,
1172 nRow,
1173 nRow + nNumRows,
1174 0,
1175 GetColumnCount()
1176 )
1177 ),
1178 Any()
1179 );
1180
1181 for (long i = nRow+1 ; i <= nRowCount ; ++i)
1182 {
1183 commitHeaderBarEvent(
1184 CHILD,
1185 makeAny( CreateAccessibleRowHeader( i ) ),
1186 Any(),
1187 false
1188 );
1189 }
1190 }
1191
1192 if ( nCurRow != nOldCurRow )
1193 CursorMoved();
1194
1195 DBG_ASSERT(nRowCount > 0,"BrowseBox: nRowCount <= 0");
1196 DBG_ASSERT(nCurRow >= 0,"BrowseBox: nCurRow < 0");
1197 DBG_ASSERT(nCurRow < nRowCount,"nCurRow >= nRowCount");
1198 }
1199
1200
RowRemoved(long nRow,long nNumRows,bool bDoPaint)1201 void BrowseBox::RowRemoved( long nRow, long nNumRows, bool bDoPaint )
1202 {
1203
1204 if ( nRow < 0 )
1205 nRow = 0;
1206 else if ( nRow >= nRowCount )
1207 nRow = nRowCount - 1;
1208
1209 if ( nNumRows <= 0 )
1210 return;
1211
1212 if ( nRowCount <= 0 )
1213 return;
1214
1215 if ( bDoPaint )
1216 {
1217 // hide cursor and selection
1218 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1219 ToggleSelection();
1220 DoHideCursor( "RowRemoved" );
1221 }
1222
1223 // adjust total row count
1224 nRowCount -= nNumRows;
1225 if (nRowCount < 0) nRowCount = 0;
1226 long nOldCurRow = nCurRow;
1227
1228 // adjust the selection
1229 if ( bMultiSelection )
1230 // uRow.pSel->Remove( nRow, nNumRows );
1231 for ( long i = 0; i < nNumRows; i++ )
1232 uRow.pSel->Remove( nRow );
1233 else if ( nRow < uRow.nSel && uRow.nSel >= nNumRows )
1234 uRow.nSel -= nNumRows;
1235 else if ( nRow <= uRow.nSel )
1236 uRow.nSel = BROWSER_ENDOFSELECTION;
1237
1238 // adjust the cursor
1239 if ( nRowCount == 0 ) // don't compare nRowCount with nNumRows as nNumRows already was subtracted from nRowCount
1240 nCurRow = BROWSER_ENDOFSELECTION;
1241 else if ( nRow < nCurRow )
1242 {
1243 nCurRow -= std::min( nCurRow - nRow, nNumRows );
1244 // with the above nCurRow points a) to the first row after the removed block or b) to the same line
1245 // as before, but moved up nNumRows
1246 // case a) needs an additional correction if the last n lines were deleted, as 'the first row after the
1247 // removed block' is an invalid position then
1248 // FS - 09/28/99 - 68429
1249 if (nCurRow == nRowCount)
1250 --nCurRow;
1251 }
1252 else if( nRow == nCurRow && nCurRow == nRowCount )
1253 nCurRow = nRowCount-1;
1254
1255 // is the deleted row visible?
1256 Size aSz = pDataWin->GetOutputSizePixel();
1257 if ( nRow >= nTopRow &&
1258 nRow <= nTopRow + aSz.Height() / GetDataRowHeight() )
1259 {
1260 if ( bDoPaint )
1261 {
1262 // scroll up the rows behind the deleted row
1263 // if there are Rows behind
1264 if (nRow < nRowCount)
1265 {
1266 long nY = (nRow-nTopRow) * GetDataRowHeight();
1267 pDataWin->SetClipRegion();
1268 if( pDataWin->GetBackground().IsScrollable() )
1269 {
1270 pDataWin->Scroll( 0, - static_cast<short>(GetDataRowHeight()) * nNumRows,
1271 tools::Rectangle( Point( 0, nY ), Size( aSz.Width(),
1272 aSz.Height() - nY + nNumRows*GetDataRowHeight() ) ),
1273 SCROLL_FLAGS );
1274 }
1275 else
1276 pDataWin->Window::Invalidate( InvalidateFlags::NoChildren );
1277 }
1278 else
1279 {
1280 // Repaint the Rect of the deleted row
1281 tools::Rectangle aRect(
1282 Point( 0, (nRow-nTopRow)*GetDataRowHeight() ),
1283 Size( pDataWin->GetSizePixel().Width(),
1284 nNumRows * GetDataRowHeight() ) );
1285 pDataWin->Invalidate( aRect );
1286 }
1287 }
1288 }
1289 // is the deleted row above of the visible area?
1290 else if ( nRow < nTopRow )
1291 nTopRow = nTopRow >= nNumRows ? nTopRow-nNumRows : 0;
1292
1293 if ( bDoPaint )
1294 {
1295 // reshow cursor and selection
1296 ToggleSelection();
1297 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1298 DoShowCursor( "RowRemoved" );
1299
1300 // adjust the vertical scrollbar
1301 UpdateScrollbars();
1302 AutoSizeLastColumn();
1303 }
1304
1305 if ( isAccessibleAlive() )
1306 {
1307 if ( nRowCount == 0 )
1308 {
1309 // all columns should be removed, so we remove the column header bar and append it again
1310 // to avoid to notify every column remove
1311 commitBrowseBoxEvent(
1312 CHILD,
1313 Any(),
1314 makeAny( m_pImpl->getAccessibleHeaderBar( vcl::BBTYPE_ROWHEADERBAR ) )
1315 );
1316
1317 // and now append it again
1318 commitBrowseBoxEvent(
1319 CHILD,
1320 makeAny(m_pImpl->getAccessibleHeaderBar(vcl::BBTYPE_ROWHEADERBAR)),
1321 Any()
1322 );
1323 commitBrowseBoxEvent(
1324 CHILD,
1325 Any(),
1326 makeAny( m_pImpl->getAccessibleTable() )
1327 );
1328
1329 // and now append it again
1330 commitBrowseBoxEvent(
1331 CHILD,
1332 makeAny( m_pImpl->getAccessibleTable() ),
1333 Any()
1334 );
1335 }
1336 else
1337 {
1338 commitTableEvent(
1339 TABLE_MODEL_CHANGED,
1340 makeAny( AccessibleTableModelChange(
1341 DELETE,
1342 nRow,
1343 nRow + nNumRows,
1344 0,
1345 GetColumnCount()
1346 )
1347 ),
1348 Any()
1349 );
1350
1351 for (long i = nRow+1 ; i <= (nRow+nNumRows) ; ++i)
1352 {
1353 commitHeaderBarEvent(
1354 CHILD,
1355 Any(),
1356 makeAny( CreateAccessibleRowHeader( i ) ),
1357 false
1358 );
1359 }
1360 }
1361 }
1362
1363 if ( nOldCurRow != nCurRow )
1364 CursorMoved();
1365
1366 DBG_ASSERT(nRowCount >= 0,"BrowseBox: nRowCount < 0");
1367 DBG_ASSERT(nCurRow >= 0 || nRowCount == 0,"BrowseBox: nCurRow < 0 && nRowCount != 0");
1368 DBG_ASSERT(nCurRow < nRowCount,"nCurRow >= nRowCount");
1369 }
1370
1371
GoToRow(long nRow)1372 bool BrowseBox::GoToRow( long nRow)
1373 {
1374 return GoToRow(nRow, false);
1375 }
1376
1377
GoToRow(long nRow,bool bRowColMove,bool bKeepSelection)1378 bool BrowseBox::GoToRow( long nRow, bool bRowColMove, bool bKeepSelection )
1379 {
1380
1381 long nOldCurRow = nCurRow;
1382
1383 // nothing to do?
1384 if ( nRow == nCurRow && ( bMultiSelection || uRow.nSel == nRow ) )
1385 return true;
1386
1387 // out of range?
1388 if ( nRow < 0 || nRow >= nRowCount )
1389 return false;
1390
1391 // not allowed?
1392 if ( !bRowColMove && !IsCursorMoveAllowed( nRow, nCurColId ) )
1393 return false;
1394
1395 // compute the last visible row
1396 Size aSz( pDataWin->GetSizePixel() );
1397 sal_uInt16 nVisibleRows = sal_uInt16( aSz.Height() / GetDataRowHeight() - 1 );
1398 long nLastRow = nTopRow + nVisibleRows;
1399
1400 // suspend Updates
1401 pDataWin->EnterUpdateLock();
1402
1403 // remove old highlight, if necessary
1404 if ( !bMultiSelection && !bKeepSelection )
1405 ToggleSelection();
1406 DoHideCursor( "GoToRow" );
1407
1408 // must we scroll?
1409 bool bWasVisible = bSelectionIsVisible;
1410 if (! bMultiSelection)
1411 {
1412 if( !bKeepSelection )
1413 bSelectionIsVisible = false;
1414 }
1415 if ( nRow < nTopRow )
1416 ScrollRows( nRow - nTopRow );
1417 else if ( nRow > nLastRow )
1418 ScrollRows( nRow - nLastRow );
1419 bSelectionIsVisible = bWasVisible;
1420
1421 // adjust cursor (selection) and thumb
1422 if ( GetUpdateMode() )
1423 pVScroll->SetThumbPos( nTopRow );
1424
1425 // relative positioning (because nCurRow might have changed in the meantime)!
1426 if (nCurRow != BROWSER_ENDOFSELECTION )
1427 nCurRow = nCurRow + (nRow - nOldCurRow);
1428
1429 // make sure that the current position is valid
1430 if (nCurRow == BROWSER_ENDOFSELECTION && nRowCount > 0)
1431 nCurRow = 0;
1432 else if ( nCurRow >= nRowCount )
1433 nCurRow = nRowCount - 1;
1434 aSelRange = Range( nCurRow, nCurRow );
1435
1436 // display new highlight if necessary
1437 if ( !bMultiSelection && !bKeepSelection )
1438 uRow.nSel = nRow;
1439
1440 // resume Updates
1441 pDataWin->LeaveUpdateLock();
1442
1443 // Cursor+Highlight
1444 if ( !bMultiSelection && !bKeepSelection)
1445 ToggleSelection();
1446 DoShowCursor( "GoToRow" );
1447 if ( !bRowColMove && nOldCurRow != nCurRow )
1448 CursorMoved();
1449
1450 if ( !bMultiSelection && !bKeepSelection )
1451 {
1452 if ( !bSelecting )
1453 Select();
1454 else
1455 bSelect = true;
1456 }
1457 return true;
1458 }
1459
1460
GoToColumnId(sal_uInt16 nColId)1461 bool BrowseBox::GoToColumnId( sal_uInt16 nColId)
1462 {
1463 return GoToColumnId(nColId, true);
1464 }
1465
1466
GoToColumnId(sal_uInt16 nColId,bool bMakeVisible,bool bRowColMove)1467 bool BrowseBox::GoToColumnId( sal_uInt16 nColId, bool bMakeVisible, bool bRowColMove)
1468 {
1469 if (!bColumnCursor)
1470 return false;
1471
1472 // allowed?
1473 if (!bRowColMove && !IsCursorMoveAllowed( nCurRow, nColId ) )
1474 return false;
1475
1476 if ( nColId != nCurColId || (bMakeVisible && !IsFieldVisible(nCurRow, nColId, true)))
1477 {
1478 sal_uInt16 nNewPos = GetColumnPos(nColId);
1479 BrowserColumn* pColumn = (nNewPos < mvCols.size()) ? mvCols[ nNewPos ].get() : nullptr;
1480 DBG_ASSERT( pColumn, "no column object - invalid id?" );
1481 if ( !pColumn )
1482 return false;
1483
1484 DoHideCursor( "GoToColumnId" );
1485 nCurColId = nColId;
1486
1487 bool bScrolled = false;
1488
1489 sal_uInt16 nFirstPos = nFirstCol;
1490 sal_uInt16 nWidth = static_cast<sal_uInt16>(pColumn->Width());
1491 sal_uInt16 nLastPos = GetColumnAtXPosPixel(
1492 pDataWin->GetSizePixel().Width()-nWidth );
1493 sal_uInt16 nFrozen = FrozenColCount();
1494 if ( bMakeVisible && nLastPos &&
1495 nNewPos >= nFrozen && ( nNewPos < nFirstPos || nNewPos > nLastPos ) )
1496 {
1497 if ( nNewPos < nFirstPos )
1498 ScrollColumns( nNewPos-nFirstPos );
1499 else if ( nNewPos > nLastPos )
1500 ScrollColumns( nNewPos-nLastPos );
1501 bScrolled = true;
1502 }
1503
1504 DoShowCursor( "GoToColumnId" );
1505 if (!bRowColMove)
1506 {
1507 //try to move to nCurRow, nColId
1508 CursorMoveAttempt aAttempt(nCurRow, nColId, bScrolled);
1509 //Detect if we are already in a call to BrowseBox::GoToColumnId
1510 //but the attempt is impossible and we are simply recursing
1511 //into BrowseBox::GoToColumnId with the same impossible to
1512 //fulfill conditions
1513 if (m_aGotoStack.empty() || aAttempt != m_aGotoStack.top())
1514 {
1515 m_aGotoStack.push(aAttempt);
1516 CursorMoved();
1517 m_aGotoStack.pop();
1518 }
1519 }
1520 return true;
1521 }
1522 return true;
1523 }
1524
1525
GoToRowColumnId(long nRow,sal_uInt16 nColId)1526 bool BrowseBox::GoToRowColumnId( long nRow, sal_uInt16 nColId )
1527 {
1528
1529 // out of range?
1530 if ( nRow < 0 || nRow >= nRowCount )
1531 return false;
1532
1533 if (!bColumnCursor)
1534 return false;
1535
1536 // nothing to do ?
1537 if ( nRow == nCurRow && ( bMultiSelection || uRow.nSel == nRow ) &&
1538 nColId == nCurColId && IsFieldVisible(nCurRow, nColId, true))
1539 return true;
1540
1541 // allowed?
1542 if (!IsCursorMoveAllowed(nRow, nColId))
1543 return false;
1544
1545 DoHideCursor( "GoToRowColumnId" );
1546 bool bMoved = GoToRow(nRow, true) && GoToColumnId(nColId, true, true);
1547 DoShowCursor( "GoToRowColumnId" );
1548
1549 if (bMoved)
1550 CursorMoved();
1551
1552 return bMoved;
1553 }
1554
1555
SetNoSelection()1556 void BrowseBox::SetNoSelection()
1557 {
1558
1559 // is there no selection
1560 if ( ( !pColSel || !pColSel->GetSelectCount() ) &&
1561 ( ( !bMultiSelection && uRow.nSel == BROWSER_ENDOFSELECTION ) ||
1562 ( bMultiSelection && !uRow.pSel->GetSelectCount() ) ) )
1563 // nothing to do
1564 return;
1565
1566 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1567 ToggleSelection();
1568
1569 // unselect all
1570 if ( bMultiSelection )
1571 uRow.pSel->SelectAll(false);
1572 else
1573 uRow.nSel = BROWSER_ENDOFSELECTION;
1574 if ( pColSel )
1575 pColSel->SelectAll(false);
1576 if ( !bSelecting )
1577 Select();
1578 else
1579 bSelect = true;
1580
1581 // restore screen
1582 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1583
1584 if ( isAccessibleAlive() )
1585 {
1586 commitTableEvent(
1587 SELECTION_CHANGED,
1588 Any(),
1589 Any()
1590 );
1591 }
1592 }
1593
1594
SelectAll()1595 void BrowseBox::SelectAll()
1596 {
1597
1598 if ( !bMultiSelection )
1599 return;
1600
1601 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1602 ToggleSelection();
1603
1604 // select all rows
1605 if ( pColSel )
1606 pColSel->SelectAll(false);
1607 uRow.pSel->SelectAll();
1608
1609 // don't highlight handle column
1610 BrowserColumn *pFirstCol = mvCols[ 0 ].get();
1611 long nOfsX = pFirstCol->GetId() ? 0 : pFirstCol->Width();
1612
1613 // highlight the row selection
1614 if ( !bHideSelect )
1615 {
1616 tools::Rectangle aHighlightRect;
1617 sal_uInt16 nVisibleRows =
1618 static_cast<sal_uInt16>(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
1619 for ( long nRow = std::max<long>( nTopRow, uRow.pSel->FirstSelected() );
1620 nRow != BROWSER_ENDOFSELECTION && nRow < nTopRow + nVisibleRows;
1621 nRow = uRow.pSel->NextSelected() )
1622 aHighlightRect.Union( tools::Rectangle(
1623 Point( nOfsX, (nRow-nTopRow)*GetDataRowHeight() ),
1624 Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) ) );
1625 pDataWin->Invalidate( aHighlightRect );
1626 }
1627
1628 if ( !bSelecting )
1629 Select();
1630 else
1631 bSelect = true;
1632
1633 // restore screen
1634 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1635
1636 if ( !isAccessibleAlive() )
1637 return;
1638
1639 commitTableEvent(
1640 SELECTION_CHANGED,
1641 Any(),
1642 Any()
1643 );
1644 commitHeaderBarEvent(
1645 SELECTION_CHANGED,
1646 Any(),
1647 Any(),
1648 true
1649 ); // column header event
1650
1651 commitHeaderBarEvent(
1652 SELECTION_CHANGED,
1653 Any(),
1654 Any(),
1655 false
1656 ); // row header event
1657 }
1658
1659
SelectRow(long nRow,bool _bSelect,bool bExpand)1660 void BrowseBox::SelectRow( long nRow, bool _bSelect, bool bExpand )
1661 {
1662
1663 if ( !bMultiSelection )
1664 {
1665 // deselecting is impossible, selecting via cursor
1666 if ( _bSelect )
1667 GoToRow(nRow, false);
1668 return;
1669 }
1670
1671 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1672
1673 // remove old selection?
1674 if ( !bExpand || !bMultiSelection )
1675 {
1676 ToggleSelection();
1677 if ( bMultiSelection )
1678 uRow.pSel->SelectAll(false);
1679 else
1680 uRow.nSel = BROWSER_ENDOFSELECTION;
1681 if ( pColSel )
1682 pColSel->SelectAll(false);
1683 }
1684
1685 // set new selection
1686 if ( !bHideSelect
1687 && ( ( bMultiSelection
1688 && uRow.pSel->GetTotalRange().Max() >= nRow
1689 && uRow.pSel->Select( nRow, _bSelect )
1690 )
1691 || ( !bMultiSelection
1692 && ( uRow.nSel = nRow ) != BROWSER_ENDOFSELECTION )
1693 )
1694 )
1695 {
1696 // don't highlight handle column
1697 BrowserColumn *pFirstCol = mvCols[ 0 ].get();
1698 long nOfsX = pFirstCol->GetId() ? 0 : pFirstCol->Width();
1699
1700 // highlight only newly selected part
1701 tools::Rectangle aRect(
1702 Point( nOfsX, (nRow-nTopRow)*GetDataRowHeight() ),
1703 Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) );
1704 pDataWin->Invalidate( aRect );
1705 }
1706
1707 if ( !bSelecting )
1708 Select();
1709 else
1710 bSelect = true;
1711
1712 // restore screen
1713 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1714
1715 if ( !isAccessibleAlive() )
1716 return;
1717
1718 commitTableEvent(
1719 SELECTION_CHANGED,
1720 Any(),
1721 Any()
1722 );
1723 commitHeaderBarEvent(
1724 SELECTION_CHANGED,
1725 Any(),
1726 Any(),
1727 false
1728 ); // row header event
1729 }
1730
1731
GetSelectRowCount() const1732 long BrowseBox::GetSelectRowCount() const
1733 {
1734
1735 return bMultiSelection ? uRow.pSel->GetSelectCount() :
1736 uRow.nSel == BROWSER_ENDOFSELECTION ? 0 : 1;
1737 }
1738
1739
SelectColumnPos(sal_uInt16 nNewColPos,bool _bSelect,bool bMakeVisible)1740 void BrowseBox::SelectColumnPos( sal_uInt16 nNewColPos, bool _bSelect, bool bMakeVisible )
1741 {
1742
1743 if ( !bColumnCursor || nNewColPos == BROWSER_INVALIDID )
1744 return;
1745
1746 if ( !bMultiSelection )
1747 {
1748 if ( _bSelect )
1749 GoToColumnId( mvCols[ nNewColPos ]->GetId(), bMakeVisible );
1750 return;
1751 }
1752 else
1753 {
1754 if ( !GoToColumnId( mvCols[ nNewColPos ]->GetId(), bMakeVisible ) )
1755 return;
1756 }
1757
1758 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
1759 ToggleSelection();
1760 if ( bMultiSelection )
1761 uRow.pSel->SelectAll(false);
1762 else
1763 uRow.nSel = BROWSER_ENDOFSELECTION;
1764 pColSel->SelectAll(false);
1765
1766 if ( pColSel->Select( nNewColPos, _bSelect ) )
1767 {
1768 // GoToColumnId( mvCols->GetObject(nNewColPos)->GetId(), bMakeVisible );
1769
1770 // only highlight painted areas
1771 pDataWin->Update();
1772 tools::Rectangle aFieldRectPix( GetFieldRectPixel( nCurRow, nCurColId, false ) );
1773 tools::Rectangle aRect(
1774 Point( aFieldRectPix.Left() - MIN_COLUMNWIDTH, 0 ),
1775 Size( mvCols[ nNewColPos ]->Width(),
1776 pDataWin->GetOutputSizePixel().Height() ) );
1777 pDataWin->Invalidate( aRect );
1778 if ( !bSelecting )
1779 Select();
1780 else
1781 bSelect = true;
1782
1783 if ( isAccessibleAlive() )
1784 {
1785 commitTableEvent(
1786 SELECTION_CHANGED,
1787 Any(),
1788 Any()
1789 );
1790 commitHeaderBarEvent(
1791 SELECTION_CHANGED,
1792 Any(),
1793 Any(),
1794 true
1795 ); // column header event
1796 }
1797 }
1798
1799 // restore screen
1800 SAL_INFO("svtools", "BrowseBox::ShowCursor " << this );
1801 }
1802
1803
GetSelectColumnCount() const1804 sal_uInt16 BrowseBox::GetSelectColumnCount() const
1805 {
1806
1807 // while bAutoSelect (==!pColSel), 1 if any rows (yes rows!) else none
1808 return pColSel ? static_cast<sal_uInt16>(pColSel->GetSelectCount()) :
1809 nCurRow >= 0 ? 1 : 0;
1810 }
1811
1812
FirstSelectedColumn() const1813 long BrowseBox::FirstSelectedColumn( ) const
1814 {
1815 return pColSel ? pColSel->FirstSelected() : BROWSER_ENDOFSELECTION;
1816 }
1817
1818
FirstSelectedRow()1819 long BrowseBox::FirstSelectedRow()
1820 {
1821
1822 return bMultiSelection ? uRow.pSel->FirstSelected() : uRow.nSel;
1823 }
1824
1825
NextSelectedRow()1826 long BrowseBox::NextSelectedRow()
1827 {
1828
1829 return bMultiSelection ? uRow.pSel->NextSelected() : BROWSER_ENDOFSELECTION;
1830 }
1831
1832
LastSelectedRow()1833 long BrowseBox::LastSelectedRow()
1834 {
1835
1836 return bMultiSelection ? uRow.pSel->LastSelected() : uRow.nSel;
1837 }
1838
1839
IsRowSelected(long nRow) const1840 bool BrowseBox::IsRowSelected( long nRow ) const
1841 {
1842
1843 return bMultiSelection ? uRow.pSel->IsSelected(nRow) : nRow == uRow.nSel;
1844 }
1845
1846
IsColumnSelected(sal_uInt16 nColumnId) const1847 bool BrowseBox::IsColumnSelected( sal_uInt16 nColumnId ) const
1848 {
1849
1850 return pColSel ? pColSel->IsSelected( GetColumnPos(nColumnId) ) :
1851 nCurColId == nColumnId;
1852 }
1853
1854
MakeFieldVisible(long nRow,sal_uInt16 nColId)1855 void BrowseBox::MakeFieldVisible
1856 (
1857 long nRow, // line number of the field (starting with 0)
1858 sal_uInt16 nColId // column ID of the field
1859 )
1860
1861 /* [Description]
1862
1863 Makes visible the field described in 'nRow' and 'nColId' by scrolling
1864 accordingly.
1865
1866 */
1867
1868 {
1869 if (!pDataWin)
1870 return;
1871
1872 Size aTestSize = pDataWin->GetSizePixel();
1873
1874 if ( !bBootstrapped ||
1875 ( aTestSize.Width() == 0 && aTestSize.Height() == 0 ) )
1876 return;
1877
1878 // is it visible already?
1879 bool bVisible = IsFieldVisible( nRow, nColId, true/*bComplete*/ );
1880 if ( bVisible )
1881 return;
1882
1883 // calculate column position, field rectangle and painting area
1884 sal_uInt16 nColPos = GetColumnPos( nColId );
1885 tools::Rectangle aFieldRect = GetFieldRectPixel( nRow, nColId, false );
1886 tools::Rectangle aDataRect( Point(0, 0), pDataWin->GetSizePixel() );
1887
1888 // positioned outside on the left?
1889 if ( nColPos >= FrozenColCount() && nColPos < nFirstCol )
1890 // => scroll to the right
1891 ScrollColumns( nColPos - nFirstCol );
1892
1893 // while outside on the right
1894 while ( aDataRect.Right() < aFieldRect.Right() )
1895 {
1896 // => scroll to the left
1897 if ( ScrollColumns( 1 ) != 1 )
1898 // no more need to scroll
1899 break;
1900 aFieldRect = GetFieldRectPixel( nRow, nColId, false );
1901 }
1902
1903 // positioned outside above?
1904 if ( nRow < nTopRow )
1905 // scroll further to the bottom
1906 ScrollRows( nRow - nTopRow );
1907
1908 // positioned outside below?
1909 long nBottomRow = nTopRow + GetVisibleRows();
1910 // decrement nBottomRow to make it the number of the last visible line
1911 // (count starts with 0!).
1912 // Example: BrowseBox contains exactly one entry. nBottomRow := 0 + 1 - 1
1913 if( nBottomRow )
1914 nBottomRow--;
1915
1916 if ( nRow > nBottomRow )
1917 // scroll further to the top
1918 ScrollRows( nRow - nBottomRow );
1919 }
1920
1921
IsFieldVisible(long nRow,sal_uInt16 nColumnId,bool bCompletely) const1922 bool BrowseBox::IsFieldVisible( long nRow, sal_uInt16 nColumnId,
1923 bool bCompletely ) const
1924 {
1925
1926 // hidden by frozen column?
1927 sal_uInt16 nColPos = GetColumnPos( nColumnId );
1928 if ( nColPos >= FrozenColCount() && nColPos < nFirstCol )
1929 return false;
1930
1931 tools::Rectangle aRect( ImplFieldRectPixel( nRow, nColumnId ) );
1932 if ( aRect.IsEmpty() )
1933 return false;
1934
1935 // get the visible area
1936 tools::Rectangle aOutRect( Point(0, 0), pDataWin->GetOutputSizePixel() );
1937
1938 if ( bCompletely )
1939 // test if the field is completely visible
1940 return aOutRect.IsInside( aRect );
1941 else
1942 // test if the field is partly of completely visible
1943 return !aOutRect.Intersection( aRect ).IsEmpty();
1944 }
1945
1946
GetFieldRectPixel(long nRow,sal_uInt16 nColumnId,bool bRelToBrowser) const1947 tools::Rectangle BrowseBox::GetFieldRectPixel( long nRow, sal_uInt16 nColumnId,
1948 bool bRelToBrowser) const
1949 {
1950
1951 // get the rectangle relative to DataWin
1952 tools::Rectangle aRect( ImplFieldRectPixel( nRow, nColumnId ) );
1953 if ( aRect.IsEmpty() )
1954 return aRect;
1955
1956 // adjust relative to BrowseBox's output area
1957 Point aTopLeft( aRect.TopLeft() );
1958 if ( bRelToBrowser )
1959 {
1960 aTopLeft = pDataWin->OutputToScreenPixel( aTopLeft );
1961 aTopLeft = ScreenToOutputPixel( aTopLeft );
1962 }
1963
1964 return tools::Rectangle( aTopLeft, aRect.GetSize() );
1965 }
1966
1967
GetRowRectPixel(long nRow) const1968 tools::Rectangle BrowseBox::GetRowRectPixel( long nRow ) const
1969 {
1970
1971 // get the rectangle relative to DataWin
1972 tools::Rectangle aRect;
1973 if ( nTopRow > nRow )
1974 // row is above visible area
1975 return aRect;
1976 aRect = tools::Rectangle(
1977 Point( 0, GetDataRowHeight() * (nRow-nTopRow) ),
1978 Size( pDataWin->GetOutputSizePixel().Width(), GetDataRowHeight() ) );
1979 if ( aRect.TopLeft().Y() > pDataWin->GetOutputSizePixel().Height() )
1980 // row is below visible area
1981 return aRect;
1982
1983 // adjust relative to BrowseBox's output area
1984 Point aTopLeft( aRect.TopLeft() );
1985 aTopLeft = pDataWin->OutputToScreenPixel( aTopLeft );
1986 aTopLeft = ScreenToOutputPixel( aTopLeft );
1987
1988 return tools::Rectangle( aTopLeft, aRect.GetSize() );
1989 }
1990
1991
ImplFieldRectPixel(long nRow,sal_uInt16 nColumnId) const1992 tools::Rectangle BrowseBox::ImplFieldRectPixel( long nRow, sal_uInt16 nColumnId ) const
1993 {
1994
1995 // compute the X-coordinate relative to DataWin by accumulation
1996 long nColX = 0;
1997 sal_uInt16 nFrozenCols = FrozenColCount();
1998 size_t nCol;
1999 for ( nCol = 0;
2000 nCol < mvCols.size() && mvCols[ nCol ]->GetId() != nColumnId;
2001 ++nCol )
2002 if ( mvCols[ nCol ]->IsFrozen() || nCol >= nFirstCol )
2003 nColX += mvCols[ nCol ]->Width();
2004
2005 if ( nCol >= mvCols.size() || ( nCol >= nFrozenCols && nCol < nFirstCol ) )
2006 return tools::Rectangle();
2007
2008 // compute the Y-coordinate relative to DataWin
2009 long nRowY = GetDataRowHeight();
2010 if ( nRow != BROWSER_ENDOFSELECTION ) // #105497# OJ
2011 nRowY = ( nRow - nTopRow ) * GetDataRowHeight();
2012
2013 // assemble the Rectangle relative to DataWin
2014 return tools::Rectangle(
2015 Point( nColX + MIN_COLUMNWIDTH, nRowY ),
2016 Size( (mvCols[nCol]->Width() == LONG_MAX
2017 ? LONG_MAX - (nColX + MIN_COLUMNWIDTH) : mvCols[ nCol ]->Width() - 2*MIN_COLUMNWIDTH),
2018 GetDataRowHeight() - 1 ) );
2019 }
2020
2021
GetRowAtYPosPixel(long nY,bool bRelToBrowser) const2022 long BrowseBox::GetRowAtYPosPixel( long nY, bool bRelToBrowser ) const
2023 {
2024
2025 // compute the Y-coordinate
2026 if ( bRelToBrowser )
2027 {
2028 Point aDataTopLeft = pDataWin->OutputToScreenPixel( Point(0, 0) );
2029 Point aTopLeft = OutputToScreenPixel( Point(0, 0) );
2030 nY -= aDataTopLeft.Y() - aTopLeft.Y();
2031 }
2032
2033 // no row there (e.g. in the header)
2034 if ( nY < 0 || nY >= pDataWin->GetOutputSizePixel().Height() )
2035 return -1;
2036
2037 return nY / GetDataRowHeight() + nTopRow;
2038 }
2039
2040
GetFieldRect(sal_uInt16 nColumnId) const2041 tools::Rectangle BrowseBox::GetFieldRect( sal_uInt16 nColumnId ) const
2042 {
2043
2044 return GetFieldRectPixel( nCurRow, nColumnId );
2045 }
2046
2047
GetColumnAtXPosPixel(long nX) const2048 sal_uInt16 BrowseBox::GetColumnAtXPosPixel( long nX ) const
2049 {
2050
2051 // accumulate the widths of the visible columns
2052 long nColX = 0;
2053 for ( size_t nCol = 0; nCol < mvCols.size(); ++nCol )
2054 {
2055 BrowserColumn *pCol = mvCols[ nCol ].get();
2056 if ( pCol->IsFrozen() || nCol >= nFirstCol )
2057 nColX += pCol->Width();
2058
2059 if ( nColX > nX )
2060 return nCol;
2061 }
2062
2063 return BROWSER_INVALIDID;
2064 }
2065
ReserveControlArea(sal_uInt16 nWidth)2066 bool BrowseBox::ReserveControlArea(sal_uInt16 nWidth)
2067 {
2068 if (nWidth != nControlAreaWidth)
2069 {
2070 OSL_ENSURE(nWidth,"Control area of 0 is not allowed, Use USHRT_MAX instead!");
2071 nControlAreaWidth = nWidth;
2072 UpdateScrollbars();
2073 return true;
2074 }
2075 return false;
2076 }
2077
GetControlArea() const2078 tools::Rectangle BrowseBox::GetControlArea() const
2079 {
2080 auto nHeight = aHScroll->GetSizePixel().Height();
2081 return tools::Rectangle(
2082 Point( 0, GetOutputSizePixel().Height() - nHeight ),
2083 Size( GetOutputSizePixel().Width() - aHScroll->GetSizePixel().Width(),
2084 nHeight ) );
2085 }
2086
SetMode(BrowserMode nMode)2087 void BrowseBox::SetMode( BrowserMode nMode )
2088 {
2089
2090 pDataWin->bAutoHScroll = BrowserMode::AUTO_HSCROLL == ( nMode & BrowserMode::AUTO_HSCROLL );
2091 pDataWin->bAutoVScroll = BrowserMode::AUTO_VSCROLL == ( nMode & BrowserMode::AUTO_VSCROLL );
2092 pDataWin->bNoHScroll = BrowserMode::NO_HSCROLL == ( nMode & BrowserMode::NO_HSCROLL );
2093 pDataWin->bNoVScroll = BrowserMode::NO_VSCROLL == ( nMode & BrowserMode::NO_VSCROLL );
2094
2095 DBG_ASSERT( !( pDataWin->bAutoHScroll && pDataWin->bNoHScroll ),
2096 "BrowseBox::SetMode: AutoHScroll *and* NoHScroll?" );
2097 DBG_ASSERT( !( pDataWin->bAutoVScroll && pDataWin->bNoVScroll ),
2098 "BrowseBox::SetMode: AutoVScroll *and* NoVScroll?" );
2099 if ( pDataWin->bAutoHScroll )
2100 pDataWin->bNoHScroll = false;
2101 if ( pDataWin->bAutoVScroll )
2102 pDataWin->bNoVScroll = false;
2103
2104 if ( pDataWin->bNoHScroll )
2105 aHScroll->Hide();
2106
2107 nControlAreaWidth = USHRT_MAX;
2108
2109 long nOldRowSel = bMultiSelection ? uRow.pSel->FirstSelected() : uRow.nSel;
2110 MultiSelection *pOldRowSel = bMultiSelection ? uRow.pSel : nullptr;
2111
2112 pVScroll.disposeAndClear();
2113
2114 bMultiSelection = bool( nMode & BrowserMode::MULTISELECTION );
2115 bColumnCursor = bool( nMode & BrowserMode::COLUMNSELECTION );
2116 bKeepHighlight = bool( nMode & BrowserMode::KEEPHIGHLIGHT );
2117
2118 bHideSelect = ((nMode & BrowserMode::HIDESELECT) == BrowserMode::HIDESELECT);
2119 // default: do not hide the cursor at all (untaken scrolling and such)
2120 bHideCursor = TRISTATE_FALSE;
2121
2122 if ( BrowserMode::HIDECURSOR == ( nMode & BrowserMode::HIDECURSOR ) )
2123 {
2124 bHideCursor = TRISTATE_TRUE;
2125 }
2126
2127 m_bFocusOnlyCursor = ((nMode & BrowserMode::CURSOR_WO_FOCUS) == BrowserMode::NONE);
2128
2129 bHLines = ( nMode & BrowserMode::HLINES ) == BrowserMode::HLINES;
2130 bVLines = ( nMode & BrowserMode::VLINES ) == BrowserMode::VLINES;
2131
2132 WinBits nVScrollWinBits =
2133 WB_VSCROLL | ( ( nMode & BrowserMode::THUMBDRAGGING ) ? WB_DRAG : 0 );
2134 pVScroll = ( nMode & BrowserMode::TRACKING_TIPS ) == BrowserMode::TRACKING_TIPS
2135 ? VclPtr<BrowserScrollBar>::Create( this, nVScrollWinBits, pDataWin.get() )
2136 : VclPtr<ScrollBar>::Create( this, nVScrollWinBits );
2137 pVScroll->SetLineSize( 1 );
2138 pVScroll->SetPageSize(1);
2139 pVScroll->SetScrollHdl( LINK( this, BrowseBox, ScrollHdl ) );
2140
2141 pDataWin->bAutoSizeLastCol =
2142 BrowserMode::AUTOSIZE_LASTCOL == ( nMode & BrowserMode::AUTOSIZE_LASTCOL );
2143
2144 // create a headerbar. what happens, if a headerbar has to be created and
2145 // there already are columns?
2146 if ( BrowserMode::HEADERBAR_NEW == ( nMode & BrowserMode::HEADERBAR_NEW ) )
2147 {
2148 if (!pDataWin->pHeaderBar)
2149 pDataWin->pHeaderBar = CreateHeaderBar( this );
2150 }
2151 else
2152 {
2153 pDataWin->pHeaderBar.disposeAndClear();
2154 }
2155
2156 if ( bColumnCursor )
2157 {
2158 if (!pColSel)
2159 pColSel.reset(new MultiSelection);
2160 pColSel->SetTotalRange( Range( 0, mvCols.size()-1 ) );
2161 }
2162 else
2163 {
2164 pColSel.reset();
2165 }
2166
2167 if ( bMultiSelection )
2168 {
2169 if ( pOldRowSel )
2170 uRow.pSel = pOldRowSel;
2171 else
2172 uRow.pSel = new MultiSelection;
2173 }
2174 else
2175 {
2176 uRow.nSel = nOldRowSel;
2177 delete pOldRowSel;
2178 }
2179
2180 if ( bBootstrapped )
2181 {
2182 StateChanged( StateChangedType::InitShow );
2183 if ( bMultiSelection && !pOldRowSel &&
2184 nOldRowSel != BROWSER_ENDOFSELECTION )
2185 uRow.pSel->Select( nOldRowSel );
2186 }
2187
2188 if ( pDataWin )
2189 pDataWin->Invalidate();
2190
2191 // no cursor on handle column
2192 if ( nCurColId == HandleColumnId )
2193 nCurColId = GetColumnId( 1 );
2194
2195 m_nCurrentMode = nMode;
2196 }
2197
2198
VisibleRowsChanged(long,sal_uInt16)2199 void BrowseBox::VisibleRowsChanged( long, sal_uInt16 )
2200 {
2201
2202 // old behavior: automatically correct NumRows:
2203 if ( nRowCount < GetRowCount() )
2204 {
2205 RowInserted(nRowCount,GetRowCount() - nRowCount, false);
2206 }
2207 else if ( nRowCount > GetRowCount() )
2208 {
2209 RowRemoved(nRowCount-(nRowCount - GetRowCount()),nRowCount - GetRowCount(), false);
2210 }
2211 }
2212
2213
IsCursorMoveAllowed(long,sal_uInt16) const2214 bool BrowseBox::IsCursorMoveAllowed( long, sal_uInt16 ) const
2215
2216 /* [Description]
2217
2218 This virtual method is always called before the cursor is moved directly.
2219 By means of 'return false', we avoid doing this if e.g. a record
2220 contradicts any rules.
2221
2222 This method is not called, if the cursor movement results from removing or
2223 deleting a row/column (thus, in cases where only a "cursor correction" happens).
2224
2225 The base implementation currently always returns true.
2226 */
2227
2228 {
2229 return true;
2230 }
2231
2232
GetDataRowHeight() const2233 long BrowseBox::GetDataRowHeight() const
2234 {
2235 return CalcZoom(nDataRowHeight ? nDataRowHeight : ImpGetDataRowHeight());
2236 }
2237
2238
CreateHeaderBar(BrowseBox * pParent)2239 VclPtr<BrowserHeader> BrowseBox::CreateHeaderBar( BrowseBox* pParent )
2240 {
2241 VclPtr<BrowserHeader> pNewBar = VclPtr<BrowserHeader>::Create( pParent );
2242 pNewBar->SetStartDragHdl( LINK( this, BrowseBox, StartDragHdl ) );
2243 return pNewBar;
2244 }
2245
SetHeaderBar(BrowserHeader * pHeaderBar)2246 void BrowseBox::SetHeaderBar( BrowserHeader* pHeaderBar )
2247 {
2248 pDataWin->pHeaderBar.disposeAndClear();
2249 pDataWin->pHeaderBar = pHeaderBar;
2250 pDataWin->pHeaderBar->SetStartDragHdl( LINK( this, BrowseBox, StartDragHdl ) );
2251 }
2252
GetTitleHeight() const2253 long BrowseBox::GetTitleHeight() const
2254 {
2255 long nHeight;
2256 // ask the header bar for the text height (if possible), as the header bar's font is adjusted with
2257 // our (and the header's) zoom factor
2258 HeaderBar* pHeaderBar = pDataWin->pHeaderBar;
2259 if ( pHeaderBar )
2260 nHeight = pHeaderBar->GetTextHeight();
2261 else
2262 nHeight = GetTextHeight();
2263
2264 return nTitleLines ? nTitleLines * nHeight + 4 : 0;
2265 }
2266
CalcReverseZoom(long nVal)2267 long BrowseBox::CalcReverseZoom(long nVal)
2268 {
2269 if (IsZoom())
2270 {
2271 const Fraction& rZoom = GetZoom();
2272 double n = static_cast<double>(nVal);
2273 n *= static_cast<double>(rZoom.GetDenominator());
2274 if (!rZoom.GetNumerator())
2275 throw o3tl::divide_by_zero();
2276 n /= static_cast<double>(rZoom.GetNumerator());
2277 nVal = n>0 ? static_cast<long>(n + 0.5) : -static_cast<long>(-n + 0.5);
2278 }
2279
2280 return nVal;
2281 }
2282
CursorMoved()2283 void BrowseBox::CursorMoved()
2284 {
2285 // before implementing more here, please adjust the EditBrowseBox
2286
2287 if ( isAccessibleAlive() && HasFocus() )
2288 commitTableEvent(
2289 ACTIVE_DESCENDANT_CHANGED,
2290 makeAny( CreateAccessibleCell( GetCurRow(),GetColumnPos( GetCurColumnId() ) ) ),
2291 Any()
2292 );
2293 }
2294
LoseFocus()2295 void BrowseBox::LoseFocus()
2296 {
2297 SAL_INFO("svtools", "BrowseBox::LoseFocus " << this );
2298
2299 if ( bHasFocus )
2300 {
2301 SAL_INFO("svtools", "BrowseBox::HideCursor " << this );
2302 DoHideCursor( "LoseFocus" );
2303
2304 if ( !bKeepHighlight )
2305 {
2306 ToggleSelection();
2307 bSelectionIsVisible = false;
2308 }
2309
2310 bHasFocus = false;
2311 }
2312 Control::LoseFocus();
2313 }
2314
2315
GetFocus()2316 void BrowseBox::GetFocus()
2317 {
2318 SAL_INFO("svtools", "BrowseBox::GetFocus " << this );
2319
2320 if ( !bHasFocus )
2321 {
2322 if ( !bSelectionIsVisible )
2323 {
2324 bSelectionIsVisible = true;
2325 if ( bBootstrapped )
2326 ToggleSelection();
2327 }
2328
2329 bHasFocus = true;
2330 DoShowCursor( "GetFocus" );
2331 }
2332 Control::GetFocus();
2333 }
2334
2335
GetVisibleRows() const2336 sal_uInt16 BrowseBox::GetVisibleRows() const
2337 {
2338 return static_cast<sal_uInt16>((pDataWin->GetOutputSizePixel().Height() - 1 )/ GetDataRowHeight() + 1);
2339 }
2340
GetDataWindow() const2341 vcl::Window& BrowseBox::GetDataWindow() const
2342 {
2343 return *pDataWin;
2344 }
2345
2346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2347